binary

Tcl8.0からバイナリデータを操作するためのbinaryコマンドが追加されました。
binaryコマンドは、ちょっと取っ付きにくい仕様になっていますが、
binaryコマンドを使うと、文字列とバイナリデータの相互変換ができます。

バイナリへの変換

binary formatコマンドは指定したtemplateに従って文字列をバイナリデータに変換します。

[形式]
binary format template ?value value ...?

templateは、タイプとカウント数から成ります。
binary formatコマンドは、バイナリデータを返します。
templateに指定するタイプには以下のものがあります。

※以下の例のバイナリデータは、バイナリデータと等価な文字列で代用しています。

a
カウント数分の文字列をバイナリに変換します。valueがカウント数以下の時はゼロ(null)をパディングします。
カウント数に*を指定すると、valueの残りをすべてを使います。
カウント数が1の時は省略できます。
binary format a6a*a hello world !
=> hello\000world!
A
ゼロ(null)の代わりにスペースをパディングする以外はaと同じです。
binary format A6A*A hello world !
=> hello world!
b
カウント数分の2進数(low-high順)文字列をバイナリに変換します。
binary format b5b* 11100 111000011010
=> \x07\x87\x05
B
カウント数分の2進数(high-low順)文字列をバイナリに変換します。
binary format B5B* 11100 111000011010
=> \xe0\xe1\xa0
h
カウント数分の16進数(high-low順)文字列をバイナリに変換します。
binary format h3h* AB def
=> \xba\x00\xed\x0f
H
カウント数分の16進数(low-high順)文字列をバイナリに変換します。
binary format H3H* ab DEF
=> \xab\x00\xde\xf0
c
カウント数分の数値文字列を8bitの整数値に変換します。
リストの要素数がカウント数より多い時は余分な要素を無視します。
リストの要素数がカウント数より少ない時はエラーになります。
binary format c3cc* {3 -3 128 1} 260 {2 5}
=> \x03\xfd\x80\x04\x02\x05

binary format c {2 5}
=> expected integer but got "2 5"
s
カウント数分の数値文字列を16bitの整数値(little-endian)に変換します。
binary format s3 {3 -3 258 1}
=> \x03\x00\xfd\xff\x02\x01
S
カウント数分の数値文字列を16bitの整数値(big-endian)に変換します。
binary format S3 {3 -3 258 1}
=> \x00\x03\xff\xfd\x01\x02
i
カウント数分の数値文字列を32bitの整数値(little-endian)に変換します。
binary format i3 {3 -3 65536 1}
=> \x03\x00\x00\x00\xfd\xff\xff\xff\x00\x00\x01\x00 
I
カウント数分の数値文字列を32bitの整数値(big-endian)に変換します。
binary format I3 {3 -3 65536 1}
=> \x00\x00\x00\x03\xff\xff\xff\xfd\x00\x01\x00\x00
f
カウント数分の数値文字列を単精度の浮動少数点数値に変換します。
binary format f2 {1.6 3.4}
=> \xcd\xcc\xcc\x3f\x9a\x99\x59\x40
d
カウント数分の数値文字列を倍精度の浮動少数点数値に変換します。
binary format d1 {1.6}
=> \x9a\x99\x99\x99\x99\x99\xf9\x3f
x
カウント数分のゼロ(null)に変換します。
カウント数に*を指定するとエラーになります。
binary format a3xa3x2a3 abc def ghi
=> abc\000def\000\000ghi
X
出力位置をカウント数分戻します。
カウント数に*を指定すると最初の位置に戻ります。
binary format a3X*a3X2a3 abc def ghi
=> dghi
@
カウント数で指定した絶対位置に出力位置を移動します。
カウント数に0を指定すると最初の位置に、*を指定すると最後の位置に移動します。
最終位置を越えてデータが置かれた時は、未初期化の位置にゼロ(null)がパディングされます。
binary format a5@2a1@*a3@10a1 abcde f ghi j
=> abfdeghi\000\000j

文字列への変換

binary scanコマンドは指定したtemplateに従ってバイナリデータを文字列に変換します。

[形式]
binary scan binaryData template ?varName varName ...? 

templateは、タイプとカウント数から成ります。
変換した結果は、varNameで指定した変数に入れられます。
binary scanコマンドは、生成した変数の数を返します。
templateに指定するタイプには以下のものがあります。

