|
|
@ -65,45 +65,46 @@ var Stream = (function() { |
|
|
|
this.dict = dict; |
|
|
|
this.dict = dict; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// required methods for a stream. if a particular stream does not
|
|
|
|
|
|
|
|
// implement these, an error should be thrown
|
|
|
|
constructor.prototype = { |
|
|
|
constructor.prototype = { |
|
|
|
get length() { |
|
|
|
get length() { |
|
|
|
return this.end - this.start; |
|
|
|
return this.end - this.start; |
|
|
|
}, |
|
|
|
}, |
|
|
|
getByte: function() { |
|
|
|
getByte: function() { |
|
|
|
var bytes = this.bytes; |
|
|
|
|
|
|
|
if (this.pos >= this.end) |
|
|
|
if (this.pos >= this.end) |
|
|
|
return -1; |
|
|
|
return; |
|
|
|
return bytes[this.pos++]; |
|
|
|
return this.bytes[this.pos++]; |
|
|
|
}, |
|
|
|
}, |
|
|
|
// returns subarray of original buffer
|
|
|
|
// returns subarray of original buffer
|
|
|
|
// should only be read
|
|
|
|
// should only be read
|
|
|
|
getBytes: function(length) { |
|
|
|
getBytes: function(length) { |
|
|
|
var bytes = this.bytes; |
|
|
|
var bytes = this.bytes; |
|
|
|
var pos = this.pos; |
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
var strEnd = this.end; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!length) |
|
|
|
|
|
|
|
return bytes.subarray(pos, strEnd); |
|
|
|
|
|
|
|
|
|
|
|
var end = pos + length; |
|
|
|
var end = pos + length; |
|
|
|
var strEnd = this.end; |
|
|
|
if (end > strEnd) |
|
|
|
if (!end || end > strEnd) |
|
|
|
|
|
|
|
end = strEnd; |
|
|
|
end = strEnd; |
|
|
|
|
|
|
|
|
|
|
|
this.pos = end; |
|
|
|
this.pos = end; |
|
|
|
return bytes.subarray(pos, end); |
|
|
|
return bytes.subarray(pos, end); |
|
|
|
}, |
|
|
|
}, |
|
|
|
lookChar: function() { |
|
|
|
lookChar: function() { |
|
|
|
var bytes = this.bytes; |
|
|
|
|
|
|
|
if (this.pos >= this.end) |
|
|
|
if (this.pos >= this.end) |
|
|
|
return; |
|
|
|
return; |
|
|
|
return String.fromCharCode(bytes[this.pos]); |
|
|
|
return String.fromCharCode(this.bytes[this.pos]); |
|
|
|
}, |
|
|
|
}, |
|
|
|
getChar: function() { |
|
|
|
getChar: function() { |
|
|
|
var ch = this.lookChar(); |
|
|
|
if (this.pos >= this.end) |
|
|
|
if (!ch) |
|
|
|
return; |
|
|
|
return ch; |
|
|
|
return String.fromCharCode(this.bytes[this.pos++]); |
|
|
|
this.pos++; |
|
|
|
|
|
|
|
return ch; |
|
|
|
|
|
|
|
}, |
|
|
|
}, |
|
|
|
skip: function(n) { |
|
|
|
skip: function(n) { |
|
|
|
if (!n && !IsNum(n)) |
|
|
|
if (!n) |
|
|
|
n = 1; |
|
|
|
n = 1; |
|
|
|
this.pos += n; |
|
|
|
this.pos += n; |
|
|
|
}, |
|
|
|
}, |
|
|
@ -135,6 +136,84 @@ var StringStream = (function() { |
|
|
|
return constructor; |
|
|
|
return constructor; |
|
|
|
})(); |
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// super class for the decoding streams
|
|
|
|
|
|
|
|
var DecodeStream = (function() { |
|
|
|
|
|
|
|
function constructor() { |
|
|
|
|
|
|
|
this.pos = 0; |
|
|
|
|
|
|
|
this.bufferLength = 0; |
|
|
|
|
|
|
|
this.eof = false; |
|
|
|
|
|
|
|
this.buffer = null; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
|
|
|
ensureBuffer: function(requested) { |
|
|
|
|
|
|
|
var buffer = this.buffer; |
|
|
|
|
|
|
|
var current = buffer ? buffer.byteLength : 0; |
|
|
|
|
|
|
|
if (requested < current) |
|
|
|
|
|
|
|
return buffer; |
|
|
|
|
|
|
|
var size = 512; |
|
|
|
|
|
|
|
while (size < requested) |
|
|
|
|
|
|
|
size <<= 1; |
|
|
|
|
|
|
|
var buffer2 = Uint8Array(size); |
|
|
|
|
|
|
|
for (var i = 0; i < current; ++i) |
|
|
|
|
|
|
|
buffer2[i] = buffer[i]; |
|
|
|
|
|
|
|
return this.buffer = buffer2; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getByte: function() { |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
|
|
|
|
if (this.eof) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
this.readBlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return this.buffer[this.pos++]; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getBytes: function(length) { |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.ensureBuffer(pos + length); |
|
|
|
|
|
|
|
while (!this.eof && this.bufferLength < pos + length) |
|
|
|
|
|
|
|
this.readBlock(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var end = pos + length; |
|
|
|
|
|
|
|
var bufEnd = this.bufferLength; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (end > bufEnd) |
|
|
|
|
|
|
|
end = bufEnd; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.pos = end; |
|
|
|
|
|
|
|
return this.buffer.subarray(pos, end) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
lookChar: function() { |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
|
|
|
|
if (this.eof) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
this.readBlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return String.fromCharCode(this.buffer[this.pos]); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getChar: function() { |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
|
|
|
|
if (this.eof) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
this.readBlock(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return String.fromCharCode(this.buffer[this.pos++]); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
skip: function(n) { |
|
|
|
|
|
|
|
if (!n) |
|
|
|
|
|
|
|
n = 1; |
|
|
|
|
|
|
|
this.pos += n; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var FlateStream = (function() { |
|
|
|
var FlateStream = (function() { |
|
|
|
const codeLenCodeMap = Uint32Array([ |
|
|
|
const codeLenCodeMap = Uint32Array([ |
|
|
|
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
|
|
|
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 |
|
|
@ -259,257 +338,195 @@ var FlateStream = (function() { |
|
|
|
|
|
|
|
|
|
|
|
this.bytes = bytes; |
|
|
|
this.bytes = bytes; |
|
|
|
this.bytesPos = bytesPos; |
|
|
|
this.bytesPos = bytesPos; |
|
|
|
this.eof = false; |
|
|
|
|
|
|
|
this.codeSize = 0; |
|
|
|
this.codeSize = 0; |
|
|
|
this.codeBuf = 0; |
|
|
|
this.codeBuf = 0; |
|
|
|
|
|
|
|
|
|
|
|
this.pos = 0; |
|
|
|
DecodeStream.call(this); |
|
|
|
this.bufferLength = 0; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
constructor.prototype = Object.create(DecodeStream.prototype); |
|
|
|
getBits: function(bits) { |
|
|
|
|
|
|
|
var codeSize = this.codeSize; |
|
|
|
|
|
|
|
var codeBuf = this.codeBuf; |
|
|
|
|
|
|
|
var bytes = this.bytes; |
|
|
|
|
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var b; |
|
|
|
constructor.prototype.getBits = function(bits) { |
|
|
|
while (codeSize < bits) { |
|
|
|
var codeSize = this.codeSize; |
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
var codeBuf = this.codeBuf; |
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
var bytes = this.bytes; |
|
|
|
codeBuf |= b << codeSize; |
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
codeSize += 8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
b = codeBuf & ((1 << bits) - 1); |
|
|
|
|
|
|
|
this.codeBuf = codeBuf >> bits; |
|
|
|
|
|
|
|
this.codeSize = codeSize -= bits; |
|
|
|
|
|
|
|
this.bytesPos = bytesPos; |
|
|
|
|
|
|
|
return b; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getCode: function(table) { |
|
|
|
|
|
|
|
var codes = table[0]; |
|
|
|
|
|
|
|
var maxLen = table[1]; |
|
|
|
|
|
|
|
var codeSize = this.codeSize; |
|
|
|
|
|
|
|
var codeBuf = this.codeBuf; |
|
|
|
|
|
|
|
var bytes = this.bytes; |
|
|
|
|
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (codeSize < maxLen) { |
|
|
|
var b; |
|
|
|
var b; |
|
|
|
while (codeSize < bits) { |
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
|
|
|
|
codeBuf |= (b << codeSize); |
|
|
|
|
|
|
|
codeSize += 8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var code = codes[codeBuf & ((1 << maxLen) - 1)]; |
|
|
|
|
|
|
|
var codeLen = code >> 16; |
|
|
|
|
|
|
|
var codeVal = code & 0xffff; |
|
|
|
|
|
|
|
if (codeSize == 0|| codeSize < codeLen || codeLen == 0) |
|
|
|
|
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
this.codeBuf = (codeBuf >> codeLen); |
|
|
|
codeBuf |= b << codeSize; |
|
|
|
this.codeSize = (codeSize - codeLen); |
|
|
|
codeSize += 8; |
|
|
|
this.bytesPos = bytesPos; |
|
|
|
} |
|
|
|
return codeVal; |
|
|
|
b = codeBuf & ((1 << bits) - 1); |
|
|
|
}, |
|
|
|
this.codeBuf = codeBuf >> bits; |
|
|
|
ensureBuffer: function(requested) { |
|
|
|
this.codeSize = codeSize -= bits; |
|
|
|
var buffer = this.buffer; |
|
|
|
this.bytesPos = bytesPos; |
|
|
|
var current = buffer ? buffer.length : 0; |
|
|
|
return b; |
|
|
|
if (requested < current) |
|
|
|
}; |
|
|
|
return buffer; |
|
|
|
constructor.prototype.getCode = function(table) { |
|
|
|
var size = 512; |
|
|
|
var codes = table[0]; |
|
|
|
while (size < requested) |
|
|
|
var maxLen = table[1]; |
|
|
|
size <<= 1; |
|
|
|
var codeSize = this.codeSize; |
|
|
|
var buffer2 = Uint8Array(size); |
|
|
|
var codeBuf = this.codeBuf; |
|
|
|
for (var i = 0; i < current; ++i) |
|
|
|
var bytes = this.bytes; |
|
|
|
buffer2[i] = buffer[i]; |
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
return this.buffer = buffer2; |
|
|
|
|
|
|
|
}, |
|
|
|
while (codeSize < maxLen) { |
|
|
|
getByte: function() { |
|
|
|
var b; |
|
|
|
var pos = this.pos; |
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
if (this.eof) |
|
|
|
codeBuf |= (b << codeSize); |
|
|
|
return; |
|
|
|
codeSize += 8; |
|
|
|
this.readBlock(); |
|
|
|
} |
|
|
|
} |
|
|
|
var code = codes[codeBuf & ((1 << maxLen) - 1)]; |
|
|
|
return this.buffer[this.pos++]; |
|
|
|
var codeLen = code >> 16; |
|
|
|
}, |
|
|
|
var codeVal = code & 0xffff; |
|
|
|
getBytes: function(length) { |
|
|
|
if (codeSize == 0|| codeSize < codeLen || codeLen == 0) |
|
|
|
var pos = this.pos; |
|
|
|
error("Bad encoding in flate stream"); |
|
|
|
|
|
|
|
this.codeBuf = (codeBuf >> codeLen); |
|
|
|
while (!this.eof && this.bufferLength < pos + length) |
|
|
|
this.codeSize = (codeSize - codeLen); |
|
|
|
this.readBlock(); |
|
|
|
this.bytesPos = bytesPos; |
|
|
|
|
|
|
|
return codeVal; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
constructor.prototype.generateHuffmanTable = function(lengths) { |
|
|
|
|
|
|
|
var n = lengths.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// find max code length
|
|
|
|
|
|
|
|
var maxLen = 0; |
|
|
|
|
|
|
|
for (var i = 0; i < n; ++i) { |
|
|
|
|
|
|
|
if (lengths[i] > maxLen) |
|
|
|
|
|
|
|
maxLen = lengths[i]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var end = pos + length; |
|
|
|
// build the table
|
|
|
|
var bufEnd = this.bufferLength; |
|
|
|
var size = 1 << maxLen; |
|
|
|
|
|
|
|
var codes = Uint32Array(size); |
|
|
|
|
|
|
|
for (var len = 1, code = 0, skip = 2; |
|
|
|
|
|
|
|
len <= maxLen; |
|
|
|
|
|
|
|
++len, code <<= 1, skip <<= 1) { |
|
|
|
|
|
|
|
for (var val = 0; val < n; ++val) { |
|
|
|
|
|
|
|
if (lengths[val] == len) { |
|
|
|
|
|
|
|
// bit-reverse the code
|
|
|
|
|
|
|
|
var code2 = 0; |
|
|
|
|
|
|
|
var t = code; |
|
|
|
|
|
|
|
for (var i = 0; i < len; ++i) { |
|
|
|
|
|
|
|
code2 = (code2 << 1) | (t & 1); |
|
|
|
|
|
|
|
t >>= 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (end > bufEnd) |
|
|
|
// fill the table entries
|
|
|
|
end = bufEnd; |
|
|
|
for (var i = code2; i < size; i += skip) |
|
|
|
|
|
|
|
codes[i] = (len << 16) | val; |
|
|
|
|
|
|
|
|
|
|
|
this.pos = end; |
|
|
|
++code; |
|
|
|
return this.buffer.subarray(pos, end) |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
lookChar: function() { |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
while (this.bufferLength <= pos) { |
|
|
|
|
|
|
|
if (this.eof) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
this.readBlock(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
return String.fromCharCode(this.buffer[pos]); |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
getChar: function() { |
|
|
|
|
|
|
|
var ch = this.lookChar(); |
|
|
|
|
|
|
|
// shouldnt matter what the position is if we get past the eof
|
|
|
|
|
|
|
|
// so no need to check if ch is undefined
|
|
|
|
|
|
|
|
this.pos++; |
|
|
|
|
|
|
|
return ch; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
skip: function(n) { |
|
|
|
|
|
|
|
if (!n) |
|
|
|
|
|
|
|
n = 1; |
|
|
|
|
|
|
|
this.pos += n; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
generateHuffmanTable: function(lengths) { |
|
|
|
|
|
|
|
var n = lengths.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// find max code length
|
|
|
|
|
|
|
|
var maxLen = 0; |
|
|
|
|
|
|
|
for (var i = 0; i < n; ++i) { |
|
|
|
|
|
|
|
if (lengths[i] > maxLen) |
|
|
|
|
|
|
|
maxLen = lengths[i]; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// build the table
|
|
|
|
|
|
|
|
var size = 1 << maxLen; |
|
|
|
|
|
|
|
var codes = Uint32Array(size); |
|
|
|
|
|
|
|
for (var len = 1, code = 0, skip = 2; |
|
|
|
|
|
|
|
len <= maxLen; |
|
|
|
|
|
|
|
++len, code <<= 1, skip <<= 1) { |
|
|
|
|
|
|
|
for (var val = 0; val < n; ++val) { |
|
|
|
|
|
|
|
if (lengths[val] == len) { |
|
|
|
|
|
|
|
// bit-reverse the code
|
|
|
|
|
|
|
|
var code2 = 0; |
|
|
|
|
|
|
|
var t = code; |
|
|
|
|
|
|
|
for (var i = 0; i < len; ++i) { |
|
|
|
|
|
|
|
code2 = (code2 << 1) | (t & 1); |
|
|
|
|
|
|
|
t >>= 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// fill the table entries
|
|
|
|
return [codes, maxLen]; |
|
|
|
for (var i = code2; i < size; i += skip) |
|
|
|
}; |
|
|
|
codes[i] = (len << 16) | val; |
|
|
|
constructor.prototype.readBlock = function() { |
|
|
|
|
|
|
|
function repeat(stream, array, len, offset, what) { |
|
|
|
|
|
|
|
var repeat = stream.getBits(len) + offset; |
|
|
|
|
|
|
|
while (repeat-- > 0) |
|
|
|
|
|
|
|
array[i++] = what; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
++code; |
|
|
|
var bytes = this.bytes; |
|
|
|
} |
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read block header
|
|
|
|
|
|
|
|
var hdr = this.getBits(3); |
|
|
|
|
|
|
|
if (hdr & 1) |
|
|
|
|
|
|
|
this.eof = true; |
|
|
|
|
|
|
|
hdr >>= 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var b; |
|
|
|
|
|
|
|
if (hdr == 0) { // uncompressed block
|
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
var blockLen = b; |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
blockLen |= (b << 8); |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
var check = b; |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
check |= (b << 8); |
|
|
|
|
|
|
|
if (check != (~this.blockLen & 0xffff)) |
|
|
|
|
|
|
|
error("Bad uncompressed block length in flate stream"); |
|
|
|
|
|
|
|
var bufferLength = this.bufferLength; |
|
|
|
|
|
|
|
var buffer = this.ensureBuffer(bufferLength + blockLen); |
|
|
|
|
|
|
|
this.bufferLength = bufferLength + blockLen; |
|
|
|
|
|
|
|
for (var n = bufferLength; n < blockLen; ++n) { |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") { |
|
|
|
|
|
|
|
this.eof = true; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
buffer[n] = b; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return [codes, maxLen]; |
|
|
|
var litCodeTable; |
|
|
|
}, |
|
|
|
var distCodeTable; |
|
|
|
readBlock: function() { |
|
|
|
if (hdr == 1) { // compressed block, fixed codes
|
|
|
|
function repeat(stream, array, len, offset, what) { |
|
|
|
litCodeTable = fixedLitCodeTab; |
|
|
|
var repeat = stream.getBits(len) + offset; |
|
|
|
distCodeTable = fixedDistCodeTab; |
|
|
|
while (repeat-- > 0) |
|
|
|
} else if (hdr == 2) { // compressed block, dynamic codes
|
|
|
|
array[i++] = what; |
|
|
|
var numLitCodes = this.getBits(5) + 257; |
|
|
|
|
|
|
|
var numDistCodes = this.getBits(5) + 1; |
|
|
|
|
|
|
|
var numCodeLenCodes = this.getBits(4) + 4; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// build the code lengths code table
|
|
|
|
|
|
|
|
var codeLenCodeLengths = Array(codeLenCodeMap.length); |
|
|
|
|
|
|
|
var i = 0; |
|
|
|
|
|
|
|
while (i < numCodeLenCodes) |
|
|
|
|
|
|
|
codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3); |
|
|
|
|
|
|
|
var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// build the literal and distance code tables
|
|
|
|
|
|
|
|
var len = 0; |
|
|
|
|
|
|
|
var i = 0; |
|
|
|
|
|
|
|
var codes = numLitCodes + numDistCodes; |
|
|
|
|
|
|
|
var codeLengths = new Array(codes); |
|
|
|
|
|
|
|
while (i < codes) { |
|
|
|
|
|
|
|
var code = this.getCode(codeLenCodeTab); |
|
|
|
|
|
|
|
if (code == 16) { |
|
|
|
|
|
|
|
repeat(this, codeLengths, 2, 3, len); |
|
|
|
|
|
|
|
} else if (code == 17) { |
|
|
|
|
|
|
|
repeat(this, codeLengths, 3, 3, len = 0); |
|
|
|
|
|
|
|
} else if (code == 18) { |
|
|
|
|
|
|
|
repeat(this, codeLengths, 7, 11, len = 0); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
codeLengths[i++] = len = code; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var bytes = this.bytes; |
|
|
|
litCodeTable = |
|
|
|
var bytesPos = this.bytesPos; |
|
|
|
this.generateHuffmanTable(codeLengths.slice(0, numLitCodes)); |
|
|
|
|
|
|
|
distCodeTable = |
|
|
|
// read block header
|
|
|
|
this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes)); |
|
|
|
var hdr = this.getBits(3); |
|
|
|
} else { |
|
|
|
if (hdr & 1) |
|
|
|
error("Unknown block type in flate stream"); |
|
|
|
this.eof = true; |
|
|
|
} |
|
|
|
hdr >>= 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var b; |
|
|
|
var pos = this.bufferLength; |
|
|
|
if (hdr == 0) { // uncompressed block
|
|
|
|
while (true) { |
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
var code1 = this.getCode(litCodeTable); |
|
|
|
error("Bad block header in flate stream"); |
|
|
|
if (code1 == 256) { |
|
|
|
var blockLen = b; |
|
|
|
this.bufferLength = pos; |
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
blockLen |= (b << 8); |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
var check = b; |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") |
|
|
|
|
|
|
|
error("Bad block header in flate stream"); |
|
|
|
|
|
|
|
check |= (b << 8); |
|
|
|
|
|
|
|
if (check != (~this.blockLen & 0xffff)) |
|
|
|
|
|
|
|
error("Bad uncompressed block length in flate stream"); |
|
|
|
|
|
|
|
var bufferLength = this.bufferLength; |
|
|
|
|
|
|
|
var buffer = this.ensureBuffer(bufferLength + blockLen); |
|
|
|
|
|
|
|
this.bufferLength = bufferLength + blockLen; |
|
|
|
|
|
|
|
for (var n = bufferLength; n < blockLen; ++n) { |
|
|
|
|
|
|
|
if (typeof (b = bytes[bytesPos++]) == "undefined") { |
|
|
|
|
|
|
|
this.eof = true; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
buffer[n] = b; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (code1 < 256) { |
|
|
|
var litCodeTable; |
|
|
|
var buffer = this.ensureBuffer(pos + 1); |
|
|
|
var distCodeTable; |
|
|
|
buffer[pos++] = code1; |
|
|
|
if (hdr == 1) { // compressed block, fixed codes
|
|
|
|
|
|
|
|
litCodeTable = fixedLitCodeTab; |
|
|
|
|
|
|
|
distCodeTable = fixedDistCodeTab; |
|
|
|
|
|
|
|
} else if (hdr == 2) { // compressed block, dynamic codes
|
|
|
|
|
|
|
|
var numLitCodes = this.getBits(5) + 257; |
|
|
|
|
|
|
|
var numDistCodes = this.getBits(5) + 1; |
|
|
|
|
|
|
|
var numCodeLenCodes = this.getBits(4) + 4; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// build the code lengths code table
|
|
|
|
|
|
|
|
var codeLenCodeLengths = Array(codeLenCodeMap.length); |
|
|
|
|
|
|
|
var i = 0; |
|
|
|
|
|
|
|
while (i < numCodeLenCodes) |
|
|
|
|
|
|
|
codeLenCodeLengths[codeLenCodeMap[i++]] = this.getBits(3); |
|
|
|
|
|
|
|
var codeLenCodeTab = this.generateHuffmanTable(codeLenCodeLengths); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// build the literal and distance code tables
|
|
|
|
|
|
|
|
var len = 0; |
|
|
|
|
|
|
|
var i = 0; |
|
|
|
|
|
|
|
var codes = numLitCodes + numDistCodes; |
|
|
|
|
|
|
|
var codeLengths = new Array(codes); |
|
|
|
|
|
|
|
while (i < codes) { |
|
|
|
|
|
|
|
var code = this.getCode(codeLenCodeTab); |
|
|
|
|
|
|
|
if (code == 16) { |
|
|
|
|
|
|
|
repeat(this, codeLengths, 2, 3, len); |
|
|
|
|
|
|
|
} else if (code == 17) { |
|
|
|
|
|
|
|
repeat(this, codeLengths, 3, 3, len = 0); |
|
|
|
|
|
|
|
} else if (code == 18) { |
|
|
|
|
|
|
|
repeat(this, codeLengths, 7, 11, len = 0); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
codeLengths[i++] = len = code; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
litCodeTable = this.generateHuffmanTable(codeLengths.slice(0, numLitCodes)); |
|
|
|
|
|
|
|
distCodeTable = this.generateHuffmanTable(codeLengths.slice(numLitCodes, codes)); |
|
|
|
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
error("Unknown block type in flate stream"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var pos = this.bufferLength; |
|
|
|
|
|
|
|
var buffer = this.buffer; |
|
|
|
|
|
|
|
var limit = buffer ? buffer.length : 0; |
|
|
|
|
|
|
|
while (true) { |
|
|
|
|
|
|
|
var code1 = this.getCode(litCodeTable); |
|
|
|
|
|
|
|
if (code1 < 256) { |
|
|
|
|
|
|
|
if (pos + 1 >= limit) { |
|
|
|
|
|
|
|
buffer = this.ensureBuffer(pos + 1); |
|
|
|
|
|
|
|
limit = buffer.length; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
buffer[pos++] = code1; |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (code1 == 256) { |
|
|
|
|
|
|
|
this.bufferLength = pos; |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
code1 -= 257; |
|
|
|
code1 -= 257; |
|
|
|
code1 = lengthDecode[code1]; |
|
|
|
code1 = lengthDecode[code1]; |
|
|
|
var code2 = code1 >> 16; |
|
|
|
var code2 = code1 >> 16; |
|
|
@ -522,10 +539,7 @@ var FlateStream = (function() { |
|
|
|
if (code2 > 0) |
|
|
|
if (code2 > 0) |
|
|
|
code2 = this.getBits(code2); |
|
|
|
code2 = this.getBits(code2); |
|
|
|
var dist = (code1 & 0xffff) + code2; |
|
|
|
var dist = (code1 & 0xffff) + code2; |
|
|
|
if (pos + len >= limit) { |
|
|
|
var buffer = this.ensureBuffer(pos + len); |
|
|
|
buffer = this.ensureBuffer(pos + len); |
|
|
|
|
|
|
|
limit = buffer.length; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (var k = 0; k < len; ++k, ++pos) |
|
|
|
for (var k = 0; k < len; ++k, ++pos) |
|
|
|
buffer[pos] = buffer[pos - dist]; |
|
|
|
buffer[pos] = buffer[pos - dist]; |
|
|
|
} |
|
|
|
} |
|
|
@ -534,30 +548,6 @@ var FlateStream = (function() { |
|
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
return constructor; |
|
|
|
})(); |
|
|
|
})(); |
|
|
|
// A JpegStream can't be read directly. We use the platform to render the underlying
|
|
|
|
|
|
|
|
// JPEG data for us.
|
|
|
|
|
|
|
|
var JpegStream = (function() { |
|
|
|
|
|
|
|
function constructor(bytes, dict) { |
|
|
|
|
|
|
|
// TODO: per poppler, some images may have "junk" before that need to be removed
|
|
|
|
|
|
|
|
this.dict = dict; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create DOM image
|
|
|
|
|
|
|
|
var img = new Image(); |
|
|
|
|
|
|
|
img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes)); |
|
|
|
|
|
|
|
this.domImage = img; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
|
|
|
getImage: function() { |
|
|
|
|
|
|
|
return this.domImage; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getChar: function() { |
|
|
|
|
|
|
|
error("internal error: getChar is not valid on JpegStream"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var PredictorStream = (function() { |
|
|
|
var PredictorStream = (function() { |
|
|
|
function constructor(stream, params) { |
|
|
|
function constructor(stream, params) { |
|
|
@ -569,9 +559,9 @@ var PredictorStream = (function() { |
|
|
|
error("Unsupported predictor"); |
|
|
|
error("Unsupported predictor"); |
|
|
|
|
|
|
|
|
|
|
|
if (predictor === 2) |
|
|
|
if (predictor === 2) |
|
|
|
this.readRow = this.readRowTiff; |
|
|
|
this.readBlock = this.readBlockTiff; |
|
|
|
else |
|
|
|
else |
|
|
|
this.readRow = this.readRowPng; |
|
|
|
this.readBlock = this.readBlockPng; |
|
|
|
|
|
|
|
|
|
|
|
this.stream = stream; |
|
|
|
this.stream = stream; |
|
|
|
this.dict = stream.dict; |
|
|
|
this.dict = stream.dict; |
|
|
@ -584,170 +574,181 @@ var PredictorStream = (function() { |
|
|
|
|
|
|
|
|
|
|
|
var pixBytes = this.pixBytes = (colors * bits + 7) >> 3; |
|
|
|
var pixBytes = this.pixBytes = (colors * bits + 7) >> 3; |
|
|
|
// add an extra pixByte to represent the pixel left of column 0
|
|
|
|
// add an extra pixByte to represent the pixel left of column 0
|
|
|
|
var rowBytes = this.rowBytes = ((columns * colors * bits + 7) >> 3) + pixBytes; |
|
|
|
var rowBytes = this.rowBytes = (columns * colors * bits + 7) >> 3; |
|
|
|
|
|
|
|
|
|
|
|
this.currentRow = new Uint8Array(rowBytes); |
|
|
|
DecodeStream.call(this); |
|
|
|
this.bufferLength = rowBytes; |
|
|
|
|
|
|
|
this.pos = rowBytes; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
constructor.prototype = Object.create(DecodeStream.prototype); |
|
|
|
readRowTiff : function() { |
|
|
|
|
|
|
|
var currentRow = this.currentRow; |
|
|
|
|
|
|
|
var rowBytes = this.rowBytes; |
|
|
|
|
|
|
|
var pixBytes = this.pixBytes; |
|
|
|
|
|
|
|
var bits = this.bits; |
|
|
|
|
|
|
|
var colors = this.colors; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var rawBytes = this.stream.getBytes(rowBytes - pixBytes); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (bits === 1) { |
|
|
|
|
|
|
|
var inbuf = 0; |
|
|
|
|
|
|
|
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) { |
|
|
|
|
|
|
|
var c = rawBytes[j]; |
|
|
|
|
|
|
|
inBuf = (inBuf << 8) | c; |
|
|
|
|
|
|
|
// bitwise addition is exclusive or
|
|
|
|
|
|
|
|
// first shift inBuf and then add
|
|
|
|
|
|
|
|
currentRow[i] = (c ^ (inBuf >> colors)) & 0xFF; |
|
|
|
|
|
|
|
// truncate inBuf (assumes colors < 16)
|
|
|
|
|
|
|
|
inBuf &= 0xFFFF; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (bits === 8) { |
|
|
|
|
|
|
|
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) |
|
|
|
|
|
|
|
currentRow[i] = currentRow[i - colors] + rawBytes[j]; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
var compArray = new Uint8Array(colors + 1); |
|
|
|
|
|
|
|
var bitMask = (1 << bits) - 1; |
|
|
|
|
|
|
|
var inbuf = 0, outbut = 0; |
|
|
|
|
|
|
|
var inbits = 0, outbits = 0; |
|
|
|
|
|
|
|
var j = 0, k = pixBytes; |
|
|
|
|
|
|
|
var columns = this.columns; |
|
|
|
|
|
|
|
for (var i = 0; i < columns; ++i) { |
|
|
|
|
|
|
|
for (var kk = 0; kk < colors; ++kk) { |
|
|
|
|
|
|
|
if (inbits < bits) { |
|
|
|
|
|
|
|
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF); |
|
|
|
|
|
|
|
inbits += 8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
compArray[kk] = (compArray[kk] + |
|
|
|
|
|
|
|
(inbuf >> (inbits - bits))) & bitMask; |
|
|
|
|
|
|
|
inbits -= bits; |
|
|
|
|
|
|
|
outbuf = (outbuf << bits) | compArray[kk]; |
|
|
|
|
|
|
|
outbits += bits; |
|
|
|
|
|
|
|
if (outbits >= 8) { |
|
|
|
|
|
|
|
currentRow[k++] = (outbuf >> (outbits - 8)) & 0xFF; |
|
|
|
|
|
|
|
outbits -= 8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (outbits > 0) { |
|
|
|
|
|
|
|
currentRow[k++] = (outbuf << (8 - outbits)) + |
|
|
|
|
|
|
|
(inbuf & ((1 << (8 - outbits)) - 1)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.pos = pixBytes; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
readRowPng : function() { |
|
|
|
|
|
|
|
var currentRow = this.currentRow; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var rowBytes = this.rowBytes; |
|
|
|
constructor.prototype.readBlockTiff = function() { |
|
|
|
var pixBytes = this.pixBytes; |
|
|
|
var buffer = this.buffer; |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
|
|
|
|
var predictor = this.stream.getByte(); |
|
|
|
var rowBytes = this.rowBytes; |
|
|
|
var rawBytes = this.stream.getBytes(rowBytes - pixBytes); |
|
|
|
var pixBytes = this.pixBytes; |
|
|
|
|
|
|
|
|
|
|
|
switch (predictor) { |
|
|
|
|
|
|
|
case 0: |
|
|
|
var buffer = this.buffer; |
|
|
|
break; |
|
|
|
var bufferLength = this.bufferLength; |
|
|
|
case 1: |
|
|
|
this.ensureBuffer(bufferLength + rowBytes); |
|
|
|
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) |
|
|
|
var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes); |
|
|
|
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[j]) & 0xFF; |
|
|
|
|
|
|
|
break; |
|
|
|
var bits = this.bits; |
|
|
|
case 2: |
|
|
|
var colors = this.colors; |
|
|
|
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) |
|
|
|
|
|
|
|
currentRow[i] = (currentRow[i] + rawBytes[j]) & 0xFF; |
|
|
|
var rawBytes = this.stream.getBytes(rowBytes); |
|
|
|
break; |
|
|
|
|
|
|
|
case 3: |
|
|
|
if (bits === 1) { |
|
|
|
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) |
|
|
|
var inbuf = 0; |
|
|
|
currentRow[i] = (((currentRow[i] + currentRow[i - pixBytes]) |
|
|
|
for (var i = 0; i < rowBytes; ++i) { |
|
|
|
>> 1) + rawBytes[j]) & 0xFF; |
|
|
|
var c = rawBytes[i]; |
|
|
|
break; |
|
|
|
inBuf = (inBuf << 8) | c; |
|
|
|
case 4: |
|
|
|
// bitwise addition is exclusive or
|
|
|
|
// we need to save the up left pixels values. the simplest way
|
|
|
|
// first shift inBuf and then add
|
|
|
|
// is to create a new buffer
|
|
|
|
currentRow[i] = (c ^ (inBuf >> colors)) & 0xFF; |
|
|
|
var lastRow = currentRow; |
|
|
|
// truncate inBuf (assumes colors < 16)
|
|
|
|
var currentRow = new Uint8Array(rowBytes); |
|
|
|
inBuf &= 0xFFFF; |
|
|
|
for (var i = pixBytes, j = 0; i < rowBytes; ++i, ++j) { |
|
|
|
|
|
|
|
var up = lastRow[i]; |
|
|
|
|
|
|
|
var upLeft = lastRow[i - pixBytes]; |
|
|
|
|
|
|
|
var left = currentRow[i - pixBytes]; |
|
|
|
|
|
|
|
var p = left + up - upLeft; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var pa = p - left; |
|
|
|
|
|
|
|
if (pa < 0) |
|
|
|
|
|
|
|
pa = -pa; |
|
|
|
|
|
|
|
var pb = p - up; |
|
|
|
|
|
|
|
if (pb < 0) |
|
|
|
|
|
|
|
pb = -pb; |
|
|
|
|
|
|
|
var pc = p - upLeft; |
|
|
|
|
|
|
|
if (pc < 0) |
|
|
|
|
|
|
|
pc = -pc; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var c = rawBytes[j]; |
|
|
|
|
|
|
|
if (pa <= pb && pa <= pc) |
|
|
|
|
|
|
|
currentRow[i] = left + c; |
|
|
|
|
|
|
|
else if (pb <= pc) |
|
|
|
|
|
|
|
currentRow[i] = up + c; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
currentRow[i] = upLeft + c; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
this.currentRow = currentRow; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
error("Unsupported predictor"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
this.pos = pixBytes; |
|
|
|
} else if (bits === 8) { |
|
|
|
}, |
|
|
|
for (var i = 0; i < colors; ++i) |
|
|
|
getByte : function() { |
|
|
|
currentRow[i] = rawBytes[i]; |
|
|
|
if (this.pos >= this.bufferLength) |
|
|
|
for (; i < rowBytes; ++i) |
|
|
|
this.readRow(); |
|
|
|
currentRow[i] = currentRow[i - colors] + rawBytes[i]; |
|
|
|
return this.currentRow[this.pos++]; |
|
|
|
} else { |
|
|
|
}, |
|
|
|
var compArray = new Uint8Array(colors + 1); |
|
|
|
getBytes : function(n) { |
|
|
|
var bitMask = (1 << bits) - 1; |
|
|
|
var i, bytes; |
|
|
|
var inbuf = 0, outbut = 0; |
|
|
|
bytes = new Uint8Array(n); |
|
|
|
var inbits = 0, outbits = 0; |
|
|
|
for (i = 0; i < n; ++i) { |
|
|
|
var j = 0, k = 0; |
|
|
|
if (this.pos >= this.bufferLength) |
|
|
|
var columns = this.columns; |
|
|
|
this.readRow(); |
|
|
|
for (var i = 0; i < columns; ++i) { |
|
|
|
bytes[i] = this.currentRow[this.pos++]; |
|
|
|
for (var kk = 0; kk < colors; ++kk) { |
|
|
|
|
|
|
|
if (inbits < bits) { |
|
|
|
|
|
|
|
inbuf = (inbuf << 8) | (rawBytes[j++] & 0xFF); |
|
|
|
|
|
|
|
inbits += 8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
compArray[kk] = (compArray[kk] + |
|
|
|
|
|
|
|
(inbuf >> (inbits - bits))) & bitMask; |
|
|
|
|
|
|
|
inbits -= bits; |
|
|
|
|
|
|
|
outbuf = (outbuf << bits) | compArray[kk]; |
|
|
|
|
|
|
|
outbits += bits; |
|
|
|
|
|
|
|
if (outbits >= 8) { |
|
|
|
|
|
|
|
currentRow[k++] = (outbuf >> (outbits - 8)) & 0xFF; |
|
|
|
|
|
|
|
outbits -= 8; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return bytes; |
|
|
|
if (outbits > 0) { |
|
|
|
}, |
|
|
|
currentRow[k++] = (outbuf << (8 - outbits)) + |
|
|
|
getChar : function() { |
|
|
|
(inbuf & ((1 << (8 - outbits)) - 1)) |
|
|
|
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.bufferLength += rowBytes; |
|
|
|
this.readRow(); |
|
|
|
}; |
|
|
|
if (this.bufferLength === 0) break; |
|
|
|
constructor.prototype.readBlockPng = function() { |
|
|
|
|
|
|
|
var buffer = this.buffer; |
|
|
|
|
|
|
|
var pos = this.pos; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var rowBytes = this.rowBytes; |
|
|
|
|
|
|
|
var pixBytes = this.pixBytes; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var predictor = this.stream.getByte(); |
|
|
|
|
|
|
|
var rawBytes = this.stream.getBytes(rowBytes); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var buffer = this.buffer; |
|
|
|
|
|
|
|
var bufferLength = this.bufferLength; |
|
|
|
|
|
|
|
this.ensureBuffer(bufferLength + pixBytes); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var currentRow = buffer.subarray(bufferLength, bufferLength + rowBytes); |
|
|
|
|
|
|
|
var prevRow = buffer.subarray(bufferLength - rowBytes, bufferLength); |
|
|
|
|
|
|
|
if (prevRow.length == 0) |
|
|
|
|
|
|
|
prevRow = currentRow; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (predictor) { |
|
|
|
|
|
|
|
case 0: |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 1: |
|
|
|
|
|
|
|
for (var i = 0; i < pixBytes; ++i) |
|
|
|
|
|
|
|
currentRow[i] = rawBytes[i]; |
|
|
|
|
|
|
|
for (; i < rowBytes; ++i) |
|
|
|
|
|
|
|
currentRow[i] = (currentRow[i - pixBytes] + rawBytes[i]) & 0xFF; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 2: |
|
|
|
|
|
|
|
for (var i = 0; i < rowBytes; ++i) |
|
|
|
|
|
|
|
currentRow[i] = (prevRow[i] + rawBytes[i]) & 0xFF; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 3: |
|
|
|
|
|
|
|
for (var i = 0; i < pixBytes; ++i) |
|
|
|
|
|
|
|
currentRow[i] = (prevRow[i] >> 1) + rawBytes[i]; |
|
|
|
|
|
|
|
for (; i < rowBytes; ++i) |
|
|
|
|
|
|
|
currentRow[i] = (((prevRow[i] + currentRow[i - pixBytes]) |
|
|
|
|
|
|
|
>> 1) + rawBytes[i]) & 0xFF; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case 4: |
|
|
|
|
|
|
|
// we need to save the up left pixels values. the simplest way
|
|
|
|
|
|
|
|
// is to create a new buffer
|
|
|
|
|
|
|
|
for (var i = 0; i < pixBytes; ++i) |
|
|
|
|
|
|
|
currentRow[i] = rawBytes[i]; |
|
|
|
|
|
|
|
for (; i < rowBytes; ++i) { |
|
|
|
|
|
|
|
var up = prevRow[i]; |
|
|
|
|
|
|
|
var upLeft = lastRow[i - pixBytes]; |
|
|
|
|
|
|
|
var left = currentRow[i - pixBytes]; |
|
|
|
|
|
|
|
var p = left + up - upLeft; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var pa = p - left; |
|
|
|
|
|
|
|
if (pa < 0) |
|
|
|
|
|
|
|
pa = -pa; |
|
|
|
|
|
|
|
var pb = p - up; |
|
|
|
|
|
|
|
if (pb < 0) |
|
|
|
|
|
|
|
pb = -pb; |
|
|
|
|
|
|
|
var pc = p - upLeft; |
|
|
|
|
|
|
|
if (pc < 0) |
|
|
|
|
|
|
|
pc = -pc; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var c = rawBytes[i]; |
|
|
|
|
|
|
|
if (pa <= pb && pa <= pc) |
|
|
|
|
|
|
|
currentRow[i] = left + c; |
|
|
|
|
|
|
|
else if (pb <= pc) |
|
|
|
|
|
|
|
currentRow[i] = up + c; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
currentRow[i] = upLeft + c; |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
this.pos += n; |
|
|
|
default: |
|
|
|
|
|
|
|
error("Unsupported predictor"); |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.bufferLength += rowBytes; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
return constructor; |
|
|
|
})(); |
|
|
|
})(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// A JpegStream can't be read directly. We use the platform to render the underlying
|
|
|
|
|
|
|
|
// JPEG data for us.
|
|
|
|
|
|
|
|
var JpegStream = (function() { |
|
|
|
|
|
|
|
function constructor(bytes, dict) { |
|
|
|
|
|
|
|
// TODO: per poppler, some images may have "junk" before that need to be removed
|
|
|
|
|
|
|
|
this.dict = dict; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// create DOM image
|
|
|
|
|
|
|
|
var img = new Image(); |
|
|
|
|
|
|
|
img.src = "data:image/jpeg;base64," + window.btoa(bytesToString(bytes)); |
|
|
|
|
|
|
|
this.domImage = img; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor.prototype = { |
|
|
|
|
|
|
|
getImage: function() { |
|
|
|
|
|
|
|
return this.domImage; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
getChar: function() { |
|
|
|
|
|
|
|
error("internal error: getChar is not valid on JpegStream"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return constructor; |
|
|
|
|
|
|
|
})(); |
|
|
|
var DecryptStream = (function() { |
|
|
|
var DecryptStream = (function() { |
|
|
|
function constructor(str, fileKey, encAlgorithm, keyLength) { |
|
|
|
function constructor(str, fileKey, encAlgorithm, keyLength) { |
|
|
|
TODO("decrypt stream is not implemented"); |
|
|
|
TODO("decrypt stream is not implemented"); |
|
|
|