You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
486 lines
18 KiB
486 lines
18 KiB
/* |
|
Stream Reader from Gordon.JS |
|
Copyright (c) 2010 Tobias Schneider |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
of this software and associated documentation files (the "Software"), to deal |
|
in the Software without restriction, including without limitation the rights |
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
copies of the Software, and to permit persons to whom the Software is |
|
furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included in |
|
all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
THE SOFTWARE. |
|
*/ |
|
|
|
var win = self, |
|
doc = win.document, |
|
fromCharCode = String.fromCharCode, |
|
push = Array.prototype.push, |
|
min = Math.min, |
|
max = Math.max; |
|
|
|
(function(window,undefined){ |
|
|
|
window.Gordon = {}; |
|
|
|
var DEFLATE_CODE_LENGTH_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15], |
|
DEFLATE_CODE_LENGHT_MAP = [ |
|
[0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 8], [0, 9], [0, 10], [1, 11], [1, 13], [1, 15], [1, 17], |
|
[2, 19], [2, 23], [2, 27], [2, 31], [3, 35], [3, 43], [3, 51], [3, 59], [4, 67], [4, 83], [4, 99], |
|
[4, 115], [5, 131], [5, 163], [5, 195], [5, 227], [0, 258] |
|
], |
|
DEFLATE_DISTANCE_MAP = [ |
|
[0, 1], [0, 2], [0, 3], [0, 4], [1, 5], [1, 7], [2, 9], [2, 13], [3, 17], [3, 25], [4, 33], [4, 49], |
|
[5, 65], [5, 97], [6, 129], [6, 193], [7, 257], [7, 385], [8, 513], [8, 769], [9, 1025], [9, 1537], |
|
[10, 2049], [10, 3073], [11, 4097], [11, 6145], [12, 8193], [12, 12289], [13, 16385], [13, 24577] |
|
]; |
|
|
|
Gordon.Stream = function(data){ |
|
var buff = [], |
|
t = this, |
|
i = t.length = data.length; |
|
t.offset = 0; |
|
for(var i = 0; data[i]; i++){ buff.push(fromCharCode(data.charCodeAt(i) & 0xff)); } |
|
t._buffer = buff.join(''); |
|
t._bitBuffer = null; |
|
t._bitOffset = 8; |
|
}; |
|
Gordon.Stream.prototype = { |
|
readByteAt: function(pos){ |
|
return this._buffer.charCodeAt(pos); |
|
}, |
|
|
|
readNumber: function(numBytes, bigEnd){ |
|
var t = this, |
|
val = 0; |
|
if(bigEnd){ |
|
while(numBytes--){ val = (val << 8) | t.readByteAt(t.offset++); } |
|
}else{ |
|
var o = t.offset, |
|
i = o + numBytes; |
|
while(i > o){ val = (val << 8) | t.readByteAt(--i); } |
|
t.offset += numBytes; |
|
} |
|
t.align(); |
|
return val; |
|
}, |
|
|
|
readSNumber: function(numBytes, bigEnd){ |
|
var val = this.readNumber(numBytes, bigEnd), |
|
numBits = numBytes * 8; |
|
if(val >> (numBits - 1)){ val -= Math.pow(2, numBits); } |
|
return val; |
|
}, |
|
|
|
readSI8: function(){ |
|
return this.readSNumber(1); |
|
}, |
|
|
|
readSI16: function(bigEnd){ |
|
return this.readSNumber(2, bigEnd); |
|
}, |
|
|
|
readSI32: function(bigEnd){ |
|
return this.readSNumber(4, bigEnd); |
|
}, |
|
|
|
readUI8: function(){ |
|
return this.readNumber(1); |
|
}, |
|
|
|
readUI16: function(bigEnd){ |
|
return this.readNumber(2, bigEnd); |
|
}, |
|
|
|
readUI24: function(bigEnd){ |
|
return this.readNumber(3, bigEnd); |
|
}, |
|
|
|
readUI32: function(bigEnd){ |
|
return this.readNumber(4, bigEnd); |
|
}, |
|
|
|
readFixed: function(){ |
|
return this._readFixedPoint(32, 16); |
|
}, |
|
|
|
_readFixedPoint: function(numBits, precision){ |
|
return this.readSB(numBits) * Math.pow(2, -precision); |
|
}, |
|
|
|
readFixed8: function(){ |
|
return this._readFixedPoint(16, 8); |
|
}, |
|
|
|
readFloat: function(){ |
|
return this._readFloatingPoint(8, 23); |
|
}, |
|
|
|
_readFloatingPoint: function(numEBits, numSBits){ |
|
var numBits = 1 + numEBits + numSBits, |
|
numBytes = numBits / 8, |
|
t = this, |
|
val = 0.0; |
|
if(numBytes > 4){ |
|
var i = Math.ceil(numBytes / 4); |
|
while(i--){ |
|
var buff = [], |
|
o = t.offset, |
|
j = o + (numBytes >= 4 ? 4 : numBytes % 4); |
|
while(j > o){ |
|
buff.push(t.readByteAt(--j)); |
|
numBytes--; |
|
t.offset++; |
|
} |
|
} |
|
var s = new Gordon.Stream(fromCharCode.apply(String, buff)), |
|
sign = s.readUB(1), |
|
expo = s.readUB(numEBits), |
|
mantis = 0, |
|
i = numSBits; |
|
while(i--){ |
|
if(s.readBool()){ mantis += Math.pow(2, i); } |
|
} |
|
}else{ |
|
var sign = t.readUB(1), |
|
expo = t.readUB(numEBits), |
|
mantis = t.readUB(numSBits); |
|
} |
|
if(sign || expo || mantis){ |
|
var maxExpo = Math.pow(2, numEBits), |
|
bias = ~~((maxExpo - 1) / 2), |
|
scale = Math.pow(2, numSBits), |
|
fract = mantis / scale; |
|
if(bias){ |
|
if(bias < maxExpo){ val = Math.pow(2, expo - bias) * (1 + fract); } |
|
else if(fract){ val = NaN; } |
|
else{ val = Infinity; } |
|
}else if(fract){ val = Math.pow(2, 1 - bias) * fract; } |
|
if(NaN != val && sign){ val *= -1; } |
|
} |
|
return val; |
|
}, |
|
|
|
readFloat16: function(){ |
|
return this._readFloatingPoint(5, 10); |
|
}, |
|
|
|
readDouble: function(){ |
|
return this._readFloatingPoint(11, 52); |
|
}, |
|
|
|
readEncodedU32: function(){ |
|
var val = 0; |
|
for(var i = 0; i < 5; i++){ |
|
var num = this.readByteAt(this._offset++); |
|
val = val | ((num & 0x7f) << (7 * i)); |
|
if(!(num & 0x80)){ break; } |
|
} |
|
return val; |
|
}, |
|
|
|
readSB: function(numBits){ |
|
var val = this.readUB(numBits); |
|
if(val >> (numBits - 1)){ val -= Math.pow(2, numBits); } |
|
return val; |
|
}, |
|
|
|
readUB: function(numBits, lsb){ |
|
var t = this, |
|
val = 0; |
|
for(var i = 0; i < numBits; i++){ |
|
if(8 == t._bitOffset){ |
|
t._bitBuffer = t.readUI8(); |
|
t._bitOffset = 0; |
|
} |
|
if(lsb){ val |= (t._bitBuffer & (0x01 << t._bitOffset++) ? 1 : 0) << i; } |
|
else{ val = (val << 1) | (t._bitBuffer & (0x80 >> t._bitOffset++) ? 1 : 0); } |
|
} |
|
return val; |
|
}, |
|
|
|
readFB: function(numBits){ |
|
return this._readFixedPoint(numBits, 16); |
|
}, |
|
|
|
readString: function(numChars){ |
|
var t = this, |
|
b = t._buffer; |
|
if(undefined != numChars){ |
|
var str = b.substr(t.offset, numChars); |
|
t.offset += numChars; |
|
}else{ |
|
var chars = [], |
|
i = t.length - t.offset; |
|
while(i--){ |
|
var code = t.readByteAt(t.offset++); |
|
if(code){ chars.push(fromCharCode(code)); } |
|
else{ break; } |
|
} |
|
var str = chars.join(''); |
|
} |
|
return str; |
|
}, |
|
|
|
readBool: function(numBits){ |
|
return !!this.readUB(numBits || 1); |
|
}, |
|
|
|
seek: function(offset, absolute){ |
|
var t = this; |
|
t.offset = (absolute ? 0 : t.offset) + offset; |
|
t.align(); |
|
return t; |
|
}, |
|
|
|
align: function(){ |
|
this._bitBuffer = null; |
|
this._bitOffset = 8; |
|
return this; |
|
}, |
|
|
|
readLanguageCode: function(){ |
|
return this.readUI8(); |
|
}, |
|
|
|
readRGB: function(){ |
|
return { |
|
red: this.readUI8(), |
|
green: this.readUI8(), |
|
blue: this.readUI8() |
|
} |
|
}, |
|
|
|
readRGBA: function(){ |
|
var rgba = this.readRGB(); |
|
rgba.alpha = this.readUI8() / 255; |
|
return rgba; |
|
}, |
|
|
|
readARGB: function(){ |
|
var alpha = this.readUI8() / 255, |
|
rgba = this.readRGB(); |
|
rgba.alpha = alpha; |
|
return rgba; |
|
}, |
|
|
|
readRect: function(){ |
|
var t = this; |
|
numBits = t.readUB(5), |
|
rect = { |
|
left: t.readSB(numBits), |
|
right: t.readSB(numBits), |
|
top: t.readSB(numBits), |
|
bottom: t.readSB(numBits) |
|
}; |
|
t.align(); |
|
return rect; |
|
}, |
|
|
|
readMatrix: function(){ |
|
var t = this, |
|
hasScale = t.readBool(); |
|
if(hasScale){ |
|
var numBits = t.readUB(5), |
|
scaleX = t.readFB(numBits), |
|
scaleY = t.readFB(numBits); |
|
}else{ var scaleX = scaleY = 1.0; } |
|
var hasRotation = t.readBool(); |
|
if(hasRotation){ |
|
var numBits = t.readUB(5), |
|
skewX = t.readFB(numBits), |
|
skewY = t.readFB(numBits); |
|
}else{ var skewX = skewY = 0.0; } |
|
var numBits = t.readUB(5); |
|
matrix = { |
|
scaleX: scaleX, scaleY: scaleY, |
|
skewX: skewX, skewY: skewY, |
|
moveX: t.readSB(numBits), moveY: t.readSB(numBits) |
|
}; |
|
t.align(); |
|
return matrix; |
|
}, |
|
|
|
readCxform: function(){ |
|
return this._readCxf(); |
|
}, |
|
|
|
readCxformA: function(){ |
|
return this._readCxf(true); |
|
}, |
|
|
|
_readCxf: function(withAlpha){ |
|
var t = this; |
|
hasAddTerms = t.readBool(), |
|
hasMultTerms = t.readBool(), |
|
numBits = t.readUB(4); |
|
if(hasMultTerms){ |
|
var multR = t.readSB(numBits) / 256, |
|
multG = t.readSB(numBits) / 256, |
|
multB = t.readSB(numBits) / 256, |
|
multA = withAlpha ? t.readSB(numBits) / 256 : 1; |
|
}else{ var multR = multG = multB = multA = 1; } |
|
if(hasAddTerms){ |
|
var addR = t.readSB(numBits), |
|
addG = t.readSB(numBits), |
|
addB = t.readSB(numBits), |
|
addA = withAlpha ? t.readSB(numBits) / 256 : 0; |
|
}else{ var addR = addG = addB = addA = 0; } |
|
var cxform = { |
|
multR: multR, multG: multG, multB: multB, multA: multA, |
|
addR: addR, addG: addG, addB: addB, addA: addA |
|
} |
|
t.align(); |
|
return cxform; |
|
}, |
|
|
|
decompress: function(){ |
|
var t = this, |
|
b = t._buffer, |
|
o = t.offset, |
|
data = b.substr(0, o) + t.unzip(); |
|
t.length = data.length; |
|
t.offset = o; |
|
t._buffer = data; |
|
return t; |
|
}, |
|
|
|
unzip: function uz(raw){ |
|
var t = this, |
|
buff = [], |
|
o = DEFLATE_CODE_LENGTH_ORDER, |
|
m = DEFLATE_CODE_LENGHT_MAP, |
|
d = DEFLATE_DISTANCE_MAP; |
|
t.seek(2); |
|
do{ |
|
var isFinal = t.readUB(1, true), |
|
type = t.readUB(2, true); |
|
if(type){ |
|
if(1 == type){ |
|
var distTable = uz.fixedDistTable, |
|
litTable = uz.fixedLitTable; |
|
if(!distTable){ |
|
var bitLengths = []; |
|
for(var i = 0; i < 32; i++){ bitLengths.push(5); } |
|
distTable = uz.fixedDistTable = buildHuffTable(bitLengths); |
|
} |
|
if(!litTable){ |
|
var bitLengths = []; |
|
for(var i = 0; i <= 143; i++){ bitLengths.push(8); } |
|
for(; i <= 255; i++){ bitLengths.push(9); } |
|
for(; i <= 279; i++){ bitLengths.push(7); } |
|
for(; i <= 287; i++){ bitLengths.push(8); } |
|
litTable = uz.fixedLitTable = buildHuffTable(bitLengths); |
|
} |
|
}else{ |
|
var numLitLengths = t.readUB(5, true) + 257, |
|
numDistLengths = t.readUB(5, true) + 1, |
|
numCodeLenghts = t.readUB(4, true) + 4, |
|
codeLengths = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; |
|
for(var i = 0; i < numCodeLenghts; i++){ codeLengths[o[i]] = t.readUB(3, true); } |
|
var codeTable = buildHuffTable(codeLengths), |
|
litLengths = [], |
|
prevCodeLen = 0, |
|
maxLengths = numLitLengths + numDistLengths; |
|
while(litLengths.length < maxLengths){ |
|
var sym = decodeSymbol(t, codeTable); |
|
switch(sym){ |
|
case 16: |
|
var i = t.readUB(2, true) + 3; |
|
while(i--){ litLengths.push(prevCodeLen); } |
|
break; |
|
case 17: |
|
var i = t.readUB(3, true) + 3; |
|
while(i--){ litLengths.push(0); } |
|
break; |
|
case 18: |
|
var i = t.readUB(7, true) + 11; |
|
while(i--){ litLengths.push(0); } |
|
break; |
|
default: |
|
if(sym <= 15){ |
|
litLengths.push(sym); |
|
prevCodeLen = sym; |
|
} |
|
} |
|
} |
|
var distTable = buildHuffTable(litLengths.splice(numLitLengths, numDistLengths)), |
|
litTable = buildHuffTable(litLengths); |
|
} |
|
do{ |
|
var sym = decodeSymbol(t, litTable); |
|
if(sym < 256){ buff.push(raw ? sym : fromCharCode(sym)); } |
|
else if(sym > 256){ |
|
var lengthMap = m[sym - 257], |
|
len = lengthMap[1] + t.readUB(lengthMap[0], true), |
|
distMap = d[decodeSymbol(t, distTable)], |
|
dist = distMap[1] + t.readUB(distMap[0], true), |
|
i = buff.length - dist; |
|
while(len--){ buff.push(buff[i++]); } |
|
} |
|
}while(256 != sym); |
|
}else{ |
|
t.align(); |
|
var len = t.readUI16(), |
|
nlen = t.readUI16(); |
|
if(raw){ while(len--){ buff.push(t.readUI8()); } } |
|
else{ buff.push(t.readString(len)); } |
|
} |
|
}while(!isFinal); |
|
t.seek(4); |
|
return raw ? buff : buff.join(''); |
|
} |
|
}; |
|
|
|
function buildHuffTable(bitLengths){ |
|
var numLengths = bitLengths.length, |
|
blCount = [], |
|
maxBits = max.apply(Math, bitLengths), |
|
nextCode = [], |
|
code = 0, |
|
table = {}, |
|
i = numLengths; |
|
while(i--){ |
|
var len = bitLengths[i]; |
|
blCount[len] = (blCount[len] || 0) + (len > 0); |
|
} |
|
for(var i = 1; i <= maxBits; i++){ |
|
var len = i - 1; |
|
if(undefined == blCount[len]){ blCount[len] = 0; } |
|
code = (code + blCount[i - 1]) << 1; |
|
nextCode[i] = code; |
|
} |
|
for(var i = 0; i < numLengths; i++){ |
|
var len = bitLengths[i]; |
|
if(len){ |
|
table[nextCode[len]] = { |
|
length: len, |
|
symbol: i |
|
}; |
|
nextCode[len]++; |
|
} |
|
} |
|
return table; |
|
} |
|
|
|
function decodeSymbol(s, table) { |
|
var code = 0, |
|
len = 0; |
|
while(true){ |
|
code = (code << 1) | s.readUB(1, true); |
|
len++; |
|
var entry = table[code]; |
|
if(undefined != entry && entry.length == len){ return entry.symbol } |
|
} |
|
} |
|
})(this); |
|
|
|
|