63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
import {getByteLength} from './common';
|
|
|
|
let crcTable!: number[];
|
|
|
|
export default class Zip {
|
|
private blob: BlobPart[] = [];
|
|
private files: {header: BlobPart[], offset: number, name: string}[] = [];
|
|
private offset = 0;
|
|
|
|
constructor() {
|
|
if(crcTable !== undefined!) return;
|
|
crcTable = [];
|
|
for(let c, n = 0; n < 256; n++) {
|
|
c = n;
|
|
for(let k = 0; k < 8; k++)
|
|
c = ((c & 1) ? ((c >>> 1) ^ 0xEDB88320) : (c >>> 1)); //tslint:disable-line:strict-boolean-expressions
|
|
crcTable[n] = c;
|
|
}
|
|
}
|
|
|
|
addFile(name: string, content: string): void {
|
|
let crc = -1;
|
|
let length = 0;
|
|
const nameLength = getByteLength(name);
|
|
for(let i = 0, strlen = content.length; i < strlen; ++i) {
|
|
let c = content.charCodeAt(i);
|
|
if(c > 0xD800 && c < 0xD8FF) //surrogate pairs
|
|
c = (c - 0xD800) * 0x400 + content.charCodeAt(++i) - 0xDC00 + 0x10000;
|
|
let l = c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : c < 0x200000 ? 4 : c < 0x4000000 ? 5 : 6;
|
|
length += l;
|
|
let byte = l === 1 ? c : ((0xFF00 >> l) % 256) | (c >>> (l - 1) * 6);
|
|
--l;
|
|
while(true) {
|
|
crc = (crc >>> 8) ^ crcTable[(crc ^ byte) & 0xFF];
|
|
if(--l >= 0) byte = ((c >>> (l * 6)) & 0x3F) | 0x80;
|
|
else break;
|
|
}
|
|
}
|
|
crc = (crc ^ (-1)) >>> 0;
|
|
const file = {
|
|
header: [Uint16Array.of(0, 0, 0, 0, 0), Uint32Array.of(crc, length, length), Uint16Array.of(nameLength, 0)],
|
|
offset: this.offset, name
|
|
};
|
|
this.blob.push(Uint32Array.of(0x04034B50));
|
|
this.blob.push(...file.header);
|
|
this.blob.push(name, content);
|
|
this.offset += nameLength + length + 30;
|
|
this.files.push(file);
|
|
}
|
|
|
|
build(): Blob {
|
|
const start = this.offset;
|
|
for(const file of this.files) {
|
|
this.blob.push(Uint16Array.of(0x4B50, 0x0201, 0));
|
|
this.blob.push(...file.header);
|
|
this.blob.push(Uint16Array.of(0, 0, 0, 0, 0), Uint32Array.of(file.offset), file.name);
|
|
this.offset += getByteLength(file.name) + 46;
|
|
}
|
|
this.blob.push(Uint16Array.of(0x4B50, 0x0605, 0, 0, this.files.length, this.files.length),
|
|
Uint32Array.of(this.offset - start, start), Uint16Array.of(0));
|
|
return new Blob(this.blob);
|
|
}
|
|
} |