summaryrefslogtreecommitdiff
path: root/std/encoding
diff options
context:
space:
mode:
authorMarcos Casagrande <marcoscvp90@gmail.com>2020-07-09 22:50:19 +0200
committerGitHub <noreply@github.com>2020-07-09 16:50:19 -0400
commitdc6b3ef714c743358703512cd766aed4abc8bd3b (patch)
tree4379f29b5eae0af0a09223ca806d22f34acff858 /std/encoding
parent634d6af7a1506bb209f972ac75af375d0e523d48 (diff)
BREAKING(std/encoding/hex): simplify API (#6690)
Diffstat (limited to 'std/encoding')
-rw-r--r--std/encoding/hex.ts97
-rw-r--r--std/encoding/hex_test.ts77
2 files changed, 56 insertions, 118 deletions
diff --git a/std/encoding/hex.ts b/std/encoding/hex.ts
index c246f7182..729df6c49 100644
--- a/std/encoding/hex.ts
+++ b/std/encoding/hex.ts
@@ -18,17 +18,16 @@ export function errLength(): Error {
return new Error("encoding/hex: odd length hex string");
}
-// fromHexChar converts a hex character into its value and a success flag.
-function fromHexChar(byte: number): [number, boolean] {
- switch (true) {
- case 48 <= byte && byte <= 57: // '0' <= byte && byte <= '9'
- return [byte - 48, true];
- case 97 <= byte && byte <= 102: // 'a' <= byte && byte <= 'f'
- return [byte - 97 + 10, true];
- case 65 <= byte && byte <= 70: // 'A' <= byte && byte <= 'F'
- return [byte - 65 + 10, true];
- }
- return [0, false];
+// fromHexChar converts a hex character into its value.
+function fromHexChar(byte: number): number {
+ // '0' <= byte && byte <= '9'
+ if (48 <= byte && byte <= 57) return byte - 48;
+ // 'a' <= byte && byte <= 'f'
+ if (97 <= byte && byte <= 102) return byte - 97 + 10;
+ // 'A' <= byte && byte <= 'F'
+ if (65 <= byte && byte <= 70) return byte - 65 + 10;
+
+ throw errInvalidByte(byte);
}
/**
@@ -41,24 +40,17 @@ export function encodedLen(n: number): number {
}
/**
- * Encode encodes `src` into `encodedLen(src.length)` bytes of `dst`.
- * As a convenience, it returns the number of bytes written to `dst`
- * but this value is always `encodedLen(src.length)`.
- * Encode implements hexadecimal encoding.
- * @param dst
+ * Encode encodes `src` into `encodedLen(src.length)` bytes.
* @param src
*/
-export function encode(src: Uint8Array, dst: Uint8Array): number {
- const srcLength = encodedLen(src.length);
- if (dst.length !== srcLength) {
- throw new Error("Out of index.");
- }
- for (let i = 0; i < src.length; i++) {
+export function encode(src: Uint8Array): Uint8Array {
+ const dst = new Uint8Array(encodedLen(src.length));
+ for (let i = 0; i < dst.length; i++) {
const v = src[i];
dst[i * 2] = hextable[v >> 4];
dst[i * 2 + 1] = hextable[v & 0x0f];
}
- return srcLength;
+ return dst;
}
/**
@@ -66,78 +58,49 @@ export function encode(src: Uint8Array, dst: Uint8Array): number {
* @param src
*/
export function encodeToString(src: Uint8Array): string {
- const dest = new Uint8Array(encodedLen(src.length));
- encode(src, dest);
- return new TextDecoder().decode(dest);
+ return new TextDecoder().decode(encode(src));
}
/**
* Decode decodes `src` into `decodedLen(src.length)` bytes
- * returning the actual number of bytes written to `dst`.
- * Decode expects that `src` contains only hexadecimal characters and that `src`
- * has even length.
- * If the input is malformed, Decode returns the number of bytes decoded before
+ * If the input is malformed an error will be thrown
* the error.
- * @param dst
* @param src
*/
-export function decode(
- src: Uint8Array,
- dst: Uint8Array
-): [number, Error | void] {
- let i = 0;
- for (; i < Math.floor(src.length / 2); i++) {
- const [a, aOK] = fromHexChar(src[i * 2]);
- if (!aOK) {
- return [i, errInvalidByte(src[i * 2])];
- }
- const [b, bOK] = fromHexChar(src[i * 2 + 1]);
- if (!bOK) {
- return [i, errInvalidByte(src[i * 2 + 1])];
- }
-
+export function decode(src: Uint8Array): Uint8Array {
+ const dst = new Uint8Array(decodedLen(src.length));
+ for (let i = 0; i < dst.length; i++) {
+ const a = fromHexChar(src[i * 2]);
+ const b = fromHexChar(src[i * 2 + 1]);
dst[i] = (a << 4) | b;
}
if (src.length % 2 == 1) {
// Check for invalid char before reporting bad length,
// since the invalid char (if present) is an earlier problem.
- const [, ok] = fromHexChar(src[i * 2]);
- if (!ok) {
- return [i, errInvalidByte(src[i * 2])];
- }
- return [i, errLength()];
+ fromHexChar(src[dst.length * 2]);
+ throw errLength();
}
- return [i, undefined];
+ return dst;
}
/**
- * DecodedLen returns the length of a decoding of `x` source bytes.
+ * DecodedLen returns the length of decoding `x` source bytes.
* Specifically, it returns `x / 2`.
* @param x
*/
export function decodedLen(x: number): number {
- return Math.floor(x / 2);
+ return x >>> 1;
}
/**
* DecodeString returns the bytes represented by the hexadecimal string `s`.
* DecodeString expects that src contains only hexadecimal characters and that
* src has even length.
- * If the input is malformed, DecodeString will throws an error.
- * @param s the `string` need to decode to `Uint8Array`
+ * If the input is malformed, DecodeString will throw an error.
+ * @param s the `string` to decode to `Uint8Array`
*/
export function decodeString(s: string): Uint8Array {
- const src = new TextEncoder().encode(s);
- // We can use the source slice itself as the destination
- // because the decode loop increments by one and then the 'seen' byte is not
- // used anymore.
- const [n, err] = decode(src, src);
-
- if (err) {
- throw err;
- }
-
- return src.slice(0, n);
+ return decode(new TextEncoder().encode(s));
}
diff --git a/std/encoding/hex_test.ts b/std/encoding/hex_test.ts
index ad1ffc2d2..a42238e53 100644
--- a/std/encoding/hex_test.ts
+++ b/std/encoding/hex_test.ts
@@ -34,15 +34,14 @@ const testCases = [
const errCases = [
// encoded(hex) / error
- ["", "", undefined],
- ["0", "", errLength()],
- ["zd4aa", "", errInvalidByte(toByte("z"))],
- ["d4aaz", "\xd4\xaa", errInvalidByte(toByte("z"))],
- ["30313", "01", errLength()],
- ["0g", "", errInvalidByte(new TextEncoder().encode("g")[0])],
- ["00gg", "\x00", errInvalidByte(new TextEncoder().encode("g")[0])],
- ["0\x01", "", errInvalidByte(new TextEncoder().encode("\x01")[0])],
- ["ffeed", "\xff\xee", errLength()],
+ ["0", errLength()],
+ ["zd4aa", errInvalidByte(toByte("z"))],
+ ["d4aaz", errInvalidByte(toByte("z"))],
+ ["30313", errLength()],
+ ["0g", errInvalidByte(new TextEncoder().encode("g")[0])],
+ ["00gg", errInvalidByte(new TextEncoder().encode("g")[0])],
+ ["0\x01", errInvalidByte(new TextEncoder().encode("\x01")[0])],
+ ["ffeed", errLength()],
];
Deno.test({
@@ -62,30 +61,15 @@ Deno.test({
{
const srcStr = "abc";
const src = new TextEncoder().encode(srcStr);
- const dest = new Uint8Array(encodedLen(src.length));
- const int = encode(src, dest);
+ const dest = encode(src);
assertEquals(src, new Uint8Array([97, 98, 99]));
- assertEquals(int, 6);
- }
-
- {
- const srcStr = "abc";
- const src = new TextEncoder().encode(srcStr);
- const dest = new Uint8Array(2); // out of index
- assertThrows(
- (): void => {
- encode(src, dest);
- },
- Error,
- "Out of index."
- );
+ assertEquals(dest.length, 6);
}
for (const [enc, dec] of testCases) {
- const dest = new Uint8Array(encodedLen(dec.length));
const src = new Uint8Array(dec as number[]);
- const n = encode(src, dest);
- assertEquals(dest.length, n);
+ const dest = encode(src);
+ assertEquals(dest.length, src.length * 2);
assertEquals(new TextDecoder().decode(dest), enc);
}
},
@@ -123,10 +107,8 @@ Deno.test({
const cases = testCases.concat(extraTestcase);
for (const [enc, dec] of cases) {
- const dest = new Uint8Array(decodedLen(enc.length));
const src = new TextEncoder().encode(enc as string);
- const [, err] = decode(src, dest);
- assertEquals(err, undefined);
+ const dest = decode(src);
assertEquals(Array.from(dest), Array.from(dec as number[]));
}
},
@@ -146,14 +128,12 @@ Deno.test({
Deno.test({
name: "[encoding.hex] decode error",
fn(): void {
- for (const [input, output, expectedErr] of errCases) {
- const out = new Uint8Array((input as string).length + 10);
- const [n, err] = decode(new TextEncoder().encode(input as string), out);
- assertEquals(
- new TextDecoder("ascii").decode(out.slice(0, n)),
- output as string
+ for (const [input, expectedErr] of errCases) {
+ assertThrows(
+ () => decode(new TextEncoder().encode(input as string)),
+ Error,
+ (expectedErr as Error).message
);
- assertEquals(err, expectedErr);
}
},
});
@@ -161,19 +141,14 @@ Deno.test({
Deno.test({
name: "[encoding.hex] decodeString error",
fn(): void {
- for (const [input, output, expectedErr] of errCases) {
- if (expectedErr) {
- assertThrows(
- (): void => {
- decodeString(input as string);
- },
- Error,
- (expectedErr as Error).message
- );
- } else {
- const out = decodeString(input as string);
- assertEquals(new TextDecoder("ascii").decode(out), output as string);
- }
+ for (const [input, expectedErr] of errCases) {
+ assertThrows(
+ (): void => {
+ decodeString(input as string);
+ },
+ Error,
+ (expectedErr as Error).message
+ );
}
},
});