Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
369 changes: 0 additions & 369 deletions packages/evolution/src/CBOR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1582,372 +1582,3 @@ const decodeSimpleOrFloatAt = (data: Uint8Array, offset: number): DecodeAtResult
}
throw new CBORError({ message: `Unsupported simple/float encoding: ${additionalInfo}` })
}

const decodeUintSync = (data: Uint8Array): CBOR => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo < 24) {
return BigInt(additionalInfo)
} else if (additionalInfo === 24) {
if (data.length < 2) throw new CBORError({ message: "Insufficient data for 1-byte unsigned integer" })
return BigInt(data[1])
} else if (additionalInfo === 25) {
if (data.length < 3) throw new CBORError({ message: "Insufficient data for 2-byte unsigned integer" })
return BigInt(data[1]) * 256n + BigInt(data[2])
} else if (additionalInfo === 26) {
if (data.length < 5) throw new CBORError({ message: "Insufficient data for 4-byte unsigned integer" })
return BigInt(data[1]) * 16777216n + BigInt(data[2]) * 65536n + BigInt(data[3]) * 256n + BigInt(data[4])
} else if (additionalInfo === 27) {
if (data.length < 9) throw new CBORError({ message: "Insufficient data for 8-byte unsigned integer" })
let result = 0n
for (let i = 1; i <= 8; i++) result = result * 256n + BigInt(data[i])
return result
} else {
throw new CBORError({ message: `Unsupported additional info for unsigned integer: ${additionalInfo}` })
}
}

const decodeNintSync = (data: Uint8Array): CBOR => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo < 24) {
return -1n - BigInt(additionalInfo)
} else if (additionalInfo === 24) {
if (data.length < 2) throw new CBORError({ message: "Insufficient data for 1-byte negative integer" })
return -1n - BigInt(data[1])
} else if (additionalInfo === 25) {
if (data.length < 3) throw new CBORError({ message: "Insufficient data for 2-byte negative integer" })
return -1n - (BigInt(data[1]) * 256n + BigInt(data[2]))
} else if (additionalInfo === 26) {
if (data.length < 5) throw new CBORError({ message: "Insufficient data for 4-byte negative integer" })
return -1n - (BigInt(data[1]) * 16777216n + BigInt(data[2]) * 65536n + BigInt(data[3]) * 256n + BigInt(data[4]))
} else if (additionalInfo === 27) {
if (data.length < 9) throw new CBORError({ message: "Insufficient data for 8-byte negative integer" })
let result = 0n
for (let i = 1; i <= 8; i++) result = result * 256n + BigInt(data[i])
return -1n - result
} else {
throw new CBORError({ message: `Unsupported additional info for negative integer: ${additionalInfo}` })
}
}

const decodeBytesWithLengthSync = (data: Uint8Array): { item: CBOR; bytesConsumed: number } => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo === CBOR_ADDITIONAL_INFO.INDEFINITE) {
let offset = 1
const chunks: Array<Uint8Array> = []
let foundBreak = false
while (offset < data.length) {
if (data[offset] === 0xff) {
offset++
foundBreak = true
break
}
const chunkFirstByte = data[offset]
const chunkMajorType = (chunkFirstByte >> 5) & 0x07
if (chunkMajorType !== CBOR_MAJOR_TYPE.BYTE_STRING) {
throw new CBORError({ message: `Invalid chunk in indefinite byte string: major type ${chunkMajorType}` })
}
const { bytesRead, length: chunkLength } = decodeLengthSync(data, offset)
offset += bytesRead
if (data.length < offset + chunkLength)
throw new CBORError({ message: "Insufficient data for byte string chunk" })
const chunk = data.slice(offset, offset + chunkLength)
chunks.push(chunk)
offset += chunkLength
}
if (!foundBreak) throw new CBORError({ message: "Missing break in indefinite-length byte string" })
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
const bytes = new Uint8Array(totalLength)
let pos = 0
for (const chunk of chunks) {
bytes.set(chunk, pos)
pos += chunk.length
}
return { item: bytes, bytesConsumed: offset }
} else {
const { bytesRead, length } = decodeLengthSync(data, 0)
if (data.length < bytesRead + length) throw new CBORError({ message: "Insufficient data for byte string" })
const bytes = data.slice(bytesRead, bytesRead + length)
return { item: bytes, bytesConsumed: bytesRead + length }
}
}

