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