| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 | /** *  Some data helpers. * * *  @_subsection api/utils:Data Helpers  [about-data] */import { assert, assertArgument } from "./errors.js";/** *  A [[HexString]] whose length is even, which ensures it is a valid *  representation of binary data. */export type DataHexString = string;/** *  A string which is prefixed with ``0x`` and followed by any number *  of case-agnostic hexadecimal characters. * *  It must match the regular expression ``/0x[0-9A-Fa-f]*\/``. */export type HexString = string;/** *  An object that can be used to represent binary data. */export type BytesLike = DataHexString | Uint8Array;function _getBytes(value: BytesLike, name?: string, copy?: boolean): Uint8Array {    if (value instanceof Uint8Array) {        if (copy) { return new Uint8Array(value); }        return value;    }    if (typeof(value) === "string" && value.match(/^0x(?:[0-9a-f][0-9a-f])*$/i)) {        const result = new Uint8Array((value.length - 2) / 2);        let offset = 2;        for (let i = 0; i < result.length; i++) {            result[i] = parseInt(value.substring(offset, offset + 2), 16);            offset += 2;        }        return result;    }    assertArgument(false, "invalid BytesLike value", name || "value", value);}/** *  Get a typed Uint8Array for %%value%%. If already a Uint8Array *  the original %%value%% is returned; if a copy is required use *  [[getBytesCopy]]. * *  @see: getBytesCopy */export function getBytes(value: BytesLike, name?: string): Uint8Array {    return _getBytes(value, name, false);}/** *  Get a typed Uint8Array for %%value%%, creating a copy if necessary *  to prevent any modifications of the returned value from being *  reflected elsewhere. * *  @see: getBytes */export function getBytesCopy(value: BytesLike, name?: string): Uint8Array {    return _getBytes(value, name, true);}/** *  Returns true if %%value%% is a valid [[HexString]]. * *  If %%length%% is ``true`` or a //number//, it also checks that *  %%value%% is a valid [[DataHexString]] of %%length%% (if a //number//) *  bytes of data (e.g. ``0x1234`` is 2 bytes). */export function isHexString(value: any, length?: number | boolean): value is `0x${ string }` {    if (typeof(value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) {        return false    }    if (typeof(length) === "number" && value.length !== 2 + 2 * length) { return false; }    if (length === true && (value.length % 2) !== 0) { return false; }    return true;}/** *  Returns true if %%value%% is a valid representation of arbitrary *  data (i.e. a valid [[DataHexString]] or a Uint8Array). */export function isBytesLike(value: any): value is BytesLike {    return (isHexString(value, true) || (value instanceof Uint8Array));}const HexCharacters: string = "0123456789abcdef";/** *  Returns a [[DataHexString]] representation of %%data%%. */export function hexlify(data: BytesLike): string {    const bytes = getBytes(data);    let result = "0x";    for (let i = 0; i < bytes.length; i++) {        const v = bytes[i];        result += HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f];    }    return result;}/** *  Returns a [[DataHexString]] by concatenating all values *  within %%data%%. */export function concat(datas: ReadonlyArray<BytesLike>): string {    return "0x" + datas.map((d) => hexlify(d).substring(2)).join("");}/** *  Returns the length of %%data%%, in bytes. */export function dataLength(data: BytesLike): number {    if (isHexString(data, true)) { return (data.length - 2) / 2; }    return getBytes(data).length;}/** *  Returns a [[DataHexString]] by slicing %%data%% from the %%start%% *  offset to the %%end%% offset. * *  By default %%start%% is 0 and %%end%% is the length of %%data%%. */export function dataSlice(data: BytesLike, start?: number, end?: number): string {    const bytes = getBytes(data);    if (end != null && end > bytes.length) {        assert(false, "cannot slice beyond data bounds", "BUFFER_OVERRUN", {            buffer: bytes, length: bytes.length, offset: end        });    }    return hexlify(bytes.slice((start == null) ? 0: start, (end == null) ? bytes.length: end));}/** *  Return the [[DataHexString]] result by stripping all **leading** ** zero bytes from %%data%%. */export function stripZerosLeft(data: BytesLike): string {    let bytes = hexlify(data).substring(2);    while (bytes.startsWith("00")) { bytes = bytes.substring(2); }    return "0x" + bytes;}function zeroPad(data: BytesLike, length: number, left: boolean): string {    const bytes = getBytes(data);    assert(length >= bytes.length, "padding exceeds data length", "BUFFER_OVERRUN", {        buffer: new Uint8Array(bytes),        length: length,        offset: length + 1    });    const result = new Uint8Array(length);    result.fill(0);    if (left) {        result.set(bytes, length - bytes.length);    } else {        result.set(bytes, 0);    }    return hexlify(result);}/** *  Return the [[DataHexString]] of %%data%% padded on the **left** *  to %%length%% bytes. * *  If %%data%% already exceeds %%length%%, a [[BufferOverrunError]] is *  thrown. * *  This pads data the same as **values** are in Solidity *  (e.g. ``uint128``). */export function zeroPadValue(data: BytesLike, length: number): string {    return zeroPad(data, length, true);}/** *  Return the [[DataHexString]] of %%data%% padded on the **right** *  to %%length%% bytes. * *  If %%data%% already exceeds %%length%%, a [[BufferOverrunError]] is *  thrown. * *  This pads data the same as **bytes** are in Solidity *  (e.g. ``bytes16``). */export function zeroPadBytes(data: BytesLike, length: number): string {    return zeroPad(data, length, false);}
 |