UNPKG

@cartbc/codecs-strings

Version:

Codecs for strings of different sizes and encodings

470 lines (454 loc) 17.1 kB
this.globalThis = this.globalThis || {}; this.globalThis.cartesWeb3 = (function (exports) { 'use strict'; // src/assertions.ts function assertValidBaseString(alphabet4, testValue, givenValue = testValue) { if (!testValue.match(new RegExp(`^[${alphabet4}]*$`))) { throw new Error(`Expected a string of base ${alphabet4.length}, got [${givenValue}].`); } } // ../codecs-core/dist/index.browser.js function assertByteArrayIsNotEmptyForCodec(codecDescription, bytes, offset = 0) { if (bytes.length - offset <= 0) { throw new Error(`Codec [${codecDescription}] cannot decode empty byte arrays.`); } } function assertByteArrayHasEnoughBytesForCodec(codecDescription, expected, bytes, offset = 0) { const bytesLength = bytes.length - offset; if (bytesLength < expected) { throw new Error(`Codec [${codecDescription}] expected ${expected} bytes, got ${bytesLength}.`); } } var mergeBytes = (byteArrays) => { const nonEmptyByteArrays = byteArrays.filter((arr) => arr.length); if (nonEmptyByteArrays.length === 0) { return byteArrays.length ? byteArrays[0] : new Uint8Array(); } if (nonEmptyByteArrays.length === 1) { return nonEmptyByteArrays[0]; } const totalLength = nonEmptyByteArrays.reduce((total, arr) => total + arr.length, 0); const result = new Uint8Array(totalLength); let offset = 0; nonEmptyByteArrays.forEach((arr) => { result.set(arr, offset); offset += arr.length; }); return result; }; var padBytes = (bytes, length) => { if (bytes.length >= length) return bytes; const paddedBytes = new Uint8Array(length).fill(0); paddedBytes.set(bytes); return paddedBytes; }; var fixBytes = (bytes, length) => padBytes(bytes.length <= length ? bytes : bytes.slice(0, length), length); function combineCodec(encoder, decoder, description) { if (encoder.fixedSize !== decoder.fixedSize) { throw new Error( `Encoder and decoder must have the same fixed size, got [${encoder.fixedSize}] and [${decoder.fixedSize}].` ); } if (encoder.maxSize !== decoder.maxSize) { throw new Error( `Encoder and decoder must have the same max size, got [${encoder.maxSize}] and [${decoder.maxSize}].` ); } if (description === void 0 && encoder.description !== decoder.description) { throw new Error( `Encoder and decoder must have the same description, got [${encoder.description}] and [${decoder.description}]. Pass a custom description as a third argument if you want to override the description and bypass this error.` ); } return { decode: decoder.decode, description: description ?? encoder.description, encode: encoder.encode, fixedSize: encoder.fixedSize, maxSize: encoder.maxSize }; } function fixCodecHelper(data, fixedBytes, description) { return { description: description ?? `fixed(${fixedBytes}, ${data.description})`, fixedSize: fixedBytes, maxSize: fixedBytes }; } function fixEncoder(encoder, fixedBytes, description) { return { ...fixCodecHelper(encoder, fixedBytes, description), encode: (value) => fixBytes(encoder.encode(value), fixedBytes) }; } function fixDecoder(decoder, fixedBytes, description) { return { ...fixCodecHelper(decoder, fixedBytes, description), decode: (bytes, offset = 0) => { assertByteArrayHasEnoughBytesForCodec("fixCodec", fixedBytes, bytes, offset); if (offset > 0 || bytes.length > fixedBytes) { bytes = bytes.slice(offset, offset + fixedBytes); } if (decoder.fixedSize !== null) { bytes = fixBytes(bytes, decoder.fixedSize); } const [value] = decoder.decode(bytes, 0); return [value, offset + fixedBytes]; } }; } // src/baseX.ts var getBaseXEncoder = (alphabet4) => { const base = alphabet4.length; const baseBigInt = BigInt(base); return { description: `base${base}`, encode(value) { assertValidBaseString(alphabet4, value); if (value === "") return new Uint8Array(); const chars = [...value]; let trailIndex = chars.findIndex((c) => c !== alphabet4[0]); trailIndex = trailIndex === -1 ? chars.length : trailIndex; const leadingZeroes = Array(trailIndex).fill(0); if (trailIndex === chars.length) return Uint8Array.from(leadingZeroes); const tailChars = chars.slice(trailIndex); let base10Number = 0n; let baseXPower = 1n; for (let i = tailChars.length - 1; i >= 0; i -= 1) { base10Number += baseXPower * BigInt(alphabet4.indexOf(tailChars[i])); baseXPower *= baseBigInt; } const tailBytes = []; while (base10Number > 0n) { tailBytes.unshift(Number(base10Number % 256n)); base10Number /= 256n; } return Uint8Array.from(leadingZeroes.concat(tailBytes)); }, fixedSize: null, maxSize: null }; }; var getBaseXDecoder = (alphabet4) => { const base = alphabet4.length; const baseBigInt = BigInt(base); return { decode(rawBytes, offset = 0) { const bytes = offset === 0 ? rawBytes : rawBytes.slice(offset); if (bytes.length === 0) return ["", 0]; let trailIndex = bytes.findIndex((n) => n !== 0); trailIndex = trailIndex === -1 ? bytes.length : trailIndex; const leadingZeroes = alphabet4[0].repeat(trailIndex); if (trailIndex === bytes.length) return [leadingZeroes, rawBytes.length]; let base10Number = bytes.slice(trailIndex).reduce((sum, byte) => sum * 256n + BigInt(byte), 0n); const tailChars = []; while (base10Number > 0n) { tailChars.unshift(alphabet4[Number(base10Number % baseBigInt)]); base10Number /= baseBigInt; } return [leadingZeroes + tailChars.join(""), rawBytes.length]; }, description: `base${base}`, fixedSize: null, maxSize: null }; }; var getBaseXCodec = (alphabet4) => combineCodec(getBaseXEncoder(alphabet4), getBaseXDecoder(alphabet4)); // src/base10.ts var alphabet = "0123456789"; var getBase10Encoder = () => getBaseXEncoder(alphabet); var getBase10Decoder = () => getBaseXDecoder(alphabet); var getBase10Codec = () => getBaseXCodec(alphabet); // src/base16.ts var getBase16Encoder = () => ({ description: "base16", encode(value) { const lowercaseValue = value.toLowerCase(); assertValidBaseString("0123456789abcdef", lowercaseValue, value); const matches = lowercaseValue.match(/.{1,2}/g); return Uint8Array.from(matches ? matches.map((byte) => parseInt(byte, 16)) : []); }, fixedSize: null, maxSize: null }); var getBase16Decoder = () => ({ decode(bytes, offset = 0) { const value = bytes.slice(offset).reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), ""); return [value, bytes.length]; }, description: "base16", fixedSize: null, maxSize: null }); var getBase16Codec = () => combineCodec(getBase16Encoder(), getBase16Decoder()); // src/base58.ts var alphabet2 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; var getBase58Encoder = () => getBaseXEncoder(alphabet2); var getBase58Decoder = () => getBaseXDecoder(alphabet2); var getBase58Codec = () => getBaseXCodec(alphabet2); // src/baseX-reslice.ts var getBaseXResliceEncoder = (alphabet4, bits) => ({ description: `base${alphabet4.length}`, encode(value) { assertValidBaseString(alphabet4, value); if (value === "") return new Uint8Array(); const charIndices = [...value].map((c) => alphabet4.indexOf(c)); return new Uint8Array(reslice(charIndices, bits, 8, false)); }, fixedSize: null, maxSize: null }); var getBaseXResliceDecoder = (alphabet4, bits) => ({ decode(rawBytes, offset = 0) { const bytes = offset === 0 ? rawBytes : rawBytes.slice(offset); if (bytes.length === 0) return ["", rawBytes.length]; const charIndices = reslice([...bytes], 8, bits, true); return [charIndices.map((i) => alphabet4[i]).join(""), rawBytes.length]; }, description: `base${alphabet4.length}`, fixedSize: null, maxSize: null }); var getBaseXResliceCodec = (alphabet4, bits) => combineCodec(getBaseXResliceEncoder(alphabet4, bits), getBaseXResliceDecoder(alphabet4, bits)); function reslice(input, inputBits, outputBits, useRemainder) { const output = []; let accumulator = 0; let bitsInAccumulator = 0; const mask = (1 << outputBits) - 1; for (const value of input) { accumulator = accumulator << inputBits | value; bitsInAccumulator += inputBits; while (bitsInAccumulator >= outputBits) { bitsInAccumulator -= outputBits; output.push(accumulator >> bitsInAccumulator & mask); } } if (useRemainder && bitsInAccumulator > 0) { output.push(accumulator << outputBits - bitsInAccumulator & mask); } return output; } var getBase64Encoder = () => { { return { description: `base64`, encode(value) { try { const bytes = atob(value).split("").map((c) => c.charCodeAt(0)); return new Uint8Array(bytes); } catch (e2) { throw new Error(`Expected a string of base 64, got [${value}].`); } }, fixedSize: null, maxSize: null }; } }; var getBase64Decoder = () => { { return { decode(bytes, offset = 0) { const slice = bytes.slice(offset); const value = btoa(String.fromCharCode(...slice)); return [value, bytes.length]; }, description: `base64`, fixedSize: null, maxSize: null }; } }; var getBase64Codec = () => combineCodec(getBase64Encoder(), getBase64Decoder()); // src/null-characters.ts var removeNullCharacters = (value) => ( // eslint-disable-next-line no-control-regex value.replace(/\u0000/g, "") ); var padNullCharacters = (value, chars) => value.padEnd(chars, "\0"); // ../codecs-numbers/dist/index.browser.js function assertNumberIsBetweenForCodec(codecDescription, min, max, value) { if (value < min || value > max) { throw new Error( `Codec [${codecDescription}] expected number to be in the range [${min}, ${max}], got ${value}.` ); } } function sharedNumberFactory(input) { let littleEndian; let defaultDescription = input.name; if (input.size > 1) { littleEndian = !("endian" in input.options) || input.options.endian === 0; defaultDescription += littleEndian ? "(le)" : "(be)"; } return { description: input.options.description ?? defaultDescription, fixedSize: input.size, littleEndian, maxSize: input.size }; } function numberEncoderFactory(input) { const codecData = sharedNumberFactory(input); return { description: codecData.description, encode(value) { if (input.range) { assertNumberIsBetweenForCodec(input.name, input.range[0], input.range[1], value); } const arrayBuffer = new ArrayBuffer(input.size); input.set(new DataView(arrayBuffer), value, codecData.littleEndian); return new Uint8Array(arrayBuffer); }, fixedSize: codecData.fixedSize, maxSize: codecData.maxSize }; } function numberDecoderFactory(input) { const codecData = sharedNumberFactory(input); return { decode(bytes, offset = 0) { assertByteArrayIsNotEmptyForCodec(codecData.description, bytes, offset); assertByteArrayHasEnoughBytesForCodec(codecData.description, input.size, bytes, offset); const view = new DataView(toArrayBuffer(bytes, offset, input.size)); return [input.get(view, codecData.littleEndian), offset + input.size]; }, description: codecData.description, fixedSize: codecData.fixedSize, maxSize: codecData.maxSize }; } function toArrayBuffer(bytes, offset, length) { const bytesOffset = bytes.byteOffset + (offset ?? 0); const bytesLength = length ?? bytes.byteLength; return bytes.buffer.slice(bytesOffset, bytesOffset + bytesLength); } var getU32Encoder = (options = {}) => numberEncoderFactory({ name: "u32", options, range: [0, Number("0xffffffff")], set: (view, value, le) => view.setUint32(0, value, le), size: 4 }); var getU32Decoder = (options = {}) => numberDecoderFactory({ get: (view, le) => view.getUint32(0, le), name: "u32", options, size: 4 }); // ../text-encoding-impl/dist/index.browser.js var e = globalThis.TextDecoder; var o = globalThis.TextEncoder; // src/utf8.ts var getUtf8Encoder = () => { let textEncoder; return { description: "utf8", encode: (value) => new Uint8Array((textEncoder || (textEncoder = new o())).encode(value)), fixedSize: null, maxSize: null }; }; var getUtf8Decoder = () => { let textDecoder; return { decode(bytes, offset = 0) { const value = (textDecoder || (textDecoder = new e())).decode(bytes.slice(offset)); return [removeNullCharacters(value), bytes.length]; }, description: "utf8", fixedSize: null, maxSize: null }; }; var getUtf8Codec = () => combineCodec(getUtf8Encoder(), getUtf8Decoder()); // src/string.ts var getStringEncoder = (options = {}) => { const size = options.size ?? getU32Encoder(); const encoding = options.encoding ?? getUtf8Encoder(); const description = options.description ?? `string(${encoding.description}; ${getSizeDescription(size)})`; if (size === "variable") { return { ...encoding, description }; } if (typeof size === "number") { return fixEncoder(encoding, size, description); } return { description, encode: (value) => { const contentBytes = encoding.encode(value); const lengthBytes = size.encode(contentBytes.length); return mergeBytes([lengthBytes, contentBytes]); }, fixedSize: null, maxSize: null }; }; var getStringDecoder = (options = {}) => { const size = options.size ?? getU32Decoder(); const encoding = options.encoding ?? getUtf8Decoder(); const description = options.description ?? `string(${encoding.description}; ${getSizeDescription(size)})`; if (size === "variable") { return { ...encoding, description }; } if (typeof size === "number") { return fixDecoder(encoding, size, description); } return { decode: (bytes, offset = 0) => { assertByteArrayIsNotEmptyForCodec("string", bytes, offset); const [lengthBigInt, lengthOffset] = size.decode(bytes, offset); const length = Number(lengthBigInt); offset = lengthOffset; const contentBytes = bytes.slice(offset, offset + length); assertByteArrayHasEnoughBytesForCodec("string", length, contentBytes); const [value, contentOffset] = encoding.decode(contentBytes); offset += contentOffset; return [value, offset]; }, description, fixedSize: null, maxSize: null }; }; var getStringCodec = (options = {}) => combineCodec(getStringEncoder(options), getStringDecoder(options)); function getSizeDescription(size) { return typeof size === "object" ? size.description : `${size}`; } exports.assertValidBaseString = assertValidBaseString; exports.getBase10Codec = getBase10Codec; exports.getBase10Decoder = getBase10Decoder; exports.getBase10Encoder = getBase10Encoder; exports.getBase16Codec = getBase16Codec; exports.getBase16Decoder = getBase16Decoder; exports.getBase16Encoder = getBase16Encoder; exports.getBase58Codec = getBase58Codec; exports.getBase58Decoder = getBase58Decoder; exports.getBase58Encoder = getBase58Encoder; exports.getBase64Codec = getBase64Codec; exports.getBase64Decoder = getBase64Decoder; exports.getBase64Encoder = getBase64Encoder; exports.getBaseXCodec = getBaseXCodec; exports.getBaseXDecoder = getBaseXDecoder; exports.getBaseXEncoder = getBaseXEncoder; exports.getBaseXResliceCodec = getBaseXResliceCodec; exports.getBaseXResliceDecoder = getBaseXResliceDecoder; exports.getBaseXResliceEncoder = getBaseXResliceEncoder; exports.getStringCodec = getStringCodec; exports.getStringDecoder = getStringDecoder; exports.getStringEncoder = getStringEncoder; exports.getUtf8Codec = getUtf8Codec; exports.getUtf8Decoder = getUtf8Decoder; exports.getUtf8Encoder = getUtf8Encoder; exports.padNullCharacters = padNullCharacters; exports.removeNullCharacters = removeNullCharacters; return exports; })({}); //# sourceMappingURL=out.js.map //# sourceMappingURL=index.development.js.map