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

@ -61,7 +61,7 @@ class ZipLocalFile {
// takes a ByteStream and parses out the local file information
constructor(bstream) {
if (typeof bstream != typeof {} || !bstream.readNumber || typeof bstream.readNumber != typeof function(){}) {
return null;
return null;
}
bstream.readNumber(4); // swallow signature
@ -78,7 +78,7 @@ class ZipLocalFile {
this.filename = null;
if (this.fileNameLength > 0) {
this.filename = bstream.readString(this.fileNameLength);
this.filename = bstream.readString(this.fileNameLength);
}
info("Zip Local File Header:");
@ -96,14 +96,14 @@ class ZipLocalFile {
this.extraField = null;
if (this.extraFieldLength > 0) {
this.extraField = bstream.readString(this.extraFieldLength);
info(" extra field=" + this.extraField);
this.extraField = bstream.readString(this.extraFieldLength);
info(" extra field=" + this.extraField);
}
// read in the compressed data
this.fileData = null;
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!)
@ -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
// from the header?!?
if ((this.generalPurpose & BIT[3]) != 0) {
this.crc32 = bstream.readNumber(4);
this.compressedSize = bstream.readNumber(4);
this.uncompressedSize = bstream.readNumber(4);
this.crc32 = bstream.readNumber(4);
this.compressedSize = bstream.readNumber(4);
this.uncompressedSize = bstream.readNumber(4);
}
}
@ -154,97 +154,95 @@ const unzip = function(arrayBuffer) {
const bstream = new bitjs.io.ByteStream(arrayBuffer);
// detect local file header signature or return null
if (bstream.peekNumber(4) == zLocalFileHeaderSignature) {
const localFiles = [];
// loop until we don't see any more local files
while (bstream.peekNumber(4) == zLocalFileHeaderSignature) {
const oneLocalFile = new ZipLocalFile(bstream);
// this should strip out directories/folders
if (oneLocalFile && oneLocalFile.uncompressedSize > 0 && oneLocalFile.fileData) {
localFiles.push(oneLocalFile);
totalUncompressedBytesInArchive += oneLocalFile.uncompressedSize;
}
}
totalFilesInArchive = localFiles.length;
const localFiles = [];
// loop until we don't see any more local files
while (bstream.peekNumber(4) == zLocalFileHeaderSignature) {
const oneLocalFile = new ZipLocalFile(bstream);
// this should strip out directories/folders
if (oneLocalFile && oneLocalFile.uncompressedSize > 0 && oneLocalFile.fileData) {
localFiles.push(oneLocalFile);
totalUncompressedBytesInArchive += oneLocalFile.uncompressedSize;
}
}
totalFilesInArchive = localFiles.length;
// got all local files, now sort them
localFiles.sort(function(a,b) {
return a.filename > b.filename ? 1 : -1;
});
// got all local files, now sort them
localFiles.sort((a,b) => a.filename > b.filename ? 1 : -1);
// archive extra data record
if (bstream.peekNumber(4) == zArchiveExtraDataSignature) {
info(" Found an Archive Extra Data Signature");
// archive extra data record
if (bstream.peekNumber(4) == zArchiveExtraDataSignature) {
info(" Found an Archive Extra Data Signature");
// skipping this record for now
bstream.readNumber(4);
const archiveExtraFieldLength = bstream.readNumber(4);
bstream.readString(archiveExtraFieldLength);
}
// skipping this record for now
bstream.readNumber(4);
const archiveExtraFieldLength = bstream.readNumber(4);
bstream.readString(archiveExtraFieldLength);
}
// central directory structure
// TODO: handle the rest of the structures (Zip64 stuff)
if (bstream.peekNumber(4) == zCentralFileHeaderSignature) {
info(" Found a Central File Header");
// central directory structure
// TODO: handle the rest of the structures (Zip64 stuff)
if (bstream.peekNumber(4) == zCentralFileHeaderSignature) {
info(" Found a Central File Header");
// read all file headers
while (bstream.peekNumber(4) == zCentralFileHeaderSignature) {
bstream.readNumber(4); // signature
bstream.readNumber(2); // version made by
bstream.readNumber(2); // version needed to extract
bstream.readNumber(2); // general purpose bit flag
bstream.readNumber(2); // compression method
bstream.readNumber(2); // last mod file time
bstream.readNumber(2); // last mod file date
bstream.readNumber(4); // crc32
bstream.readNumber(4); // compressed size
bstream.readNumber(4); // uncompressed size
const fileNameLength = bstream.readNumber(2); // file name length
const extraFieldLength = bstream.readNumber(2); // extra field length
const fileCommentLength = bstream.readNumber(2); // file comment length
bstream.readNumber(2); // disk number start
bstream.readNumber(2); // internal file attributes
bstream.readNumber(4); // external file attributes
bstream.readNumber(4); // relative offset of local header
// read all file headers
while (bstream.peekNumber(4) == zCentralFileHeaderSignature) {
bstream.readNumber(4); // signature
bstream.readNumber(2); // version made by
bstream.readNumber(2); // version needed to extract
bstream.readNumber(2); // general purpose bit flag
bstream.readNumber(2); // compression method
bstream.readNumber(2); // last mod file time
bstream.readNumber(2); // last mod file date
bstream.readNumber(4); // crc32
bstream.readNumber(4); // compressed size
bstream.readNumber(4); // uncompressed size
const fileNameLength = bstream.readNumber(2); // file name length
const extraFieldLength = bstream.readNumber(2); // extra field length
const fileCommentLength = bstream.readNumber(2); // file comment length
bstream.readNumber(2); // disk number start
bstream.readNumber(2); // internal file attributes
bstream.readNumber(4); // external file attributes
bstream.readNumber(4); // relative offset of local header
bstream.readString(fileNameLength); // file name
bstream.readString(extraFieldLength); // extra field
bstream.readString(fileCommentLength); // file comment
}
}
bstream.readString(fileNameLength); // file name
bstream.readString(extraFieldLength); // extra field
bstream.readString(fileCommentLength); // file comment
}
}
// digital signature
if (bstream.peekNumber(4) == zDigitalSignatureSignature) {
info(" Found a Digital Signature");
// digital signature
if (bstream.peekNumber(4) == zDigitalSignatureSignature) {
info(" Found a Digital Signature");
bstream.readNumber(4);
const sizeOfSignature = bstream.readNumber(2);
bstream.readString(sizeOfSignature); // digital signature data
}
bstream.readNumber(4);
const sizeOfSignature = bstream.readNumber(2);
bstream.readString(sizeOfSignature); // digital signature data
}
// report # files and total length
if (localFiles.length > 0) {
postProgress();
}
// report # files and total length
if (localFiles.length > 0) {
postProgress();
}
// now do the unzipping of each file
for (let i = 0; i < localFiles.length; ++i) {
const localfile = localFiles[i];
// now do the unzipping of each file
for (let i = 0; i < localFiles.length; ++i) {
const localfile = localFiles[i];
// update progress
currentFilename = localfile.filename;
currentFileNumber = i;
currentBytesUnarchivedInFile = 0;
// update progress
currentFilename = localfile.filename;
currentFileNumber = i;
currentBytesUnarchivedInFile = 0;
// actually do the unzipping
localfile.unzip();
// actually do the unzipping
localfile.unzip();
if (localfile.fileData != null) {
postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile));
postProgress();
}
}
if (localfile.fileData != null) {
postMessage(new bitjs.archive.UnarchiveExtractEvent(localfile));
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
// containing {length: 6, symbol: X}
function getHuffmanCodes(bitLengths) {
// ensure bitLengths is an array containing at least one element
if (typeof bitLengths != typeof [] || bitLengths.length < 1) {
err("Error! getHuffmanCodes() called with an invalid array");
return null;
// ensure bitLengths is an array containing at least one element
if (typeof bitLengths != typeof [] || bitLengths.length < 1) {
err("Error! getHuffmanCodes() called with an invalid array");
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
const numLengths = bitLengths.length;
const bl_count = [];
let MAX_BITS = 1;
// Step 2: Find the numerical value of the smallest code for each code length
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 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;
// 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;
// Step 2: Find the numerical value of the smallest code for each code length
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;
return table;
}
/*
@ -341,42 +338,42 @@ function getFixedLiteralTable() {
}
function getFixedDistanceTable() {
// create once
if (!fixedHCtoDistance) {
const bitlengths = new Array(32);
for (let i = 0; i < 32; ++i) { bitlengths[i] = 5; }
// create once
if (!fixedHCtoDistance) {
const bitlengths = new Array(32);
for (let i = 0; i < 32; ++i) { bitlengths[i] = 5; }
// get huffman code table
fixedHCtoDistance = getHuffmanCodes(bitlengths);
}
return fixedHCtoDistance;
// get huffman code table
fixedHCtoDistance = getHuffmanCodes(bitlengths);
}
return fixedHCtoDistance;
}
// extract one bit at a time until we find a matching Huffman Code
// then return that symbol
function decodeSymbol(bstream, hcTable) {
let code = 0;
let len = 0;
let match = false;
let code = 0;
let len = 0;
let match = false;
// loop until we match
for (;;) {
// read in next bit
const bit = bstream.readBits(1);
code = (code<<1) | bit;
++len;
// loop until we match
for (;;) {
// read in next bit
const bit = bstream.readBits(1);
code = (code<<1) | bit;
++len;
// check against Huffman Code table and break if found
if (hcTable.hasOwnProperty(code) && hcTable[code].length == len) {
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;
}
// check against Huffman Code table and break if found
if (hcTable.hasOwnProperty(code) && hcTable[code].length == len) {
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) {
/*
loop (until end of block code recognized)
decode literal/length value from input stream
if value < 256
copy value (literal byte) to output stream
otherwise
if value = end of block (256)
break from loop
otherwise (value = 257..285)
decode distance from input stream
/*
loop (until end of block code recognized)
decode literal/length value from input stream
if value < 256
copy value (literal byte) to output stream
otherwise
if value = end of block (256)
break from loop
otherwise (value = 257..285)
decode distance from input stream
move backwards distance bytes in the output
stream, and copy length bytes from this
position to the output stream.
*/
let numSymbols = 0;
let blockSize = 0;
for (;;) {
const symbol = decodeSymbol(bstream, hcLiteralTable);
++numSymbols;
if (symbol < 256) {
// copy literal byte to output
buffer.insertByte(symbol);
blockSize++;
move backwards distance bytes in the output
stream, and copy length bytes from this
position to the output stream.
*/
let numSymbols = 0;
let blockSize = 0;
for (;;) {
const symbol = decodeSymbol(bstream, hcLiteralTable);
++numSymbols;
if (symbol < 256) {
// copy literal byte to output
buffer.insertByte(symbol);
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 {
// 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))
}
} // length-distance pair
} // length-distance pair or end-of-block
} // loop until we reach end of block
return blockSize;
} // 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.
@ -520,101 +515,96 @@ function inflate(compressedData, numDecompressedBytes) {
// block format: http://tools.ietf.org/html/rfc1951#page-9
let bFinal = 0;
do {
bFinal = bstream.readBits(1);
let bType = bstream.readBits(2);
blockSize = 0;
++numBlocks;
// no compression
if (bType == 0) {
// skip remaining bits in this byte
while (bstream.bitPtr != 0) bstream.readBits(1);
const len = bstream.readBits(16);
const nlen = bstream.readBits(16);
// TODO: check if nlen is the ones-complement of len?
if (len > 0) buffer.insertBytes(bstream.readBytes(len));
blockSize = len;
bFinal = bstream.readBits(1);
let bType = bstream.readBits(2);
blockSize = 0;
++numBlocks;
// no compression
if (bType == 0) {
// skip remaining bits in this byte
while (bstream.bitPtr != 0) bstream.readBits(1);
const len = bstream.readBits(16);
const nlen = bstream.readBits(16);
// TODO: check if nlen is the ones-complement of len?
if (len > 0) buffer.insertBytes(bstream.readBytes(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)
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);
}
// now split the distance code lengths out of the literal code array
const distanceCodeLengths = literalCodeLengths.splice(numLiteralLengthCodes, numDistanceCodes);
// get the Huffman Codes for the code lengths
const codeLengthsCodes = getHuffmanCodes(codeLengthsCodeLengths);
// 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);
} else { // error
err("Error! Encountered deflate block of type 3");
return null;
}
// 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);
}
}
}
// 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();
// update progress
currentBytesUnarchivedInFile += blockSize;
currentBytesUnarchived += blockSize;
postProgress();
} while (bFinal != 1);
// we are done reading blocks if the bFinal bit was set for this block