const decodeTextWithLengthSync = (data: Uint8Array): { item: CBOR; bytesConsumed: number } => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo === CBOR_ADDITIONAL_INFO.INDEFINITE) {
let offset = 1
const parts: Array<string> = []
let foundBreak = false
while (offset < data.length) {
if (data[offset] === 0xff) {
offset++
foundBreak = true
break
}
const chunkFirstByte = data[offset]
const chunkMajorType = (chunkFirstByte >> 5) & 0x07
if (chunkMajorType !== CBOR_MAJOR_TYPE.TEXT_STRING) {
throw new CBORError({ message: `Invalid chunk in indefinite text string: major type ${chunkMajorType}` })
}
const { bytesRead, length: chunkLength } = decodeLengthSync(data, offset)
offset += bytesRead
if (data.length < offset + chunkLength)
throw new CBORError({ message: "Insufficient data for text string chunk" })
const chunkBytes = data.slice(offset, offset + chunkLength)
const chunkText = TEXT_DECODER.decode(chunkBytes)
parts.push(chunkText)
offset += chunkLength
}
if (!foundBreak) throw new CBORError({ message: "Missing break in indefinite-length text string" })
return { item: parts.join(""), bytesConsumed: offset }
} else {
const { bytesRead, length } = decodeLengthSync(data, 0)
if (data.length < bytesRead + length) throw new CBORError({ message: "Insufficient data for text string" })
const textBytes = data.slice(bytesRead, bytesRead + length)
const text = TEXT_DECODER.decode(textBytes)
return { item: text, bytesConsumed: bytesRead + length }
}
}

// Decode an item and return both the item and bytes consumed (sync)
const decodeItemWithLengthSync = (data: Uint8Array, options: CodecOptions): { item: CBOR; bytesConsumed: number } => {
const firstByte = data[0]
const majorType = (firstByte >> 5) & 0x07
let item: CBOR
let bytesConsumed: number
switch (majorType) {
case CBOR_MAJOR_TYPE.UNSIGNED_INTEGER: {
item = decodeUintSync(data)
const additionalInfo = firstByte & 0x1f
bytesConsumed =
additionalInfo < 24 ? 1 : additionalInfo === 24 ? 2 : additionalInfo === 25 ? 3 : additionalInfo === 26 ? 5 : 9
break
}
case CBOR_MAJOR_TYPE.NEGATIVE_INTEGER: {
item = decodeNintSync(data)
const additionalInfo = firstByte & 0x1f
bytesConsumed =
additionalInfo < 24 ? 1 : additionalInfo === 24 ? 2 : additionalInfo === 25 ? 3 : additionalInfo === 26 ? 5 : 9
break
}
case CBOR_MAJOR_TYPE.BYTE_STRING: {
const { bytesConsumed: b, item: it } = decodeBytesWithLengthSync(data)
item = it
bytesConsumed = b
break
}
case CBOR_MAJOR_TYPE.TEXT_STRING: {
const { bytesConsumed: b, item: it } = decodeTextWithLengthSync(data)
item = it
bytesConsumed = b
break
}
case CBOR_MAJOR_TYPE.ARRAY: {
const { bytesConsumed: b, item: it } = decodeArrayWithLengthSync(data, options)
item = it
bytesConsumed = b
break
}
case CBOR_MAJOR_TYPE.MAP: {
const { bytesConsumed: b, item: it } = decodeMapWithLengthSync(data, options)
item = it
bytesConsumed = b
break
}
case CBOR_MAJOR_TYPE.TAG: {
const { bytesConsumed: b, item: it } = decodeTagWithLengthSync(data, options)
item = it
bytesConsumed = b
break
}
case CBOR_MAJOR_TYPE.SIMPLE_FLOAT: {
item = decodeSimpleOrFloatSync(data)
const additionalInfo = firstByte & 0x1f
bytesConsumed =
additionalInfo < 24 ? 1 : additionalInfo === 24 ? 2 : additionalInfo === 25 ? 3 : additionalInfo === 26 ? 5 : 9
break
}
default:
throw new CBORError({ message: `Unsupported major type: ${majorType}` })
}
return { item, bytesConsumed }
}

