All files / encoding / _common16.ts

100.00% Branches 9/9
100.00% Lines 49/49
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
 
 
 
 
 
x36
x36
x36
x36
x36
x36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
x36
x1823
x1823
 
x36
x36
x36
x36
x36
 
x1814
x117284
x117284
x117284
x117284
x1814
x1814
 
x36
x36
x36
x36
x36
 
x83
x90
x90
x90
x90
 
x90
 
x167
x127
x9400
x9400
x9400
x115
x83
 
x18577
x18577
x18577
x18585
x18585
x18585
x18585
 
x18585
x37110
x18577












































































// Copyright 2018-2025 the Deno authors. MIT license.

import type { Uint8Array_ } from "./_types.ts";
export type { Uint8Array_ };

export const alphabet = new TextEncoder().encode("0123456789abcdef");
export const rAlphabet = new Uint8Array(128).fill(16); // alphabet.Hex.length
alphabet.forEach((byte, i) => rAlphabet[byte] = i);
new TextEncoder()
  .encode("ABCDEF")
  .forEach((byte, i) => rAlphabet[byte] = i + 10);

/**
 * Calculate the output size needed to encode a given input size for
 * {@linkcode encodeIntoHex}.
 *
 * @param originalSize The size of the input buffer.
 * @returns The size of the output buffer.
 *
 * @example Basic Usage
 * ```ts
 * import { assertEquals } from "@std/assert";
 * import { calcSizeHex } from "@std/encoding/unstable-hex";
 *
 * assertEquals(calcSizeHex(1), 2);
 * ```
 */
export function calcSizeHex(originalSize: number): number {
  return originalSize * 2;
}

export function encode(
  buffer: Uint8Array_,
  i: number,
  o: number,
  alphabet: Uint8Array,
): number {
  for (; i < buffer.length; ++i) {
    const x = buffer[i]!;
    buffer[o++] = alphabet[x >> 4]!;
    buffer[o++] = alphabet[x & 0xF]!;
  }
  return o;
}

export function decode(
  buffer: Uint8Array_,
  i: number,
  o: number,
  alphabet: Uint8Array,
): number {
  if ((buffer.length - o) % 2 === 1) {
    throw new RangeError(
      `Cannot decode input as hex: Length (${
        buffer.length - o
      }) must be divisible by 2`,
    );
  }

  i += 1;
  for (; i < buffer.length; i += 2) {
    buffer[o++] = (getByte(buffer[i - 1]!, alphabet) << 4) |
      getByte(buffer[i]!, alphabet);
  }
  return o;
}

function getByte(char: number, alphabet: Uint8Array): number {
  const byte = alphabet[char] ?? 16;
  if (byte === 16) { // alphabet.Hex.length
    throw new TypeError(
      `Cannot decode input as hex: Invalid character (${
        String.fromCharCode(char)
      })`,
    );
  }
  return byte;
}