Previous: Bindat Functions, Up: Byte Packing [Contents][Index]
以下はバイトにたいしてunpackおよびpackを行う完全な例です:
(require 'bindat)
(defvar fcookie-index-spec
'((:version u32)
(:count u32)
(:longest u32)
(:shortest u32)
(:flags u32)
(:delim u8)
(:ignored fill 3)
(:offset repeat (:count) (:foo u32)))
"fortuneクッキーのインデックスファイル内容")
(defun fcookie (cookies &optional index)
"ファイルCOOKIESからランダムなfortuneクッキーを表示する。
オプションの第2引数INDEXは関連付けられるインデックス
ファイル名を指定し、デフォルトは\"COOKIES.dat\"。
バッファー\"*Fortune Cookie: BASENAME*\"内にクッキーを表示。
BASENAMEはディレクトリー部分を除いたCOOKIES"
(interactive "fCookies file: ")
(let* ((info (with-temp-buffer
(insert-file-contents-literally
(or index (concat cookies ".dat")))
(bindat-unpack fcookie-index-spec
(buffer-string))))
(sel (random (bindat-get-field info :count)))
(beg (cdar (bindat-get-field info :offset sel)))
(end (or (cdar (bindat-get-field info
:offset (1+ sel)))
(nth 7 (file-attributes cookies)))))
(switch-to-buffer
(get-buffer-create
(format "*Fortune Cookie: %s*"
(file-name-nondirectory cookies))))
(erase-buffer)
(insert-file-contents-literally
cookies nil beg (- end 3))))
(defun fcookie-create-index (cookies &optional index delim)
"ファイルCOOKIESをスキャンしてインデックスファイルに書き込む。
オプション引数INDEXは、インデックスファイル名を指定。デフォルトは\"COOKIES.dat\"。
オプション引数DELIMはユニバイト文字で、それがCOOKIES内
のある行で見つかったら、その行はエントリー間の境界を示す。"
(interactive "fCookies file: ")
(setq delim (or delim ?%))
(let ((delim-line (format "\n%c\n" delim))
(count 0)
(max 0)
min p q len offsets)
(unless (= 3 (string-bytes delim-line))
(error "Delimiter cannot be represented in one byte"))
(with-temp-buffer
(insert-file-contents-literally cookies)
(while (and (setq p (point))
(search-forward delim-line (point-max) t)
(setq len (- (point) 3 p)))
(setq count (1+ count)
max (max max len)
min (min (or min max) len)
offsets (cons (1- p) offsets))))
(with-temp-buffer
(set-buffer-multibyte nil)
(insert
(bindat-pack
fcookie-index-spec
`((:version . 2)
(:count . ,count)
(:longest . ,max)
(:shortest . ,min)
(:flags . 0)
(:delim . ,delim)
(:offset . ,(mapcar (lambda (o)
(list (cons :foo o)))
(nreverse offsets))))))
(let ((coding-system-for-write 'raw-text-unix))
(write-file (or index (concat cookies ".dat")))))))
以下は複雑な構造体を定義してunpackする例です。以下のようなCの構造体があるものとします:
struct header {
unsigned long dest_ip;
unsigned long src_ip;
unsigned short dest_port;
unsigned short src_port;
};
struct data {
unsigned char type;
unsigned char opcode;
unsigned short length; /* ネットワークバイトオーダー */
unsigned char id[8]; /* NUL終端文字列 */
unsigned char data[/* (length + 3) & ~3 */];
};
struct packet {
struct header header;
unsigned long counters[2]; /* リトルエンディアンオーダー */
unsigned char items;
unsigned char filler[3];
struct data item[/* items */];
};
対応するデータレイアウト仕様が以下です:
(setq header-spec
'((dest-ip ip)
(src-ip ip)
(dest-port u16)
(src-port u16)))
(setq data-spec
'((type u8)
(opcode u8)
(length u16) ; ネットワークバイトオーダー
(id strz 8)
(data vec (length))
(align 4)))
(setq packet-spec
'((header struct header-spec)
(counters vec 2 u32r) ; リトルエンディアンオーダー
(items u8)
(fill 3)
(item repeat (items)
(struct data-spec))))
バイナリーデータによる表現は:
(setq binary-data
[ 192 168 1 100 192 168 1 101 01 28 21 32
160 134 1 0 5 1 0 0 2 0 0 0
2 3 0 5 ?A ?B ?C ?D ?E ?F 0 0 1 2 3 4 5 0 0 0
1 4 0 7 ?B ?C ?D ?E ?F ?G 0 0 6 7 8 9 10 11 12 0 ])
対応するデコードされた構造体は:
(setq decoded (bindat-unpack packet-spec binary-data))
⇒
((header
(dest-ip . [192 168 1 100])
(src-ip . [192 168 1 101])
(dest-port . 284)
(src-port . 5408))
(counters . [100000 261])
(items . 2)
(item ((data . [1 2 3 4 5])
(id . "ABCDEF")
(length . 5)
(opcode . 3)
(type . 2))
((data . [6 7 8 9 10 11 12])
(id . "BCDEFG")
(length . 7)
(opcode . 4)
(type . 1))))
以下はこの構造体からデータを取得する例です:
(bindat-get-field decoded 'item 1 'id)
⇒ "BCDEFG"
Previous: Bindat Functions, Up: Byte Packing [Contents][Index]