Spaces:
Sleeping
Sleeping
File size: 3,214 Bytes
b5430db 73f1392 075be5d 73f1392 b5430db 73f1392 b5430db 73f1392 b5430db 73f1392 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import { checkFilename } from './check-filename';
import { WebBlob } from './WebBlob';
export async function* checkDduf(url: string): AsyncGenerator<string> {
const blob = await WebBlob.create(new URL(url));
yield 'File size: ' + blob.size;
// DDUF is a zip file, uncompressed.
const last100kB = await blob.slice(blob.size - 100000, blob.size).arrayBuffer();
const view = new DataView(last100kB);
let index = view.byteLength - 22;
let found = false;
while (index >= 0) {
if (view.getUint32(index, true) === 0x06054b50) {
found = true;
break;
}
index--;
}
if (!found) {
throw new Error('DDUF footer not found in last 100kB of file');
}
yield 'DDUF footer found at offset ' + (blob.size - last100kB.byteLength + index);
const diskNumber = view.getUint16(index + 4, true);
if (diskNumber === 0xffff) {
throw new Error('Spanned archives (ZIP64) not yet supported');
}
if (diskNumber !== 0) {
throw new Error('Multi-disk archives not supported');
}
const fileCount = view.getUint16(index + 10, true);
const centralDirSize = view.getUint32(index + 12, true);
const centralDirOffset = view.getUint32(index + 16, true);
yield 'File count: ' + fileCount;
yield 'Central directory size: ' + centralDirSize;
yield 'Central directory offset: ' + centralDirOffset;
const centralDir =
centralDirOffset > blob.size - last100kB.byteLength
? last100kB.slice(
centralDirOffset - (blob.size - last100kB.byteLength),
centralDirOffset - (blob.size - last100kB.byteLength) + centralDirSize
)
: await blob.slice(centralDirOffset, centralDirOffset + centralDirSize).arrayBuffer();
const centralDirView = new DataView(centralDir);
let offset = 0;
for (let i = 0; i < fileCount; i++) {
if (centralDirView.getUint32(offset + 0, true) !== 0x02014b50) {
throw new Error('Invalid central directory file header');
}
if (offset + 46 > centralDir.byteLength) {
throw new Error('Unexpected end of central directory');
}
const compressionMethod = centralDirView.getUint16(offset + 10, true);
if (compressionMethod !== 0) {
throw new Error('Unsupported compression method: ' + compressionMethod);
}
const size = centralDirView.getUint32(offset + 24, true);
const compressedSize = centralDirView.getUint32(offset + 20, true);
if (size !== compressedSize) {
throw new Error('Compressed size and size differ');
}
const filenameLength = centralDirView.getUint16(offset + 28, true);
const fileName = new TextDecoder().decode(
new Uint8Array(centralDir, offset + 46, filenameLength)
);
yield 'File ' + i;
yield 'File name: ' + fileName;
yield 'File size: ' + size;
checkFilename(fileName);
const fileDiskNumber = centralDirView.getUint16(34, true);
if (fileDiskNumber !== 0) {
throw new Error('Multi-disk archives not supported');
}
const extraFieldLength = centralDirView.getUint16(offset + 30, true);
const commentLength = centralDirView.getUint16(offset + 32, true);
const filePosition = centralDirView.getUint32(offset + 42, true);
yield 'File position in archive: ' + filePosition;
offset += 46 + filenameLength + extraFieldLength + commentLength;
}
yield 'All files checked';
}
|