1
0
Fork 0
mirror of https://github.com/codedread/bitjs synced 2025-10-04 18:19:15 +02:00

Whitespace and a couple arrow functions

This commit is contained in:
codedread 2017-02-21 12:05:03 -08:00
parent 0d27e9d9c0
commit d2a4329893
5 changed files with 302 additions and 317 deletions

View file

@ -21,7 +21,6 @@ bitjs.archive.UnarchiveEvent = class {
constructor(type) { constructor(type) {
/** /**
* The event type. * The event type.
*
* @type {string} * @type {string}
*/ */
this.type = type; this.type = type;
@ -52,7 +51,6 @@ bitjs.archive.UnarchiveInfoEvent = class extends bitjs.archive.UnarchiveEvent {
/** /**
* The information message. * The information message.
*
* @type {string} * @type {string}
*/ */
this.msg = msg; this.msg = msg;
@ -71,7 +69,6 @@ bitjs.archive.UnarchiveErrorEvent = class extends bitjs.archive.UnarchiveEvent {
/** /**
* The information message. * The information message.
*
* @type {string} * @type {string}
*/ */
this.msg = msg; this.msg = msg;

View file

@ -135,9 +135,7 @@ const untar = function(arrayBuffer) {
totalFilesInArchive = localFiles.length; totalFilesInArchive = localFiles.length;
// got all local files, now sort them // got all local files, now sort them
localFiles.sort(function(a,b) { localFiles.sort((a,b) => a.filename > b.filename ? 1 : -1);
return a.filename > b.filename ? 1 : -1;
});
// report # files and total length // report # files and total length
if (localFiles.length > 0) { if (localFiles.length > 0) {

View file

@ -61,7 +61,7 @@ class ZipLocalFile {
// takes a ByteStream and parses out the local file information // takes a ByteStream and parses out the local file information
constructor(bstream) { constructor(bstream) {
if (typeof bstream != typeof {} || !bstream.readNumber || typeof bstream.readNumber != typeof function(){}) { if (typeof bstream != typeof {} || !bstream.readNumber || typeof bstream.readNumber != typeof function(){}) {
return null; return null;
} }
bstream.readNumber(4); // swallow signature bstream.readNumber(4); // swallow signature
@ -78,7 +78,7 @@ class ZipLocalFile {
this.filename = null; this.filename = null;
if (this.fileNameLength > 0) { if (this.fileNameLength > 0) {
this.filename = bstream.readString(this.fileNameLength); this.filename = bstream.readString(this.fileNameLength);
} }
info("Zip Local File Header:"); info("Zip Local File Header:");
@ -96,14 +96,14 @@ class ZipLocalFile {
this.extraField = null; this.extraField = null;
if (this.extraFieldLength > 0) { if (this.extraFieldLength > 0) {
this.extraField = bstream.readString(this.extraFieldLength); this.extraField = bstream.readString(this.extraFieldLength);
info(" extra field=" + this.extraField); info(" extra field=" + this.extraField);
} }
// read in the compressed data // read in the compressed data
this.fileData = null; this.fileData = null;
if (this.compressedSize > 0) { if (this.compressedSize > 0) {
this.fileData = new Uint8Array(bstream.readBytes(this.compressedSize)); this.fileData = new Uint8Array(bstream.readBytes(this.compressedSize));
} }
// TODO: deal with data descriptor if present (we currently assume no data descriptor!) // TODO: deal with data descriptor if present (we currently assume no data descriptor!)
@ -111,9 +111,9 @@ class ZipLocalFile {
// But how do you figure out how big the file data is if you don't know the compressedSize // But how do you figure out how big the file data is if you don't know the compressedSize
// from the header?!? // from the header?!?
if ((this.generalPurpose & BIT[3]) != 0) { if ((this.generalPurpose & BIT[3]) != 0) {
this.crc32 = bstream.readNumber(4); this.crc32 = bstream.readNumber(4);
this.compressedSize = bstream.readNumber(4); this.compressedSize = bstream.readNumber(4);
this.uncompressedSize = bstream.readNumber(4); this.uncompressedSize = bstream.readNumber(4);
} }
} }
@ -154,97 +154,95 @@ const unzip = function(arrayBuffer) {
const bstream = new bitjs.io.ByteStream(arrayBuffer); const bstream = new bitjs.io.ByteStream(arrayBuffer);
// detect local file header signature or return null // detect local file header signature or return null
if (bstream.peekNumber(4) == zLocalFileHeaderSignature) { if (bstream.peekNumber(4) == zLocalFileHeaderSignature) {
const localFiles = []; const localFiles = [];
// loop until we don't see any more local files // loop until we don't see any more local files
while (bstream.peekNumber(4) == zLocalFileHeaderSignature) { while (bstream.peekNumber(4) == zLocalFileHeaderSignature) {
const oneLocalFile = new ZipLocalFile(bstream); const oneLocalFile = new ZipLocalFile(bstream);
// this should strip out directories/folders // this should strip out directories/folders
if (oneLocalFile && oneLocalFile.uncompressedSize > 0 && oneLocalFile.fileData) { if (oneLocalFile && oneLocalFile.uncompressedSize > 0 && oneLocalFile.fileData) {
localFiles.push(oneLocalFile); localFiles.push(oneLocalFile);
totalUncompressedBytesInArchive += oneLocalFile.uncompressedSize; totalUncompressedBytesInArchive += oneLocalFile.uncompressedSize;
} }
} }
totalFilesInArchive = localFiles.length; totalFilesInArchive = localFiles.length;
// got all local files, now sort them // got all local files, now sort them
localFiles.sort(function(a,b) { localFiles.sort((a,b) => a.filename > b.filename ? 1 : -1);
return a.filename > b.filename ? 1 : -1;
});
// archive extra data record // archive extra data record
if (bstream.peekNumber(4) == zArchiveExtraDataSignature) { if (bstream.peekNumber(4) == zArchiveExtraDataSignature) {
info(" Found an Archive Extra Data Signature"); info(" Found an Archive Extra Data Signature");
// skipping this record for now // skipping this record for now
bstream.readNumber(4); bstream.readNumber(4);
const archiveExtraFieldLength = bstream.readNumber(4); const archiveExtraFieldLength = bstream.readNumber(4);
bstream.readString(archiveExtraFieldLength); bstream.readString(archiveExtraFieldLength);
} }
// central directory structure // central directory structure
// TODO: handle the rest of the structures (Zip64 stuff) // TODO: handle the rest of the structures (Zip64 stuff)
if (bstream.peekNumber(4) == zCentralFileHeaderSignature) { if (bstream.peekNumber(4) == zCentralFileHeaderSignature) {
info(" Found a Central File Header"); info(" Found a Central File Header");
// read all file headers // read all file headers
while (bstream.peekNumber(4) == zCentralFileHeaderSignature) { while (bstream.peekNumber(4) == zCentralFileHeaderSignature) {
bstream.readNumber(4); // signature bstream.readNumber(4); // signature
bstream.readNumber(2); // version made by bstream.readNumber(2); // version made by
bstream.readNumber(2); // version needed to extract bstream.readNumber(2); // version needed to extract
bstream.readNumber(2); // general purpose bit flag bstream.readNumber(2); // general purpose bit flag
bstream.readNumber(2); // compression method bstream.readNumber(2); // compression method
bstream.readNumber(2); // last mod file time bstream.readNumber(2); // last mod file time
bstream.readNumber(2); // last mod file date bstream.readNumber(2); // last mod file date
bstream.readNumber(4); // crc32 bstream.readNumber(4); // crc32
bstream.readNumber(4); // compressed size bstream.readNumber(4); // compressed size
bstream.readNumber(4); // uncompressed size bstream.readNumber(4); // uncompressed size
const fileNameLength = bstream.readNumber(2); // file name length const fileNameLength = bstream.readNumber(2); // file name length
const extraFieldLength = bstream.readNumber(2); // extra field length const extraFieldLength = bstream.readNumber(2); // extra field length
const fileCommentLength = bstream.readNumber(2); // file comment length const fileCommentLength = bstream.readNumber(2); // file comment length
bstream.readNumber(2); // disk number start bstream.readNumber(2); // disk number start
bstream.readNumber(2); // internal file attributes bstream.readNumber(2); // internal file attributes
bstream.readNumber(4); // external file attributes bstream.readNumber(4); // external file attributes
bstream.readNumber(4); // relative offset of local header bstream.readNumber(4); // relative offset of local header
bstream.readString(fileNameLength); // file name bstream.readString(fileNameLength); // file name
bstream.readString(extraFieldLength); // extra field bstream.readString(extraFieldLength); // extra field
bstream.readString(fileCommentLength); // file comment bstream.readString(fileCommentLength); // file comment
} }
} }
// digital signature // digital signature
if (bstream.peekNumber(4) == zDigitalSignatureSignature) { if (bstream.peekNumber(4) == zDigitalSignatureSignature) {
info(" Found a Digital Signature"); info(" Found a Digital Signature");
bstream.readNumber(4); bstream.readNumber(4);
const sizeOfSignature = bstream.readNumber(2); const sizeOfSignature = bstream.readNumber(2);
bstream.readString(sizeOfSignature); // digital signature data bstream.readString(sizeOfSignature); // digital signature data
} }
// report # files and total length // report # files and total length
if (localFiles.length > 0) { if (localFiles.length > 0) {
postProgress(); postProgress();
} }
// now do the unzipping of each file // now do the unzipping of each file
for (let i = 0; i < localFiles.length; ++i) { for (let i = 0; i < localFiles.length; ++i) {
const localfile = localFiles[i]; const localfile = localFiles[i];
// update progress // update progress
currentFilename = localfile.filename; currentFilename = localfile.filename;
currentFileNumber = i; currentFileNumber = i;
currentBytesUnarchivedInFile = 0; currentBytesUnarchivedInFile = 0;
// actually do the unzipping // actually do the unzipping
localfile.unzip(); localfile.unzip();
if (localfile.fileData != null) { if (localfile.fileData != null) {
postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile)); postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile));
postProgress();
}
}
postProgress(); postProgress();
postMessage(new bitjs.archive.UnarchiveFinishEvent()); }
}
postProgress();
postMessage(new bitjs.archive.UnarchiveFinishEvent());
} }
} }
@ -252,58 +250,57 @@ const unzip = function(arrayBuffer) {
// each entry's index is its code and its value is a JavaScript object // each entry's index is its code and its value is a JavaScript object
// containing {length: 6, symbol: X} // containing {length: 6, symbol: X}
function getHuffmanCodes(bitLengths) { function getHuffmanCodes(bitLengths) {
// ensure bitLengths is an array containing at least one element // ensure bitLengths is an array containing at least one element
if (typeof bitLengths != typeof [] || bitLengths.length < 1) { if (typeof bitLengths != typeof [] || bitLengths.length < 1) {
err("Error! getHuffmanCodes() called with an invalid array"); err("Error! getHuffmanCodes() called with an invalid array");
return null; return null;
}
// Reference: http://tools.ietf.org/html/rfc1951#page-8
const numLengths = bitLengths.length;
const bl_count = [];
let MAX_BITS = 1;
// Step 1: count up how many codes of each length we have
for (let i = 0; i < numLengths; ++i) {
const length = bitLengths[i];
// test to ensure each bit length is a positive, non-zero number
if (typeof length != typeof 1 || length < 0) {
err("bitLengths contained an invalid number in getHuffmanCodes(): " + length + " of type " + (typeof length));
return null;
} }
// increment the appropriate bitlength count
if (bl_count[length] == undefined) bl_count[length] = 0;
// a length of zero means this symbol is not participating in the huffman coding
if (length > 0) bl_count[length]++;
if (length > MAX_BITS) MAX_BITS = length;
}
// Reference: http://tools.ietf.org/html/rfc1951#page-8 // Step 2: Find the numerical value of the smallest code for each code length
const numLengths = bitLengths.length; const next_code = [];
const bl_count = []; let code = 0;
let MAX_BITS = 1; for (let bits = 1; bits <= MAX_BITS; ++bits) {
const length = bits-1;
// ensure undefined lengths are zero
if (bl_count[length] == undefined) bl_count[length] = 0;
code = (code + bl_count[bits-1]) << 1;
next_code[bits] = code;
}
// Step 1: count up how many codes of each length we have // Step 3: Assign numerical values to all codes
for (let i = 0; i < numLengths; ++i) { const table = {};
const length = bitLengths[i]; let tableLength = 0;
// test to ensure each bit length is a positive, non-zero number for (let n = 0; n < numLengths; ++n) {
if (typeof length != typeof 1 || length < 0) { const len = bitLengths[n];
err("bitLengths contained an invalid number in getHuffmanCodes(): " + length + " of type " + (typeof length)); if (len != 0) {
return null; table[next_code[len]] = { length: len, symbol: n }; //, bitstring: binaryValueToString(next_code[len],len) };
} tableLength++;
// increment the appropriate bitlength count next_code[len]++;
if (bl_count[length] == undefined) bl_count[length] = 0;
// a length of zero means this symbol is not participating in the huffman coding
if (length > 0) bl_count[length]++;
if (length > MAX_BITS) MAX_BITS = length;
} }
}
table.maxLength = tableLength;
// Step 2: Find the numerical value of the smallest code for each code length return table;
const next_code = [];
let code = 0;
for (let bits = 1; bits <= MAX_BITS; ++bits) {
const length = bits-1;
// ensure undefined lengths are zero
if (bl_count[length] == undefined) bl_count[length] = 0;
code = (code + bl_count[bits-1]) << 1;
next_code[bits] = code;
}
// Step 3: Assign numerical values to all codes
const table = {};
let tableLength = 0;
for (let n = 0; n < numLengths; ++n) {
const len = bitLengths[n];
if (len != 0) {
table[next_code[len]] = { length: len, symbol: n }; //, bitstring: binaryValueToString(next_code[len],len) };
tableLength++;
next_code[len]++;
}
}
table.maxLength = tableLength;
return table;
} }
/* /*
@ -341,42 +338,42 @@ function getFixedLiteralTable() {
} }
function getFixedDistanceTable() { function getFixedDistanceTable() {
// create once // create once
if (!fixedHCtoDistance) { if (!fixedHCtoDistance) {
const bitlengths = new Array(32); const bitlengths = new Array(32);
for (let i = 0; i < 32; ++i) { bitlengths[i] = 5; } for (let i = 0; i < 32; ++i) { bitlengths[i] = 5; }
// get huffman code table // get huffman code table
fixedHCtoDistance = getHuffmanCodes(bitlengths); fixedHCtoDistance = getHuffmanCodes(bitlengths);
} }
return fixedHCtoDistance; return fixedHCtoDistance;
} }
// extract one bit at a time until we find a matching Huffman Code // extract one bit at a time until we find a matching Huffman Code
// then return that symbol // then return that symbol
function decodeSymbol(bstream, hcTable) { function decodeSymbol(bstream, hcTable) {
let code = 0; let code = 0;
let len = 0; let len = 0;
let match = false; let match = false;
// loop until we match // loop until we match
for (;;) { for (;;) {
// read in next bit // read in next bit
const bit = bstream.readBits(1); const bit = bstream.readBits(1);
code = (code<<1) | bit; code = (code<<1) | bit;
++len; ++len;
// check against Huffman Code table and break if found // check against Huffman Code table and break if found
if (hcTable.hasOwnProperty(code) && hcTable[code].length == len) { if (hcTable.hasOwnProperty(code) && hcTable[code].length == len) {
break; break;
}
if (len > hcTable.maxLength) {
err("Bit stream out of sync, didn't find a Huffman Code, length was " + len +
" and table only max code length of " + hcTable.maxLength);
break;
}
} }
return hcTable[code].symbol; if (len > hcTable.maxLength) {
err("Bit stream out of sync, didn't find a Huffman Code, length was " + len +
" and table only max code length of " + hcTable.maxLength);
break;
}
}
return hcTable[code].symbol;
} }
@ -441,67 +438,65 @@ const DistLookupTable = [
]; ];
function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) {
/* /*
loop (until end of block code recognized) loop (until end of block code recognized)
decode literal/length value from input stream decode literal/length value from input stream
if value < 256 if value < 256
copy value (literal byte) to output stream copy value (literal byte) to output stream
otherwise otherwise
if value = end of block (256) if value = end of block (256)
break from loop break from loop
otherwise (value = 257..285) otherwise (value = 257..285)
decode distance from input stream decode distance from input stream
move backwards distance bytes in the output move backwards distance bytes in the output
stream, and copy length bytes from this stream, and copy length bytes from this
position to the output stream. position to the output stream.
*/ */
let numSymbols = 0; let numSymbols = 0;
let blockSize = 0; let blockSize = 0;
for (;;) { for (;;) {
const symbol = decodeSymbol(bstream, hcLiteralTable); const symbol = decodeSymbol(bstream, hcLiteralTable);
++numSymbols; ++numSymbols;
if (symbol < 256) { if (symbol < 256) {
// copy literal byte to output // copy literal byte to output
buffer.insertByte(symbol); buffer.insertByte(symbol);
blockSize++; blockSize++;
} else {
// end of block reached
if (symbol == 256) {
break;
} else {
const lengthLookup = LengthLookupTable[symbol - 257];
let length = lengthLookup[1] + bstream.readBits(lengthLookup[0]);
const distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)];
let distance = distLookup[1] + bstream.readBits(distLookup[0]);
// now apply length and distance appropriately and copy to output
// TODO: check that backward distance < data.length?
// http://tools.ietf.org/html/rfc1951#page-11
// "Note also that the referenced string may overlap the current
// position; for example, if the last 2 bytes decoded have values
// X and Y, a string reference with <length = 5, distance = 2>
// adds X,Y,X,Y,X to the output stream."
//
// loop for each character
let ch = buffer.ptr - distance;
blockSize += length;
if(length > distance) {
const data = buffer.data;
while (length--) {
buffer.insertByte(data[ch++]);
}
} else {
buffer.insertBytes(buffer.data.subarray(ch, ch + length))
} }
else { } // length-distance pair
// end of block reached } // length-distance pair or end-of-block
if (symbol == 256) { } // loop until we reach end of block
break; return blockSize;
}
else {
const lengthLookup = LengthLookupTable[symbol - 257];
let length = lengthLookup[1] + bstream.readBits(lengthLookup[0]);
const distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)];
let distance = distLookup[1] + bstream.readBits(distLookup[0]);
// now apply length and distance appropriately and copy to output
// TODO: check that backward distance < data.length?
// http://tools.ietf.org/html/rfc1951#page-11
// "Note also that the referenced string may overlap the current
// position; for example, if the last 2 bytes decoded have values
// X and Y, a string reference with <length = 5, distance = 2>
// adds X,Y,X,Y,X to the output stream."
//
// loop for each character
let ch = buffer.ptr - distance;
blockSize += length;
if(length > distance) {
const data = buffer.data;
while (length--) {
buffer.insertByte(data[ch++]);
}
} else {
buffer.insertBytes(buffer.data.subarray(ch, ch + length))
}
} // length-distance pair
} // length-distance pair or end-of-block
} // loop until we reach end of block
return blockSize;
} }
// {Uint8Array} compressedData A Uint8Array of the compressed file data. // {Uint8Array} compressedData A Uint8Array of the compressed file data.
@ -520,101 +515,96 @@ function inflate(compressedData, numDecompressedBytes) {
// block format: http://tools.ietf.org/html/rfc1951#page-9 // block format: http://tools.ietf.org/html/rfc1951#page-9
let bFinal = 0; let bFinal = 0;
do { do {
bFinal = bstream.readBits(1); bFinal = bstream.readBits(1);
let bType = bstream.readBits(2); let bType = bstream.readBits(2);
blockSize = 0; blockSize = 0;
++numBlocks; ++numBlocks;
// no compression // no compression
if (bType == 0) { if (bType == 0) {
// skip remaining bits in this byte // skip remaining bits in this byte
while (bstream.bitPtr != 0) bstream.readBits(1); while (bstream.bitPtr != 0) bstream.readBits(1);
const len = bstream.readBits(16); const len = bstream.readBits(16);
const nlen = bstream.readBits(16); const nlen = bstream.readBits(16);
// TODO: check if nlen is the ones-complement of len? // TODO: check if nlen is the ones-complement of len?
if (len > 0) buffer.insertBytes(bstream.readBytes(len)); if (len > 0) buffer.insertBytes(bstream.readBytes(len));
blockSize = len; blockSize = len;
}
// fixed Huffman codes
else if(bType == 1) {
blockSize = inflateBlockData(bstream, getFixedLiteralTable(), getFixedDistanceTable(), buffer);
}
// dynamic Huffman codes
else if(bType == 2) {
const numLiteralLengthCodes = bstream.readBits(5) + 257;
const numDistanceCodes = bstream.readBits(5) + 1;
const numCodeLengthCodes = bstream.readBits(4) + 4;
// populate the array of code length codes (first de-compaction)
const codeLengthsCodeLengths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
for (let i = 0; i < numCodeLengthCodes; ++i) {
codeLengthsCodeLengths[ CodeLengthCodeOrder[i] ] = bstream.readBits(3);
}
// get the Huffman Codes for the code lengths
const codeLengthsCodes = getHuffmanCodes(codeLengthsCodeLengths);
// now follow this mapping
/*
0 - 15: Represent code lengths of 0 - 15
16: Copy the previous code length 3 - 6 times.
The next 2 bits indicate repeat length
(0 = 3, ... , 3 = 6)
Example: Codes 8, 16 (+2 bits 11),
16 (+2 bits 10) will expand to
12 code lengths of 8 (1 + 6 + 5)
17: Repeat a code length of 0 for 3 - 10 times.
(3 bits of length)
18: Repeat a code length of 0 for 11 - 138 times
(7 bits of length)
*/
// to generate the true code lengths of the Huffman Codes for the literal
// and distance tables together
const literalCodeLengths = [];
let prevCodeLength = 0;
while (literalCodeLengths.length < numLiteralLengthCodes + numDistanceCodes) {
const symbol = decodeSymbol(bstream, codeLengthsCodes);
if (symbol <= 15) {
literalCodeLengths.push(symbol);
prevCodeLength = symbol;
} else if (symbol == 16) {
let repeat = bstream.readBits(2) + 3;
while (repeat--) {
literalCodeLengths.push(prevCodeLength);
}
} else if (symbol == 17) {
let repeat = bstream.readBits(3) + 3;
while (repeat--) {
literalCodeLengths.push(0);
}
} else if (symbol == 18) {
let repeat = bstream.readBits(7) + 11;
while (repeat--) {
literalCodeLengths.push(0);
}
} }
// fixed Huffman codes }
else if(bType == 1) {
blockSize = inflateBlockData(bstream, getFixedLiteralTable(), getFixedDistanceTable(), buffer);
}
// dynamic Huffman codes
else if(bType == 2) {
const numLiteralLengthCodes = bstream.readBits(5) + 257;
const numDistanceCodes = bstream.readBits(5) + 1;
const numCodeLengthCodes = bstream.readBits(4) + 4;
// populate the array of code length codes (first de-compaction) // now split the distance code lengths out of the literal code array
const codeLengthsCodeLengths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; const distanceCodeLengths = literalCodeLengths.splice(numLiteralLengthCodes, numDistanceCodes);
for (let i = 0; i < numCodeLengthCodes; ++i) {
codeLengthsCodeLengths[ CodeLengthCodeOrder[i] ] = bstream.readBits(3);
}
// get the Huffman Codes for the code lengths // now generate the true Huffman Code tables using these code lengths
const codeLengthsCodes = getHuffmanCodes(codeLengthsCodeLengths); const hcLiteralTable = getHuffmanCodes(literalCodeLengths);
const hcDistanceTable = getHuffmanCodes(distanceCodeLengths);
blockSize = inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer);
} else { // error
err("Error! Encountered deflate block of type 3");
return null;
}
// now follow this mapping // update progress
/* currentBytesUnarchivedInFile += blockSize;
0 - 15: Represent code lengths of 0 - 15 currentBytesUnarchived += blockSize;
16: Copy the previous code length 3 - 6 times. postProgress();
The next 2 bits indicate repeat length
(0 = 3, ... , 3 = 6)
Example: Codes 8, 16 (+2 bits 11),
16 (+2 bits 10) will expand to
12 code lengths of 8 (1 + 6 + 5)
17: Repeat a code length of 0 for 3 - 10 times.
(3 bits of length)
18: Repeat a code length of 0 for 11 - 138 times
(7 bits of length)
*/
// to generate the true code lengths of the Huffman Codes for the literal
// and distance tables together
const literalCodeLengths = [];
let prevCodeLength = 0;
while (literalCodeLengths.length < numLiteralLengthCodes + numDistanceCodes) {
const symbol = decodeSymbol(bstream, codeLengthsCodes);
if (symbol <= 15) {
literalCodeLengths.push(symbol);
prevCodeLength = symbol;
}
else if (symbol == 16) {
let repeat = bstream.readBits(2) + 3;
while (repeat--) {
literalCodeLengths.push(prevCodeLength);
}
}
else if (symbol == 17) {
let repeat = bstream.readBits(3) + 3;
while (repeat--) {
literalCodeLengths.push(0);
}
}
else if (symbol == 18) {
let repeat = bstream.readBits(7) + 11;
while (repeat--) {
literalCodeLengths.push(0);
}
}
}
// now split the distance code lengths out of the literal code array
const distanceCodeLengths = literalCodeLengths.splice(numLiteralLengthCodes, numDistanceCodes);
// now generate the true Huffman Code tables using these code lengths
const hcLiteralTable = getHuffmanCodes(literalCodeLengths);
const hcDistanceTable = getHuffmanCodes(distanceCodeLengths);
blockSize = inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer);
}
// error
else {
err("Error! Encountered deflate block of type 3");
return null;
}
// update progress
currentBytesUnarchivedInFile += blockSize;
currentBytesUnarchived += blockSize;
postProgress();
} while (bFinal != 1); } while (bFinal != 1);
// we are done reading blocks if the bFinal bit was set for this block // we are done reading blocks if the bFinal bit was set for this block

View file

@ -124,7 +124,6 @@ bitjs.io.BitStream = class {
// shifting/masking it to just extract the bits we want. // shifting/masking it to just extract the bits we want.
// This could be considerably faster when reading more than 3 or 4 bits at a time. // This could be considerably faster when reading more than 3 or 4 bits at a time.
while (n > 0) { while (n > 0) {
if (bytePtr >= bytes.length) { if (bytePtr >= bytes.length) {
throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" + throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" +
bytes.length + ", bitPtr=" + bitPtr; bytes.length + ", bitPtr=" + bitPtr;

View file

@ -40,8 +40,9 @@ bitjs.io.ByteStream = class {
*/ */
peekNumber(n) { peekNumber(n) {
// TODO: return error if n would go past the end of the stream? // TODO: return error if n would go past the end of the stream?
if (n <= 0 || typeof n != typeof 1) if (n <= 0 || typeof n != typeof 1) {
return -1; return -1;
}
let result = 0; let result = 0;
// read from last byte to first byte and roll them in // read from last byte to first byte and roll them in