const decodeArrayWithLengthSync = (data: Uint8Array, options: CodecOptions): { item: CBOR; bytesConsumed: number } => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo === CBOR_ADDITIONAL_INFO.INDEFINITE) {
const result: Array<CBOR> = []
let offset = 1
while (offset < data.length) {
if (data[offset] === 0xff) {
offset++
break
}
const { bytesConsumed, item } = decodeItemWithLengthSync(data.slice(offset), options)
result.push(item)
offset += bytesConsumed
}
return { item: result, bytesConsumed: offset }
} else {
const { bytesRead, length } = decodeLengthSync(data, 0)
const result: Array<CBOR> = []
let offset = bytesRead
for (let i = 0; i < length; i++) {
const { bytesConsumed, item } = decodeItemWithLengthSync(data.slice(offset), options)
result.push(item)
offset += bytesConsumed
}
return { item: result, bytesConsumed: offset }
}
}

const decodeMapWithLengthSync = (data: Uint8Array, options: CodecOptions): { item: CBOR; bytesConsumed: number } => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo === CBOR_ADDITIONAL_INFO.INDEFINITE) {
const result =
options.mode === "custom" && options.mapsAsObjects ? ({} as Record<string, CBOR>) : new Map<CBOR, CBOR>()
let offset = 1
while (offset < data.length) {
if (data[offset] === 0xff) {
offset++
break
}
const { bytesConsumed: keyBytes, item: key } = decodeItemWithLengthSync(data.slice(offset), options)
offset += keyBytes
const { bytesConsumed: valueBytes, item: value } = decodeItemWithLengthSync(data.slice(offset), options)
offset += valueBytes
if (result instanceof Map) {
result.set(key, value)
} else {
result[String(key as any)] = value
}
}
return { item: result, bytesConsumed: offset }
} else {
const { bytesRead, length } = decodeLengthSync(data, 0)
const result =
options.mode === "custom" && options.mapsAsObjects ? ({} as Record<string, CBOR>) : new Map<CBOR, CBOR>()
let offset = bytesRead
for (let i = 0; i < length; i++) {
const { bytesConsumed: keyBytes, item: key } = decodeItemWithLengthSync(data.slice(offset), options)
offset += keyBytes
const { bytesConsumed: valueBytes, item: value } = decodeItemWithLengthSync(data.slice(offset), options)
offset += valueBytes
if (result instanceof Map) {
result.set(key, value)
} else {
result[String(key as any)] = value
}
}
return { item: result, bytesConsumed: offset }
}
}

const decodeTagWithLengthSync = (data: Uint8Array, options: CodecOptions): { item: CBOR; bytesConsumed: number } => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
let tag: number
let dataOffset: number
if (additionalInfo < 24) {
tag = additionalInfo
dataOffset = 1
} else if (additionalInfo === 24) {
if (data.length < 2) throw new CBORError({ message: "Insufficient data for 1-byte tag" })
tag = data[1]
dataOffset = 2
} else if (additionalInfo === 25) {
if (data.length < 3) throw new CBORError({ message: "Insufficient data for 2-byte tag" })
tag = data[1] * 256 + data[2]
dataOffset = 3
} else {
throw new CBORError({ message: `Unsupported additional info for tag: ${additionalInfo}` })
}
const { bytesConsumed, item: innerValue } = decodeItemWithLengthSync(data.slice(dataOffset), options)
if (tag === 2 || tag === 3) {
if (!(innerValue instanceof Uint8Array)) throw new CBORError({ message: `Invalid value for bigint tag ${tag}` })
const bigintValue = (() => {
let result = 0n
for (let i = 0; i < innerValue.length; i++) result = (result << 8n) + BigInt(innerValue[i])
return tag === 2 ? result : -1n - result
})()
return { item: bigintValue, bytesConsumed: dataOffset + bytesConsumed }
}
return { item: { _tag: "Tag", tag, value: innerValue }, bytesConsumed: dataOffset + bytesConsumed }
}

