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