Coverage Report - org.yaml.snakeyaml.reader.StreamReader
 
Classes in this File Line Coverage Branch Coverage Complexity
StreamReader
100%
83/83
95%
46/48
2.647
 
 1  
 /**
 2  
  * Copyright (c) 2008-2012, http://www.snakeyaml.org
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *     http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.yaml.snakeyaml.reader;
 17  
 
 18  
 import java.io.IOException;
 19  
 import java.io.Reader;
 20  
 import java.nio.charset.Charset;
 21  
 import java.util.regex.Matcher;
 22  
 import java.util.regex.Pattern;
 23  
 
 24  
 import org.yaml.snakeyaml.error.Mark;
 25  
 import org.yaml.snakeyaml.error.YAMLException;
 26  
 import org.yaml.snakeyaml.scanner.Constant;
 27  
 
 28  
 /**
 29  
  * Reader: checks if characters are in allowed range, adds '\0' to the end.
 30  
  */
 31  
 public class StreamReader {
 32  1
     public final static Pattern NON_PRINTABLE = Pattern
 33  
             .compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFD]");
 34  
     private String name;
 35  
     private final Reader stream;
 36  133071
     private int pointer = 0;
 37  133071
     private boolean eof = true;
 38  
     private String buffer;
 39  133071
     private int index = 0;
 40  133071
     private int line = 0;
 41  133071
     private int column = 0;
 42  
     private char[] data;
 43  
 
 44  131598
     public StreamReader(String stream) {
 45  131598
         this.name = "'string'";
 46  131598
         this.buffer = ""; // to set length to 0
 47  131598
         checkPrintable(stream);
 48  131595
         this.buffer = stream + "\0";
 49  131595
         this.stream = null;
 50  131595
         this.eof = true;
 51  131595
         this.data = null;
 52  131595
     }
 53  
 
 54  1473
     public StreamReader(Reader reader) {
 55  1473
         this.name = "'reader'";
 56  1473
         this.buffer = "";
 57  1473
         this.stream = reader;
 58  1473
         this.eof = false;
 59  1473
         this.data = new char[1024];
 60  1473
         this.update();
 61  1471
     }
 62  
 
 63  
     void checkPrintable(CharSequence data) {
 64  131599
         Matcher em = NON_PRINTABLE.matcher(data);
 65  131599
         if (em.find()) {
 66  3
             int position = this.index + this.buffer.length() - this.pointer + em.start();
 67  3
             throw new ReaderException(name, position, em.group().charAt(0),
 68  
                     "special characters are not allowed");
 69  
         }
 70  131596
     }
 71  
 
 72  
     /**
 73  
      * Checks <code>chars</chars> for the non-printable characters.
 74  
      * 
 75  
      * @param chars
 76  
      *            the array where to search.
 77  
      * @param begin
 78  
      *            the beginning index, inclusive.
 79  
      * @param end
 80  
      *            the ending index, exclusive.
 81  
      * @throws ReaderException
 82  
      *             if <code>chars</code> contains non-printable character(s).
 83  
      */
 84  
     void checkPrintable(final char[] chars, final int begin, final int end) {
 85  1758125
         for (int i = begin; i < end; i++) {
 86  1691794
             final char c = chars[i];
 87  
 
 88  1691794
             if (isPrintable(c)) {
 89  1689683
                 continue;
 90  
             }
 91  
 
 92  2111
             int position = this.index + this.buffer.length() - this.pointer + i;
 93  2111
             throw new ReaderException(name, position, c, "special characters are not allowed");
 94  
         }
 95  66331
     }
 96  
 
 97  
     public static boolean isPrintable(final char c) {
 98  1691797
         return (c >= '\u0020' && c <= '\u007E') || c == '\n' || c == '\r' || c == '\t'
 99  
                 || c == '\u0085' || (c >= '\u00A0' && c <= '\uD7FF')
 100  
                 || (c >= '\uE000' && c <= '\uFFFD');
 101  
     }
 102  
 
 103  
     public Mark getMark() {
 104  2230947
         return new Mark(name, this.index, this.line, this.column, this.buffer, this.pointer);
 105  
     }
 106  
 
 107  
     public void forward() {
 108  1812243
         forward(1);
 109  1812240
     }
 110  
 
 111  
     /**
 112  
      * read the next length characters and move the pointer.
 113  
      * 
 114  
      * @param length
 115  
      */
 116  
     public void forward(int length) {
 117  2264374
         if (this.pointer + length + 1 >= this.buffer.length()) {
 118  134687
             update();
 119  
         }
 120  2264371
         char ch = 0;
 121  4906899
         for (int i = 0; i < length; i++) {
 122  2642528
             ch = this.buffer.charAt(this.pointer);
 123  2642528
             this.pointer++;
 124  2642528
             this.index++;
 125  2642528
             if (Constant.LINEBR.has(ch) || (ch == '\r' && buffer.charAt(pointer) != '\n')) {
 126  269745
                 this.line++;
 127  269745
                 this.column = 0;
 128  2372783
             } else if (ch != '\uFEFF') {
 129  2372783
                 this.column++;
 130  
             }
 131  
         }
 132  2264371
     }
 133  
 
 134  
     public char peek() {
 135  5730756
         return this.buffer.charAt(this.pointer);
 136  
     }
 137  
 
 138  
     /**
 139  
      * Peek the next index-th character
 140  
      * 
 141  
      * @param index
 142  
      * @return the next index-th character
 143  
      */
 144  
     public char peek(int index) {
 145  4548658
         if (this.pointer + index + 1 > this.buffer.length()) {
 146  497
             update();
 147  
         }
 148  4548658
         return this.buffer.charAt(this.pointer + index);
 149  
     }
 150  
 
 151  
     /**
 152  
      * peek the next length characters
 153  
      * 
 154  
      * @param length
 155  
      * @return the next length characters
 156  
      */
 157  
     public String prefix(int length) {
 158  826822
         if (this.pointer + length >= this.buffer.length()) {
 159  443
             update();
 160  
         }
 161  826822
         if (this.pointer + length > this.buffer.length()) {
 162  338
             return this.buffer.substring(this.pointer);
 163  
         }
 164  826484
         return this.buffer.substring(this.pointer, this.pointer + length);
 165  
     }
 166  
 
 167  
     /**
 168  
      * prefix(length) immediately followed by forward(length)
 169  
      */
 170  
     public String prefixForward(int length) {
 171  629293
         final String prefix = prefix(length);
 172  629293
         this.pointer += length;
 173  629293
         this.index += length;
 174  
         // prefix never contains new line characters
 175  629293
         this.column += length;
 176  629293
         return prefix;
 177  
     }
 178  
 
 179  
     private void update() {
 180  137100
         if (!this.eof) {
 181  4291
             this.buffer = buffer.substring(this.pointer);
 182  4291
             this.pointer = 0;
 183  
             try {
 184  4291
                 int converted = this.stream.read(data);
 185  4287
                 if (converted > 0) {
 186  
                     /*
 187  
                      * Let's create StringBuilder manually. Anyway str1 + str2
 188  
                      * generates new StringBuilder(str1).append(str2).toSting()
 189  
                      * Giving correct capacity to the constructor prevents
 190  
                      * unnecessary operations in appends.
 191  
                      */
 192  2906
                     checkPrintable(data, 0, converted);
 193  2905
                     this.buffer = new StringBuilder(buffer.length() + converted).append(buffer)
 194  
                             .append(data, 0, converted).toString();
 195  
                 } else {
 196  1381
                     this.eof = true;
 197  1381
                     this.buffer += "\0";
 198  
                 }
 199  4
             } catch (IOException ioe) {
 200  4
                 throw new YAMLException(ioe);
 201  4286
             }
 202  
         }
 203  137095
     }
 204  
 
 205  
     public int getColumn() {
 206  2145840
         return column;
 207  
     }
 208  
 
 209  
     public Charset getEncoding() {
 210  4
         return Charset.forName(((UnicodeReader) this.stream).getEncoding());
 211  
     }
 212  
 
 213  
     public int getIndex() {
 214  2041556
         return index;
 215  
     }
 216  
 
 217  
     public int getLine() {
 218  1234122
         return line;
 219  
     }
 220  
 }