diff --git a/pdf.js b/pdf.js index 943c4cea2..bfcaa48a3 100644 --- a/pdf.js +++ b/pdf.js @@ -1,36 +1,56 @@ -var EOF = -1; +/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- / +/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */ + +var HashMap = (function() { + function constructor() { + } + + constructor.prototype = { + get: function(key) { + return this["$" + key]; + }, + set: function(key, value) { + this["$" + key] = value; + }, + contains: function(key) { + return ("$" + key) in this; + } + }; + + return constructor; +})(); var Obj = (function() { function constructor(type, value) { - this.type = type; - this.value = value; + this.type = type; + this.value = value; } constructor.prototype = { }; var types = [ - "Bool", "Int", "Real", "String", "Name", "Null", - "Array", "Dict", "Stream", "Ref", - "Cmd", "Error", "EOF", "None" - ]; + "Bool", "Int", "Real", "String", "Name", "Null", + "Array", "Dict", "Stream", "Ref", + "Cmd", "Error", "EOF", "None" + ]; for (var i = 0; i < types.length; ++i) { - var typeName = types[i]; - constructor[typeName] = i; - constructor.prototype["is" + typeName] = - (function (value) { - return this.type == i && - (typeof value == "undefined" || value == this.value); - }); + var typeName = types[i]; + constructor[typeName] = i; + constructor.prototype["is" + typeName] = + (function (value) { + return this.type == i && + (typeof value == "undefined" || value == this.value); + }); } constructor.prototype.lookup = function(key) { - function lookup(key) { - if (!(this.value.contains(key))) - return Obj.nullObj; - return this.value.get(key); - } + function lookup(key) { + if (!(this.value.contains(key))) + return Obj.nullObj; + return this.value.get(key); + } } Object.freeze(constructor.trueObj = new constructor(constructor.Bool, true)); @@ -43,50 +63,33 @@ var Obj = (function() { return constructor; })(); -var HashMap = (function() { - function constructor() { - } - - constructor.prototype = { - get: function(key) { - return this["$" + key]; - }, - set: function(key, value) { - this["$" + key] = value; - }, - contains: function(key) { - return ("$" + key) in this; - } - }; - - return constructor; -})(); - var Lexer = (function() { + const EOF = -1; + function constructor(bytes) { - this.bytes = bytes; - this.pos = 0; + this.bytes = bytes; + this.pos = 0; } // A '1' in this array means the character is white space. A '1' or // '2' means the character ends a name or command. var specialChars = [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x + 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx ]; const MIN_INT = (1<<31) | 0; @@ -95,276 +98,275 @@ var Lexer = (function() { const MAX_UINT = ((1<<30) * 4) - 1; function ToHexDigit(ch) { - if (ch >= "0" && ch <= "9") - return ch - "0"; - ch = ch.toLowerCase(); - if (ch >= "a" && ch <= "f") - return ch - "a"; - return -1; + if (ch >= "0" && ch <= "9") + return ch - "0"; + ch = ch.toLowerCase(); + if (ch >= "a" && ch <= "f") + return ch - "a"; + return -1; } constructor.prototype = { - error: function(msg) { - }, - lookChar: function() { - var bytes = this.bytes; - if (this.pos >= bytes.length) - return EOF; - return String.fromCharCode(bytes[this.pos]); - }, - getChar: function() { - var ch = this.lookChar(); - this.pos++: - return ch; - }, - putBack(): function() { - this.pos--; - }, - skipChar(): function() { - this.pos++; - }, - getNumber: function(ch) { - var floating = false; - var str = ch; - do { - ch = this.getChar(); - if (ch == "." && !floating) { - str += ch; - floating = true; - } else if (ch == "-") { - // ignore minus signs in the middle of numbers to match - // Adobe's behavior - this.error("Badly formated number"); - } else if (ch >= "0" && ch <= "9") { - str += ch; - } else if (ch == "e" || ch == "E") { - floating = true; - } else { - // put back the last character, it doesn't belong to us - this.putBack(); - break; - } - } while (true); - var value = parseNumber(str); - if (isNaN(value)) - return Obj.errorObj; - if (floating) { - type = Obj.Floating; - } else { - if (value >= MIN_INT && value <= MAX_INT) - type = Obj.Int; - else if (value >= MAX_UINT && value <= MAX_UINT) - type = Obj.Uint; - else - return Obj.errorObj; - } - return new Obj(type, value); + error: function(msg) { }, - getString: function(ch) { - var n = 0; - var numParent = 1; - var done = false; - var str = ch; - do { - switch (ch = this.getChar()) { - case EOF: - this.error("Unterminated string"); - done = true; - break; - case '(': - ++numParen; - str += ch; - break; - case ')': - if (--numParen == 0) { - done = true; - } else { - str += ch; - } - break; - case '\\': - switch (ch = this.getChar()) { - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case '\\': - case '(': - case ')': - str += c; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - var x = ch - '0'; - ch = this.lookChar(); - if (ch >= '0' && ch <= '7') { - this.getChar(); - x = (x << 3) + (x - '0'); - ch = this.lookChar(); - if (ch >= '0' && ch <= '7') { - getChar(); - x = (x << 3) + (x - '0'); - } - } - str += String.fromCharCode(x); - break; - case '\r': - ch = this.lookChar(); - if (ch == '\n') { - this.getChar(); - } - break; - case '\n': - break; - case EOF: - this.error("Unterminated string"); - done = true; - break; - default: - str += ch; - break; - } - break; - - default: - str += ch; - break; - } - } while (!done); - if (!str.length) - return new Obj(Obj.EOF); - return new Obj(Obj.String, str); - }, - getName: function(ch) { - var str = ""; - while ((ch = this.lookChar()) != EOF && !specialChars[ch.toCharCode()]) { - this.getChar(); - if (ch == "#") { - ch = this.lookChar(); - var x = ToHexDigit(ch); - if (x != -1) { - this.getChar(); - var x2 = ToHexDigit(this.getChar()); - if (x2 == -1) - this.error("Illegal digit in hex char in name"); - str += String.fromCharCode((x << 4) | x2); - } else { - str += "#"; - str += ch; - } - } else { - str += ch; - } - } - if (str.length > 128) - this.error("Warning: name token is longer than allowed by the specification"); - return new Obj(Obj.Name, str); - }, - getHexString: function(ch) { - var str = ""; - while (1) { - ch = this.getChar(); - if (ch == '>') { - break; - } else if (ch == EOF) { - this.error("Unterminated hex string"); - break; - } else if (specialChars[ch.toCharCode()] != 1) { - var x, x2; - if (((x = ToHexDigit(ch)) == -1) || - ((x2 = ToHexDigit(this.getChar())) == -1)) { - error("Illegal character in hex string"); - break; - } - str += String.fromCharCode((x << 4) | x2); - } - } - return new Obj(Obj.String, str); - }, - getObj: function() { - // skip whitespace and comments - var comment = false; - while (true) { - var ch; - if ((ch = this.getChar()) == EOF) - return new Obj(Object.EOF); - if (comment) { - if (ch == '\r' || ch == '\n') - comment = false; - } else if (ch == '%') { - comment = true; - } else if (specialChars[ch.chatCodeAt(0)] != 1) { - break; - } - } - - // start reading token - switch (c) { - 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 '(': - return this.getString(ch); - case '/': - return this.getName(ch); - // array punctuation - case '[': - case ']': - return new Obj(Obj.Cmd, ch); - // hex string or dict punctuation - case '<': - ch = this.lookChar(); - if (ch == '<') { - // dict punctuation - this.getChar(); - return new Obj(Obj.Cmd, ch); - } - return this.getHexString(ch); - // dict punctuation - case '>': - ch = this.lookChar(); - if (ch == '>') { - this.getChar(); - return new Obj(Obj.Cmd, ch); - } + lookChar: function() { + var bytes = this.bytes; + if (this.pos >= bytes.length) + return EOF; + return String.fromCharCode(bytes[this.pos]); + }, + getChar: function() { + var ch = this.lookChar(); + this.pos++: + return ch; + }, + putBack(): function() { + this.pos--; + }, + skipChar(): function() { + this.pos++; + }, + getNumber: function(ch) { + var floating = false; + var str = ch; + do { + ch = this.getChar(); + if (ch == "." && !floating) { + str += ch; + floating = true; + } else if (ch == "-") { + // ignore minus signs in the middle of numbers to match + // Adobe's behavior + this.error("Badly formated number"); + } else if (ch >= "0" && ch <= "9") { + str += ch; + } else if (ch == "e" || ch == "E") { + floating = true; + } else { + // put back the last character, it doesn't belong to us + this.putBack(); + break; + } + } while (true); + var value = parseNumber(str); + if (isNaN(value)) + return Obj.errorObj; + if (floating) { + type = Obj.Floating; + } else { + if (value >= MIN_INT && value <= MAX_INT) + type = Obj.Int; + else if (value >= MAX_UINT && value <= MAX_UINT) + type = Obj.Uint; + else + return Obj.errorObj; + } + return new Obj(type, value); + }, + getString: function(ch) { + var n = 0; + var numParent = 1; + var done = false; + var str = ch; + do { + switch (ch = this.getChar()) { + case EOF: + this.error("Unterminated string"); + done = true; + break; + case '(': + ++numParen; + str += ch; + break; + case ')': + if (--numParen == 0) { + done = true; + } else { + str += ch; + } + break; + case '\\': + switch (ch = this.getChar()) { + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; + case 'b': + str += '\b'; + break; + case 'f': + str += '\f'; + break; + case '\\': + case '(': + case ')': + str += c; + break; + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + var x = ch - '0'; + ch = this.lookChar(); + if (ch >= '0' && ch <= '7') { + this.getChar(); + x = (x << 3) + (x - '0'); + ch = this.lookChar(); + if (ch >= '0' && ch <= '7') { + getChar(); + x = (x << 3) + (x - '0'); + } + } + str += String.fromCharCode(x); + break; + case '\r': + ch = this.lookChar(); + if (ch == '\n') { + this.getChar(); + } + break; + case '\n': + break; + case EOF: + this.error("Unterminated string"); + done = true; + break; + default: + str += ch; + break; + } + break; + default: + str += ch; + break; + } + } while (!done); + if (!str.length) + return new Obj(Obj.EOF); + return new Obj(Obj.String, str); + }, + getName: function(ch) { + var str = ""; + while ((ch = this.lookChar()) != EOF && !specialChars[ch.toCharCode()]) { + this.getChar(); + if (ch == "#") { + ch = this.lookChar(); + var x = ToHexDigit(ch); + if (x != -1) { + this.getChar(); + var x2 = ToHexDigit(this.getChar()); + if (x2 == -1) + this.error("Illegal digit in hex char in name"); + str += String.fromCharCode((x << 4) | x2); + } else { + str += "#"; + str += ch; + } + } else { + str += ch; + } + } + if (str.length > 128) + this.error("Warning: name token is longer than allowed by the specification"); + return new Obj(Obj.Name, str); + }, + getHexString: function(ch) { + var str = ""; + while (1) { + ch = this.getChar(); + if (ch == '>') { + break; + } else if (ch == EOF) { + this.error("Unterminated hex string"); + break; + } else if (specialChars[ch.toCharCode()] != 1) { + var x, x2; + if (((x = ToHexDigit(ch)) == -1) || + ((x2 = ToHexDigit(this.getChar())) == -1)) { + error("Illegal character in hex string"); + break; + } + str += String.fromCharCode((x << 4) | x2); + } + } + return new Obj(Obj.String, str); + }, + getObj: function() { + // skip whitespace and comments + var comment = false; + while (true) { + var ch; + if ((ch = this.getChar()) == EOF) + return new Obj(Object.EOF); + if (comment) { + if (ch == '\r' || ch == '\n') + comment = false; + } else if (ch == '%') { + comment = true; + } else if (specialChars[ch.chatCodeAt(0)] != 1) { + break; + } + } + + // start reading token + switch (c) { + 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 '(': + return this.getString(ch); + case '/': + return this.getName(ch); + // array punctuation + case '[': + case ']': + return new Obj(Obj.Cmd, ch); + // hex string or dict punctuation + case '<': + ch = this.lookChar(); + if (ch == '<') { + // dict punctuation + this.getChar(); + return new Obj(Obj.Cmd, ch); + } + return this.getHexString(ch); + // dict punctuation + case '>': + ch = this.lookChar(); + if (ch == '>') { + this.getChar(); + return new Obj(Obj.Cmd, ch); + } // fall through - case ')': - case '{': - case '}': - this.error("Illegal character"); - return Obj.errorObj; - } + case ')': + case '{': + case '}': + this.error("Illegal character"); + return Obj.errorObj; + } - // command - var str = ch; - while ((ch = this.lookChar()) != EOF && !specialChars[ch.toCharCode()]) { - getChar(); - if (str.length == 128) { - error("Command token too long"); - break; - } - str += ch; - } - if (str == "true") - return Obj.trueObj; - if (str == "false") - return Obj.falseObj; - if (str == "null") - return Obj.nullObj; - return new Obj(Obj.Cmd, str); - } + // command + var str = ch; + while ((ch = this.lookChar()) != EOF && !specialChars[ch.toCharCode()]) { + getChar(); + if (str.length == 128) { + error("Command token too long"); + break; + } + str += ch; + } + if (str == "true") + return Obj.trueObj; + if (str == "false") + return Obj.falseObj; + if (str == "null") + return Obj.nullObj; + return new Obj(Obj.Cmd, str); + } }; Object.freeze(constructor.prototype); @@ -374,108 +376,103 @@ var Lexer = (function() { var Parser = (function() { function constructor(lexer, allowStreams) { - this.lexer = lexer; - this.allowStreams = allowStreams; - this.inlineImg = 0; - this.refill(); + this.lexer = lexer; + this.allowStreams = allowStreams; + this.inlineImg = 0; + this.refill(); } constructor.prototype = { - refill: function() { - this.buf1 = lexer.getObj(); - this.buf2 = lexer.getObj(); - } - shift: function() { - if (this.inlineImg > 0) { - if (this.inlineImg < 2) { - this.inlineImg++; - } else { - // in a damaged content stream, if 'ID' shows up in the middle - // of a dictionary, we need to reset - this.inlineImg = 0; - } - } else if (this.buf2.isCmd("ID")) { - this.lexer.skipChar(); // skip char after 'ID' command - this.inlineImg = 1; - } - this.buf1 = this.buf2; - // don't buffer inline image data - this.buf2 = (this.inlineImg > 0) ? Obj.nullObj : this.lexer.getObj(); - }, - getObj: function() { - // refill buffer after inline image data - if (this.inlineImg == 2) - this.refill(); + refill: function() { + this.buf1 = lexer.getObj(); + this.buf2 = lexer.getObj(); + } + shift: function() { + if (this.inlineImg > 0) { + if (this.inlineImg < 2) { + this.inlineImg++; + } else { + // in a damaged content stream, if 'ID' shows up in the middle + // of a dictionary, we need to reset + this.inlineImg = 0; + } + } else if (this.buf2.isCmd("ID")) { + this.lexer.skipChar(); // skip char after 'ID' command + this.inlineImg = 1; + } + this.buf1 = this.buf2; + // don't buffer inline image data + this.buf2 = (this.inlineImg > 0) ? Obj.nullObj : this.lexer.getObj(); + }, + getObj: function() { + // refill buffer after inline image data + if (this.inlineImg == 2) + this.refill(); - // array - if (this.buf1.isCmd("[")) { - var obj = new Obj(Obj.Array, []); - while (!this.buf1.isCmd("]") && !this.buf1.isEOF()) - obj.value.push(this.getObj()); - if (this.buf1.isEOF()) - this.error("End of file inside array"); - this.shift(); - return obj; + if (this.buf1.isCmd("[")) { // array + var obj = new Obj(Obj.Array, []); + while (!this.buf1.isCmd("]") && !this.buf1.isEOF()) + obj.value.push(this.getObj()); + if (this.buf1.isEOF()) + this.error("End of file inside array"); + this.shift(); + return obj; + } else if (this.buf1.isCmd("<<")) { // dictionary or stream + this.shift(); + var obj = new Obj(Obj.Dict, new HashMap()); + while (!this.buf1.isCmd(">>") && !this.buf1.isEOF()) { + if (!this.buf1.isName()) { + error("Dictionary key must be a name object"); + shift(); + } else { + var key = buf1.value; + this.shift(); + if (this.buf1.isEOF() || this.buf1.isError()) + break; + obj.value.set(key, this.getObj()); + } + } + if (this.buf1.isEOF()) + error("End of file inside dictionary"); - // dictionary or stream - } else if (this.buf1.isCmd("<<")) { - this.shift(); - var obj = new Obj(Obj.Dict, new HashMap()); - while (!this.buf1.isCmd(">>") && !this.buf1.isEOF()) { - if (!this.buf1.isName()) { - error("Dictionary key must be a name object"); - shift(); - } else { - var key = buf1.value; - this.shift(); - if (this.buf1.isEOF() || this.buf1.isError()) - break; - obj.value.set(key, this.getObj()); - } - } - if (this.buf1.isEOF()) - error("End of file inside dictionary"); - // stream objects are not allowed inside content streams or - // object streams - if (this.allowStreams && this.buf2.isCmd("stream")) { - return this.makeStream(); - } else { - this.shift(); - } - return obj; + // stream objects are not allowed inside content streams or + // object streams + if (this.allowStreams && this.buf2.isCmd("stream")) { + return this.makeStream(); + } else { + this.shift(); + } + return obj; - // indirect reference or integer - } else if (this.buf1.isInt()) { - var num = this.buf1.value; - this.shift(); - if (this.buf1.isInt() && this.buf2.isCmd("R")) { - var obj = new Obj(Obj.Ref, [num, this.buf1.value]); - this.shift(); - this.shift(); - return obj; - } - return new Obj(Obj.Int, num); - - // string - } else if (this.buf1.isString()) { - var obj = this.decrypt(this.buf1); - this.shift(); - return obj; - } + } else if (this.buf1.isInt()) { // indirect reference or integer + var num = this.buf1.value; + this.shift(); + if (this.buf1.isInt() && this.buf2.isCmd("R")) { + var obj = new Obj(Obj.Ref, [num, this.buf1.value]); + this.shift(); + this.shift(); + return obj; + } + return new Obj(Obj.Int, num); + } else if (this.buf1.isString()) { // string + var obj = this.decrypt(this.buf1); + this.shift(); + return obj; + } - // simple object - var obj = this.buf1; - this.shift(); - return obj; - }, - decrypt: function(obj) { - // TODO - return obj; - }, - makeStream: function() { - // TODO - return new Obj(Obj.Error); - } + // simple object + var obj = this.buf1; + this.shift(); + return obj; + }, + decrypt: function(obj) { + // TODO + return obj; + }, + makeStream: function() { + // TODO + return new Obj(Obj.Error); + } }; Object.freeze(constructor.prototype); @@ -486,74 +483,74 @@ var Parser = (function() { var Linearization = (function () { function constructor(bytes) { - this.parser = new Parser(new Lexer(bytes), false); - var obj1 = this.parser.getObj(); - var obj2 = this.parser.getObj(); - var obj3 = this.parser.getObj(); - this.linDict = this.parser.getObj(); - if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) { - var obj = linDict.lookup("Linearized"); - if (!(obj.isNum() && obj.value > 0)) - this.linDict = Obj.nullObj; - } + this.parser = new Parser(new Lexer(bytes), false); + var obj1 = this.parser.getObj(); + var obj2 = this.parser.getObj(); + var obj3 = this.parser.getObj(); + this.linDict = this.parser.getObj(); + if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && linDict.isDict()) { + var obj = linDict.lookup("Linearized"); + if (!(obj.isNum() && obj.value > 0)) + this.linDict = Obj.nullObj; + } } constructor.prototype = { - function getInt(name) { - var linDict = this.linDict; - var obj; - if (!linDict.isDict() && - (obj = linDict.lookup(name)).isInt() && - obj.value > 0) { - return length; - } - error("'" + name + "' field in linearization table is invalid"); - return 0; - }, - function getHint(index) { - var linDict = this.linDict; - var obj1, obj2; - if (linDict.isDict() && - (obj1 = linDict.lookup("H")).isArray() && - obj1.value.length >= 2 && - (obj2 = obj1.value[index]).isInt() && - obj2.value > 0) { - return obj2.value; - } - this.error("Hints table in linearization table is invalid"); - return 0; - }, - get length() { - return this.getInt("L"); - }, - get hintsOffset() { - return this.getHint(0); - }, - get hintsLength() { - return this.getHint(1); - }, - get hintsOffset2() { - return this.getHint(2); - }, - get hintsLenth2() { - return this.getHint(3); - }, - get objectNumberFirst() { - return this.getInt("O"); - }, - get endFirst() { - return this.getInt("E"); - }, - get numPages() { - return this.getInt("N"); - }, - get mainXRefEntriesOffset() { - return this.getInt("T"); - }, - get pageFirst() { - return this.getInt("P"); - } - }; + function getInt(name) { + var linDict = this.linDict; + var obj; + if (!linDict.isDict() && + (obj = linDict.lookup(name)).isInt() && + obj.value > 0) { + return length; + } + error("'" + name + "' field in linearization table is invalid"); + return 0; + }, + function getHint(index) { + var linDict = this.linDict; + var obj1, obj2; + if (linDict.isDict() && + (obj1 = linDict.lookup("H")).isArray() && + obj1.value.length >= 2 && + (obj2 = obj1.value[index]).isInt() && + obj2.value > 0) { + return obj2.value; + } + this.error("Hints table in linearization table is invalid"); + return 0; + }, + get length() { + return this.getInt("L"); + }, + get hintsOffset() { + return this.getHint(0); + }, + get hintsLength() { + return this.getHint(1); + }, + get hintsOffset2() { + return this.getHint(2); + }, + get hintsLenth2() { + return this.getHint(3); + }, + get objectNumberFirst() { + return this.getInt("O"); + }, + get endFirst() { + return this.getInt("E"); + }, + get numPages() { + return this.getInt("N"); + }, + get mainXRefEntriesOffset() { + return this.getInt("T"); + }, + get pageFirst() { + return this.getInt("P"); + } + }; })(); var linearization; @@ -578,15 +575,15 @@ function checkHeader(arrayBuffer) { var skip = 0; var header = "%PDF-"; while (skip < headerSearchSize) { - for (var i = 0; i < header.length; ++i) - if (stream[skip+i] != header.charCodeAt(i)) - break; + for (var i = 0; i < header.length; ++i) + if (stream[skip+i] != header.charCodeAt(i)) + break; - // Found the header, trim off any garbage before it. - if (i == header.length) { - stream = new Uint8Array(arrayBuffer, skip); - return; - } + // Found the header, trim off any garbage before it. + if (i == header.length) { + stream = new Uint8Array(arrayBuffer, skip); + return; + } } // May not be a PDF file, continue anyway. @@ -595,5 +592,3 @@ function checkHeader(arrayBuffer) { function setup(arrayBuffer, ownerPassword, userPassword) { var ub = checkHeader(arrayBuffer); } - -}) \ No newline at end of file