import { Cbor, CborByte } from "."; import { CborArray } from "./array"; import { CborInteger } from "./integer"; import { CborText } from "./text"; const sizeToCbor = (mapLength: number) => { if (mapLength <= 15) { return `a${mapLength.toString(16)}`; } else if (mapLength >= 16 && mapLength <= 23) { return `b${(mapLength - 16).toString(16)}`; } else if (mapLength >= 24 && mapLength <= 255) { return `b8${mapLength.toString(16).padStart(2, "0")}`; } else if (mapLength >= 256 && mapLength <= 65535) { return `b9${mapLength.toString(16).padStart(4, "0")}`; } else { throw "Map is too long, not supported."; } }; const getFirstValueCharIndex = (value: string) => { if (value.charAt(0) === "a") { return 2; } else if (value.charAt(0) === "b") { switch (value.charAt(1)) { case "8": return 4; case "9": return 6; case "a": return 10; case "b": return 18; case "f": return 2; default: return 2; } } else { throw "Not a map"; } }; const readSize = (value: string) => { if (value.charAt(0) === "a") { return parseInt(value.charAt(1), 16); } else if (value.charAt(0) === "b") { switch (value.charAt(1)) { case "8": return parseInt(value.substring(2, 4), 16); case "9": return parseInt(value.substring(2, 6), 16); case "a": return parseInt(value.substring(2, 10), 16); case "b": return parseInt(value.substring(2, 18), 16); case "f": return Cbor.countItemsUntilBreak(value); default: return parseInt(value.charAt(1), 16) + 16; } } else { throw "Not a map"; } }; const read = (value: string): T => { if ( value.charAt(0).toLowerCase() === "a" || value.charAt(0).toLowerCase() === "b" ) { const mapSize = readSize(value); let set = {}; let MAP_START = getFirstValueCharIndex(value); for (let i = 0; i < mapSize; i++) { const type = Cbor.identifyType(value.substring(MAP_START)); const key = type === "text" ? CborText.read(value.substring(MAP_START)) : type === "unsigned" || type === "integer" ? CborInteger.read(value.substring(MAP_START)) : CborByte.read(value.substring(MAP_START)); const byteLength = Cbor.readNextItemStringLength( value.substring(MAP_START) ); MAP_START += byteLength; const setItemStart = value.substring(MAP_START); const setItemLength = Cbor.readNextItemStringLength(setItemStart); const setItemValue = setItemStart.substring(0, setItemLength); if (Cbor.identifyType(setItemValue) === "set") { set = { ...set, [key]: read(setItemValue), }; } else if ( Cbor.identifyType(setItemValue) === "integer" || Cbor.identifyType(setItemValue) === "unsigned" ) { set = { ...set, [key]: CborInteger.read(setItemValue), }; } else if (Cbor.identifyType(setItemValue) === "array") { set = { ...set, [key]: CborArray.decode(setItemValue), }; } else if (Cbor.identifyType(setItemValue) === "byte") { set = { ...set, [key]: CborByte.read(setItemValue), }; } else if (Cbor.identifyType(setItemValue) === "primitive") { set = { ...set, [key]: setItemValue.toLowerCase() === "f4" ? false : true, }; } else { throw `Unidentified set value ${setItemValue}`; } MAP_START += setItemValue.length; } return set as T; } else { throw "Not a map"; } }; export const CborSet = { read, readSize, sizeToCbor, getFirstValueCharIndex, };