a
バイナリデータをカウント数分の文字列に変換します。
カウント数に*を指定すると、binaryDataの残りをすべてを使います。
カウント数が1の時は省略できます。
binary scan abcde\000fghi a6a10 var1 var2
=> 1
set var1
=> abcde\000
set var2
=> can't read "var2": no such variable
A
ゼロ(null)を最終的に取り除く以外はaと同じです。
binary scan "abc efghi  \000" A* var1
=> 1
set var1
=> abc efghi
b
バイナリデータをカウント数分の2進数(low-high順)の文字列に変換します。
binary scan \x07\x87\x05 b5b* var1 var2
=> 2
set var1
=> 01110
set var2
=> 1110000110100000
B
バイナリデータをカウント数分の2進数(high-low順)の文字列に変換します。
binary scan \x07\x87\x05 B5B* var1 var2
=> 2
set var1
=> 01110
set var2
=> 1000011100000101
h
バイナリデータをカウント数分の16進数(low-high順)の文字列に変換します。
binary scan \x07\x86\x05 h3h* var1 var2
=> 2
set var1
=> 706
set var2
=> 50
H
バイナリデータをカウント数分の16進数(high-low順)の文字列に変換します。
binary scan \x07\x86\x05 H3H* var1 var2
=> 2
set var1
=> 078
set var2
=> 05
c
カウント数分の8bit整数のバイナリデータを8bitの符号付き整数の文字列に変換します。
binary scan \x07\x86\x05 c2c* var1 var2
=> 2
set var1
=> 7 -122
set var2
=> 5
返ってきた値は、符号付きの整数ですが、以下の式で符号なし整数に変換できます。
expr ( $num + 0x100 ) % 0x100
s
カウント数分の16bit整数のバイナリデータを16bitの符号付き整数(little-endian)の文字列に変換します。
binary scan \x05\x00\x07\x00\xf0\xff s2s* var1 var2
=> 2
set var1
=> 5 7
set var2
=> -16
返ってきた値は、符号付きの整数ですが、以下の式で符号なし整数に変換できます。
expr ( $num + 0x10000 ) % 0x10000
S
カウント数分の16bit整数のバイナリデータを16bitの符号付き整数(big-endian)の文字列に変換します。
binary scan \x00\x05\x00\x07\xff\xf0 S2S* var1 var2
=> 2
set var1
=> 5 7
set var2
=> -16
i
カウント数分の32bit整数のバイナリデータを32bitの符号付き整数(litle-endian)の文字列に変換します。
binary scan \x05\x00\x00\x00\x07\x00\x00\x00\xf0\xff\xff\xff i2i* var1 var2
=> 2
set var1
=> 5 7
set var2
=> -16
返ってきた値は、符号付きの整数ですが、Tclでは符号なし整数として表現できません。
I
カウント数分の32bit整数のバイナリデータを32bitの符号付き整数(big-endian)の文字列に変換します。
binary \x00\x00\x00\x05\x00\x00\x00\x07\xff\xff\xff\xf0 I2I* var1 var2
=> 2
set var1
=> 5 7
set var2
=> -16
f
カウント数分の浮動少数点数のバイナリデータを単精度浮動少数点数の文字列に変換します。
binary scan \x3f\xcc\xcc\xcd f var1
=> 1
set var1
=> 1.6000000238418579
d
カウント数分の浮動少数点数のバイナリデータを倍精度浮動少数点数の文字列に変換します。
binary scan \x9a\x99\x99\x99\x99\x99\xf9\x3f d var1
=> 1
set var1
=> 1.6000000000000001
x
カウント数分のバイト数だけスキャン位置を先に進めます。
カウント数に*を指定すると最後の位置に進みます。
binary scan \x01\x02\x03\x04 x2H* var1
=> 1
set var1
=> 0304
X
カウント数分のバイト数だけスキャン位置を後に戻します。
カウント数に*を指定すると最初の位置に戻ります。
binary scan \x01\x02\x03\x04 c2XH* var1 var2
=> 2
set var1
=> 1 2
set var2
=> 020304
@
カウント数で指定した絶対位置にスキャン位置を移動します。
カウント数に0を指定すると最初の位置に、*を指定すると最後の位置に移動します。
binary scan \x01\x02\x03\x04 c2@1H* var1 var2
=> 2
set var1
=> 1 2
set var2
=> 020304

注意事項