123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- 'use strict';
- var fs = require('fs');
- var $$ = require('./common');
- var _errors = require('./errors');
- // "\x20-\x7E" -> " -~" for JSLint
- var NON_PRINTABLE = new RegExp('[^\x09\x0A\x0D -~\x85\xA0-\uD7FF\uE000-\uFFFD]');
- // IE 7-8 hack. As we use ONLY strings in browsers as input stream, there's no
- // need for stream.slice() call and we can simply use stream.charAt() when we
- // are running on that shit...
- var getSingleChar = (undefined === ('a')[0])
- ? function (str, pos) { return str.charAt(pos); }
- : function (str, pos) { return str[pos]; };
- function ReaderError(name, position, character, encoding, reason) {
- _errors.YAMLError.apply(this);
- this.name = 'ReaderError';
- this.name = name;
- this.position = position;
- this.character = character;
- this.encoding = encoding;
- this.reason = reason;
- this.toString = function toString() {
- return 'unacceptable character ' + this.character + ': ' + this.reason +
- '\n in "' + this.name + '", position ' + this.position;
- };
- }
- $$.inherits(ReaderError, _errors.YAMLError);
- function Reader(stream) {
- this.name = '<unicode string>';
- this.stream = null;
- this.streamPointer = 0;
- this.eof = true;
- this.buffer = '';
- this.pointer = 0;
- this.rawBuffer = null;
- this.encoding = 'utf-8';
- this.index = 0;
- this.line = 0;
- this.column = 0;
- if ('string' === typeof stream) { // simple string
- this.name = '<unicode string>';
- this.checkPrintable(stream);
- this.buffer = stream + '\x00';
- } else if (Buffer.isBuffer(stream)) { // buffer
- this.name = '<buffer>';
- this.rawBuffer = stream;
- this.update(1);
- } else { // file descriptor
- this.name = '<file>';
- this.stream = stream;
- this.eof = false;
- this.updateRaw();
- this.update(1);
- }
- }
- Reader.prototype.peek = function peek(index) {
- var data;
- index = +index || 0;
- data = getSingleChar(this.buffer, this.pointer + index);
- if (undefined === data) {
- this.update(index + 1);
- data = getSingleChar(this.buffer, this.pointer + index);
- }
- return data;
- };
- Reader.prototype.prefix = function prefix(length) {
- length = +length || 1;
- if (this.pointer + length >= this.buffer.length) {
- this.update(length);
- }
- return this.buffer.slice(this.pointer, this.pointer + length);
- };
- Reader.prototype.forward = function forward(length) {
- var ch;
- // WARNING!!! length default is <int:1>, but method cn be called with
- // <int:0> which is absolutely NOT default length value, so
- // that's why we have ternary operator instead of lazy assign.
- length = (undefined !== length) ? (+length) : 1;
- if (this.pointer + length + 1 >= this.buffer.length) {
- this.update(length + 1);
- }
- while (length) {
- ch = this.buffer[this.pointer];
- this.pointer += 1;
- this.index += 1;
- if (0 <= '\n\x85\u2028\u2029'.indexOf(ch)
- || ('\r' === ch && '\n' !== this.buffer[this.pointer])) {
- this.line += 1;
- this.column = 0;
- } else if (ch !== '\uFEFF') {
- this.column += 1;
- }
- length -= 1;
- }
- };
- Reader.prototype.getMark = function getMark() {
- if (null === this.stream) {
- return new _errors.Mark(this.name, this.index, this.line, this.column,
- this.buffer, this.pointer);
- } else {
- return new _errors.Mark(this.name, this.index, this.line, this.column,
- null, null);
- }
- };
- Reader.prototype.checkPrintable = function checkPrintable(data) {
- var match = data.toString().match(NON_PRINTABLE), position;
- if (match) {
- position = this.index + this.buffer.length - this.pointer + match.index;
- throw new ReaderError(this.name, position, match[0],
- 'unicode', 'special characters are not allowed');
- }
- };
- Reader.prototype.update = function update(length) {
- var data;
- if (null === this.rawBuffer) {
- return;
- }
- this.buffer = this.buffer.slice(this.pointer);
- this.pointer = 0;
- while (this.buffer.length < length) {
- if (!this.eof) {
- this.updateRaw();
- }
- data = this.rawBuffer;
- this.checkPrintable(data);
- this.buffer += data;
- this.rawBuffer = this.rawBuffer.slice(data.length);
- if (this.eof) {
- this.buffer += '\x00';
- this.rawBuffer = null;
- break;
- }
- }
- };
- Reader.prototype.updateRaw = function updateRaw(size) {
- var data = new Buffer(+size || 4096), count, tmp;
- count = fs.readSync(this.stream, data, 0, data.length);
- if (null === this.rawBuffer) {
- this.rawBuffer = data.slice(0, count);
- } else {
- tmp = new Buffer(this.rawBuffer.length + count);
- this.rawBuffer.copy(tmp);
- data.copy(tmp, this.rawBuffer.length);
- this.rawBuffer = tmp;
- }
- this.streamPointer += count;
- if (!count || count < data.length) {
- this.eof = true;
- }
- };
- module.exports.Reader = Reader;
- ////////////////////////////////////////////////////////////////////////////////
- // vim:ts=2:sw=2
- ////////////////////////////////////////////////////////////////////////////////
|