Previous: Bindat Functions, Up: Byte Packing [Contents][Index]
Here is a complete example of byte unpacking and packing:
(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))) "Description of a fortune cookie index file's contents.") (defun fcookie (cookies &optional index) "Display a random fortune cookie from file COOKIES. Optional second arg INDEX specifies the associated index filename, by default \"COOKIES.dat\". Display cookie text in buffer \"*Fortune Cookie: BASENAME*\", where BASENAME is COOKIES without the directory part." (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) "Scan file COOKIES, and write out its index file. Optional arg INDEX specifies the index filename, which by default is \"COOKIES.dat\". Optional arg DELIM specifies the unibyte character that, when found on a line of its own in COOKIES, indicates the border between entries." (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")))))))
The following is an example of defining and unpacking a complex structure. Consider the following C structures:
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; /* in network byte order */ unsigned char id[8]; /* null-terminated string */ unsigned char data[/* (length + 3) & ~3 */]; }; struct packet { struct header header; unsigned long counters[2]; /* in little endian order */ unsigned char items; unsigned char filler[3]; struct data item[/* items */]; };
The corresponding data layout specification is:
(setq header-spec '((dest-ip ip) (src-ip ip) (dest-port u16) (src-port u16))) (setq data-spec '((type u8) (opcode u8) (length u16) ; network byte order (id strz 8) (data vec (length)) (align 4))) (setq packet-spec '((header struct header-spec) (counters vec 2 u32r) ; little endian order (items u8) (fill 3) (item repeat (items) (struct data-spec))))
A binary data representation is:
(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 ])
The corresponding decoded structure is:
(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))))
An example of fetching data from this structure:
(bindat-get-field decoded 'item 1 'id) ⇒ "BCDEFG"
Previous: Bindat Functions, Up: Byte Packing [Contents][Index]