return constructor;
})();
+var PredictorStream = (function() {
+ function constructor(stream, params) {
+ this.stream = stream;
+ this.predictor = params.get("Predictor") || 1;
+ if (this.predictor <= 1) {
+ return stream; // no prediction
+ }
+ if (params.has("EarlyChange")) {
+ error("EarlyChange predictor parameter is not supported");
+ }
+ this.colors = params.get("Colors") || 1;
+ this.bitsPerComponent = params.get("BitsPerComponent") || 8;
+ this.columns = params.get("Columns") || 1;
+ if (this.colors !== 1 || this.bitsPerComponent !== 8) {
+ error("Multi-color and multi-byte predictors are not supported");
+ }
+ if (this.predictor < 10 || this.predictor > 15) {
+ error("Unsupported predictor");
+ }
+ this.currentRow = new Uint8Array(this.columns);
+ this.pos = 0;
+ this.bufferLength = 0;
+ }
+
+ constructor.prototype = {
+ readRow : function() {
+ var lastRow = this.currentRow;
+ var predictor = this.stream.getByte();
+ var currentRow = this.stream.getBytes(this.columns), i;
+ switch (predictor) {
+ default:
+ error("Unsupported predictor");
+ break;
+ case 0:
+ break;
+ case 2:
+ for (i = 0; i < currentRow.length; ++i) {
+ currentRow[i] = (lastRow[i] + currentRow[i]) & 0xFF;
+ }
+ break;
+ }
+ this.pos = 0;
+ this.bufferLength = currentRow.length;
+ this.currentRow = currentRow;
+ },
+ getByte : function() {
+ if (this.pos >= this.bufferLength) {
+ this.readRow();
+ }
+ return this.currentRow[this.pos++];
+ },
+ getBytes : function(n) {
+ var i, bytes;
+ bytes = new Uint8Array(n);
+ for (i = 0; i < n; ++i) {
+ if (this.pos >= this.bufferLength) {
+ this.readRow();
+ }
+ bytes[i] = this.currentRow[this.pos++];
+ }
+ return bytes;
+ },
+ getChar : function() {
+ return String.formCharCode(this.getByte());
+ },
+ lookChar : function() {
+ if (this.pos >= this.bufferLength) {
+ this.readRow();
+ }
+ return String.formCharCode(this.currentRow[this.pos]);
+ },
+ skip : function(n) {
+ var i;
+ if (!n) {
+ n = 1;
+ }
+ while (n > this.bufferLength - this.pos) {
+ n -= this.bufferLength - this.pos;
+ this.readRow();
+ if (this.bufferLength === 0) break;
+ }
+ this.pos += n;
+ }
+ };
+
+ return constructor;
+})();
+
var DecryptStream = (function() {
function constructor(str, fileKey, encAlgorithm, keyLength) {
// TODO
this.encAlgorithm,
this.keyLength);
}
- return this.filter(stream, dict);
+ stream = this.filter(stream, dict);
+ stream.parameters = dict;
+ return stream;
},
filter: function(stream, dict) {
var filter = dict.get2("Filter", "F");
},
makeFilter: function(stream, name, params) {
if (name == "FlateDecode" || name == "Fl") {
- if (params)
- error("params not supported yet for FlateDecode");
+ if (params) {
+ return new PredictorStream(new FlateStream(stream), params);
+ }
return new FlateStream(stream);
} else {
error("filter '" + name + "' not supported yet");
this.stream = stream;
this.entries = [];
this.xrefstms = {};
- this.readXRef(startXRef);
+ var trailerDict = this.readXRef(startXRef);
// get the root dictionary (catalog) object
- if (!IsRef(this.root = this.trailerDict.get("Root")))
+ if (!IsRef(this.root = trailerDict.get("Root")))
error("Invalid root reference");
// prepare the XRef cache
error("Invalid XRef table");
// get the 'Prev' pointer
- var more = false;
+ var prev;
obj = dict.get("Prev");
if (IsInt(obj)) {
- this.prev = obj;
- more = true;
+ prev = obj;
} else if (IsRef(obj)) {
// certain buggy PDF generators generate "/Prev NNN 0 R" instead
// of "/Prev NNN"
- this.prev = obj.num;
- more = true;
+ prev = obj.num;
+ }
+ if (prev) {
+ this.readXRef(prev);
}
- this.trailerDict = dict;
// check for 'XRefStm' key
if (IsInt(obj = dict.get("XRefStm"))) {
this.xrefstms[pos] = 1; // avoid infinite recursion
this.readXRef(pos);
}
-
- return more;
- },
- readXRefStream: function(parser) {
- error("Invalid XRef stream");
+ return dict;
+ },
+ readXRefStream: function(stream) {
+ var streamParameters = stream.parameters;
+ var length = streamParameters.get("Length");
+ var byteWidths = streamParameters.get("W");
+ var range = streamParameters.get("Index");
+ if (!range) {
+ range = [0, streamParameters.get("Size")];
+ }
+ var i, j;
+ while (range.length > 0) {
+ var first = range[0], n = range[1];
+ if (!IsInt(first) || !IsInt(n)) {
+ error("Invalid XRef range fields");
+ }
+ var typeFieldWidth = byteWidths[0], offsetFieldWidth = byteWidths[1], generationFieldWidth = byteWidths[2];
+ if (!IsInt(typeFieldWidth) || !IsInt(offsetFieldWidth) || !IsInt(generationFieldWidth)) {
+ error("Invalid XRef entry fields length");
+ }
+ for (i = 0; i < n; ++i) {
+ var type = 0, offset = 0, generation = 0;
+ for (j = 0; j < typeFieldWidth; ++j) {
+ type = (type << 8) | stream.getByte();
+ }
+ for (j = 0; j < offsetFieldWidth; ++j) {
+ offset = (offset << 8) | stream.getByte();
+ }
+ for (j = 0; j < generationFieldWidth; ++j) {
+ generation = (generation << 8) | stream.getByte();
+ }
+ var entry = { offset: offset, gen: generation };
+ if (typeFieldWidth > 0) {
+ switch (type) {
+ case 0:
+ entry.free = true;
+ break;
+ case 1:
+ entry.uncompressed = true;
+ break;
+ case 2:
+ break;
+ default:
+ error("Invalid XRef entry type");
+ break;
+ }
+ }
+ if (!this.entries[first + i]) {
+ this.entries[first + i] = entry;
+ }
+ }
+ range.splice(0, 2);
+ }
+ var prev = streamParameters.get("Prev");
+ if (IsInt(prev)) {
+ this.readXRef(prev);
+ }
+ return streamParameters;
},
readXRef: function(startXRef) {
var stream = this.stream;
},
getPage: function(n) {
var linearization = this.linearization;
- assert(!linearization, "linearized page access not implemented");
+ // assert(!linearization, "linearized page access not implemented");
return this.catalog.getPage(n);
}
};