UNPKG

@cartbc/codecs-strings

Version:

Codecs for strings of different sizes and encodings

266 lines (256 loc) 9.67 kB
import { combineCodec, fixEncoder, mergeBytes, fixDecoder, assertByteArrayIsNotEmptyForCodec, assertByteArrayHasEnoughBytesForCodec } from '@cartbc/codecs-core'; import { getU32Encoder, getU32Decoder } from '@cartbc/codecs-numbers'; // 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}].`); } } 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); 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); 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; } // src/base64.ts var alphabet3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var getBase64Encoder = () => { { return { description: `base64`, encode(value) { assertValidBaseString(alphabet3, value.replace(/=/g, "")); return new Uint8Array(Buffer.from(value, "base64")); }, fixedSize: null, maxSize: null }; } }; var getBase64Decoder = () => { { return { decode: (bytes, offset = 0) => [Buffer.from(bytes, offset).toString("base64"), 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"); // ../text-encoding-impl/dist/index.node.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}`; } export { assertValidBaseString, getBase10Codec, getBase10Decoder, getBase10Encoder, getBase16Codec, getBase16Decoder, getBase16Encoder, getBase58Codec, getBase58Decoder, getBase58Encoder, getBase64Codec, getBase64Decoder, getBase64Encoder, getBaseXCodec, getBaseXDecoder, getBaseXEncoder, getBaseXResliceCodec, getBaseXResliceDecoder, getBaseXResliceEncoder, getStringCodec, getStringDecoder, getStringEncoder, getUtf8Codec, getUtf8Decoder, getUtf8Encoder, padNullCharacters, removeNullCharacters }; //# sourceMappingURL=out.js.map //# sourceMappingURL=index.node.js.map