1*890232f2SAndroid Build Coastguard Workerimport { BitWidth } from './bit-width.js' 2*890232f2SAndroid Build Coastguard Workerimport { toByteWidth, fromByteWidth } from './bit-width-util.js' 3*890232f2SAndroid Build Coastguard Workerimport { toUTF8Array, fromUTF8Array } from './flexbuffers-util.js' 4*890232f2SAndroid Build Coastguard Worker 5*890232f2SAndroid Build Coastguard Workerexport function validateOffset(dataView: DataView, offset: number, width: number): void { 6*890232f2SAndroid Build Coastguard Worker if (dataView.byteLength <= offset + width || (offset & (toByteWidth(width) - 1)) !== 0) { 7*890232f2SAndroid Build Coastguard Worker throw "Bad offset: " + offset + ", width: " + width; 8*890232f2SAndroid Build Coastguard Worker } 9*890232f2SAndroid Build Coastguard Worker} 10*890232f2SAndroid Build Coastguard Worker 11*890232f2SAndroid Build Coastguard Workerexport function readInt(dataView: DataView, offset: number, width: number): number | bigint { 12*890232f2SAndroid Build Coastguard Worker if (width < 2) { 13*890232f2SAndroid Build Coastguard Worker if (width < 1) { 14*890232f2SAndroid Build Coastguard Worker return dataView.getInt8(offset); 15*890232f2SAndroid Build Coastguard Worker } else { 16*890232f2SAndroid Build Coastguard Worker return dataView.getInt16(offset, true); 17*890232f2SAndroid Build Coastguard Worker } 18*890232f2SAndroid Build Coastguard Worker } else { 19*890232f2SAndroid Build Coastguard Worker if (width < 3) { 20*890232f2SAndroid Build Coastguard Worker return dataView.getInt32(offset, true) 21*890232f2SAndroid Build Coastguard Worker } else { 22*890232f2SAndroid Build Coastguard Worker if (dataView.setBigInt64 === undefined) { 23*890232f2SAndroid Build Coastguard Worker return BigInt(dataView.getUint32(offset, true)) + (BigInt(dataView.getUint32(offset + 4, true)) << BigInt(32)); 24*890232f2SAndroid Build Coastguard Worker } 25*890232f2SAndroid Build Coastguard Worker return dataView.getBigInt64(offset, true) 26*890232f2SAndroid Build Coastguard Worker } 27*890232f2SAndroid Build Coastguard Worker } 28*890232f2SAndroid Build Coastguard Worker} 29*890232f2SAndroid Build Coastguard Worker 30*890232f2SAndroid Build Coastguard Workerexport function readUInt(dataView: DataView, offset: number, width: number): number | bigint { 31*890232f2SAndroid Build Coastguard Worker if (width < 2) { 32*890232f2SAndroid Build Coastguard Worker if (width < 1) { 33*890232f2SAndroid Build Coastguard Worker return dataView.getUint8(offset); 34*890232f2SAndroid Build Coastguard Worker } else { 35*890232f2SAndroid Build Coastguard Worker return dataView.getUint16(offset, true); 36*890232f2SAndroid Build Coastguard Worker } 37*890232f2SAndroid Build Coastguard Worker } else { 38*890232f2SAndroid Build Coastguard Worker if (width < 3) { 39*890232f2SAndroid Build Coastguard Worker return dataView.getUint32(offset, true) 40*890232f2SAndroid Build Coastguard Worker } else { 41*890232f2SAndroid Build Coastguard Worker if (dataView.getBigUint64 === undefined) { 42*890232f2SAndroid Build Coastguard Worker return BigInt(dataView.getUint32(offset, true)) + (BigInt(dataView.getUint32(offset + 4, true)) << BigInt(32)); 43*890232f2SAndroid Build Coastguard Worker } 44*890232f2SAndroid Build Coastguard Worker return dataView.getBigUint64(offset, true) 45*890232f2SAndroid Build Coastguard Worker } 46*890232f2SAndroid Build Coastguard Worker } 47*890232f2SAndroid Build Coastguard Worker} 48*890232f2SAndroid Build Coastguard Worker 49*890232f2SAndroid Build Coastguard Workerexport function readFloat(dataView: DataView, offset: number, width: number): number { 50*890232f2SAndroid Build Coastguard Worker if (width < BitWidth.WIDTH32) { 51*890232f2SAndroid Build Coastguard Worker throw "Bad width: " + width; 52*890232f2SAndroid Build Coastguard Worker } 53*890232f2SAndroid Build Coastguard Worker if (width === BitWidth.WIDTH32) { 54*890232f2SAndroid Build Coastguard Worker return dataView.getFloat32(offset, true); 55*890232f2SAndroid Build Coastguard Worker } 56*890232f2SAndroid Build Coastguard Worker return dataView.getFloat64(offset, true); 57*890232f2SAndroid Build Coastguard Worker} 58*890232f2SAndroid Build Coastguard Worker 59*890232f2SAndroid Build Coastguard Workerexport function indirect(dataView: DataView, offset: number, width: number): number { 60*890232f2SAndroid Build Coastguard Worker const step = readUInt(dataView, offset, width) as number; 61*890232f2SAndroid Build Coastguard Worker return offset - step; 62*890232f2SAndroid Build Coastguard Worker} 63*890232f2SAndroid Build Coastguard Worker 64*890232f2SAndroid Build Coastguard Workerexport function keyIndex(key: string, dataView: DataView, offset: number, parentWidth: number, byteWidth: number, length: number): number | null { 65*890232f2SAndroid Build Coastguard Worker const input = toUTF8Array(key); 66*890232f2SAndroid Build Coastguard Worker const keysVectorOffset = indirect(dataView, offset, parentWidth) - byteWidth * 3; 67*890232f2SAndroid Build Coastguard Worker const bitWidth = fromByteWidth(byteWidth); 68*890232f2SAndroid Build Coastguard Worker const indirectOffset = keysVectorOffset - Number(readUInt(dataView, keysVectorOffset, bitWidth)); 69*890232f2SAndroid Build Coastguard Worker const _byteWidth = Number(readUInt(dataView, keysVectorOffset + byteWidth, bitWidth)); 70*890232f2SAndroid Build Coastguard Worker let low = 0; 71*890232f2SAndroid Build Coastguard Worker let high = length - 1; 72*890232f2SAndroid Build Coastguard Worker while (low <= high) { 73*890232f2SAndroid Build Coastguard Worker const mid = (high + low) >> 1; 74*890232f2SAndroid Build Coastguard Worker const dif = diffKeys(input, mid, dataView, indirectOffset, _byteWidth); 75*890232f2SAndroid Build Coastguard Worker if (dif === 0) return mid; 76*890232f2SAndroid Build Coastguard Worker if (dif < 0) { 77*890232f2SAndroid Build Coastguard Worker high = mid - 1; 78*890232f2SAndroid Build Coastguard Worker } else { 79*890232f2SAndroid Build Coastguard Worker low = mid + 1; 80*890232f2SAndroid Build Coastguard Worker } 81*890232f2SAndroid Build Coastguard Worker } 82*890232f2SAndroid Build Coastguard Worker return null; 83*890232f2SAndroid Build Coastguard Worker} 84*890232f2SAndroid Build Coastguard Worker 85*890232f2SAndroid Build Coastguard Workerexport function diffKeys(input: Uint8Array, index: number, dataView: DataView, offset: number, width: number): number { 86*890232f2SAndroid Build Coastguard Worker const keyOffset = offset + index * width; 87*890232f2SAndroid Build Coastguard Worker const keyIndirectOffset = keyOffset - Number(readUInt(dataView, keyOffset, fromByteWidth(width))); 88*890232f2SAndroid Build Coastguard Worker for (let i = 0; i < input.length; i++) { 89*890232f2SAndroid Build Coastguard Worker const dif = input[i] - dataView.getUint8(keyIndirectOffset + i); 90*890232f2SAndroid Build Coastguard Worker if (dif !== 0) { 91*890232f2SAndroid Build Coastguard Worker return dif; 92*890232f2SAndroid Build Coastguard Worker } 93*890232f2SAndroid Build Coastguard Worker } 94*890232f2SAndroid Build Coastguard Worker return dataView.getUint8(keyIndirectOffset + input.length) === 0 ? 0 : -1; 95*890232f2SAndroid Build Coastguard Worker} 96*890232f2SAndroid Build Coastguard Worker 97*890232f2SAndroid Build Coastguard Workerexport function keyForIndex(index: number, dataView: DataView, offset: number, parentWidth: number, byteWidth: number): string { 98*890232f2SAndroid Build Coastguard Worker const keysVectorOffset = indirect(dataView, offset, parentWidth) - byteWidth * 3; 99*890232f2SAndroid Build Coastguard Worker const bitWidth = fromByteWidth(byteWidth); 100*890232f2SAndroid Build Coastguard Worker const indirectOffset = keysVectorOffset - Number(readUInt(dataView, keysVectorOffset, bitWidth)); 101*890232f2SAndroid Build Coastguard Worker const _byteWidth = Number(readUInt(dataView, keysVectorOffset + byteWidth, bitWidth)); 102*890232f2SAndroid Build Coastguard Worker const keyOffset = indirectOffset + index * _byteWidth; 103*890232f2SAndroid Build Coastguard Worker const keyIndirectOffset = keyOffset - Number(readUInt(dataView, keyOffset, fromByteWidth(_byteWidth))); 104*890232f2SAndroid Build Coastguard Worker let length = 0; 105*890232f2SAndroid Build Coastguard Worker while (dataView.getUint8(keyIndirectOffset + length) !== 0) { 106*890232f2SAndroid Build Coastguard Worker length++; 107*890232f2SAndroid Build Coastguard Worker } 108*890232f2SAndroid Build Coastguard Worker return fromUTF8Array(new Uint8Array(dataView.buffer, keyIndirectOffset, length)); 109*890232f2SAndroid Build Coastguard Worker} 110