/src/stream.js
JavaScript | 452 lines | 414 code | 38 blank | 0 comment | 58 complexity | 853d6b0ea6fd97bb0f72baca1fd9ae40 MD5 | raw file
- (function(){
- 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 }
- }
- }
- })();