コンテンツにスキップ
UniKVS
日本語
Esc
↑↓移動↵開く⌘Jプレビュー
このページの内容

@unikvs/hex

バイト列を 16 進文字列として表すバイト列へ透過的に変換する Transformer プラグインの使い方を説明します。

概要

@unikvs/hex は、バイト列を 16 進文字列 (hex) として表すバイト列へ変換する Transformer プラグインです。Transformer

書き込み時は encode で hex 化し、読み取り時は decode で元のバイト列に戻すため、変換の詳細を意識せずに読み書きできます。ハッシュ値やバイナリー内容の確認、デバッグ出力、テキストしか保存できない保存先への格納に使います。

入出力はどちらも Uint8Array<ArrayBuffer> です。出力は常に小文字 (0-9・a-f) で、入力は大文字・小文字のどちらも受け付けます。変換後のサイズは元のサイズのちょうど 2 倍になります。

常にオープン状態です。open・close は不要で、isOpen は常に true、name は常に "Hex" を返します。

インストールは次のとおりです。

npm install @unikvs/hex
pnpm add @unikvs/hex
yarn add @unikvs/hex
bun add @unikvs/hex
nub add @unikvs/hex
aube add @unikvs/hex

使い方

通常は引数なしで生成します。UTF-8 変換に使うインスタンスを差し替えたい場合にだけ HexOptions を指定します。

import { Hex } from "@unikvs/hex";

const hex = new Hex();
import { Hex, type HexOptions } from "@unikvs/hex";
import { FastUtf8 } from "fast-utf8";

const options: HexOptions = {
  encoder: new FastUtf8(),
  decoder: new FastUtf8({ strict: true }),
};

const hex = new Hex(options);

HexOptions の内容は次のとおりです。通常は省略し、既定のまま使います。decoder に strict: false のインスタンスを指定した場合は、不正な UTF-8 は HexDecodeError として投げられます。詳しくはエラーを参照してください。

type HexOptions = {
  readonly encoder?: FastUtf8 | undefined;
  readonly decoder?: FastUtf8 | undefined;
};

主なメンバーは次のとおりです。

メンバー 概要
new Hex(options?) オプションなしで初期化します。差し替えが必要な場合だけ HexOptions を渡します。
name 常に "Hex" を返します。
isOpen 常に true を返します。
encode({ data }) Uint8Array<ArrayBuffer> を小文字 hex の Uint8Array<ArrayBuffer> に変換します。
decode({ data }) 小文字・大文字の hex の Uint8Array<ArrayBuffer> を元のバイト列に戻します。
getEncodable() hex 化用の TransformStream を返します。
getDecodable() hex 復元用の TransformStream を返します。

一括変換の例です。encode の結果を UTF-8 文字列として解釈すると小文字の hex になります。

import { Hex } from "@unikvs/hex";

const hex = new Hex();

const encoded = hex.encode({ data: Uint8Array.from([0xde, 0xad, 0xbe, 0xef]) });
console.log(new TextDecoder().decode(encoded)); // "deadbeef"

const decoded = hex.decode({ data: new TextEncoder().encode("DEADBEEF") });
console.log(decoded); // Uint8Array(4) [ 222, 173, 190, 239 ]

UniKvs には appendTransformer で登録します。以降に登録するストレージの前段になります。

import { Hex } from "@unikvs/hex";
import UniKvs from "unikvs";

const kvs = UniKvs.config()
  .appendTransformer(new Hex())
  .appendStorage(storage)
  .create();

await kvs.open();

await kvs.set("data", input);

const output = await kvs.get("data");

set で hex 化して保存し、get で自動的に元のバイト列へ戻します。

ストリーム

単体値とストリームの両方に対応しています。

  • 単体値は encode・decode で変換します。
  • ストリーム値は getEncodable・getDecodable の TransformStream で変換します。

getEncodable は、入力チャンクをそれぞれ独立に hex 化して順に送出します。

getDecodable は、チャンク境界で分割された hex も正しく復元します。

  • 空のストリームと長さ 0 のチャンクは値を 1 つも生成せず、エラーにもなりません。
  • 終了時に半端な 1 文字が残っている場合は HexDecodeError を投げます。
  • hex として不正な文字が含まれている場合は、その時点で HexDecodeError を投げます。
  • 既定では、不正な UTF-8 や途中で切れたマルチバイト文字が含まれている場合は TypeError を投げます。詳しくはエラーを参照してください。
import { Hex } from "@unikvs/hex";

const hex = new Hex();

const source = new ReadableStream({
  start(controller) {
    controller.enqueue(Uint8Array.from([0xde, 0xad]));
    controller.enqueue(Uint8Array.from([0xbe, 0xef]));
    controller.close();
  },
});

const decoded = source.pipeThrough(hex.getEncodable()).pipeThrough(hex.getDecodable());

注意点

形式の扱いは次のとおりです。

  • 0x の接頭辞は付加も除去もしません。"0x..." を渡すと x が不正文字として拒否されます。必要な場合は呼び出し側で付け外ししてください。
  • 空白・改行・コロンなどの区切りは読み飛ばしません。不正文字として拒否されます。
  • 空入力は空出力です。new Uint8Array(0) を渡してもエラーになりません。

サイズ(バイト長)は元のサイズのちょうど 2 倍になります。圧縮や暗号化、改ざん検知の目的には使えません。

エラー

このパッケージが投げるエラーは次のとおりです。

エラー 意味 対処
HexDecodeError hex として解釈できません。奇数長、不正な文字が原因です。 入力が偶数長の hex (0-9・a-f・A-F の連続) か確認してください。

既定では(一括・ストリームいずれも)、UTF-8 として不正なバイト列は HexDecodeError ではなくネイティブの TypeError として伝わります。HexOptions で strict: false の decoder を注入した場合は HexDecodeError として投げられます。

import { Hex, HexDecodeError } from "@unikvs/hex";

const hex = new Hex();

try {
  hex.decode({ data: new TextEncoder().encode("abc") });
} catch (error) {
  if (error instanceof HexDecodeError) {
    console.log("hex として解釈できません。");
  } else {
    throw error;
  }
}

使用例

Memory と組み合わせた最小例です。書き込んだ値は hex 化して保存し、読み取り時に自動的に元のバイト列に戻します。

import { Hex } from "@unikvs/hex";
import { Memory } from "@unikvs/memory";
import UniKvs, { type PlainValue } from "unikvs";

const kvs = UniKvs.config<{ data: PlainValue<Uint8Array<ArrayBuffer>> }>()
  .appendTransformer(new Hex())
  .appendStorage(new Memory())
  .create();

await kvs.open();

const input = Uint8Array.from([0xde, 0xad, 0xbe, 0xef]);
await kvs.set("data", input);

const output = await kvs.get("data");
console.log(output.length === input.length);

await kvs.close();

このページは役に立ちましたか?