first commit
This commit is contained in:
273
assets/scripts/libs/gzip/gzip.ts
Normal file
273
assets/scripts/libs/gzip/gzip.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
|
||||
|
||||
import { crc32 } from "./crc32";
|
||||
import * as deflate from "./deflate-js";
|
||||
|
||||
// magic numbers marking this file as GZIP
|
||||
var ID1 = 0x1F,
|
||||
ID2 = 0x8B,
|
||||
compressionMethods = {
|
||||
'deflate': 8
|
||||
},
|
||||
possibleFlags = {
|
||||
'FTEXT': 0x01,
|
||||
'FHCRC': 0x02,
|
||||
'FEXTRA': 0x04,
|
||||
'FNAME': 0x08,
|
||||
'FCOMMENT': 0x10
|
||||
},
|
||||
osMap = {
|
||||
'fat': 0, // FAT file system (DOS, OS/2, NT) + PKZIPW 2.50 VFAT, NTFS
|
||||
'amiga': 1, // Amiga
|
||||
'vmz': 2, // VMS (VAX or Alpha AXP)
|
||||
'unix': 3, // Unix
|
||||
'vm/cms': 4, // VM/CMS
|
||||
'atari': 5, // Atari
|
||||
'hpfs': 6, // HPFS file system (OS/2, NT 3.x)
|
||||
'macintosh': 7, // Macintosh
|
||||
'z-system': 8, // Z-System
|
||||
'cplm': 9, // CP/M
|
||||
'tops-20': 10, // TOPS-20
|
||||
'ntfs': 11, // NTFS file system (NT)
|
||||
'qdos': 12, // SMS/QDOS
|
||||
'acorn': 13, // Acorn RISC OS
|
||||
'vfat': 14, // VFAT file system (Win95, NT)
|
||||
'vms': 15, // MVS (code also taken for PRIMOS)
|
||||
'beos': 16, // BeOS (BeBox or PowerMac)
|
||||
'tandem': 17, // Tandem/NSK
|
||||
'theos': 18 // THEOS
|
||||
},
|
||||
os = 'unix',
|
||||
DEFAULT_LEVEL = 6;
|
||||
|
||||
function putByte(n, arr) {
|
||||
arr.push(n & 0xFF);
|
||||
}
|
||||
|
||||
// LSB first
|
||||
function putShort(n, arr) {
|
||||
arr.push(n & 0xFF);
|
||||
arr.push(n >>> 8);
|
||||
}
|
||||
|
||||
// LSB first
|
||||
function putLong(n, arr) {
|
||||
putShort(n & 0xffff, arr);
|
||||
putShort(n >>> 16, arr);
|
||||
}
|
||||
|
||||
function putString(s, arr) {
|
||||
var i, len = s.length;
|
||||
for (i = 0; i < len; i += 1) {
|
||||
putByte(s.charCodeAt(i), arr);
|
||||
}
|
||||
}
|
||||
|
||||
function readByte(arr) {
|
||||
return arr.shift();
|
||||
}
|
||||
|
||||
function readShort(arr) {
|
||||
return arr.shift() | (arr.shift() << 8);
|
||||
}
|
||||
|
||||
function readLong(arr) {
|
||||
var n1 = readShort(arr),
|
||||
n2 = readShort(arr);
|
||||
|
||||
// JavaScript can't handle bits in the position 32
|
||||
// we'll emulate this by removing the left-most bit (if it exists)
|
||||
// and add it back in via multiplication, which does work
|
||||
if (n2 > 32768) {
|
||||
n2 -= 32768;
|
||||
|
||||
return ((n2 << 16) | n1) + 32768 * Math.pow(2, 16);
|
||||
}
|
||||
|
||||
return (n2 << 16) | n1;
|
||||
}
|
||||
|
||||
function readString(arr) {
|
||||
var charArr = [];
|
||||
|
||||
// turn all bytes into chars until the terminating null
|
||||
while (arr[0] !== 0) {
|
||||
charArr.push(String.fromCharCode(arr.shift()));
|
||||
}
|
||||
|
||||
// throw away terminating null
|
||||
arr.shift();
|
||||
|
||||
// join all characters into a cohesive string
|
||||
return charArr.join('');
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads n number of bytes and return as an array.
|
||||
*
|
||||
* @param arr- Array of bytes to read from
|
||||
* @param n- Number of bytes to read
|
||||
*/
|
||||
function readBytes(arr, n) {
|
||||
var i, ret = [];
|
||||
for (i = 0; i < n; i += 1) {
|
||||
ret.push(arr.shift());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* ZIPs a file in GZIP format. The format is as given by the spec, found at:
|
||||
* http://www.gzip.org/zlib/rfc-gzip.html
|
||||
*
|
||||
* Omitted parts in this implementation:
|
||||
*/
|
||||
export function zip(data, options) {
|
||||
var flags = 0,
|
||||
level,
|
||||
crc, out = [];
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
level = options.level || DEFAULT_LEVEL;
|
||||
|
||||
if (typeof data === 'string') {
|
||||
data = Array.prototype.map.call(data, function (char) {
|
||||
return char.charCodeAt(0);
|
||||
});
|
||||
}
|
||||
|
||||
// magic number marking this file as GZIP
|
||||
putByte(ID1, out);
|
||||
putByte(ID2, out);
|
||||
|
||||
putByte(compressionMethods['deflate'], out);
|
||||
|
||||
if (options.name) {
|
||||
flags |= possibleFlags['FNAME'];
|
||||
}
|
||||
|
||||
putByte(flags, out);
|
||||
putLong(options.timestamp || parseInt(Date.now() / 1000, 10), out);
|
||||
|
||||
// put deflate args (extra flags)
|
||||
if (level === 1) {
|
||||
// fastest algorithm
|
||||
putByte(4, out);
|
||||
} else if (level === 9) {
|
||||
// maximum compression (fastest algorithm)
|
||||
putByte(2, out);
|
||||
} else {
|
||||
putByte(0, out);
|
||||
}
|
||||
|
||||
// OS identifier
|
||||
putByte(osMap[os], out);
|
||||
|
||||
if (options.name) {
|
||||
// ignore the directory part
|
||||
putString(options.name.substring(options.name.lastIndexOf('/') + 1), out);
|
||||
|
||||
// terminating null
|
||||
putByte(0, out);
|
||||
}
|
||||
|
||||
deflate.deflate(data, level).forEach(function (byte) {
|
||||
putByte(byte, out);
|
||||
});
|
||||
|
||||
putLong(parseInt(crc32(data), 16), out);
|
||||
putLong(data.length, out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
export function unzip(data) {
|
||||
// start with a copy of the array
|
||||
var arr = Array.prototype.slice.call(data, 0),
|
||||
t,
|
||||
compressionMethod,
|
||||
flags,
|
||||
mtime,
|
||||
xFlags,
|
||||
key,
|
||||
os,
|
||||
crc,
|
||||
size,
|
||||
res;
|
||||
|
||||
// check the first two bytes for the magic numbers
|
||||
if (readByte(arr) !== ID1 || readByte(arr) !== ID2) {
|
||||
throw 'Not a GZIP file';
|
||||
}
|
||||
|
||||
t = readByte(arr);
|
||||
t = Object.keys(compressionMethods).some(function (key) {
|
||||
compressionMethod = key;
|
||||
return compressionMethods[key] === t;
|
||||
});
|
||||
|
||||
if (!t) {
|
||||
throw 'Unsupported compression method';
|
||||
}
|
||||
|
||||
flags = readByte(arr);
|
||||
mtime = readLong(arr);
|
||||
xFlags = readByte(arr);
|
||||
t = readByte(arr);
|
||||
Object.keys(osMap).some(function (key) {
|
||||
if (osMap[key] === t) {
|
||||
os = key;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// just throw away the bytes for now
|
||||
if (flags & possibleFlags['FEXTRA']) {
|
||||
t = readShort(arr);
|
||||
readBytes(arr, t);
|
||||
}
|
||||
|
||||
// just throw away for now
|
||||
if (flags & possibleFlags['FNAME']) {
|
||||
readString(arr);
|
||||
}
|
||||
|
||||
// just throw away for now
|
||||
if (flags & possibleFlags['FCOMMENT']) {
|
||||
readString(arr);
|
||||
}
|
||||
|
||||
// just throw away for now
|
||||
if (flags & possibleFlags['FHCRC']) {
|
||||
readShort(arr);
|
||||
}
|
||||
|
||||
if (compressionMethod === 'deflate') {
|
||||
// give deflate everything but the last 8 bytes
|
||||
// the last 8 bytes are for the CRC32 checksum and filesize
|
||||
res = deflate.inflate(arr.splice(0, arr.length - 8));
|
||||
}
|
||||
|
||||
if (flags & possibleFlags['FTEXT']) {
|
||||
res = Array.prototype.map.call(res, function (byte) {
|
||||
return String.fromCharCode(byte);
|
||||
}).join('');
|
||||
}
|
||||
|
||||
crc = readLong(arr) >>> 0;
|
||||
if (crc !== parseInt(crc32(res), 16)) {
|
||||
throw 'Checksum does not match';
|
||||
}
|
||||
|
||||
size = readLong(arr);
|
||||
if (size !== res.length) {
|
||||
throw 'Size of decompressed file not correct';
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user