/* -*- 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 Stream = (function() {
function constructor(arrayBuffer) {
this.bytes = Uint8Array(arrayBuffer);
return constructor;
})();
-var Obj = (function() {
- function constructor(type, value) {
- this.type = type;
- this.value = value;
+var Name = (function() {
+ function constructor(name) {
+ this.name = name;
}
constructor.prototype = {
};
- var types = [
- "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 is(value) {
- return this.type == is.type &&
- (typeof value == "undefined" || value == this.value);
- });
- constructor.prototype["is" + typeName].type = i;
- }
+ return constructor;
+})();
- constructor.prototype.isNum = function(value) {
- return this.isInt(value) || this.isReal(value);
+var Cmd = (function() {
+ function constructor(cmd) {
+ this.cmd = cmd;
}
- constructor.prototype.lookup = function(key) {
- function lookup(key) {
- if (!(this.value.contains(key)))
- return Obj.nullObj;
- return this.value.get(key);
- }
+
+ constructor.prototype = {
+ };
+
+ return constructor;
+})();
+
+var Dict = (function() {
+ function constructor() {
}
- constructor.prototype.lowerToJS = function() {
- if (this.isInt() || this.isReal() || this.isString()
- || this.isName() || this.isBool() || this.isNone()) {
- return this.value;
- } else if (this.isNull()) {
- return null;
- } else if (this.isArray()) {
- return this.value.map(function (e) { return e.lowerToJS(); });
- } else {
- return undefined;
+
+ 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 Ref = (function() {
+ function constructor(num, ref) {
+ this.num = num;
+ this.ref = ref;
}
- constructor.trueObj = new constructor(constructor.Bool, true);
- constructor.falseObj = new constructor(constructor.Bool, false);
- constructor.nullObj = new constructor(constructor.Null);
- constructor.errorObj = new constructor(constructor.Error);
- constructor.eofObj = new constructor(constructor.EOF);
+ constructor.prototype = {
+ };
return constructor;
})();
+function IsBool(v) {
+ return typeof v == "boolean";
+}
+
+function IsInt(v) {
+ return typeof v == "number" && ((v|0) == v);
+}
+
+function IsNum(v) {
+ return typeof v == "number";
+}
+
+function IsString(v) {
+ return typeof v == "string";
+}
+
+function IsNull(v) {
+ return v == null;
+}
+
+function IsName(v) {
+ return v instanceof Name;
+}
+
+function IsCmd(v, cmd) {
+ return v instanceof Cmd && (!cmd || v.cmd == cmd);
+}
+
+function IsDict(v) {
+ return v instanceof Dict;
+}
+
+function IsArray(v) {
+ return v instanceof Array;
+}
+
+function IsStream(v) {
+ return v instanceof Stream;
+}
+
+function IsRef(v) {
+ return v instanceof Ref;
+}
+
+var EOF = {};
+
+function IsEOF(v) {
+ return v == EOF;
+}
+
+var Error = {};
+
+function IsError(v) {
+ return v == Error;
+}
+
+var None = {};
+
+function IsNone(v) {
+ return v == None;
+}
+
var Lexer = (function() {
function constructor(stream) {
this.stream = stream;
} while (true);
var value = parseFloat(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);
+ return Error;
+ return value;
},
getString: function(ch) {
var n = 0;
}
} while (!done);
if (!str.length)
- return new Obj(Obj.EOF);
- return new Obj(Obj.String, str);
+ return EOF;
+ return str;
},
getName: function(ch) {
var str = "";
}
if (str.length > 128)
this.error("Warning: name token is longer than allowed by the specification");
- return new Obj(Obj.Name, str);
+ return new Name(str);
},
getHexString: function(ch) {
var str = "";
str += String.fromCharCode((x << 4) | x2);
}
}
- return new Obj(Obj.String, str);
+ return str;
},
getObj: function() {
// skip whitespace and comments
var ch;
while (true) {
if (!(ch = stream.getChar()))
- return new Obj(Object.EOF);
+ return EOF;
if (comment) {
if (ch == '\r' || ch == '\n')
comment = false;
// array punctuation
case '[':
case ']':
- return new Obj(Obj.Cmd, ch);
+ return new Cmd(ch);
// hex string or dict punctuation
case '<':
ch = stream.lookChar();
if (ch == '<') {
// dict punctuation
stream.getChar();
- return new Obj(Obj.Cmd, ch);
+ return new Cmd(ch);
}
return this.getHexString(ch);
// dict punctuation
ch = stream.lookChar();
if (ch == '>') {
stream.getChar();
- return new Obj(Obj.Cmd, ch);
+ return new Cmd(ch);
}
// fall through
case ')':
case '{':
case '}':
this.error("Illegal character");
- return Obj.errorObj;
+ return Error;
}
// command
str += ch;
}
if (str == "true")
- return Obj.trueObj;
+ return true;
if (str == "false")
- return Obj.falseObj;
+ return false;
if (str == "null")
- return Obj.nullObj;
- return new Obj(Obj.Cmd, str);
+ return null;
+ return new Cmd(str);
}
};
// of a dictionary, we need to reset
this.inlineImg = 0;
}
- } else if (this.buf2.isCmd("ID")) {
+ } else if (IsCmd(this.buf2, "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();
+ this.buf2 = (this.inlineImg > 0) ? null : this.lexer.getObj();
},
getObj: function() {
// refill buffer after inline image data
if (this.inlineImg == 2)
this.refill();
- 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())
+ if (IsCmd(this.buf1, "[")) { // array
+ var array = [];
+ while (!IsCmd(this.buf1, "]") && !IsEOF(this.buf1))
+ array.push(this.getObj());
+ if (IsEOF(this.buf1))
this.error("End of file inside array");
this.shift();
- return obj;
- } else if (this.buf1.isCmd("<<")) { // dictionary or stream
+ return array;
+ } else if (IsCmd(this.buf1, "<<")) { // dictionary or stream
this.shift();
- var obj = new Obj(Obj.Dict, new HashMap());
- while (!this.buf1.isCmd(">>") && !this.buf1.isEOF()) {
- if (!this.buf1.isName()) {
+ var dict = new Dict();
+ while (!IsCmd(this.buf1, ">>") && !IsEOF(this.buf1)) {
+ if (!IsName(this.buf1)) {
error("Dictionary key must be a name object");
shift();
} else {
- var key = buf1.value;
+ var key = buf1;
this.shift();
- if (this.buf1.isEOF() || this.buf1.isError())
+ if (IsEOF(this.buf1) || IsError(this.buf1))
break;
- obj.value.set(key, this.getObj());
+ dict.set(key, this.getObj());
}
}
- if (this.buf1.isEOF())
+ if (IsEOF(this.buf1))
error("End of file inside dictionary");
// stream objects are not allowed inside content streams or
// object streams
- if (this.allowStreams && this.buf2.isCmd("stream")) {
+ if (this.allowStreams && IsCmd(this.buf2, "stream")) {
return this.makeStream();
} else {
this.shift();
}
- return obj;
+ return dict;
- } else if (this.buf1.isInt()) { // indirect reference or integer
- var num = this.buf1.value;
+ } else if (IsInt(this.buf1)) { // indirect reference or integer
+ var num = this.buf1;
this.shift();
- if (this.buf1.isInt() && this.buf2.isCmd("R")) {
- var obj = new Obj(Obj.Ref, [num, this.buf1.value]);
+ if (IsInt(this.buf1) && IsCmd(this.buf2, "R")) {
+ var ref = new Ref(num, this.buf1);
this.shift();
this.shift();
- return obj;
+ return ref;
}
- return new Obj(Obj.Int, num);
- } else if (this.buf1.isString()) { // string
- var obj = this.decrypt(this.buf1);
+ return num;
+ } else if (IsString(this.buf1)) { // string
+ var str = this.decrypt(this.buf1);
this.shift();
- return obj;
+ return str;
}
// simple object
},
makeStream: function() {
// TODO
- return new Obj(Obj.Error);
+ return Error;
}
};
var obj2 = this.parser.getObj();
var obj3 = this.parser.getObj();
this.linDict = this.parser.getObj();
- if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && this.linDict.isDict()) {
+ if (IsInt(obj1) && IsInt(obj2) && IsCmd(obj3, "obj") && IsDict(this.linDict)) {
var obj = this.linDict.lookup("Linearized");
- if (!(obj.isNum() && obj.value > 0))
- this.linDict = Obj.nullObj;
+ if (!(IsNum(obj) && obj > 0))
+ this.linDict = null;
}
}
getInt: function(name) {
var linDict = this.linDict;
var obj;
- if (linDict.isDict() &&
- (obj = linDict.lookup(name)).isInt() &&
- obj.value > 0) {
+ if (IsDict(linDict) &&
+ IsInt(obj = linDict.lookup(name)) &&
+ obj > 0) {
return length;
}
error("'" + name + "' field in linearization table is invalid");
getHint: function(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;
+ if (IsDict(linDict) &&
+ IsArray(obj1 = linDict.lookup("H")) &&
+ obj1.length >= 2 &&
+ IsInt(obj2 = obj1[index]) &&
+ obj2 > 0) {
+ return obj2;
}
this.error("Hints table in linearization table is invalid");
return 0;
},
get length() {
- if (!this.linDict.isDict())
+ if (!IsDict(this.linDict))
return 0;
return this.getInt("L");
},
readXRefTable: function(parser) {
while (true) {
var obj;
- if ((obj = parser.getObj()).isCmd("trailer"))
+ if (IsCmd(obj = parser.getObj(), "trailer"))
break;
- if (!obj.isInt())
+ if (!IsInt(obj))
return false;
- var first = obj.value;
- if (!(obj = parser.getObj()).isInt())
+ var first = obj;
+ if (!IsInt(obj = parser.getObj()))
return false;
- var n = obj.value;
+ var n = obj;
if (first < 0 || n < 0 || (first + n) != ((first + n) | 0))
return false;
for (var i = first; i < first + n; ++i) {
var entry = {};
- if (!(obj = parser.getObj()).isInt())
+ if (!IsInt(obj = parser.getObj()))
return false;
- entry.offset = obj.value;
- if (!(obj = parser.getObj()).isInt())
+ entry.offset = obj;
+ if (!IsInt(obj = parser.getObj()))
return false;
- entry.gen = obj.value;
+ entry.gen = obj;
obj = parser.getObj();
- if (obj.isCmd("n")) {
+ if (IsCmd(obj, "n")) {
entry.uncompressed = true;
- } else if (obj.isCmd("f")) {
+ } else if (IsCmd(obj, "f")) {
entry.free = true;
} else {
return false;
var parser = new Parser(new Lexer(stream), false);
var obj = parser.getObj();
// parse an old-style xref table
- if (obj.isCmd("xref"))
+ if (IsCmd(obj, "xref"))
return this.readXRefTable(parser);
// parse an xref stream
- if (obj.isInt()) {
- if (!parser.getObj().isInt() ||
- !parser.getObj().isCmd("obj") ||
- !(obj = parser.getObj()).isStream()) {
+ if (IsInt(obj)) {
+ if (!IsInt(parser.getObj()) ||
+ !IsCmd(parser.getObj(), "obj") ||
+ !IsStream(obj = parser.getObj())) {
return false;
}
- return this.readXRefStream(obj.value);
+ return this.readXRefStream(obj);
}
return false;
}
var args = [ ];
var obj;
- while (!((obj = parser.getObj()).isEOF())) {
- if (obj.isCmd()) {
- var cmd = obj.value;
+ while (!IsEOF(obj = parser.getObj())) {
+ if (IsCmd(obj)) {
+ var cmd = obj.cmd;
if (!(cmd in CMD_TABLE))
this.error("Unknown command '"+ cmd +"'");
var op = CMD_TABLE[cmd];
- if (!this.typeCheck(op.params, args))
- this.error("Wrong arguments for command '"+ cmd +"'");
+ //if (!this.typeCheck(op.params, args))
+ //this.error("Wrong arguments for command '"+ cmd +"'");
- op.op.call(this,
- args.map(function (a) { return a.lowerToJS() }));
+ op.op.call(this, args);
args.length = 0;
} else if (MAX_ARGS == args.length) {
this.error("Too many arguments");
} else {
- args.push(obj);
+ args.push(IsName(obj) ? obj.name : obj);
}
}
return constructor;
})();
-function cmd(c) { return new Obj(Obj.Cmd, c); }
-function name(n) { return new Obj(Obj.Name, n); }
-function int(i) { return new Obj(Obj.Int, i); }
-function string(s) { return new Obj(Obj.String, s); }
-function eof() { return Obj.eofObj; }
-function array(a) { return new Obj(Obj.Array, a); }
-function real(r) { return new Obj(Obj.Real, r); }
+function cmd(c) { return new Cmd(c); }
+function name(n) { return new Name(n); }
+function int(i) { return i; }
+function string(s) { return s; }
+function eof() { return EOF; }
+function array(a) { return a; }
+function real(r) { return r; }
var tests = [
{ name: "Hello world",