I have encountered the following function and its usage, yet I am unable to ascertain the reason behind the reported error stating that the offset is out of bounds.
My function:
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);
But the browser throws this error
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
The line with the error is the call to zipFile.set() in
centralDirectory.forEach((entry) => {
zipFile.set(entry, currentOffset);
currentOffset += entry.length;
});
"I haven't attempted anything thus far, but I find myself in need of assistance!
Could someone please guide me on how to solve this issue? Alternatively, is it possible that there's a bug within the zip function? If so, could you please point out where it might be located?
The problem is that you're starting the loops that fill in
zipFileusing the value ofcurrentOffsetat the end of thezipData.foreach()loop. You need to reset it to0before filling inzipFile. So addbefore