diff --git a/src/chunked_stream.js b/src/chunked_stream.js index 625dbc18d..05add6a8c 100644 --- a/src/chunked_stream.js +++ b/src/chunked_stream.js @@ -114,7 +114,7 @@ var ChunkedStream = (function ChunkedStreamClosure() { getByte: function ChunkedStream_getByte() { var pos = this.pos; if (pos >= this.end) { - return null; + return -1; } this.ensureRange(pos, pos + 1); return this.bytes[this.pos++]; @@ -152,22 +152,6 @@ var ChunkedStream = (function ChunkedStreamClosure() { return this.bytes.subarray(begin, end); }, - lookChar: function ChunkedStream_lookChar() { - var pos = this.pos; - if (pos >= this.end) - return null; - this.ensureRange(pos, pos + 1); - return String.fromCharCode(this.bytes[pos]); - }, - - getChar: function ChunkedStream_getChar() { - var pos = this.pos; - if (pos >= this.end) - return null; - this.ensureRange(pos, pos + 1); - return String.fromCharCode(this.bytes[this.pos++]); - }, - skip: function ChunkedStream_skip(n) { if (!n) n = 1; diff --git a/src/core.js b/src/core.js index b795eb504..4b005361c 100644 --- a/src/core.js +++ b/src/core.js @@ -313,7 +313,7 @@ var PDFDocument = (function PDFDocumentClosure() { if (pos + limit > end) limit = end - pos; for (var n = 0; n < limit; ++n) - str += stream.getChar(); + str += String.fromCharCode(stream.getByte()); stream.pos = pos; var index = backwards ? str.lastIndexOf(needle) : str.indexOf(needle); if (index == -1) @@ -392,12 +392,12 @@ var PDFDocument = (function PDFDocumentClosure() { stream.skip(9); var ch; do { - ch = stream.getChar(); + ch = stream.getByte(); } while (Lexer.isSpace(ch)); var str = ''; - while ((ch - '0') <= 9) { - str += ch; - ch = stream.getChar(); + while (ch >= 0x20 && ch <= 0x39) { // < '9' + str += String.fromCharCode(ch); + ch = stream.getByte(); } startXRef = parseInt(str, 10); if (isNaN(startXRef)) @@ -426,11 +426,11 @@ var PDFDocument = (function PDFDocumentClosure() { // Reading file format version var MAX_VERSION_LENGTH = 12; var version = '', ch; - while ((ch = stream.getChar()) > ' ') { + while ((ch = stream.getByte()) > 0x20) { // SPACE if (version.length >= MAX_VERSION_LENGTH) { break; } - version += ch; + version += String.fromCharCode(ch); } // removing "%PDF-"-prefix this.pdfFormatVersion = version.substring(5); diff --git a/src/fonts.js b/src/fonts.js index 6ee5a2a73..846cbf3ee 100644 --- a/src/fonts.js +++ b/src/fonts.js @@ -3589,8 +3589,9 @@ var Font = (function FontClosure() { while (font.pos < end) { var stringLength = font.getByte(); var string = ''; - for (var i = 0; i < stringLength; ++i) - string += font.getChar(); + for (var i = 0; i < stringLength; ++i) { + string += String.fromCharCode(font.getByte()); + } customNames.push(string); } glyphNames = []; @@ -5202,10 +5203,10 @@ var Type1Parser = (function Type1ParserClosure() { } function isSpecial(c) { - return c === '/' || - c === '[' || c === ']' || - c === '{' || c === '}' || - c === '(' || c === ')'; + return c === 0x2F || // '/' + c === 0x5B || c === 0x5D || // '[', ']' + c === 0x7B || c === 0x7D || // '{', '}' + c === 0x28 || c === 0x29; // '(', ')' } function Type1Parser(stream, encrypted) { @@ -5213,6 +5214,7 @@ var Type1Parser = (function Type1ParserClosure() { stream = new Stream(decrypt(stream.getBytes(), EEXEC_ENCRYPT_KEY, 4)); } this.stream = stream; + this.nextChar(); } Type1Parser.prototype = { @@ -5248,36 +5250,39 @@ var Type1Parser = (function Type1ParserClosure() { return token === 'true' ? 1 : 0; }, + nextChar : function Type1_nextChar() { + return (this.currentChar = this.stream.getByte()); + }, + getToken: function Type1Parser_getToken() { // Eat whitespace and comments. var comment = false; - var ch; - var stream = this.stream; + var ch = this.currentChar; while (true) { - if ((ch = stream.lookChar()) === null) + if (ch === -1) { return null; + } if (comment) { - if (ch === '\x0a' || ch === '\x0d') { + if (ch === 0x0A || ch === 0x0D) { comment = false; } - } else if (ch === '%') { + } else if (ch === 0x25) { // '%' comment = true; } else if (!Lexer.isSpace(ch)) { break; } - stream.skip(); + ch = this.nextChar(); } if (isSpecial(ch)) { - stream.skip(); - return ch; + this.nextChar(); + return String.fromCharCode(ch); } var token = ''; do { - token += ch; - stream.skip(); - ch = stream.lookChar(); - } while (ch !== null && !Lexer.isSpace(ch) && !isSpecial(ch)); + token += String.fromCharCode(ch); + ch = this.nextChar(); + } while (ch >= 0 && !Lexer.isSpace(ch) && !isSpecial(ch)); return token; }, @@ -5324,12 +5329,13 @@ var Type1Parser = (function Type1ParserClosure() { var glyph = this.getToken(); var length = this.readInt(); this.getToken(); // read in 'RD' or '-|' - var data = stream.makeSubStream(stream.pos + 1, length); + var data = stream.makeSubStream(stream.pos, length); var lenIV = program.properties.privateData['lenIV']; var encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV); // Skip past the required space and binary data. - stream.skip(1 + length); + stream.skip(length); + this.nextChar(); token = this.getToken(); // read in 'ND' or '|-' if (token === 'noaccess') { this.getToken(); // read in 'def' @@ -5347,12 +5353,13 @@ var Type1Parser = (function Type1ParserClosure() { var index = this.readInt(); var length = this.readInt(); this.getToken(); // read in 'RD' or '-|' - var data = stream.makeSubStream(stream.pos + 1, length); + var data = stream.makeSubStream(stream.pos, length); var lenIV = program.properties.privateData['lenIV']; var encoded = decrypt(data.getBytes(), CHAR_STRS_ENCRYPT_KEY, lenIV); // Skip past the required space and binary data. - stream.skip(1 + length); + stream.skip(length); + this.nextChar(); token = this.getToken(); // read in 'NP' or '|' if (token === 'noaccess') { this.getToken(); // read in 'put' diff --git a/src/function.js b/src/function.js index 6d4627e99..0606bac46 100644 --- a/src/function.js +++ b/src/function.js @@ -816,53 +816,54 @@ var PostScriptToken = (function PostScriptTokenClosure() { var PostScriptLexer = (function PostScriptLexerClosure() { function PostScriptLexer(stream) { this.stream = stream; + this.nextChar(); } PostScriptLexer.prototype = { + nextChar: function PostScriptLexer_nextChar() { + return (this.currentChar = this.stream.getByte()); + }, getToken: function PostScriptLexer_getToken() { var s = ''; - var ch; var comment = false; - var stream = this.stream; + var ch = this.currentChar; // skip comments while (true) { - if (!(ch = stream.getChar())) + if (ch < 0) { return EOF; + } if (comment) { - if (ch == '\x0a' || ch == '\x0d') + if (ch === 0x0A || ch === 0x0D) { comment = false; - } else if (ch == '%') { + } + } else if (ch == 0x25) { // '%' comment = true; } else if (!Lexer.isSpace(ch)) { break; } + ch = this.nextChar(); } - switch (ch) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '+': case '-': case '.': + switch (ch | 0) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4' + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9' + case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.' return new PostScriptToken(PostScriptTokenTypes.NUMBER, - this.getNumber(ch)); - case '{': + this.getNumber()); + case 0x7B: // '{' + this.nextChar(); return PostScriptToken.LBRACE; - case '}': + case 0x7D: // '}' + this.nextChar(); return PostScriptToken.RBRACE; } // operator - var str = ch.toLowerCase(); - while (true) { - ch = stream.lookChar(); - if (ch === null) - break; - ch = ch.toLowerCase(); - if (ch >= 'a' && ch <= 'z') - str += ch; - else - break; - stream.skip(); + var str = String.fromCharCode(ch); + while ((ch = this.nextChar()) >= 0 && // and 'A'-'Z', 'a'-'z' + ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { + str += String.fromCharCode(ch); } - switch (str) { + switch (str.toLowerCase()) { case 'if': return PostScriptToken.IF; case 'ifelse': @@ -871,16 +872,16 @@ var PostScriptLexer = (function PostScriptLexerClosure() { return PostScriptToken.getOperator(str); } }, - getNumber: function PostScriptLexer_getNumber(ch) { - var str = ch; - var stream = this.stream; - while (true) { - ch = stream.lookChar(); - if ((ch >= '0' && ch <= '9') || ch == '-' || ch == '.') - str += ch; - else + getNumber: function PostScriptLexer_getNumber() { + var ch = this.currentChar; + var str = String.fromCharCode(ch); + while ((ch = this.nextChar()) >= 0) { + if ((ch >= 0x30 && ch <= 0x39) || // '0'-'9' + ch === 0x2D || ch === 0x2E) { // '-', '.' + str += String.fromCharCode(ch); + } else { break; - stream.skip(); + } } var value = parseFloat(str); if (isNaN(value)) diff --git a/src/parser.js b/src/parser.js index 9cdad12b0..f7e14675d 100644 --- a/src/parser.js +++ b/src/parser.js @@ -59,8 +59,6 @@ var Parser = (function ParserClosure() { if (isCmd(this.buf2, 'ID')) { this.buf1 = this.buf2; this.buf2 = null; - // skip byte after ID - this.lexer.skip(); } else { this.buf1 = this.buf2; this.buf2 = this.lexer.getObj(); @@ -155,9 +153,8 @@ var Parser = (function ParserClosure() { // searching for the /EI\s/ var state = 0, ch, i, ii; - while (state != 4 && - (ch = stream.getByte()) !== null && ch !== undefined) { - switch (ch) { + while (state != 4 && (ch = stream.getByte()) !== -1) { + switch (ch | 0) { case 0x20: case 0x0D: case 0x0A: @@ -165,7 +162,8 @@ var Parser = (function ParserClosure() { var followingBytes = stream.peekBytes(5); for (i = 0, ii = followingBytes.length; i < ii; i++) { ch = followingBytes[i]; - if (ch !== 0x0A && ch != 0x0D && (ch < 0x20 || ch > 0x7F)) { + if (ch !== 0x0A && ch !== 0x0D && (ch < 0x20 || ch > 0x7F)) { + // not a LF, CR, SPACE or any visible ASCII character state = 0; break; // some binary stuff found, resetting the state } @@ -206,7 +204,7 @@ var Parser = (function ParserClosure() { // get stream start position lexer.skipToNextLine(); - var pos = stream.pos; + var pos = stream.pos - 1; // get length var length = this.fetchIfRef(dict.get('Length')); @@ -215,6 +213,8 @@ var Parser = (function ParserClosure() { // skip over the stream data stream.pos = pos + length; + lexer.nextChar(); + this.shift(); // '>>' this.shift(); // 'stream' if (!isCmd(this.buf1, 'endstream')) { @@ -254,6 +254,8 @@ var Parser = (function ParserClosure() { error('Missing endstream'); } length = skipped; + + lexer.nextChar(); this.shift(); this.shift(); } @@ -344,6 +346,8 @@ var Parser = (function ParserClosure() { var Lexer = (function LexerClosure() { function Lexer(stream, knownCommands) { this.stream = stream; + this.nextChar(); + // The PDFs might have "glued" commands with other commands, operands or // literals, e.g. "q1". The knownCommands is a dictionary of the valid // commands and their prefixes. The prefixes are built the following way: @@ -355,7 +359,8 @@ var Lexer = (function LexerClosure() { } Lexer.isSpace = function Lexer_isSpace(ch) { - return ch == ' ' || ch == '\t' || ch == '\x0d' || ch == '\x0a'; + // space is one of the following characters: SPACE, TAB, CR, or LF + return ch === 0x20 || ch === 0x09 || ch === 0x0D || ch === 0x0A; }; // A '1' in this array means the character is white space. A '1' or @@ -380,36 +385,40 @@ var Lexer = (function LexerClosure() { ]; function toHexDigit(ch) { - if (ch >= '0' && ch <= '9') - return ch.charCodeAt(0) - 48; - ch = ch.toUpperCase(); - if (ch >= 'A' && ch <= 'F') - return ch.charCodeAt(0) - 55; + if (ch >= 0x30 && ch <= 0x39) { // '0'-'9' + return ch & 0x0F; + } + if ((ch >= 0x41 && ch <= 0x46) || (ch >= 0x61 && ch <= 0x66)) { + // 'A'-'F', 'a'-'f' + return (ch & 0x0F) + 9; + } return -1; } Lexer.prototype = { - getNumber: function Lexer_getNumber(ch) { + nextChar: function Lexer_nextChar() { + return (this.currentChar = this.stream.getByte()); + }, + getNumber: function Lexer_getNumber() { var floating = false; - var str = ch; - var stream = this.stream; - while ((ch = stream.lookChar())) { - if (ch == '.' && !floating) { - str += ch; + var ch = this.currentChar; + var str = String.fromCharCode(ch); + while ((ch = this.nextChar()) >= 0) { + if (ch === 0x2E && !floating) { // '.' + str += '.'; floating = true; - } else if (ch == '-') { + } else if (ch === 0x2D) { // '-' // ignore minus signs in the middle of numbers to match // Adobe's behavior warn('Badly formated number'); - } else if (ch >= '0' && ch <= '9') { - str += ch; - } else if (ch == 'e' || ch == 'E') { + } else if (ch >= 0x30 && ch <= 0x39) { // '0'-'9' + str += String.fromCharCode(ch); + } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e' floating = true; } else { // the last character doesn't belong to us break; } - stream.skip(); } var value = parseFloat(str); if (isNaN(value)) @@ -420,148 +429,150 @@ var Lexer = (function LexerClosure() { var numParen = 1; var done = false; var str = ''; - var stream = this.stream; - var ch; - do { - ch = stream.getChar(); - switch (ch) { - case null: - case undefined: + + var ch = this.nextChar(); + while (true) { + var charBuffered = false; + switch (ch | 0) { + case -1: warn('Unterminated string'); done = true; break; - case '(': + case 0x28: // '(' ++numParen; - str += ch; + str += '('; break; - case ')': + case 0x29: // ')' if (--numParen === 0) { + this.nextChar(); // consume strings ')' done = true; } else { - str += ch; + str += ')'; } break; - case '\\': - ch = stream.getChar(); + case 0x5C: // '\\' + ch = this.nextChar(); switch (ch) { - case null: - case undefined: + case -1: warn('Unterminated string'); done = true; break; - case 'n': + case 0x6E: // 'n' str += '\n'; break; - case 'r': + case 0x72: // 'r' str += '\r'; break; - case 't': + case 0x74: // 't' str += '\t'; break; - case 'b': + case 0x62: // 'b' str += '\b'; break; - case 'f': + case 0x66: // 'f' str += '\f'; break; - case '\\': - case '(': - case ')': - str += ch; + case 0x5C: // '\' + case 0x28: // '(' + case 0x29: // ')' + str += String.fromCharCode(ch); break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - var x = ch - '0'; - ch = stream.lookChar(); - if (ch >= '0' && ch <= '7') { - stream.skip(); - x = (x << 3) + (ch - '0'); - ch = stream.lookChar(); - if (ch >= '0' && ch <= '7') { - stream.skip(); - x = (x << 3) + (ch - '0'); + case 0x30: case 0x31: case 0x32: case 0x33: // '0'-'3' + case 0x34: case 0x35: case 0x36: case 0x37: // '4'-'7' + var x = ch & 0x0F; + ch = this.nextChar(); + charBuffered = true; + if (ch >= 0x30 && ch <= 0x37) { // '0'-'7' + x = (x << 3) + (ch & 0x0F); + ch = this.nextChar(); + if (ch >= 0x30 && ch <= 0x37) { // '0'-'7' + charBuffered = false; + x = (x << 3) + (ch & 0x0F); } } str += String.fromCharCode(x); break; - case '\r': - ch = stream.lookChar(); - if (ch == '\n') - stream.skip(); - break; - case '\n': + case 0x0A: case 0x0D: // LF, CR break; default: - str += ch; + str += String.fromCharCode(ch); break; } break; default: - str += ch; + str += String.fromCharCode(ch); break; } - } while (!done); + if (done) { + break; + } + if (!charBuffered) { + ch = this.nextChar(); + } + } return str; }, - getName: function Lexer_getName(ch) { - var str = ''; - var stream = this.stream; - while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) { - stream.skip(); - if (ch == '#') { - ch = stream.lookChar(); + getName: function Lexer_getName() { + var str = '', ch; + while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { + if (ch === 0x23) { // '#' + ch = this.nextChar(); var x = toHexDigit(ch); if (x != -1) { - stream.skip(); - var x2 = toHexDigit(stream.getChar()); + var x2 = toHexDigit(this.nextChar()); if (x2 == -1) error('Illegal digit in hex char in name: ' + x2); str += String.fromCharCode((x << 4) | x2); } else { str += '#'; - str += ch; + str += String.fromCharCode(ch); } } else { - str += ch; + str += String.fromCharCode(ch); } } - if (str.length > 128) + if (str.length > 128) { error('Warning: name token is longer than allowed by the spec: ' + str.length); + } return new Name(str); }, - getHexString: function Lexer_getHexString(ch) { + getHexString: function Lexer_getHexString() { var str = ''; - var stream = this.stream; + var ch = this.currentChar; var isFirstHex = true; var firstDigit; var secondDigit; while (true) { - ch = stream.getChar(); - if (!ch) { + if (ch < 0) { warn('Unterminated hex string'); break; - } else if (ch === '>') { + } else if (ch === 0x3E) { // '>' + this.nextChar(); break; - } else if (specialChars[ch.charCodeAt(0)] === 1) { + } else if (specialChars[ch] === 1) { + ch = this.nextChar(); continue; } else { if (isFirstHex) { firstDigit = toHexDigit(ch); if (firstDigit === -1) { warn('Ignoring invalid character "' + ch + '" in hex string'); + ch = this.nextChar(); continue; } } else { secondDigit = toHexDigit(ch); if (secondDigit === -1) { warn('Ignoring invalid character "' + ch + '" in hex string'); + ch = this.nextChar(); continue; } str += String.fromCharCode((firstDigit << 4) | secondDigit); } isFirstHex = !isFirstHex; + ch = this.nextChar(); } } return str; @@ -569,73 +580,81 @@ var Lexer = (function LexerClosure() { getObj: function Lexer_getObj() { // skip whitespace and comments var comment = false; - var stream = this.stream; - var ch; + var ch = this.currentChar; while (true) { - if (!(ch = stream.getChar())) + if (ch < 0) { return EOF; + } if (comment) { - if (ch == '\r' || ch == '\n') + if (ch === 0x0A || ch == 0x0D) // LF, CR comment = false; - } else if (ch == '%') { + } else if (ch === 0x25) { // '%' comment = true; - } else if (specialChars[ch.charCodeAt(0)] != 1) { + } else if (specialChars[ch] !== 1) { break; } + ch = this.nextChar(); } // start reading token - switch (ch) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '+': case '-': case '.': - return this.getNumber(ch); - case '(': + switch (ch | 0) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: // '0'-'4' + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: // '5'-'9' + case 0x2B: case 0x2D: case 0x2E: // '+', '-', '.' + return this.getNumber(); + case 0x28: // '(' return this.getString(); - case '/': - return this.getName(ch); + case 0x2F: // '/' + return this.getName(); // array punctuation - case '[': - case ']': - return Cmd.get(ch); + case 0x5B: // '[' + this.nextChar(); + return Cmd.get('['); + case 0x5D: // ']' + this.nextChar(); + return Cmd.get(']'); // hex string or dict punctuation - case '<': - ch = stream.lookChar(); - if (ch == '<') { + case 0x3C: // '<' + ch = this.nextChar(); + if (ch === 0x3C) { // dict punctuation - stream.skip(); + this.nextChar(); return Cmd.get('<<'); } - return this.getHexString(ch); + return this.getHexString(); // dict punctuation - case '>': - ch = stream.lookChar(); - if (ch == '>') { - stream.skip(); + case 0x3E: // '>' + ch = this.nextChar(); + if (ch === 0x3E) { + this.nextChar(); return Cmd.get('>>'); } - return Cmd.get(ch); - case '{': - case '}': - return Cmd.get(ch); - // fall through - case ')': + return Cmd.get('>'); + case 0x7B: // '{' + this.nextChar(); + return Cmd.get('{'); + case 0x7D: // '}' + this.nextChar(); + return Cmd.get('}'); + case 0x29: // ')' error('Illegal character: ' + ch); + break; } // command - var str = ch; + var str = String.fromCharCode(ch); var knownCommands = this.knownCommands; var knownCommandFound = knownCommands && (str in knownCommands); - while (!!(ch = stream.lookChar()) && !specialChars[ch.charCodeAt(0)]) { + while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) { // stop if known command is found and next character does not make // the str a command - if (knownCommandFound && !((str + ch) in knownCommands)) + var possibleCommand = str + String.fromCharCode(ch); + if (knownCommandFound && !(possibleCommand in knownCommands)) { break; - stream.skip(); + } if (str.length == 128) error('Command token too long: ' + str.length); - str += ch; + str = possibleCommand; knownCommandFound = knownCommands && (str in knownCommands); } if (str == 'true') @@ -648,19 +667,20 @@ var Lexer = (function LexerClosure() { }, skipToNextLine: function Lexer_skipToNextLine() { var stream = this.stream; - while (true) { - var ch = stream.getChar(); - if (!ch || ch == '\n') - return; - if (ch == '\r') { - if ((ch = stream.lookChar()) == '\n') - stream.skip(); - return; + var ch = this.currentChar; + while (ch >= 0) { + if (ch === 0x0D) { // CR + ch = this.nextChar(); + if (ch === 0x0A) { // LF + this.nextChar(); + } + break; + } else if (ch === 0x0A) { // LF + this.nextChar(); + break; } + ch = this.nextChar(); } - }, - skip: function Lexer_skip() { - this.stream.skip(); } }; diff --git a/src/stream.js b/src/stream.js index 77e6fe463..a691f8e27 100644 --- a/src/stream.js +++ b/src/stream.js @@ -37,7 +37,7 @@ var Stream = (function StreamClosure() { }, getByte: function Stream_getByte() { if (this.pos >= this.end) - return null; + return -1; return this.bytes[this.pos++]; }, // returns subarray of original buffer @@ -62,16 +62,6 @@ var Stream = (function StreamClosure() { this.pos -= bytes.length; return bytes; }, - lookChar: function Stream_lookChar() { - if (this.pos >= this.end) - return null; - return String.fromCharCode(this.bytes[this.pos]); - }, - getChar: function Stream_getChar() { - if (this.pos >= this.end) - return null; - return String.fromCharCode(this.bytes[this.pos++]); - }, skip: function Stream_skip(n) { if (!n) n = 1; @@ -133,7 +123,7 @@ var DecodeStream = (function DecodeStreamClosure() { var pos = this.pos; while (this.bufferLength <= pos) { if (this.eof) - return null; + return -1; this.readBlock(); } return this.buffer[this.pos++]; @@ -171,31 +161,13 @@ var DecodeStream = (function DecodeStreamClosure() { this.pos -= bytes.length; return bytes; }, - lookChar: function DecodeStream_lookChar() { - var pos = this.pos; - while (this.bufferLength <= pos) { - if (this.eof) - return null; - this.readBlock(); - } - return String.fromCharCode(this.buffer[this.pos]); - }, - getChar: function DecodeStream_getChar() { - var pos = this.pos; - while (this.bufferLength <= pos) { - if (this.eof) - return null; - this.readBlock(); - } - return String.fromCharCode(this.buffer[this.pos++]); - }, makeSubStream: function DecodeStream_makeSubStream(start, length, dict) { var end = start + length; while (this.bufferLength <= end && !this.eof) this.readBlock(); return new Stream(this.buffer, start, length, dict); }, - skip: function DecodeStream_skip(n) { + skip: function Stream_skip(n) { if (!n) n = 1; this.pos += n; @@ -882,9 +854,6 @@ var JpegStream = (function JpegStreamClosure() { JpegStream.prototype.getIR = function JpegStream_getIR() { return bytesToString(this.bytes); }; - JpegStream.prototype.getChar = function JpegStream_getChar() { - error('internal error: getChar is not valid on JpegStream'); - }; /** * Checks if the image can be decoded and displayed by the browser without any * further processing such as color space conversions. @@ -1012,9 +981,6 @@ var JpxStream = (function JpxStreamClosure() { this.bufferLength = data.length; this.eof = true; }; - JpxStream.prototype.getChar = function JpxStream_getChar() { - error('internal error: getChar is not valid on JpxStream'); - }; return JpxStream; })(); @@ -1057,9 +1023,6 @@ var Jbig2Stream = (function Jbig2StreamClosure() { this.bufferLength = dataLength; this.eof = true; }; - Jbig2Stream.prototype.getChar = function Jbig2Stream_getChar() { - error('internal error: getChar is not valid on Jbig2Stream'); - }; return Jbig2Stream; })(); @@ -1120,15 +1083,18 @@ var Ascii85Stream = (function Ascii85StreamClosure() { Ascii85Stream.prototype = Object.create(DecodeStream.prototype); Ascii85Stream.prototype.readBlock = function Ascii85Stream_readBlock() { - var tildaCode = '~'.charCodeAt(0); - var zCode = 'z'.charCodeAt(0); + var TILDA_CHAR = 0x7E; // '~' + var Z_LOWER_CHAR = 0x7A; // 'z' + var EOF = -1; + var str = this.str; var c = str.getByte(); - while (Lexer.isSpace(String.fromCharCode(c))) + while (Lexer.isSpace(c)) { c = str.getByte(); + } - if (!c || c === tildaCode) { + if (c === EOF || c === TILDA_CHAR) { this.eof = true; return; } @@ -1136,7 +1102,7 @@ var Ascii85Stream = (function Ascii85StreamClosure() { var bufferLength = this.bufferLength, buffer; // special code for z - if (c == zCode) { + if (c == Z_LOWER_CHAR) { buffer = this.ensureBuffer(bufferLength + 4); for (var i = 0; i < 4; ++i) buffer[bufferLength + i] = 0; @@ -1146,12 +1112,13 @@ var Ascii85Stream = (function Ascii85StreamClosure() { input[0] = c; for (var i = 1; i < 5; ++i) { c = str.getByte(); - while (Lexer.isSpace(String.fromCharCode(c))) + while (Lexer.isSpace(c)) { c = str.getByte(); + } input[i] = c; - if (!c || c == tildaCode) + if (c === EOF || c == TILDA_CHAR) break; } buffer = this.ensureBuffer(bufferLength + i - 1); @@ -2239,7 +2206,7 @@ var CCITTFaxStream = (function CCITTFaxStreamClosure() { CCITTFaxStream.prototype.lookBits = function CCITTFaxStream_lookBits(n) { var c; while (this.inputBits < n) { - if ((c = this.str.getByte()) === null || c === undefined) { + if ((c = this.str.getByte()) === -1) { if (this.inputBits === 0) return EOF; return ((this.inputBuf << (n - this.inputBits)) & @@ -2293,7 +2260,7 @@ var LZWStream = (function LZWStreamClosure() { var cachedData = this.cachedData; while (bitsCached < n) { var c = this.str.getByte(); - if (c === null || c === undefined) { + if (c === -1) { this.eof = true; return null; } diff --git a/src/util.js b/src/util.js index 82994170e..3f03fd62b 100644 --- a/src/util.js +++ b/src/util.js @@ -623,7 +623,7 @@ function isArray(v) { function isStream(v) { return typeof v == 'object' && v !== null && v !== undefined && - ('getChar' in v); + ('getBytes' in v); } function isArrayBuffer(v) { diff --git a/test/unit/parser_spec.js b/test/unit/parser_spec.js index 400b1940f..53aadb315 100644 --- a/test/unit/parser_spec.js +++ b/test/unit/parser_spec.js @@ -7,20 +7,20 @@ describe('parser', function() { describe('Lexer', function() { it('should stop parsing numbers at the end of stream', function() { - var input = new StringStream('1.234'); + var input = new StringStream('11.234'); var lexer = new Lexer(input); - var result = lexer.getNumber('1'); + var result = lexer.getNumber(); expect(result).toEqual(11.234); }); it('should stop parsing strings at the end of stream', function() { - var input = new StringStream('1$4)'); - input.getChar = function(super_getChar) { + var input = new StringStream('(1$4)'); + input.getByte = function(super_getByte) { // simulating end of file using null (see issue 2766) - var ch = super_getChar.call(input); - return ch == '$' ? null : ch; - }.bind(input, input.getChar); + var ch = super_getByte.call(input); + return ch === 0x24 /* '$' */ ? -1 : ch; + }.bind(input, input.getByte); var lexer = new Lexer(input); var result = lexer.getString(); @@ -31,9 +31,9 @@ describe('parser', function() { // '8 0 2 15 5 2 2 2 4 3 2 4' // should be parsed as // '80 21 55 22 24 32' - var input = new StringStream('7 0 2 15 5 2 2 2 4 3 2 4>'); + var input = new StringStream('<7 0 2 15 5 2 2 2 4 3 2 4>'); var lexer = new Lexer(input); - var result = lexer.getHexString('<'); + var result = lexer.getHexString(); expect(result).toEqual('p!U"$2'); });