const decodeSimpleOrFloatSync = (data: Uint8Array): CBOR => {
const firstByte = data[0]
const additionalInfo = firstByte & 0x1f
if (additionalInfo < 20) {
// Return unassigned simple values as numbers
return additionalInfo
} else if (additionalInfo === CBOR_SIMPLE.FALSE) {
return false
} else if (additionalInfo === CBOR_SIMPLE.TRUE) {
return true
} else if (additionalInfo === CBOR_SIMPLE.NULL) {
return null
} else if (additionalInfo === CBOR_SIMPLE.UNDEFINED) {
return undefined
} else if (additionalInfo === CBOR_ADDITIONAL_INFO.DIRECT) {
if (data.length < 2) throw new CBORError({ message: "Insufficient data for simple value (one byte)" })
const simpleValue = data[1]
return simpleValue
} else if (additionalInfo === CBOR_ADDITIONAL_INFO.UINT16) {
if (data.length < 3) throw new CBORError({ message: "Insufficient data for half-precision float" })
const value = (data[1] << 8) | data[2]
const float = decodeFloat16(value)
return float
} else if (additionalInfo === CBOR_ADDITIONAL_INFO.UINT32) {
if (data.length < 5) throw new CBORError({ message: "Insufficient data for single-precision float" })
const buffer = data.slice(1, 5)
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
return view.getFloat32(0, false)
} else if (additionalInfo === CBOR_ADDITIONAL_INFO.UINT64) {
if (data.length < 9) throw new CBORError({ message: "Insufficient data for double-precision float" })
const buffer = data.slice(1, 9)
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
return view.getFloat64(0, false)
}
throw new CBORError({ message: `Unsupported additional info for simple/float: ${additionalInfo}` })
}

const decodeLengthSync = (data: Uint8Array, offset: number): { length: number; bytesRead: number } => {
const firstByte = data[offset]
const majorType = (firstByte >> 5) & 0x07
const additionalInfo = firstByte & 0x1f
let length = 0
let bytesRead = 0
if (
majorType !== CBOR_MAJOR_TYPE.BYTE_STRING &&
majorType !== CBOR_MAJOR_TYPE.TEXT_STRING &&
majorType !== CBOR_MAJOR_TYPE.ARRAY &&
majorType !== CBOR_MAJOR_TYPE.MAP
) {
throw new CBORError({ message: `Invalid major type for length decoding: ${majorType}` })
}
if (additionalInfo < 24) {
length = additionalInfo
bytesRead = 1
} else if (additionalInfo === 24) {
if (data.length < offset + 2) throw new CBORError({ message: "Insufficient data for 1-byte length" })
length = data[offset + 1]
bytesRead = 2
} else if (additionalInfo === 25) {
if (data.length < offset + 3) throw new CBORError({ message: "Insufficient data for 2-byte length" })
length = data[offset + 1] * 256 + data[offset + 2]
bytesRead = 3
} else if (additionalInfo === 26) {
if (data.length < offset + 5) throw new CBORError({ message: "Insufficient data for 4-byte length" })
length = (data[offset + 1] << 24) | (data[offset + 2] << 16) | (data[offset + 3] << 8) | data[offset + 4]
bytesRead = 5
} else {
throw new CBORError({ message: `Unsupported additional info for length: ${additionalInfo}` })
}
return { length, bytesRead }
}