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]