Copyright (c) 2008, http://www.snakeyaml.org Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
/** * Copyright (c) 2008, http://www.snakeyaml.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
package org.yaml.snakeyaml.reader; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.Arrays; import org.yaml.snakeyaml.error.Mark; import org.yaml.snakeyaml.error.YAMLException; import org.yaml.snakeyaml.scanner.Constant;
Reader: checks if code points are in allowed range. Returns '\0' when end of data has been reached.
/** * Reader: checks if code points are in allowed range. Returns '\0' when end of * data has been reached. */
public class StreamReader { private String name; private final Reader stream;
Read data (as a moving window for input stream)
/** * Read data (as a moving window for input stream) */
private int[] dataWindow;
Real length of the data in dataWindow
/** * Real length of the data in dataWindow */
private int dataLength;
The variable points to the current position in the data array
/** * The variable points to the current position in the data array */
private int pointer = 0; private boolean eof;
index is only required to implement 1024 key length restriction http://yaml.org/spec/1.1/#simple key/ It must count code points, but it counts characters (to be fixed)
/** * index is only required to implement 1024 key length restriction * http://yaml.org/spec/1.1/#simple key/ * It must count code points, but it counts characters (to be fixed) */
private int index = 0; // in code points private int line = 0; private int column = 0; //in code points private char[] buffer; // temp buffer for one read operation (to avoid // creating the array in stack) private static final int BUFFER_SIZE = 1025; public StreamReader(String stream) { this(new StringReader(stream)); this.name = "'string'"; } public StreamReader(Reader reader) { this.name = "'reader'"; this.dataWindow = new int[0]; this.dataLength = 0; this.stream = reader; this.eof = false; this.buffer = new char[BUFFER_SIZE]; } public static boolean isPrintable(final String data) { final int length = data.length(); for (int offset = 0; offset < length; ) { final int codePoint = data.codePointAt(offset); if (!isPrintable(codePoint)) { return false; } offset += Character.charCount(codePoint); } return true; } public static boolean isPrintable(final int c) { return (c >= 0x20 && c <= 0x7E) || c == 0x9 || c == 0xA || c == 0xD || c == 0x85 || (c >= 0xA0 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF); } public Mark getMark() { return new Mark(name, this.index, this.line, this.column, this.dataWindow, this.pointer); } public void forward() { forward(1); }
read the next length characters and move the pointer. if the last character is high surrogate one more character will be read
Params:
  • length – amount of characters to move forward
/** * read the next length characters and move the pointer. * if the last character is high surrogate one more character will be read * * @param length amount of characters to move forward */
public void forward(int length) { for (int i = 0; i < length && ensureEnoughData(); i++) { int c = dataWindow[pointer++]; this.index++; if (Constant.LINEBR.has(c) || (c == '\r' && (ensureEnoughData() && dataWindow[pointer] != '\n'))) { this.line++; this.column = 0; } else if (c != 0xFEFF) { this.column++; } } } public int peek() { return (ensureEnoughData()) ? dataWindow[pointer] : '\0'; }
Peek the next index-th code point
Params:
  • index – to peek
Returns:the next index-th code point
/** * Peek the next index-th code point * * @param index to peek * @return the next index-th code point */
public int peek(int index) { return (ensureEnoughData(index)) ? dataWindow[pointer + index] : '\0'; }
peek the next length code points
Params:
  • length – amount of the characters to peek
Returns:the next length code points
/** * peek the next length code points * * @param length amount of the characters to peek * @return the next length code points */
public String prefix(int length) { if (length == 0) { return ""; } else if (ensureEnoughData(length)) { return new String(this.dataWindow, pointer, length); } else { return new String(this.dataWindow, pointer, Math.min(length, dataLength - pointer)); } }
prefix(length) immediately followed by forward(length)
Params:
  • length – amount of characters to get
Returns:the next length code points
/** * prefix(length) immediately followed by forward(length) * @param length amount of characters to get * @return the next length code points */
public String prefixForward(int length) { final String prefix = prefix(length); this.pointer += length; this.index += length; // prefix never contains new line characters this.column += length; return prefix; } private boolean ensureEnoughData() { return ensureEnoughData(0); } private boolean ensureEnoughData(int size) { if (!eof && pointer + size >= dataLength) { update(); } return (this.pointer + size) < dataLength; } private void update() { try { int read = stream.read(buffer, 0, BUFFER_SIZE - 1); if (read > 0) { int cpIndex = (dataLength - pointer); dataWindow = Arrays.copyOfRange(dataWindow, pointer, dataLength + read); if (Character.isHighSurrogate(buffer[read - 1])) { if (stream.read(buffer, read, 1) == -1) { eof = true; } else { read++; } } int nonPrintable = ' '; for (int i = 0; i < read; cpIndex++) { int codePoint = Character.codePointAt(buffer, i); dataWindow[cpIndex] = codePoint; if (isPrintable(codePoint)) { i += Character.charCount(codePoint); } else { nonPrintable = codePoint; i = read; } } dataLength = cpIndex; pointer = 0; if (nonPrintable != ' ') { throw new ReaderException(name, cpIndex - 1, nonPrintable, "special characters are not allowed"); } } else { eof = true; } } catch (IOException ioe) { throw new YAMLException(ioe); } } public int getColumn() { return column; }
Returns:current position as number (in characters) from the beginning of the stream
/** * @return current position as number (in characters) from the beginning of the stream */
public int getIndex() { return index; } public int getLine() { return line; } }