文件压缩期间的越界偏移

问题描述 投票:0回答:1

嗯,我有以下功能和用法,但无法弄清楚为什么它说偏移量超出范围。

我的功能:

function zip(files, zipFileName) {
    const zipData = [];
    files.forEach((file) => {
        const content = new TextEncoder().encode(file.content);
        zipData.push({
            name: file.name,
            content,
            contentLength: content.length
        });
    });
    const centralDirectory = [];
    let currentOffset = 0;
    zipData.forEach((file) => {
        centralDirectory.push({
            name: file.name,
            offset: currentOffset,
            contentLength: file.contentLength
        });
        currentOffset += file.contentLength;
    });
    const zipArray = [];
    zipData.forEach((file) => {
        const header = new Uint8Array([
            0x50, 0x4b, 0x03, 0x04, // local file header signature
            0x0A, 0x00, // version needed to extract
            0x00, 0x00, // general purpose bit flag
            0x00, 0x00, // compression method
            0x00, 0x00, 0x00, 0x00, // file modification time
            0x00, 0x00, 0x00, 0x00, // file modification date
            0x00, 0x00, 0x00, 0x00, // CRC-32
            0x00, 0x00, 0x00, 0x00, // compressed size
            0x00, 0x00, 0x00, 0x00, // uncompressed size
            file.name.length, 0x00 // file name length
        ]);
        const headerArray = new Uint8Array(header.length + file.name.length);
        headerArray.set(header);
        headerArray.set(new TextEncoder().encode(file.name), header.length);
        const content = new Uint8Array(file.content);
        const fileEntry = new Uint8Array(headerArray.length + content.length);
        fileEntry.set(headerArray);
        fileEntry.set(content, headerArray.length);
        zipArray.push(fileEntry);
    });
    const centralDirectoryArray = [];
    centralDirectory.forEach((file) => {
        const header = new Uint8Array([
            0x50, 0x4b, 0x01, 0x02, // central file header signature
            0x0A, 0x00, // version made by
            0x0A, 0x00, // version needed to extract
            0x00, 0x00, // general purpose bit flag
            0x00, 0x00, // compression method
            0x00, 0x00, 0x00, 0x00, // file modification time
            0x00, 0x00, 0x00, 0x00, // file modification date
            0x00, 0x00, 0x00, 0x00, // CRC-32
            0x00, 0x00, 0x00, 0x00, // compressed size
            0x00, 0x00, 0x00, 0x00, // uncompressed size
            file.name.length, 0x00, // file name length
            0x00, 0x00, // extra field length
            0x00, 0x00, // file comment length
            0x00, 0x00, // disk number start
            0x00, 0x00, // internal file attributes
            0x00, 0x00, 0x00, 0x00, // external file attributes
            file.currentOffset & 0xFF, // relative offset of local header (lo)
            (file.currentOffset >> 8) & 0xFF, // relative offset of local header (hi)
        ]);
        const headerArray = new Uint8Array(header.length + file.name.length);
        headerArray.set(header);
        headerArray.set(new TextEncoder().encode(file.name), header.length);
        centralDirectoryArray.push(headerArray);
    });
    const endOfCentralDirectory = new Uint8Array([
        0x50, 0x4b, 0x05, 0x06, // end of central directory signature
        0x00, 0x00, 0x00, 0x00, // number of this disk
        0x00, 0x00, 0x00, 0x00, // number of the disk with the start of the central directory
        centralDirectoryArray.length & 0xFF, // total number of entries in the central directory on this disk (lo)
        (centralDirectoryArray.length >> 8) & 0xFF, // total number of entries in the central directory on this disk (hi)
        centralDirectoryArray.length & 0xFF, // total number of entries in the central directory (lo)
        (centralDirectoryArray.length >> 8) & 0xFF, // total number of entries in the central directory (hi)
        centralDirectoryArray.reduce((acc, entry) => acc + entry.length, 0) & 0xFFFFFFFF, // size of the central directory (lo)
        ((centralDirectoryArray.reduce((acc, entry) => acc + entry.length, 0) >> 8) & 0xFFFFFFFF) & 0xFF, // size of the central directory (hi)
        (currentOffset & 0xFFFFFFFF) & 0xFF, // offset of start of central directory with respect to the starting disk number (lo)
        ((currentOffset & 0xFFFFFFFF) >> 8) & 0xFF, // offset of start of central directory with respect to the starting disk number (hi)
        0x00, 0x00 // .zip file comment length
    ]);
    const zipFile = new Uint8Array(zipArray.reduce((acc, entry) => acc + entry.length, 0) + centralDirectoryArray.reduce((acc, entry) => acc + entry.length, 0) + endOfCentralDirectory.length);
    zipArray.forEach((entry) => {
        zipFile.set(entry, currentOffset);
        currentOffset += entry.length;
    });
    centralDirectoryArray.forEach((entry) => {
        zipFile.set(entry, currentOffset);
        currentOffset += entry.length;
    });
    zipFile.set(endOfCentralDirectory, currentOffset);
    const zipBlob = new Blob([zipFile], { type: 'application/zip' });
    const link = document.createElement('a');
    link.href = window.URL.createObjectURL(zipBlob);
    link.download = zipFileName;
    link.click();
    return zipBlob;
}

我这样使用它:

const files = [
    {
        name: 'file1.txt',
        content: 'This is the content of file 1.',
    },
    {
        name: 'file2.txt',
        content: 'This is the content of file 2.',
    }
];

// Zip the files
const zipFileName = 'Archive.zip';
zip(files, zipFileName);

但是浏览器抛出这个错误

Uncaught RangeError: offset is out of bounds
at Uint8Array.set (<anonymous>)
at file.js:228:21
at Array.forEach (<anonymous>)
at File.zip (file.js:227:31)
at index.js:17:19

我没有尝试过任何东西,但我需要帮助,伙计们!!

我该如何解决它,或者是函数中的错误

zip

如果是bug,你能告诉我哪里吗!!

javascript zip offset
1个回答
0
投票

我怀疑问题在于,当您创建

Uint8Array
时,您使用类似
+ file.name.length
的内容来指定长度。但是当你存储到数组中时,你使用
Textencoder.encode(file.name)
。编码器返回的数据可能比原始名称长,因此这里尝试设置在数组之外。使用编码名称的长度。更改代码如下

        const headerArray = new Uint8Array(header.length + file.name.length);
        headerArray.set(header);
        headerArray.set(new TextEncoder().encode(file.name), header.length);

        const encodedName = new TextEncoder().encode(file.name);
        const headerArray = new Uint8Array(header.length + encodedName.length);
        headerArray.set(header);
        headerArray.set(encodedName, header.length);
© www.soinside.com 2019 - 2024. All rights reserved.