@cartbc/codecs-strings
Version:
Codecs for strings of different sizes and encodings
470 lines (454 loc) • 17.1 kB
JavaScript
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