voile.bindat
Binary data serializer/deserializer
- enum Endian
littleEndian
; - リトルエンディアンのデータに付与するUDA
- enum Endian
bigEndian
; - ビッグエンディアンのデータに付与するUDA
- enum Endian
systemEndian
; - システムのエンディアンがリトルかビッグかで切り替えが行われるUDA
- template
preLength
(T) - 配列の長さがバイナリの前方に現れる場合のUDA
- enum auto
arrayLength
(string pred);
ArrayLengtharrayLength
()(string pred); - 配列の長さを計算によって行うUDA
- enum bool
isInputBinary
(InputRange); - 入力対象のバイナリデータ型
- enum bool
isOutputBinary
(OutputRange); - 出力対象のバイナリデータ型
- template
isBasicArray
(T) - 基本型要素をもつ配列
- template
hasBinaryConvertionProxy
(T)
templatehasBinaryConvertionProxy
(T, string memberName) - Proxy
- 以下の関数を持つ
void writeBinary(InputRange)(ref InputRange) const;
void readBinary(OutputRange)(ref OutputRange);
- 【未実装】以下の関数を持つ
size_t binaryLength() const @property;
immutable(ubyte)[] toBinary() const;
void fromBinary(in byte[]);
- 【未実装】型の宣言に以下のUDAを持つ
@convBy!Proxy
- Proxy:
void to(OutputRange)(in T src, ref OutputRange r);
- Proxy:
void from(InputRange)(ref InputRange r, ref T dst);
- Proxy:
- メンバの宣言に以下のUDAを持つ
@convBy!Proxy
- Proxy type3:
void to(OutputRange)(in T src, ref OutputRange);
- Proxy type3:
void from(InputRange)(ref InputRange, ref T dst);
- Proxy type3:
- 【未実装】メンバの宣言に以下のUDAを持つ
@preLength!Size
@convBy!Proxy
:immutable(ubyte)[]
- 【未実装】メンバの宣言に以下のUDAを持つ
@arrayLength!"..."
@convBy!Proxy
:immutable(ubyte)[]
- 以下の関数を持つ
- @trusted void
serializeToBinDat
(Endian endian, OutputRange, T)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && isBasicType!T);
voidserializeToBinDat
(Endian endian, OutputRange, T : ubyte)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && isBasicType!T);
@trusted voidserializeToBinDat
(OutputRange, T)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && isBasicType!T);
voidserializeToBinDat
(OutputRange, T : ubyte)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && isBasicType!T);
voidserializeToBinDat
(Endian endian, OutputRange, T)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && isBasicArray!T);
voidserializeToBinDat
(OutputRange, T)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && isArray!T);
voidserializeToBinDat
(OutputRange, T)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && is(T == struct));
voidserializeToBinDat
(OutputRange, T : Endata!U, U)(ref OutputRange r, in T data)
if(isOutputBinary!OutputRange && is(T == struct));
@trusted immutable(ubyte)[]serializeToBinDat
(T)(in T data);
@trusted immutable(ubyte)[]serializeToBinDat
(Endian endian, T)(in T data)
if(isBasicType!T || isArray!T); - バイナリのシリアライズExamples: 基本型と列挙値
ubyte a = 10; assert(a.serializeToBinDat!littleEndian() == [10]); uint b = 10; assert(b.serializeToBinDat!bigEndian() == [0, 0, 0, 10]); version (LittleEndian) assert(b.serializeToBinDat() == [10, 0, 0, 0]); version (BigEndian) assert(b.serializeToBinDat() == [0, 0, 0, 10]); enum E { a, b } E e = E.a; assert(e.serializeToBinDat!littleEndian() == [0, 0, 0, 0]); e = E.b; assert(e.serializeToBinDat!littleEndian() == [1, 0, 0, 0]); assert(e.serializeToBinDat!bigEndian() == [0, 0, 0, 1]);
Examples: 配列ubyte[] a = [10, 20]; assert(a.serializeToBinDat!littleEndian() == [10, 20]); uint[] b = [10, 20]; assert(b.serializeToBinDat!bigEndian() == [0, 0, 0, 10, 0, 0, 0, 20]); version (LittleEndian) assert(b.serializeToBinDat() == [10, 0, 0, 0, 20, 0, 0, 0]); version (BigEndian) assert(b.serializeToBinDat() == [0, 0, 0, 10, 0, 0, 0, 20]); uint[2] c = [1,2]; assert(c.serializeToBinDat!littleEndian() == [1, 0, 0, 0, 2, 0, 0, 0]); ubyte[8] d = [1,2,3,4,5,6,7,8]; assert(d.serializeToBinDat() == [1,2,3,4,5,6,7,8]);
Examples: エンディアン変換struct A { @bigEndian ushort a; @littleEndian ushort b; } auto a = A(10, 20); assert(a.serializeToBinDat() == [0, 10, 20, 0]);
Examples: 構造体struct A { @preLength!ushort @bigEndian ubyte[] data; } auto a = A([10, 20]); assert(a.serializeToBinDat() == [0, 2, 10, 20]); struct B { @bigEndian uint length; @arrayLength!"length" @littleEndian ushort[] data; } auto b = B(2, [10, 20]); assert(b.serializeToBinDat() == [0, 0, 0, 2, 10, 0, 20, 0]); struct C { A a; @bigEndian ushort[4] x; B b; } auto c = C(A([10, 20]), [1,2,3,4], B(2, [10, 20])); assert(c.serializeToBinDat() == [ 0, 2, 10, 20, 0,1, 0,2, 0,3, 0,4, 0, 0, 0, 2, 10, 0, 20, 0]);
Examples: Endata@littleEndian enum A: short { @bigEndian @data!int a, @littleEndian @data!short b } Endata!A a; a.a = 10; assert(a.serializeToBinDat() == [0x00, 0x00, 0x00, 0x00, 0x00, 0x0a]); a.b = 11; assert(a.serializeToBinDat() == [0x01, 0x00, 0x0b, 0x00]);
Examples: Proxystruct A { int a; void writeBinary(OutputRange)(ref OutputRange r) const if (isOutputBinary!OutputRange) { put(r, cast(ubyte)(a + 100)); } void readBinary(InputRange)(ref InputRange r) if (isInputBinary!InputRange) { a = r.front - 100; r.popFront(); } } static assert(hasBinaryConvertionProxy!A); A a = A(-10); assert(a.serializeToBinDat() == [90]); import std.datetime; struct B { static struct Proxy { static void to(OutputRange)(in DateTime d, ref OutputRange r) @trusted { r.serializeToBinDat!bigEndian(cast(ushort)d.year); r.serializeToBinDat!bigEndian(cast(ubyte)d.month); r.serializeToBinDat!bigEndian(cast(ubyte)d.day); r.serializeToBinDat!bigEndian(cast(ubyte)d.hour); r.serializeToBinDat!bigEndian(cast(ubyte)d.minute); r.serializeToBinDat!bigEndian(cast(ubyte)d.second); } static void from(InputRange)(ref InputRange r, ref DateTime d) @trusted { ushort year; ubyte month; ubyte day; ubyte hour; ubyte minute; ubyte second; year.deserializeFromBinDat!bigEndian(r); month.deserializeFromBinDat!bigEndian(r); day.deserializeFromBinDat!bigEndian(r); hour.deserializeFromBinDat!bigEndian(r); minute.deserializeFromBinDat!bigEndian(r); second.deserializeFromBinDat!bigEndian(r); d = DateTime(year, month, day, hour, minute, second); } } @convBy!Proxy DateTime dt; } B b = B(DateTime(2020, 12, 25)); assert(b.serializeToBinDat() == [0x07, 0xE4, 12, 25, 0, 0, 0]);
- void
deserializeFromBinDat
(Endian endian, T, InputRange)(ref T dst, ref InputRange r)
if(isInputBinary!InputRange && isBasicType!T);
voiddeserializeFromBinDat
(T, InputRange)(ref T dst, ref InputRange r)
if(isInputBinary!InputRange && isBasicType!T);
voiddeserializeFromBinDat
(Endian endian, T, InputRange)(ref T dst, ref InputRange r)
if(isInputBinary!InputRange && isBasicArray!T);
voiddeserializeFromBinDat
(T, InputRange)(ref T dst, ref InputRange r)
if(isInputBinary!InputRange && isArray!T);
voiddeserializeFromBinDat
(T, InputRange)(ref T dst, ref InputRange r)
if(isInputBinary!InputRange && is(T == struct));
voiddeserializeFromBinDat
(T : Endata!U, InputRange, U)(ref T dst, ref InputRange r)
if(isInputBinary!InputRange && is(T == struct));
voiddeserializeFromBinDat
(Endian endian, T, InputRange)(ref T dst, InputRange r)
if(isInputBinary!InputRange);
voiddeserializeFromBinDat
(T, InputRange)(ref T dst, InputRange r)
if(isInputBinary!InputRange);
TdeserializeFromBinDat
(T, InputRange)(InputRange r)
if(isInputBinary!InputRange); - バイナリのデシリアライズExamples: 基本型と列挙値
//ubyte[] bin(ubyte[] dat...) { return dat; } template bin(args...) { ubyte[args.length] inst = [args[]]; ubyte[] bin() { return inst[]; } } ubyte a; a.deserializeFromBinDat!littleEndian(bin!(10)); assert(a == 10); uint b; b.deserializeFromBinDat!bigEndian(bin!(0, 0, 0, 10)); assert(b == 10); version (LittleEndian) b.deserializeFromBinDat(bin!(10, 0, 0, 0)); version (BigEndian) b.deserializeFromBinDat(bin!(0, 0, 0, 10)); assert(b == 10); enum E { a, b } E e; e.deserializeFromBinDat!littleEndian(bin!(0, 0, 0, 0)); assert(e == E.a); e.deserializeFromBinDat!littleEndian(bin!(1, 0, 0, 0)); assert(e == E.b); e.deserializeFromBinDat!bigEndian(bin!(0, 0, 0, 1)); assert(e == E.b);
Examples: 配列template bin(args...) { ubyte[args.length] inst = [args[]]; ubyte[] bin() { return inst[]; } } ubyte[] a = new ubyte[2]; a.deserializeFromBinDat!littleEndian(bin!(10, 20)); assert(a == [10, 20]); uint[] b = new uint[2]; b.deserializeFromBinDat!bigEndian(bin!(0, 0, 0, 10, 0, 0, 0, 20)); assert(b == [10, 20]); version (LittleEndian) b.deserializeFromBinDat(bin!(10, 0, 0, 0, 20, 0, 0, 0)); version (BigEndian) b.deserializeFromBinDat(bin!(0, 0, 0, 10, 0, 0, 0, 20)); assert(b == [10, 20]); uint[2] c; c.deserializeFromBinDat!littleEndian(bin!(1, 0, 0, 0, 2, 0, 0, 0)); assert(c == [1, 2]); ubyte[8] d; d.deserializeFromBinDat(bin!(1, 0, 0, 0, 2, 0, 0, 0)); assert(d == [1, 0, 0, 0, 2, 0, 0, 0]);
Examples: エンディアン変換template bin(args...) { ubyte[args.length] inst = [args[]]; ubyte[] bin() { return inst[]; } } struct A { @bigEndian ushort a; @littleEndian ushort b; } A a; a.deserializeFromBinDat(bin!(0, 10, 20, 0)); assert(a == A(10, 20));
Examples: 構造体template bin(args...) { ubyte[args.length] inst = [args[]]; ubyte[] bin() { return inst[]; } } struct A { @preLength!ushort @bigEndian ubyte[] data; } A a; a.deserializeFromBinDat(bin!(0, 2, 10, 20)); assert (a == A([10, 20])); struct B { @bigEndian uint length; @arrayLength!"length" @littleEndian ushort[] data; } B b; b.deserializeFromBinDat(bin!(0, 0, 0, 2, 10, 0, 20, 0)); assert(b == B(2, [10, 20])); struct C { A a; @bigEndian ushort[4] x; B b; } C c; c.deserializeFromBinDat(bin!( 0, 2, 10, 20, 0,1, 0,2, 0,3, 0,4, 0, 0, 0, 2, 10, 0, 20, 0)); assert(c == C(A([10, 20]), [1,2,3,4], B(2, [10, 20])));
Examples: Endatatemplate bin(args...) { ubyte[args.length] inst = [args[]]; ubyte[] bin() { return inst[]; } } @littleEndian enum A: short { @bigEndian @data!int a, @littleEndian @data!short b, c } Endata!A a; a.deserializeFromBinDat(bin!(0x00, 0x00, 0x00, 0x00, 0x00, 0x0a)); Endata!A tmp; tmp.a = 10; assert(a == tmp); a.deserializeFromBinDat(bin!(0x01, 0x00, 0x0b, 0x00)); tmp.b = 11; assert(a == tmp); a.deserializeFromBinDat(bin!(0x02, 0x00)); tmp.initialize!(A.c); assert(a == tmp); assert(tmp.serializeToBinDat() == bin!(0x02, 0x00));
Examples: Proxytemplate bin(args...) { ubyte[args.length] inst = [args[]]; ubyte[] bin() { return inst[]; } } struct A { int a; void writeBinary(OutputRange)(ref OutputRange r) const if (isOutputBinary!OutputRange) { put(r, cast(ubyte)(a + 100)); } void readBinary(InputRange)(ref InputRange r) if (isInputBinary!InputRange) { a = r.front - 100; r.popFront(); } } A a; a.deserializeFromBinDat(bin!(90)); assert(a == A(-10)); import std.datetime; struct B { static struct Proxy { static void to(OutputRange)(in DateTime d, ref OutputRange r) @trusted { r.serializeToBinDat!bigEndian(cast(ushort)d.year); r.serializeToBinDat!bigEndian(cast(ubyte)d.month); r.serializeToBinDat!bigEndian(cast(ubyte)d.day); r.serializeToBinDat!bigEndian(cast(ubyte)d.hour); r.serializeToBinDat!bigEndian(cast(ubyte)d.minute); r.serializeToBinDat!bigEndian(cast(ubyte)d.second); } static void from(InputRange)(ref InputRange r, ref DateTime d) @trusted { ushort year; ubyte month; ubyte day; ubyte hour; ubyte minute; ubyte second; year.deserializeFromBinDat!bigEndian(r); month.deserializeFromBinDat!bigEndian(r); day.deserializeFromBinDat!bigEndian(r); hour.deserializeFromBinDat!bigEndian(r); minute.deserializeFromBinDat!bigEndian(r); second.deserializeFromBinDat!bigEndian(r); d = DateTime(year, month, day, hour, minute, second); } } @convBy!Proxy DateTime dt; } B b; b.deserializeFromBinDat(bin!(0x07, 0xE4, 12, 25, 0, 0, 0)); assert(b == B(DateTime(2020, 12, 25)));
Examples: バイナリの解析- [0-2] タグタイプ
- if [0-2]が 0x0001
- [2-4] 長さ
- [4-X] ペイロード
- if [0-2]が 0x0002
- [2] コマンド種別
- if [2] が 0x01
- [3-5] 付与データ
- if [2] が 0x02
- (なし)
- if [2] が 0x03
- [3.0] フラグ1
- [3.1-3.3] フラグ2
- [3.3-3.6] reserved
- [3.7] フラグ8
- if [2] が 0x01
- [2] コマンド種別
- if [0-2]が 0x0001
import voile.munion; struct TypeAPayload { @bigEndian @preLength!ushort ubyte[] payload; } struct TypeBPayload { struct CommandAPayload { @bigEndian ushort payload; } struct CommandCPayload { ubyte flag1; ubyte flag2; ubyte flag7; } enum CommandType: ubyte { @data!CommandAPayload a = 0x0001, b = 0x0002, @data!CommandCPayload c = 0x0003, } @bigEndian Endata!CommandType commandType; } @bigEndian enum TagType: ushort { @data!TypeAPayload a = 0x0001, @data!TypeBPayload b = 0x0002, } Endata!TagType bindat; static immutable ubyte[] binary1 = [ 0x00, 0x01, // [0-2] タグタイプ 0x00, 0x04, // [2-4] 長さ 0x00, 0x01, 0x02, 0x03 // [4-X] ペイロード ]; bindat.deserializeFromBinDat(binary1[]); assert(bindat.tag == TagType.a); assert(bindat.a.payload == [0x00, 0x01, 0x02, 0x03]); static immutable ubyte[] binary2 = [ 0x00, 0x02, // [0-2] タグタイプ 0x01, // [2] コマンド種別 0x00, 0x01 // [3-5] 付与データ ]; bindat.deserializeFromBinDat(binary2[]); assert(bindat.tag == TagType.b); assert(bindat.b.commandType.tag == TypeBPayload.CommandType.a); assert(bindat.b.commandType.a.payload == 0x0001);
- [0-2] タグタイプ