1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.yaml.snakeyaml.reader;
18
19 import java.io.IOException;
20 import java.io.Reader;
21 import java.nio.charset.Charset;
22 import java.util.regex.Matcher;
23 import java.util.regex.Pattern;
24
25 import org.yaml.snakeyaml.error.Mark;
26 import org.yaml.snakeyaml.error.YAMLException;
27 import org.yaml.snakeyaml.scanner.Constant;
28
29
30
31
32 public class StreamReader {
33
34
35 final static Pattern NON_PRINTABLE = Pattern
36 .compile("[^\t\n\r\u0020-\u007E\u0085\u00A0-\uD7FF\uE000-\uFFFC]");
37 private String name;
38 private final Reader stream;
39 private int pointer = 0;
40 private boolean eof = true;
41 private String buffer;
42 private int index = 0;
43 private int line = 0;
44 private int column = 0;
45 private char[] data;
46
47 public StreamReader(String stream) {
48 this.name = "<string>";
49 this.buffer = "";
50 checkPrintable(stream);
51 this.buffer = stream + "\0";
52 this.stream = null;
53 this.eof = true;
54 this.data = null;
55 }
56
57 public StreamReader(Reader reader) {
58 this.name = "<reader>";
59 this.buffer = "";
60 this.stream = reader;
61 this.eof = false;
62 this.data = new char[1024];
63 this.update();
64 }
65
66 void checkPrintable(CharSequence data) {
67 Matcher em = NON_PRINTABLE.matcher(data);
68 if (em.find()) {
69 int position = this.index + this.buffer.length() - this.pointer + em.start();
70 throw new ReaderException(name, position, em.group().charAt(0),
71 "special characters are not allowed");
72 }
73 }
74
75
76
77
78
79
80
81
82
83
84
85
86
87 void checkPrintable(final char[] chars, final int begin, final int end) {
88 for (int i = begin; i < end; i++) {
89 final char c = chars[i];
90
91 if ((c >= '\u0020' && c <= '\u007E') || c == '\n' || c == '\r' || c == '\t'
92 || c == '\u0085' || (c >= '\u00A0' && c <= '\uD7FF')
93 || (c >= '\uE000' && c <= '\uFFFC')) {
94 continue;
95 }
96
97 int position = this.index + this.buffer.length() - this.pointer + i;
98 throw new ReaderException(name, position, c, "special characters are not allowed");
99 }
100 }
101
102 public Mark getMark() {
103 return new Mark(name, this.index, this.line, this.column, this.buffer, this.pointer);
104 }
105
106 public void forward() {
107 forward(1);
108 }
109
110
111
112
113
114
115 public void forward(int length) {
116 if (this.pointer + length + 1 >= this.buffer.length()) {
117 update();
118 }
119 char ch = 0;
120 for (int i = 0; i < length; i++) {
121 ch = this.buffer.charAt(this.pointer);
122 this.pointer++;
123 this.index++;
124 if (Constant.LINEBR.has(ch) || (ch == '\r' && buffer.charAt(pointer) != '\n')) {
125 this.line++;
126 this.column = 0;
127 } else if (ch != '\uFEFF') {
128 this.column++;
129 }
130 }
131 }
132
133 public char peek() {
134 return this.buffer.charAt(this.pointer);
135 }
136
137
138
139
140
141
142
143 public char peek(int index) {
144 if (this.pointer + index + 1 > this.buffer.length()) {
145 update();
146 }
147 return this.buffer.charAt(this.pointer + index);
148 }
149
150
151
152
153
154
155
156 public String prefix(int length) {
157 if (this.pointer + length >= this.buffer.length()) {
158 update();
159 }
160 if (this.pointer + length > this.buffer.length()) {
161 return this.buffer.substring(this.pointer);
162 }
163 return this.buffer.substring(this.pointer, this.pointer + length);
164 }
165
166
167
168
169 public String prefixForward(int length) {
170 final String prefix = prefix(length);
171 this.pointer += length;
172 this.index += length;
173
174 this.column += length;
175 return prefix;
176 }
177
178 private void update() {
179 if (!this.eof) {
180 this.buffer = buffer.substring(this.pointer);
181 this.pointer = 0;
182 try {
183 int converted = this.stream.read(data);
184 if (converted > 0) {
185
186
187
188
189
190
191 checkPrintable(data, 0, converted);
192 this.buffer = new StringBuilder(buffer.length() + converted).append(buffer)
193 .append(data, 0, converted).toString();
194 } else {
195 this.eof = true;
196 this.buffer += "\0";
197 }
198 } catch (IOException ioe) {
199 throw new YAMLException(ioe);
200 }
201 }
202 }
203
204 public int getColumn() {
205 return column;
206 }
207
208 public Charset getEncoding() {
209 return Charset.forName(((UnicodeReader) this.stream).getEncoding());
210 }
211
212 public int getIndex() {
213 return index;
214 }
215
216 public int getLine() {
217 return line;
218 }
219 }