I'm writing code to read a gimp XCF file in the browser, and from XCF version 11 and up a 'POINTER' data type is 64 bit instead of 32 bit for the sake of >4GB XCF files.
My issue is that I don't think DataView is capable of handling BigInt offsets with its get* functions. Reading BigInt from dataview yes, reading at BigInt offsets no.
Has anyone else encountered this, and if so how did you deal with it?
A snippet of my code:
word(signed: boolean = true): number {
let result = signed ?
this.view.getInt32(this.offset, false) :
this.view.getUint32(this.offset, false);
this.offset += 4;
return result;
}
word64(signed: boolean = true): BigInt {
let result = signed ?
this.view.getBigInt64(this.offset, false) :
this.view.getBigUint64(this.offset, false);
this.offset += 8;
return result;
}
pointer(xcfVersion: number): number | BigInt {
if (xcfVersion < 11) {
return this.word(false);
} else {
return this.word64(false);
}
}
//....
let nv = 11; //XCF version 11
let ptr: BigInt|number = 0;
let layerPointers = new Array<BigInt|number>();
while ( (ptr = this.pointer(nv)) != 0) {
console.log("layer pointer", ptr);
layerPointers.push(ptr);
if (ptr > this.view.byteLength) {
console.log("gtr than allowed");
}
//Now I want to read 'this.view' at 'ptr' offset
this.view.getUint32 (ptr);
//yields: Uncaught TypeError: can't convert BigInt to number
}
The solution is to convert the 64-bit pointer to a Number:
pointer(xcfVersion: number): number {
if (xcfVersion < 11) {
return this.word(false);
} else {
return Number(this.word64(false));
}
}
Certainly, that won't cover the full 64-bit range, it's only safe up to 2**53
. But that's fine, because ArrayBuffer
s are spec'ed to have 2**53
as their maximum size, so any ArrayBuffer that can be created, can be fully indexed this way.
(Before you consider this a limitation, take a moment to think about how large that number is, and how long it'll be until XCF files might reach that size.)