Mercurial > emacs
annotate lisp/emacs-lisp/bindat.el @ 83004:7900111db01c
Converted display hooks to be display-local. Plus many bugfixes.
lib-src/emacsclient.c (window_change_signal): Renamed to pass_signal_to_emacs.
(init_signal): Pass SIGINT and SIGQUIT to the emacs process.
lisp/faces.el (face-valid-attribute-values): Use the window-system
function, not the variable.
(read-face-attribute, face-spec-set-match-display, frame-set-background-mode)
(face-set-after-frame-default): Ditto.
lisp/frame.el (make-frame-on-tty): Added interactive declaration
(suggested by Robert J. Chassell). Use tty-create-frame-with-faces,
not make-terminal-frame.
src/termhooks.h (struct display_method): Renamed to display for brevity.
(struct display): Added all display hook variables as members of this structure.
Added next_display, reference_count, type and display_info components.
(FRAME_MUST_WRITE_SPACES, FRAME_FAST_CLEAR_END_OF_LINE, FRAME_LINE_INS_DEL_OK)
(FRAME_CHAR_INS_DEL_OK, FRAME_SCROLL_REGION_OK, FRAME_SCROLL_REGION_COST)
(FRAME_MEMORY_BELOW_FRAME, FRAME_RIF): Updated for struct display.
(FRAME_DISPLAY): New macro.
(create_display, delete_display): New prototypes.
src/frame.h (struct frame): Added `display' member, removed display_method.
(FRAME_LIVE_P): Look at f->display, not f->output_data.
src/termchar.h (struct tty_display_info): Removed display_method component.
(FRAME_TTY): Use the display structure, not output_data.
src/term.c (display_list): New variable.
(cursor_to_hook, raw_cursor_to_hook, clear_to_end_hook, clear_frame_hook)
(clear_end_of_line_hook, ins_del_lines_hook, delete_glyphs_hook)
(ring_bell_hook, reset_terminal_modes_hook, set_terminal_modes_hook)
(update_begin_hook, update_end_hook, set_terminal_window_hook)
(insert_glyphs_hook, write_glyphs_hook, delete_glyphs_hoo, read_socket_hook)
(frame_up_to_date_hook, mouse_position_hook, frame_rehighlight_hook)
(frame_raise_lower_hook, set_vertical_scroll_bar_hook, condemn_scroll_bars_hook)
(redeem_scroll_bar_hook, judge_scroll_bars_hook): Moved to struct display.
(tty_display_method_template): Removed.
(syms_of_term): Don't initialize tty_display_method_template.
(ring_bell, set_terminal_modes, reset_terminal_modes, update_begin)
(update_end, set_terminal_window, cursor_to, raw_cursor_to, clear_to_end)
(clear_frame, clear_end_of_line, write_glyphs, insert_glyphs)
(delete_glyphs, ins_del_lines): Access display hooks through the frame pointer.
(Ftty_display_color_p): Use the frame given as a parameter, or else return nil.
(Ftty_display_color_cells): Ditto.
(get_named_tty): Renamed to get_named_tty_display, changed return type to struct display.
(term_dummy_init): Renamed to initial_term_init. Create and return an initial display.
(term_init): Initialize a new struct display and return a pointer to
it instead of tty_display_info. Removed frame initialization kludge.
(Fdelete_tty): Updated for struct display.
(delete_tty): The parameter type is now struct display, not tty_display_info.
Delete the display, too.
(create_tty_output): New function for creating tty_output structures.
(delete_tty_output): New function for deleting tty_output structures.
(create_display): New function for creating and registering display structures.
(delete_display): New function for deleting and unregistering display structures.
src/dispextern.h: Updated prototypes.
src/dispnew.c: Include frame.h before termhooks.h.
(init_display): Updated term_init call to new signature.
src/emacs.c: Include frame.h (for termhooks.h).
src/keymap.c: Ditto.
src/lread.c: Ditto.
src/xsmfns.c: Ditto.
src/process.c: Include frame.h before termhooks.h.
src/frame.c (Fwindow_system): New function.
(syms_of_frame): Initialize it.
(make_terminal_frame): Open the terminal device before creating the new frame.
Disable scrollbars here, term_init cannot do that anymore.
(Fdelete_frame): Use the new delete_frame_hook, don't do display-specific
frame deletion here. Ditto for delete_display_hook.
(Fmouse_position, Fmouse_pixel_position, Fraise_frame, Flower_frame)
(Fredirect_frame_focus): Access display hooks through the frame pointer.
src/keyboard.c: Include frame.h before termhooks.h.
(start_polling, input_polling_used, stop_polling, gobble_input): Ignore read_socket_hook.
(kbd_buffer_get_event, Fset_input_mode): Access display hooks through the frame pointer.
(read_avail_input): Loop through all display devices for and call all read_socket_hook functions. Check ttys even if read_socket_hook returned an error.
src/sysdep.c (discard_tty_input): Ignore read_socket_hook.
(stuff_char): Don't do anything if the current frame is not on a termcap display.
(request_sigio, unrequest_sigio): Ignore read_socket_hook.
(init_sys_modes): Always call narrow_foreground_group. Set up terminal modes and sigio even under X.
src/xdisp.c (message2_nolog, message3_nolog, redisplay_internal)
(set_vertical_scroll_bar, redisplay_window): Access display hooks through the frame pointer.
(echo_area_display): Don't be afraid of termcap frames during an X+tty combo session.
src/xfaces.c: Include termhooks.h.
(Ftty_supports_face_attributes_p): Use the given frame, not selected_frame.
src/xfns.c (x_set_scroll_bar_foreground, x_set_scroll_bar_background): Access display hooks through the frame pointer.
(Fx_create_frame, x_create_tip_frame): Initialize the frame's display structure.
src/xmenu.c: Include termhooks.h after frame.h.
src/xselect.c (x_own_selection, some_frame_on_display, x_get_foreign_selection)
(Fx_disown_selection_internal, Fx_get_cut_buffer_internal)
(Fx_store_cut_buffer_internal, Fx_rotate_cut_buffers_internal): Don't do anything
if the selected frame is not an X frame.
src/xterm.c (x_display_method): Removed.
(x_create_frame_display, x_delete_frame_display): New functions for handling struct display objects.
(x_term_init): Set up a new struct display object, too.
(x_delete_display): Delete the struct display corresponding to the X display.
(x_initialize): Moved hook initialization to x_create_frame_display.
src/xterm.h (x_display_method): Removed.
(struct x_display_info): Added frame_display component.
git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-44
author | Karoly Lorentey <lorentey@elte.hu> |
---|---|
date | Mon, 05 Jan 2004 05:54:35 +0000 |
parents | 695cf19ef79e |
children | 3fc0c472c166 375f2633d815 |
rev | line source |
---|---|
46122 | 1 ;;; bindat.el --- binary data structure packing and unpacking. |
2 | |
3 ;; Copyright (C) 2002 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Kim F. Storm <storm@cua.dk> | |
6 ;; Assignment name: struct.el | |
7 ;; Keywords: comm data processes | |
8 | |
9 ;; This file is part of GNU Emacs. | |
10 | |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
12 ;; it under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; GNU Emacs is distributed in the hope that it will be useful, | |
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 ;; GNU General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 ;; Boston, MA 02111-1307, USA. | |
25 | |
26 ;;; Commentary: | |
27 | |
28 ;; Packing and unpacking of (binary) data structures. | |
29 ;; | |
30 ;; The data formats used in binary files and network protocols are | |
31 ;; often structed data which can be described by a C-style structure | |
32 ;; such as the one shown below. Using the bindat package, decoding | |
33 ;; and encoding binary data formats like these is made simple using a | |
34 ;; structure specification which closely resembles the C style | |
35 ;; structure declarations. | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
36 ;; |
46122 | 37 ;; Encoded (binary) data is stored in a unibyte string or vector, |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
38 ;; while the decoded data is stored in an alist with (FIELD . VALUE) |
46122 | 39 ;; pairs. |
40 | |
41 ;; Example: | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
42 |
46122 | 43 ;; Consider the following C structures: |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
44 ;; |
46122 | 45 ;; struct header { |
46 ;; unsigned long dest_ip; | |
47 ;; unsigned long src_ip; | |
48 ;; unsigned short dest_port; | |
49 ;; unsigned short src_port; | |
50 ;; }; | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
51 ;; |
46122 | 52 ;; struct data { |
53 ;; unsigned char type; | |
54 ;; unsigned char opcode; | |
55 ;; unsigned long length; /* In little endian order */ | |
56 ;; unsigned char id[8]; /* nul-terminated string */ | |
57 ;; unsigned char data[/* (length + 3) & ~3 */]; | |
58 ;; }; | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
59 ;; |
46122 | 60 ;; struct packet { |
61 ;; struct header header; | |
62 ;; unsigned char items; | |
63 ;; unsigned char filler[3]; | |
64 ;; struct data item[/* items */]; | |
65 ;; }; | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
66 ;; |
46122 | 67 ;; The corresponding Lisp bindat specification looks like this: |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
68 ;; |
46122 | 69 ;; (setq header-spec |
70 ;; '((dest-ip ip) | |
71 ;; (src-ip ip) | |
72 ;; (dest-port u16) | |
73 ;; (src-port u16))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
74 ;; |
46122 | 75 ;; (setq data-spec |
76 ;; '((type u8) | |
77 ;; (opcode u8) | |
78 ;; (length u16r) ;; little endian order | |
79 ;; (id strz 8) | |
80 ;; (data vec (length)) | |
81 ;; (align 4))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
82 ;; |
46122 | 83 ;; (setq packet-spec |
84 ;; '((header struct header-spec) | |
85 ;; (items u8) | |
86 ;; (fill 3) | |
87 ;; (item repeat (items) | |
88 ;; ((struct data-spec))))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
89 ;; |
46122 | 90 ;; |
91 ;; A binary data representation may look like | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
92 ;; [ 192 168 1 100 192 168 1 101 01 28 21 32 2 0 0 0 |
46122 | 93 ;; 2 3 5 0 ?A ?B ?C ?D ?E ?F 0 0 1 2 3 4 5 0 0 0 |
94 ;; 1 4 7 0 ?B ?C ?D ?E ?F ?G 0 0 6 7 8 9 10 11 12 0 ] | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
95 ;; |
46122 | 96 ;; The corresponding decoded structure looks like |
97 ;; | |
98 ;; ((header | |
99 ;; (dest-ip . [192 168 1 100]) | |
100 ;; (src-ip . [192 168 1 101]) | |
101 ;; (dest-port . 284) | |
102 ;; (src-port . 5408)) | |
103 ;; (items . 2) | |
104 ;; (item ((data . [1 2 3 4 5]) | |
105 ;; (id . "ABCDEF") | |
106 ;; (length . 5) | |
107 ;; (opcode . 3) | |
108 ;; (type . 2)) | |
109 ;; ((data . [6 7 8 9 10 11 12]) | |
110 ;; (id . "BCDEFG") | |
111 ;; (length . 7) | |
112 ;; (opcode . 4) | |
113 ;; (type . 1)))) | |
114 ;; | |
115 ;; To access a specific value in this structure, use the function | |
116 ;; bindat-get-field with the structure as first arg followed by a list | |
117 ;; of field names and array indexes, e.g. using the data above, | |
118 ;; (bindat-get-field decoded-structure 'item 1 'id) | |
119 ;; returns "BCDEFG". | |
120 | |
121 ;; Binary Data Structure Specification Format | |
122 ;; ------------------------------------------ | |
123 | |
124 ;; The data specification is formatted as follows: | |
125 | |
126 ;; SPEC ::= ( ITEM... ) | |
127 | |
128 ;; ITEM ::= ( [FIELD] TYPE ) | |
129 ;; | ( [FIELD] eval FORM ) -- eval FORM for side-effect only | |
130 ;; | ( [FIELD] fill LEN ) -- skip LEN bytes | |
131 ;; | ( [FIELD] align LEN ) -- skip to next multiple of LEN bytes | |
132 ;; | ( [FIELD] struct SPEC_NAME ) | |
133 ;; | ( [FIELD] union TAG_VAL (TAG SPEC)... [(t SPEC)] ) | |
134 ;; | ( [FIELD] repeat COUNT SPEC ) | |
135 | |
136 ;; -- In (eval EXPR), the value of the last field is available in | |
137 ;; the dynamically bound variable `last'. | |
138 | |
139 ;; TYPE ::= ( eval EXPR ) -- interpret result as TYPE | |
140 ;; | u8 | byte -- length 1 | |
141 ;; | u16 | word | short -- length 2, network byte order | |
142 ;; | u24 -- 3-byte value | |
143 ;; | u32 | dword | long -- length 4, network byte order | |
144 ;; | u16r | u24r | u32r -- little endian byte order. | |
145 ;; | str LEN -- LEN byte string | |
146 ;; | strz LEN -- LEN byte (zero-terminated) string | |
147 ;; | vec LEN -- LEN byte vector | |
148 ;; | ip -- 4 byte vector | |
149 ;; | bits LEN -- List with bits set in LEN bytes. | |
150 ;; | |
151 ;; -- Note: 32 bit values may be limited by emacs' INTEGER | |
152 ;; implementation limits. | |
153 ;; | |
154 ;; -- Example: bits 2 will map bytes 0x1c 0x28 to list (2 3 7 11 13) | |
155 | |
156 ;; FIELD ::= ( eval EXPR ) -- use result as NAME | |
157 ;; | NAME | |
158 | |
159 ;; LEN ::= ARG | |
160 ;; | <omitted> | nil -- LEN = 1 | |
161 | |
162 | |
163 ;; TAG_VAL ::= ARG | |
164 | |
165 ;; TAG ::= LISP_CONSTANT | |
166 ;; | ( eval EXPR ) -- return non-nil if tag match; | |
167 ;; current TAG_VAL in `tag'. | |
168 | |
169 ;; ARG ::= ( eval EXPR ) -- interpret result as ARG | |
170 ;; | INTEGER_CONSTANT | |
171 ;; | DEREF | |
172 | |
173 ;; DEREF ::= ( [NAME | INTEGER]... ) -- Field NAME or Array index relative to | |
174 ;; current structure spec. | |
175 ;; -- see bindat-get-field | |
176 | |
177 ;; A `union' specification | |
178 ;; ([FIELD] union TAG_VAL (TAG SPEC) ... [(t SPEC)]) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
179 ;; is interpreted by evalling TAG_VAL and then comparing that to |
46122 | 180 ;; each TAG using equal; if a match is found, the corresponding SPEC |
181 ;; is used. | |
182 ;; If TAG is a form (eval EXPR), EXPR is evalled with `tag' bound to the | |
183 ;; value of TAG_VAL; the corresponding SPEC is used if the result is non-nil. | |
184 ;; Finally, if TAG is t, the corresponding SPEC is used unconditionally. | |
185 ;; | |
186 ;; An `eval' specification | |
187 ;; ([FIELD] eval FORM) | |
188 ;; is interpreted by evalling FORM for its side effects only. | |
189 ;; If FIELD is specified, the value is bound to that field. | |
190 ;; The FORM may access and update `raw-data' and `pos' (see `bindat-unpack'), | |
191 ;; as well as the lisp data structure in `struct'. | |
192 | |
193 ;;; Code: | |
194 | |
195 ;; Helper functions for structure unpacking. | |
196 ;; Relies on dynamic binding of RAW-DATA and POS | |
197 | |
198 (defvar raw-data) | |
199 (defvar pos) | |
200 | |
201 (defun bindat--unpack-u8 () | |
202 (prog1 | |
203 (if (stringp raw-data) | |
204 (string-to-char (substring raw-data pos (1+ pos))) | |
205 (aref raw-data pos)) | |
206 (setq pos (1+ pos)))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
207 |
46122 | 208 (defun bindat--unpack-u16 () |
209 (let* ((a (bindat--unpack-u8)) (b (bindat--unpack-u8))) | |
210 (logior (lsh a 8) b))) | |
211 | |
212 (defun bindat--unpack-u24 () | |
213 (let* ((a (bindat--unpack-u16)) (b (bindat--unpack-u8))) | |
214 (logior (lsh a 8) b))) | |
215 | |
216 (defun bindat--unpack-u32 () | |
217 (let* ((a (bindat--unpack-u16)) (b (bindat--unpack-u16))) | |
218 (logior (lsh a 16) b))) | |
219 | |
220 (defun bindat--unpack-u16r () | |
221 (let* ((a (bindat--unpack-u8)) (b (bindat--unpack-u8))) | |
222 (logior a (lsh b 8)))) | |
223 | |
224 (defun bindat--unpack-u24r () | |
225 (let* ((a (bindat--unpack-u16r)) (b (bindat--unpack-u8))) | |
226 (logior a (lsh b 16)))) | |
227 | |
228 (defun bindat--unpack-u32r () | |
229 (let* ((a (bindat--unpack-u16r)) (b (bindat--unpack-u16r))) | |
230 (logior a (lsh b 16)))) | |
231 | |
232 (defun bindat--unpack-item (type len) | |
233 (if (eq type 'ip) | |
234 (setq type 'vec len 4)) | |
235 (cond | |
236 ((memq type '(u8 byte)) | |
237 (bindat--unpack-u8)) | |
238 ((memq type '(u16 word short)) | |
239 (bindat--unpack-u16)) | |
240 ((eq type 'u24) | |
241 (bindat--unpack-u24)) | |
242 ((memq type '(u32 dword long)) | |
243 (bindat--unpack-u32)) | |
244 ((eq type 'u16r) | |
245 (bindat--unpack-u16r)) | |
246 ((eq type 'u24r) | |
247 (bindat--unpack-u24r)) | |
248 ((eq type 'u32r) | |
249 (bindat--unpack-u32r)) | |
250 ((eq type 'bits) | |
251 (let ((bits nil) (bnum (1- (* 8 len))) j m) | |
252 (while (>= bnum 0) | |
253 (if (= (setq m (bindat--unpack-u8)) 0) | |
254 (setq bnum (- bnum 8)) | |
255 (setq j 128) | |
256 (while (> j 0) | |
257 (if (/= 0 (logand m j)) | |
258 (setq bits (cons bnum bits))) | |
259 (setq bnum (1- bnum) | |
260 j (lsh j -1))))) | |
261 bits)) | |
262 ((eq type 'str) | |
263 (let ((s (substring raw-data pos (+ pos len)))) | |
264 (setq pos (+ pos len)) | |
265 (if (stringp s) s | |
266 (string-make-unibyte (concat s))))) | |
267 ((eq type 'strz) | |
268 (let ((i 0) s) | |
269 (while (and (< i len) (/= (aref raw-data (+ pos i)) 0)) | |
270 (setq i (1+ i))) | |
271 (setq s (substring raw-data pos (+ pos i))) | |
272 (setq pos (+ pos len)) | |
273 (if (stringp s) s | |
274 (string-make-unibyte (concat s))))) | |
275 ((eq type 'vec) | |
276 (let ((v (make-vector len 0)) (i 0)) | |
277 (while (< i len) | |
278 (aset v i (bindat--unpack-u8)) | |
279 (setq i (1+ i))) | |
280 v)) | |
281 (t nil))) | |
282 | |
283 (defun bindat--unpack-group (spec) | |
284 (let (struct last) | |
285 (while spec | |
286 (let* ((item (car spec)) | |
287 (field (car item)) | |
288 (type (nth 1 item)) | |
289 (len (nth 2 item)) | |
290 (tail 3) | |
291 data) | |
292 (setq spec (cdr spec)) | |
293 (if (and (consp field) (eq (car field) 'eval)) | |
294 (setq field (eval (car (cdr field))))) | |
295 (if (and type (consp type) (eq (car type) 'eval)) | |
296 (setq type (eval (car (cdr type))))) | |
297 (if (and len (consp len) (eq (car len) 'eval)) | |
298 (setq len (eval (car (cdr len))))) | |
299 (if (memq field '(eval fill align struct union)) | |
300 (setq tail 2 | |
301 len type | |
302 type field | |
303 field nil)) | |
304 (if (and (consp len) (not (eq type 'eval))) | |
305 (setq len (apply 'bindat-get-field struct len))) | |
306 (if (not len) | |
307 (setq len 1)) | |
308 (cond | |
309 ((eq type 'eval) | |
310 (if field | |
311 (setq data (eval len)) | |
312 (eval len))) | |
313 ((eq type 'fill) | |
314 (setq pos (+ pos len))) | |
315 ((eq type 'align) | |
316 (while (/= (% pos len) 0) | |
317 (setq pos (1+ pos)))) | |
318 ((eq type 'struct) | |
319 (setq data (bindat--unpack-group (eval len)))) | |
320 ((eq type 'repeat) | |
321 (let ((index 0)) | |
322 (while (< index len) | |
323 (setq data (cons (bindat--unpack-group (nthcdr tail item)) data)) | |
324 (setq index (1+ index))) | |
325 (setq data (nreverse data)))) | |
326 ((eq type 'union) | |
327 (let ((tag len) (cases (nthcdr tail item)) case cc) | |
328 (while cases | |
329 (setq case (car cases) | |
330 cases (cdr cases) | |
331 cc (car case)) | |
332 (if (or (equal cc tag) (equal cc t) | |
333 (and (consp cc) (eval cc))) | |
334 (setq data (bindat--unpack-group (cdr case)) | |
335 cases nil))))) | |
336 (t | |
337 (setq data (bindat--unpack-item type len) | |
338 last data))) | |
339 (if data | |
340 (if field | |
341 (setq struct (cons (cons field data) struct)) | |
342 (setq struct (append data struct)))))) | |
343 struct)) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
344 |
46122 | 345 (defun bindat-unpack (spec raw-data &optional pos) |
346 "Return structured data according to SPEC for binary data in RAW-DATA. | |
347 RAW-DATA is a string or vector. Optional third arg POS specifies the | |
348 starting offset in RAW-DATA." | |
349 (unless pos (setq pos 0)) | |
350 (bindat--unpack-group spec)) | |
351 | |
352 (defun bindat-get-field (struct &rest field) | |
353 "In structured data STRUCT, return value of field named FIELD. | |
354 If multiple field names are specified, use the field names to | |
355 lookup nested sub-structures in STRUCT, corresponding to the | |
356 C-language syntax STRUCT.FIELD1.FIELD2.FIELD3... | |
357 An integer value in the field list is taken as an array index, | |
358 e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..." | |
359 (while (and struct field) | |
360 (setq struct (if (integerp (car field)) | |
361 (nth (car field) struct) | |
362 (let ((val (assq (car field) struct))) | |
363 (if (consp val) (cdr val))))) | |
364 (setq field (cdr field))) | |
365 struct) | |
366 | |
367 | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
368 ;; Calculate raw-data length of structured data |
46122 | 369 |
370 (defvar bindat--fixed-length-alist | |
371 '((u8 . 1) (byte . 1) | |
372 (u16 . 2) (u16r . 2) (word . 2) (short . 2) | |
373 (u24 . 3) (u24r . 3) | |
374 (u32 . 4) (u32r . 4) (dword . 4) (long . 4) | |
375 (ip . 4))) | |
376 | |
377 (defun bindat--length-group (struct spec) | |
378 (let (last) | |
379 (while spec | |
380 (let* ((item (car spec)) | |
381 (field (car item)) | |
382 (type (nth 1 item)) | |
383 (len (nth 2 item)) | |
384 (tail 3)) | |
385 (setq spec (cdr spec)) | |
386 (if (and (consp field) (eq (car field) 'eval)) | |
387 (setq field (eval (car (cdr field))))) | |
388 (if (and type (consp type) (eq (car type) 'eval)) | |
389 (setq type (eval (car (cdr type))))) | |
390 (if (and len (consp len) (eq (car len) 'eval)) | |
391 (setq len (eval (car (cdr len))))) | |
392 (if (memq field '(eval fill align struct union)) | |
393 (setq tail 2 | |
394 len type | |
395 type field | |
396 field nil)) | |
397 (if (and (consp len) (not (eq type 'eval))) | |
398 (setq len (apply 'bindat-get-field struct len))) | |
399 (if (not len) | |
400 (setq len 1)) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
401 (cond |
46122 | 402 ((eq type 'eval) |
403 (if field | |
404 (setq struct (cons (cons field (eval len)) struct)) | |
405 (eval len))) | |
406 ((eq type 'fill) | |
407 (setq pos (+ pos len))) | |
408 ((eq type 'align) | |
409 (while (/= (% pos len) 0) | |
410 (setq pos (1+ pos)))) | |
411 ((eq type 'struct) | |
412 (bindat--length-group | |
413 (if field (bindat-get-field struct field) struct) (eval len))) | |
414 ((eq type 'repeat) | |
415 (let ((index 0)) | |
416 (while (< index len) | |
417 (bindat--length-group (nth index (bindat-get-field struct field)) (nthcdr tail item)) | |
418 (setq index (1+ index))))) | |
419 ((eq type 'union) | |
420 (let ((tag len) (cases (nthcdr tail item)) case cc) | |
421 (while cases | |
422 (setq case (car cases) | |
423 cases (cdr cases) | |
424 cc (car case)) | |
425 (if (or (equal cc tag) (equal cc t) | |
426 (and (consp cc) (eval cc))) | |
427 (progn | |
428 (bindat--length-group struct (cdr case)) | |
429 (setq cases nil)))))) | |
430 (t | |
431 (if (setq type (assq type bindat--fixed-length-alist)) | |
432 (setq len (cdr type))) | |
433 (if field | |
434 (setq last (bindat-get-field struct field))) | |
435 (setq pos (+ pos len)))))))) | |
436 | |
437 (defun bindat-length (spec struct) | |
438 "Calculate raw-data length for STRUCT according to bindat specification SPEC." | |
439 (let ((pos 0)) | |
440 (bindat--length-group struct spec) | |
441 pos)) | |
442 | |
443 | |
444 ;; Pack structured data into raw-data | |
445 | |
446 (defun bindat--pack-u8 (v) | |
447 (aset raw-data pos (logand v 255)) | |
448 (setq pos (1+ pos))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
449 |
46122 | 450 (defun bindat--pack-u16 (v) |
451 (aset raw-data pos (logand (lsh v -8) 255)) | |
452 (aset raw-data (1+ pos) (logand v 255)) | |
453 (setq pos (+ pos 2))) | |
454 | |
455 (defun bindat--pack-u24 (v) | |
456 (bindat--pack-u8 (lsh v -16)) | |
457 (bindat--pack-u16 v)) | |
458 | |
459 (defun bindat--pack-u32 (v) | |
460 (bindat--pack-u16 (lsh v -16)) | |
461 (bindat--pack-u16 v)) | |
462 | |
463 (defun bindat--pack-u16r (v) | |
464 (aset raw-data (1+ pos) (logand (lsh v -8) 255)) | |
465 (aset raw-data pos (logand v 255)) | |
466 (setq pos (+ pos 2))) | |
467 | |
468 (defun bindat--pack-u24r (v) | |
469 (bindat--pack-u16r v) | |
470 (bindat--pack-u8 (lsh v -16))) | |
471 | |
472 (defun bindat--pack-u32r (v) | |
473 (bindat--pack-u16r v) | |
474 (bindat--pack-u16r (lsh v -16))) | |
475 | |
476 (defun bindat--pack-item (v type len) | |
477 (if (eq type 'ip) | |
478 (setq type 'vec len 4)) | |
479 (cond | |
480 ((null v) | |
481 (setq pos (+ pos len))) | |
482 ((memq type '(u8 byte)) | |
483 (bindat--pack-u8 v)) | |
484 ((memq type '(u16 word short)) | |
485 (bindat--pack-u16 v)) | |
486 ((eq type 'u24) | |
487 (bindat--pack-u24 v)) | |
488 ((memq type '(u32 dword long)) | |
489 (bindat--pack-u32 v)) | |
490 ((eq type 'u16r) | |
491 (bindat--pack-u16r v)) | |
492 ((eq type 'u24r) | |
493 (bindat--pack-u24r v)) | |
494 ((eq type 'u32r) | |
495 (bindat--pack-u32r v)) | |
496 ((eq type 'bits) | |
497 (let ((bnum (1- (* 8 len))) j m) | |
498 (while (>= bnum 0) | |
499 (setq m 0) | |
500 (if (null v) | |
501 (setq bnum (- bnum 8)) | |
502 (setq j 128) | |
503 (while (> j 0) | |
504 (if (memq bnum v) | |
505 (setq m (logior m j))) | |
506 (setq bnum (1- bnum) | |
507 j (lsh j -1)))) | |
508 (bindat--pack-u8 m)))) | |
509 ((memq type '(str strz vec)) | |
510 (let ((l (length v)) (i 0)) | |
511 (if (> l len) (setq l len)) | |
512 (while (< i l) | |
513 (aset raw-data (+ pos i) (aref v i)) | |
514 (setq i (1+ i))) | |
515 (setq pos (+ pos len)))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
516 (t |
46122 | 517 (setq pos (+ pos len))))) |
518 | |
519 (defun bindat--pack-group (struct spec) | |
520 (let (last) | |
521 (while spec | |
522 (let* ((item (car spec)) | |
523 (field (car item)) | |
524 (type (nth 1 item)) | |
525 (len (nth 2 item)) | |
526 (tail 3)) | |
527 (setq spec (cdr spec)) | |
528 (if (and (consp field) (eq (car field) 'eval)) | |
529 (setq field (eval (car (cdr field))))) | |
530 (if (and type (consp type) (eq (car type) 'eval)) | |
531 (setq type (eval (car (cdr type))))) | |
532 (if (and len (consp len) (eq (car len) 'eval)) | |
533 (setq len (eval (car (cdr len))))) | |
534 (if (memq field '(eval fill align struct union)) | |
535 (setq tail 2 | |
536 len type | |
537 type field | |
538 field nil)) | |
539 (if (and (consp len) (not (eq type 'eval))) | |
540 (setq len (apply 'bindat-get-field struct len))) | |
541 (if (not len) | |
542 (setq len 1)) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
543 (cond |
46122 | 544 ((eq type 'eval) |
545 (if field | |
546 (setq struct (cons (cons field (eval len)) struct)) | |
547 (eval len))) | |
548 ((eq type 'fill) | |
549 (setq pos (+ pos len))) | |
550 ((eq type 'align) | |
551 (while (/= (% pos len) 0) | |
552 (setq pos (1+ pos)))) | |
553 ((eq type 'struct) | |
554 (bindat--pack-group | |
555 (if field (bindat-get-field struct field) struct) (eval len))) | |
556 ((eq type 'repeat) | |
557 (let ((index 0)) | |
558 (while (< index len) | |
559 (bindat--pack-group (nth index (bindat-get-field struct field)) (nthcdr tail item)) | |
560 (setq index (1+ index))))) | |
561 ((eq type 'union) | |
562 (let ((tag len) (cases (nthcdr tail item)) case cc) | |
563 (while cases | |
564 (setq case (car cases) | |
565 cases (cdr cases) | |
566 cc (car case)) | |
567 (if (or (equal cc tag) (equal cc t) | |
568 (and (consp cc) (eval cc))) | |
569 (progn | |
570 (bindat--pack-group struct (cdr case)) | |
571 (setq cases nil)))))) | |
572 (t | |
573 (setq last (bindat-get-field struct field)) | |
574 (bindat--pack-item last type len) | |
575 )))))) | |
576 | |
577 (defun bindat-pack (spec struct &optional raw-data pos) | |
48031 | 578 "Return binary data packed according to SPEC for structured data STRUCT. |
46122 | 579 Optional third arg RAW-DATA is a pre-allocated string or vector to unpack into. |
580 Optional fourth arg POS is the starting offset into RAW-DATA. | |
581 Note: The result is a multibyte string; use `string-make-unibyte' on it | |
582 to make it unibyte if necessary." | |
583 (let ((no-return raw-data)) | |
584 (unless pos (setq pos 0)) | |
585 (unless raw-data (setq raw-data (make-vector (+ pos (bindat-length spec struct)) 0))) | |
586 (bindat--pack-group struct spec) | |
587 (if no-return nil (concat raw-data)))) | |
588 | |
589 | |
590 ;; Misc. format conversions | |
591 | |
592 (defun bindat-format-vector (vect fmt sep &optional len) | |
593 "Format vector VECT using element format FMT and separator SEP. | |
594 Result is a string with each element of VECT formatted using FMT and | |
595 separated by the string SEP. If optional fourth arg LEN is given, use | |
596 only that many elements from VECT." | |
597 (unless len | |
598 (setq len (length vect))) | |
599 (let ((i len) (fmt2 (concat sep fmt)) (s nil)) | |
600 (while (> i 0) | |
601 (setq i (1- i) | |
602 s (cons (format (if (= i 0) fmt fmt2) (aref vect i)) s))) | |
603 (apply 'concat s))) | |
49598
0d8b17d428b5
Trailing whitepace deleted.
Juanma Barranquero <lekktu@gmail.com>
parents:
48031
diff
changeset
|
604 |
46122 | 605 (defun bindat-vector-to-dec (vect &optional sep) |
606 "Format vector VECT in decimal format separated by dots. | |
607 If optional second arg SEP is a string, use that as separator." | |
608 (bindat-format-vector vect "%d" (if (stringp sep) sep "."))) | |
609 | |
610 (defun bindat-vector-to-hex (vect &optional sep) | |
611 "Format vector VECT in hex format separated by dots. | |
612 If optional second arg SEP is a string, use that as separator." | |
613 (bindat-format-vector vect "%02x" (if (stringp sep) sep ":"))) | |
614 | |
615 (defun bindat-ip-to-string (ip) | |
616 "Format vector IP as an ip address in dotted notation." | |
617 (format "%d.%d.%d.%d" | |
618 (aref ip 0) (aref ip 1) (aref ip 2) (aref ip 3))) | |
619 | |
620 (provide 'bindat) | |
621 | |
52401 | 622 ;;; arch-tag: 5e6708c3-03e2-4ad7-9885-5041b779c3fb |
46122 | 623 ;;; bindat.el ends here |