refactor(zip): Use DataView
MODIFY
packages/zip/src/buffer-reader.js
packages/zip/src/buffer-reader.js
@@ -10,10 +10,12 @@ export class BufferReader {
* @param {ArrayBuffer} buffer
*/
constructor(buffer) {
- const data = new Uint8Array(buffer);
+ const bytes = new Uint8Array(buffer);
+ const data = new DataView(bytes.buffer);
privateFields.set(this, {
+ bytes,
data,
- length: data.length,
+ length: bytes.length,
index: 0,
offset: 0,
});
@@ -45,14 +47,14 @@ export class BufferReader {
*/
set offset(offset) {
const fields = privateFields.get(this);
- if (offset > fields.data.length) {
+ if (offset > fields.data.byteLength) {
throw new Error('Cannot set offset beyond length of underlying data');
}
if (offset < 0) {
throw new Error('Cannot set negative offset');
}
fields.offset = offset;
- fields.length = fields.data.length - fields.offset;
+ fields.length = fields.data.byteLength - fields.offset;
}
/**
@@ -102,7 +104,7 @@ export class BufferReader {
// in IE10, when using subarray(idx, idx), we get the array [0x00] instead of [].
return new Uint8Array(0);
}
- const result = fields.data.subarray(
+ const result = fields.bytes.subarray(
fields.offset + fields.index,
fields.offset + fields.index + size,
);
@@ -148,37 +150,34 @@ export class BufferReader {
readUint8() {
const fields = privateFields.get(this);
this.assertCanRead(1);
- const value = fields.data[fields.offset + fields.index];
+ const index = fields.offset + fields.index;
+ const value = fields.data.getUint8(index);
fields.index += 1;
return value;
}
/**
* @returns {number}
+ * @param {boolean=} littleEndian
*/
- readUint16LE() {
+ readUint16(littleEndian) {
const fields = privateFields.get(this);
this.assertCanRead(2);
const index = fields.offset + fields.index;
- const a = fields.data[index + 0];
- const b = fields.data[index + 1];
- const value = (b << 8) | a;
+ const value = fields.data.getUint16(index, littleEndian);
fields.index += 2;
return value;
}
/**
* @returns {number}
+ * @param {boolean=} littleEndian
*/
- readUint32LE() {
+ readUint32(littleEndian) {
const fields = privateFields.get(this);
this.assertCanRead(4);
const index = fields.offset + fields.index;
- const a = fields.data[index + 0];
- const b = fields.data[index + 1];
- const c = fields.data[index + 2];
- const d = fields.data[index + 3];
- const value = ((d << 24) >>> 0) + ((c << 16) | (b << 8) | a);
+ const value = fields.data.getUint32(index, littleEndian);
fields.index += 4;
return value;
}
@@ -189,7 +188,7 @@ export class BufferReader {
*/
byteAt(index) {
const fields = privateFields.get(this);
- return fields.data[fields.offset + index];
+ return fields.bytes[fields.offset + index];
}
/**

MODIFY
packages/zip/src/buffer-writer.js
packages/zip/src/buffer-writer.js
@@ -29,8 +29,10 @@ export class BufferWriter {
* @param {number=} capacity
*/
constructor(capacity = 16) {
- const data = new Uint8Array(capacity);
+ const bytes = new Uint8Array(capacity);
+ const data = new DataView(bytes.buffer);
privateFields.set(this, {
+ bytes,
data,
index: 0,
length: 0,
@@ -47,8 +49,10 @@ export class BufferWriter {
while (capacity < required) {
capacity *= 2;
}
- const data = new Uint8Array(capacity);
- data.set(fields.data.subarray(0, fields.length));
+ const bytes = new Uint8Array(capacity);
+ const data = new DataView(bytes.buffer);
+ bytes.set(fields.bytes.subarray(0, fields.length));
+ fields.bytes = bytes;
fields.data = data;
fields.capacity = capacity;
}
@@ -77,7 +81,7 @@ export class BufferWriter {
write(bytes) {
const fields = privateFields.get(this);
this.ensureCanWrite(bytes.length);
- fields.data.set(bytes, fields.index);
+ fields.bytes.set(bytes, fields.index);
fields.index += bytes.length;
fields.length = Math.max(fields.index, fields.length);
}
@@ -90,7 +94,7 @@ export class BufferWriter {
const fields = privateFields.get(this);
const size = end - start;
this.ensureCanWrite(size);
- fields.data.copyWithin(fields.index, start, end);
+ fields.bytes.copyWithin(fields.index, start, end);
fields.index += size;
fields.length = Math.max(fields.index, fields.length);
}
@@ -101,35 +105,33 @@ export class BufferWriter {
writeUint8(value) {
const fields = privateFields.get(this);
this.ensureCanWrite(1);
- fields.data[fields.index] = value;
+ fields.data.setUint8(fields.index, value);
fields.index += 1;
fields.length = Math.max(fields.index, fields.length);
}
/**
* @param {number} value
+ * @param {boolean=} littleEndian
*/
- writeUint16LE(value) {
+ writeUint16(value, littleEndian) {
const fields = privateFields.get(this);
this.ensureCanWrite(2);
const index = fields.index;
- fields.data[index + 0] = value >>> 0;
- fields.data[index + 1] = value >>> 8;
+ fields.data.setUint16(index, value, littleEndian);
fields.index += 2;
fields.length = Math.max(fields.index, fields.length);
}
/**
* @param {number} value
+ * @param {boolean=} littleEndian
*/
- writeUint32LE(value) {
+ writeUint32(value, littleEndian) {
const fields = privateFields.get(this);
this.ensureCanWrite(4);
const index = fields.index;
- fields.data[index + 0] = value >>> 0;
- fields.data[index + 1] = value >>> 8;
- fields.data[index + 2] = value >>> 16;
- fields.data[index + 3] = value >>> 24;
+ fields.data.setUint32(index, value, littleEndian);
fields.index += 4;
fields.length = Math.max(fields.index, fields.length);
}
@@ -141,7 +143,7 @@ export class BufferWriter {
*/
subarray(begin, end) {
const fields = privateFields.get(this);
- return fields.data.subarray(0, fields.length).subarray(begin, end);
+ return fields.bytes.subarray(0, fields.length).subarray(begin, end);
}
/**

MODIFY
packages/zip/src/format-reader.js
packages/zip/src/format-reader.js
* seek: (index: number) => void,
* expect: (bytes: Uint8Array) => boolean,
* readUint8: () => number,
- * readUint16LE: () => number,
- * readUint32LE: () => number,
+ * readUint16: (littleEndian?: boolean) => number,
+ * readUint32: (littleEndian?: boolean) => number,
* }} BufferReader
*/
@@ -69,7 +69,7 @@ function isEncrypted(bitFlag) {
* @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
*/
function readDosDateTime(reader) {
- const dosTime = reader.readUint32LE();
+ const dosTime = reader.readUint32(true);
return new Date(
Date.UTC(
((dosTime >> 25) & 0x7f) + 1980, // year
@@ -88,13 +88,13 @@ function readDosDateTime(reader) {
*/
function readHeaders(reader) {
return {
- versionNeeded: reader.readUint16LE(),
- bitFlag: reader.readUint16LE(),
- compressionMethod: reader.readUint16LE(),
+ versionNeeded: reader.readUint16(true),
+ bitFlag: reader.readUint16(true),
+ compressionMethod: reader.readUint16(true),
date: readDosDateTime(reader),
- crc32: reader.readUint32LE(),
- compressedLength: reader.readUint32LE(),
- uncompressedLength: reader.readUint32LE(),
+ crc32: reader.readUint32(true),
+ compressedLength: reader.readUint32(true),
+ uncompressedLength: reader.readUint32(true),
};
}
@@ -106,13 +106,13 @@ function readCentralFileHeader(reader) {
const version = reader.readUint8();
const madeBy = reader.readUint8();
const headers = readHeaders(reader);
- const nameLength = reader.readUint16LE();
- const extraFieldsLength = reader.readUint16LE();
- const commentLength = reader.readUint16LE();
- const diskNumberStart = reader.readUint16LE();
- const internalFileAttributes = reader.readUint16LE();
- const externalFileAttributes = reader.readUint32LE();
- const fileStart = reader.readUint32LE();
+ const nameLength = reader.readUint16(true);
+ const extraFieldsLength = reader.readUint16(true);
+ const commentLength = reader.readUint16(true);
+ const diskNumberStart = reader.readUint16(true);
+ const internalFileAttributes = reader.readUint16(true);
+ const externalFileAttributes = reader.readUint32(true);
+ const fileStart = reader.readUint32(true);
const name = reader.read(nameLength);
// TODO read extra fields, particularly Zip64
@@ -179,8 +179,8 @@ function readCentralDirectory(reader, locator) {
function readFile(reader) {
reader.expect(signature.LOCAL_FILE_HEADER);
const headers = readHeaders(reader);
- const nameLength = reader.readUint16LE();
- const extraFieldsLength = reader.readUint16LE();
+ const nameLength = reader.readUint16(true);
+ const extraFieldsLength = reader.readUint16(true);
const name = reader.read(nameLength);
reader.skip(extraFieldsLength);
const content = reader.read(headers.compressedLength);
@@ -212,13 +212,13 @@ function readBlockEndOfCentral(reader) {
'Corrupt zip file, or zip file containing an unsupported variable-width end-of-archive comment, or an unsupported zip file with 64 bit sizes',
);
}
- const diskNumber = reader.readUint16LE();
- const diskWithCentralDirStart = reader.readUint16LE();
- const centralDirectoryRecordsOnThisDisk = reader.readUint16LE();
- const centralDirectoryRecords = reader.readUint16LE();
- const centralDirectorySize = reader.readUint32LE();
- const centralDirectoryOffset = reader.readUint32LE();
- const commentLength = reader.readUint16LE();
+ const diskNumber = reader.readUint16(true);
+ const diskWithCentralDirStart = reader.readUint16(true);
+ const centralDirectoryRecordsOnThisDisk = reader.readUint16(true);
+ const centralDirectoryRecords = reader.readUint16(true);
+ const centralDirectorySize = reader.readUint32(true);
+ const centralDirectoryOffset = reader.readUint32(true);
+ const commentLength = reader.readUint16(true);
// Warning: the encoding depends of the system locale.
// On a Linux machine with LANG=en_US.utf8, this field is utf8 encoded.
// On a Windows machine, this field is encoded with the localized Windows

MODIFY
packages/zip/src/format-writer.js
packages/zip/src/format-writer.js
* write: (bytes: Uint8Array) => void,
* writeCopy: (start: number, end: number) => void,
* writeUint8: (number: number) => void,
- * writeUint16LE: (number: number) => void,
- * writeUint32LE: (number: number) => void,
+ * writeUint16: (number: number, littleEndian?: boolean) => void,
+ * writeUint32: (number: number, littleEndian?: boolean) => void,
* }} BufferWriter
*/
@@ -56,7 +56,7 @@ function writeDosDateTime(writer, date) {
(date.getUTCMinutes() << 5) | // minute
(date.getUTCSeconds() >> 1) // second
: 0; // Epoch origin by default.
- writer.writeUint32LE(dosTime);
+ writer.writeUint32(dosTime, true);
}
/**
@@ -70,18 +70,18 @@ function writeFile(writer, file) {
writer.write(signature.LOCAL_FILE_HEADER);
const headerStart = writer.index;
// Version needed to extract
- writer.writeUint16LE(10);
- writer.writeUint16LE(file.bitFlag);
- writer.writeUint16LE(file.compressionMethod);
+ writer.writeUint16(10, true);
+ writer.writeUint16(file.bitFlag, true);
+ writer.writeUint16(file.compressionMethod, true);
writeDosDateTime(writer, file.date);
- writer.writeUint32LE(file.crc32);
- writer.writeUint32LE(file.compressedLength);
- writer.writeUint32LE(file.uncompressedLength);
- writer.writeUint16LE(file.name.length);
+ writer.writeUint32(file.crc32, true);
+ writer.writeUint32(file.compressedLength, true);
+ writer.writeUint32(file.uncompressedLength, true);
+ writer.writeUint16(file.name.length, true);
const headerEnd = writer.length;
// TODO count of extra fields length
- writer.writeUint16LE(0);
+ writer.writeUint16(0, true);
writer.write(file.name);
// TODO write extra fields
writer.write(file.content);
@@ -104,12 +104,12 @@ function writeCentralFileHeader(writer, file, locator) {
writer.writeUint8(file.madeBy);
writer.writeCopy(locator.headerStart, locator.headerEnd);
// TODO extra fields length
- writer.writeUint16LE(0);
- writer.writeUint16LE(file.comment.length);
- writer.writeUint16LE(file.diskNumberStart);
- writer.writeUint16LE(file.internalFileAttributes);
- writer.writeUint32LE(file.externalFileAttributes);
- writer.writeUint32LE(locator.fileStart);
+ writer.writeUint16(0, true);
+ writer.writeUint16(file.comment.length, true);
+ writer.writeUint16(file.diskNumberStart, true);
+ writer.writeUint16(file.internalFileAttributes, true);
+ writer.writeUint32(file.externalFileAttributes, true);
+ writer.writeUint32(locator.fileStart, true);
writer.write(file.centralName);
// TODO extra fields
writer.write(file.comment);
@@ -130,13 +130,13 @@ function writeEndOfCentralDirectoryRecord(
commentBytes,
) {
writer.write(signature.CENTRAL_DIRECTORY_END);
- writer.writeUint16LE(0);
- writer.writeUint16LE(0);
- writer.writeUint16LE(entriesCount);
- writer.writeUint16LE(entriesCount);
- writer.writeUint32LE(centralDirectoryLength);
- writer.writeUint32LE(centralDirectoryStart);
- writer.writeUint16LE(commentBytes.length);
+ writer.writeUint16(0, true);
+ writer.writeUint16(0, true);
+ writer.writeUint16(entriesCount, true);
+ writer.writeUint16(entriesCount, true);
+ writer.writeUint32(centralDirectoryLength, true);
+ writer.writeUint32(centralDirectoryStart, true);
+ writer.writeUint16(commentBytes.length, true);
writer.write(commentBytes);
}

refactor(zip): Use DataView