2021-01-28 14:42:21 -05:00
|
|
|
;;; bindat.el --- binary data structure packing and unpacking. -*- lexical-binding: t; -*-
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-01-01 01:13:56 -08:00
|
|
|
;; Copyright (C) 2002-2021 Free Software Foundation, Inc.
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;; Author: Kim F. Storm <storm@cua.dk>
|
|
|
|
;; Assignment name: struct.el
|
|
|
|
;; Keywords: comm data processes
|
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
2008-05-06 03:21:21 +00:00
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
2002-07-01 22:01:13 +00:00
|
|
|
;; it under the terms of the GNU General Public License as published by
|
2008-05-06 03:21:21 +00:00
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
;; (at your option) any later version.
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2017-09-13 15:52:52 -07:00
|
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;; Packing and unpacking of (binary) data structures.
|
|
|
|
;;
|
|
|
|
;; The data formats used in binary files and network protocols are
|
2021-02-15 10:50:07 -05:00
|
|
|
;; often structured data which can be described by a C-style structure
|
2002-07-01 22:01:13 +00:00
|
|
|
;; such as the one shown below. Using the bindat package, decoding
|
|
|
|
;; and encoding binary data formats like these is made simple using a
|
|
|
|
;; structure specification which closely resembles the C style
|
|
|
|
;; structure declarations.
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; Encoded (binary) data is stored in a unibyte string or vector,
|
2003-02-04 13:24:35 +00:00
|
|
|
;; while the decoded data is stored in an alist with (FIELD . VALUE)
|
2002-07-01 22:01:13 +00:00
|
|
|
;; pairs.
|
|
|
|
|
|
|
|
;; Example:
|
2003-02-04 13:24:35 +00:00
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
;; Consider the following C structures:
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; struct header {
|
2021-02-18 11:15:13 -05:00
|
|
|
;; uint32_t dest_ip;
|
|
|
|
;; uint32_t src_ip;
|
|
|
|
;; uint16_t dest_port;
|
|
|
|
;; uint16_t src_port;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; };
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; struct data {
|
2021-02-18 11:15:13 -05:00
|
|
|
;; uint8_t type;
|
|
|
|
;; uint8_t opcode;
|
|
|
|
;; uint32_t length; /* In little endian order */
|
2002-07-01 22:01:13 +00:00
|
|
|
;; unsigned char id[8]; /* nul-terminated string */
|
|
|
|
;; unsigned char data[/* (length + 3) & ~3 */];
|
|
|
|
;; };
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; struct packet {
|
|
|
|
;; struct header header;
|
2021-02-18 11:15:13 -05:00
|
|
|
;; uint8_t items;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; unsigned char filler[3];
|
|
|
|
;; struct data item[/* items */];
|
|
|
|
;; };
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; The corresponding Lisp bindat specification looks like this:
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2006-09-08 11:59:33 +00:00
|
|
|
;; (setq header-bindat-spec
|
2021-02-15 21:25:15 -05:00
|
|
|
;; (bindat-spec
|
|
|
|
;; (dest-ip ip)
|
2002-07-01 22:01:13 +00:00
|
|
|
;; (src-ip ip)
|
|
|
|
;; (dest-port u16)
|
|
|
|
;; (src-port u16)))
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2006-09-08 11:59:33 +00:00
|
|
|
;; (setq data-bindat-spec
|
2021-02-15 21:25:15 -05:00
|
|
|
;; (bindat-spec
|
|
|
|
;; (type u8)
|
2002-07-01 22:01:13 +00:00
|
|
|
;; (opcode u8)
|
2021-02-18 11:15:13 -05:00
|
|
|
;; (length u32r) ;; little endian order
|
2002-07-01 22:01:13 +00:00
|
|
|
;; (id strz 8)
|
|
|
|
;; (data vec (length))
|
|
|
|
;; (align 4)))
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2006-09-08 11:59:33 +00:00
|
|
|
;; (setq packet-bindat-spec
|
2021-02-15 21:25:15 -05:00
|
|
|
;; (bindat-spec
|
|
|
|
;; (header struct header-bindat-spec)
|
2002-07-01 22:01:13 +00:00
|
|
|
;; (items u8)
|
|
|
|
;; (fill 3)
|
|
|
|
;; (item repeat (items)
|
2006-09-08 11:59:33 +00:00
|
|
|
;; (struct data-bindat-spec))))
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;;
|
|
|
|
;; A binary data representation may look like
|
2003-02-04 13:24:35 +00:00
|
|
|
;; [ 192 168 1 100 192 168 1 101 01 28 21 32 2 0 0 0
|
2002-07-01 22:01:13 +00:00
|
|
|
;; 2 3 5 0 ?A ?B ?C ?D ?E ?F 0 0 1 2 3 4 5 0 0 0
|
|
|
|
;; 1 4 7 0 ?B ?C ?D ?E ?F ?G 0 0 6 7 8 9 10 11 12 0 ]
|
2003-02-04 13:24:35 +00:00
|
|
|
;;
|
2002-07-01 22:01:13 +00:00
|
|
|
;; The corresponding decoded structure looks like
|
|
|
|
;;
|
|
|
|
;; ((header
|
|
|
|
;; (dest-ip . [192 168 1 100])
|
|
|
|
;; (src-ip . [192 168 1 101])
|
|
|
|
;; (dest-port . 284)
|
|
|
|
;; (src-port . 5408))
|
|
|
|
;; (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))))
|
|
|
|
;;
|
|
|
|
;; To access a specific value in this structure, use the function
|
|
|
|
;; bindat-get-field with the structure as first arg followed by a list
|
|
|
|
;; of field names and array indexes, e.g. using the data above,
|
|
|
|
;; (bindat-get-field decoded-structure 'item 1 'id)
|
|
|
|
;; returns "BCDEFG".
|
|
|
|
|
|
|
|
;; Binary Data Structure Specification Format
|
|
|
|
;; ------------------------------------------
|
|
|
|
|
2006-09-08 11:59:33 +00:00
|
|
|
;; We recommend using names that end in `-bindat-spec'; such names
|
|
|
|
;; are recognized automatically as "risky" variables.
|
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
;; The data specification is formatted as follows:
|
|
|
|
|
|
|
|
;; SPEC ::= ( ITEM... )
|
|
|
|
|
2021-02-15 23:22:09 -05:00
|
|
|
;; ITEM ::= ( FIELD TYPE )
|
2002-07-01 22:01:13 +00:00
|
|
|
;; | ( [FIELD] eval FORM ) -- eval FORM for side-effect only
|
|
|
|
;; | ( [FIELD] fill LEN ) -- skip LEN bytes
|
|
|
|
;; | ( [FIELD] align LEN ) -- skip to next multiple of LEN bytes
|
|
|
|
;; | ( [FIELD] struct SPEC_NAME )
|
|
|
|
;; | ( [FIELD] union TAG_VAL (TAG SPEC)... [(t SPEC)] )
|
2021-02-15 23:22:09 -05:00
|
|
|
;; | ( FIELD repeat ARG ITEM... )
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;; -- In (eval EXPR), the value of the last field is available in
|
2021-02-15 10:50:07 -05:00
|
|
|
;; the dynamically bound variable `last' and all the previous
|
|
|
|
;; ones in the variable `struct'.
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;; TYPE ::= ( eval EXPR ) -- interpret result as TYPE
|
|
|
|
;; | u8 | byte -- length 1
|
|
|
|
;; | u16 | word | short -- length 2, network byte order
|
|
|
|
;; | u24 -- 3-byte value
|
|
|
|
;; | u32 | dword | long -- length 4, network byte order
|
2021-02-15 23:54:45 -05:00
|
|
|
;; | u64 -- length 8, network byte order
|
|
|
|
;; | u16r | u24r | u32r | u64r - little endian byte order.
|
2002-07-01 22:01:13 +00:00
|
|
|
;; | str LEN -- LEN byte string
|
|
|
|
;; | strz LEN -- LEN byte (zero-terminated) string
|
2007-02-17 22:02:25 +00:00
|
|
|
;; | vec LEN [TYPE] -- vector of LEN items of TYPE (default: u8)
|
2002-07-01 22:01:13 +00:00
|
|
|
;; | ip -- 4 byte vector
|
2021-02-15 23:22:09 -05:00
|
|
|
;; | bits LEN -- bit vector using LEN bytes.
|
2002-07-01 22:01:13 +00:00
|
|
|
;;
|
2005-06-11 23:56:33 +00:00
|
|
|
;; -- Example: `bits 2' will unpack 0x28 0x1c to (2 3 4 11 13)
|
|
|
|
;; and 0x1c 0x28 to (3 5 10 11 12).
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;; FIELD ::= ( eval EXPR ) -- use result as NAME
|
|
|
|
;; | NAME
|
|
|
|
|
|
|
|
;; LEN ::= ARG
|
|
|
|
;; | <omitted> | nil -- LEN = 1
|
|
|
|
|
|
|
|
|
|
|
|
;; TAG_VAL ::= ARG
|
|
|
|
|
|
|
|
;; TAG ::= LISP_CONSTANT
|
|
|
|
;; | ( eval EXPR ) -- return non-nil if tag match;
|
|
|
|
;; current TAG_VAL in `tag'.
|
|
|
|
|
|
|
|
;; ARG ::= ( eval EXPR ) -- interpret result as ARG
|
|
|
|
;; | INTEGER_CONSTANT
|
|
|
|
;; | DEREF
|
|
|
|
|
2006-05-23 08:04:25 +00:00
|
|
|
;; DEREF ::= ( [NAME | INTEGER]... ) -- Field NAME or Array index relative
|
|
|
|
;; to current structure spec.
|
2002-07-01 22:01:13 +00:00
|
|
|
;; -- see bindat-get-field
|
|
|
|
|
|
|
|
;; A `union' specification
|
|
|
|
;; ([FIELD] union TAG_VAL (TAG SPEC) ... [(t SPEC)])
|
2003-02-04 13:24:35 +00:00
|
|
|
;; is interpreted by evalling TAG_VAL and then comparing that to
|
2002-07-01 22:01:13 +00:00
|
|
|
;; each TAG using equal; if a match is found, the corresponding SPEC
|
|
|
|
;; is used.
|
2021-02-15 21:25:15 -05:00
|
|
|
;; If TAG is a form (eval EXPR), EXPR is eval'ed with `tag' bound to the
|
2002-07-01 22:01:13 +00:00
|
|
|
;; value of TAG_VAL; the corresponding SPEC is used if the result is non-nil.
|
|
|
|
;; Finally, if TAG is t, the corresponding SPEC is used unconditionally.
|
|
|
|
;;
|
|
|
|
;; An `eval' specification
|
|
|
|
;; ([FIELD] eval FORM)
|
|
|
|
;; is interpreted by evalling FORM for its side effects only.
|
|
|
|
;; If FIELD is specified, the value is bound to that field.
|
2006-05-28 22:19:52 +00:00
|
|
|
;; The FORM may access and update `bindat-raw' and `bindat-idx' (see `bindat-unpack').
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
;; Helper functions for structure unpacking.
|
2021-02-15 10:50:07 -05:00
|
|
|
;; Relies on dynamic binding of `bindat-raw' and `bindat-idx'.
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2020-10-24 14:22:58 +02:00
|
|
|
(defvar bindat-raw)
|
|
|
|
(defvar bindat-idx)
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-03-05 13:31:16 -05:00
|
|
|
(defsubst bindat--unpack-u8 ()
|
2002-07-01 22:01:13 +00:00
|
|
|
(prog1
|
2021-01-28 14:42:21 -05:00
|
|
|
(aref bindat-raw bindat-idx)
|
2006-05-28 22:19:52 +00:00
|
|
|
(setq bindat-idx (1+ bindat-idx))))
|
2003-02-04 13:24:35 +00:00
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
(defun bindat--unpack-u16 ()
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(logior (ash (bindat--unpack-u8) 8) (bindat--unpack-u8)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--unpack-u24 ()
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(logior (ash (bindat--unpack-u16) 8) (bindat--unpack-u8)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--unpack-u32 ()
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(logior (ash (bindat--unpack-u16) 16) (bindat--unpack-u16)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-02-15 23:54:45 -05:00
|
|
|
(defun bindat--unpack-u64 ()
|
|
|
|
(logior (ash (bindat--unpack-u32) 32) (bindat--unpack-u32)))
|
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
(defun bindat--unpack-u16r ()
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(logior (bindat--unpack-u8) (ash (bindat--unpack-u8) 8)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--unpack-u24r ()
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(logior (bindat--unpack-u16r) (ash (bindat--unpack-u8) 16)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--unpack-u32r ()
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(logior (bindat--unpack-u16r) (ash (bindat--unpack-u16r) 16)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-02-15 23:54:45 -05:00
|
|
|
(defun bindat--unpack-u64r ()
|
|
|
|
(logior (bindat--unpack-u32r) (ash (bindat--unpack-u32r) 32)))
|
|
|
|
|
2021-03-05 13:31:16 -05:00
|
|
|
(defun bindat--unpack-str (len)
|
|
|
|
(let ((s (substring bindat-raw bindat-idx (+ bindat-idx len))))
|
|
|
|
(setq bindat-idx (+ bindat-idx len))
|
|
|
|
(if (stringp s) s
|
|
|
|
(apply #'unibyte-string s))))
|
|
|
|
|
|
|
|
(defun bindat--unpack-strz (len)
|
|
|
|
(let ((i 0) s)
|
|
|
|
(while (and (< i len) (/= (aref bindat-raw (+ bindat-idx i)) 0))
|
|
|
|
(setq i (1+ i)))
|
|
|
|
(setq s (substring bindat-raw bindat-idx (+ bindat-idx i)))
|
|
|
|
(setq bindat-idx (+ bindat-idx len))
|
|
|
|
(if (stringp s) s
|
|
|
|
(apply #'unibyte-string s))))
|
|
|
|
|
|
|
|
(defun bindat--unpack-bits (len)
|
|
|
|
(let ((bits nil) (bnum (1- (* 8 len))) j m)
|
|
|
|
(while (>= bnum 0)
|
|
|
|
(if (= (setq m (bindat--unpack-u8)) 0)
|
|
|
|
(setq bnum (- bnum 8))
|
|
|
|
(setq j 128)
|
|
|
|
(while (> j 0)
|
|
|
|
(if (/= 0 (logand m j))
|
|
|
|
(setq bits (cons bnum bits)))
|
|
|
|
(setq bnum (1- bnum)
|
|
|
|
j (ash j -1)))))
|
|
|
|
bits))
|
|
|
|
|
2007-02-17 22:02:25 +00:00
|
|
|
(defun bindat--unpack-item (type len &optional vectype)
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (eq type 'ip)
|
|
|
|
(setq type 'vec len 4))
|
2021-02-15 23:22:09 -05:00
|
|
|
(pcase type
|
2021-03-05 13:31:16 -05:00
|
|
|
((or 'u8 'byte) (bindat--unpack-u8))
|
|
|
|
((or 'u16 'word 'short) (bindat--unpack-u16))
|
2021-02-15 23:54:45 -05:00
|
|
|
('u24 (bindat--unpack-u24))
|
2021-03-05 13:31:16 -05:00
|
|
|
((or 'u32 'dword 'long) (bindat--unpack-u32))
|
2021-02-15 23:54:45 -05:00
|
|
|
('u64 (bindat--unpack-u64))
|
|
|
|
('u16r (bindat--unpack-u16r))
|
|
|
|
('u24r (bindat--unpack-u24r))
|
|
|
|
('u32r (bindat--unpack-u32r))
|
|
|
|
('u64r (bindat--unpack-u64r))
|
2021-03-05 13:31:16 -05:00
|
|
|
('bits (bindat--unpack-bits len))
|
|
|
|
('str (bindat--unpack-str len))
|
|
|
|
('strz (bindat--unpack-strz len))
|
2021-02-15 23:22:09 -05:00
|
|
|
('vec
|
|
|
|
(let ((v (make-vector len 0)) (vlen 1))
|
2007-02-17 22:02:25 +00:00
|
|
|
(if (consp vectype)
|
|
|
|
(setq vlen (nth 1 vectype)
|
|
|
|
vectype (nth 2 vectype))
|
|
|
|
(setq type (or vectype 'u8)
|
|
|
|
vectype nil))
|
2021-02-15 23:22:09 -05:00
|
|
|
(dotimes (i len)
|
|
|
|
(aset v i (bindat--unpack-item type vlen vectype)))
|
2002-07-01 22:01:13 +00:00
|
|
|
v))
|
2021-02-15 23:22:09 -05:00
|
|
|
(_ nil)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-03-05 13:31:16 -05:00
|
|
|
(defsubst bindat--align (n len)
|
|
|
|
(* len (/ (+ n (1- len)) len))) ;Isn't there a simpler way?
|
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
(defun bindat--unpack-group (spec)
|
2021-02-15 10:50:07 -05:00
|
|
|
(with-suppressed-warnings ((lexical struct last))
|
|
|
|
(defvar struct) (defvar last))
|
2020-10-24 14:22:58 +02:00
|
|
|
(let (struct last)
|
2021-02-15 23:22:09 -05:00
|
|
|
(dolist (item spec)
|
|
|
|
(let* ((field (car item))
|
2002-07-01 22:01:13 +00:00
|
|
|
(type (nth 1 item))
|
|
|
|
(len (nth 2 item))
|
2007-02-17 22:02:25 +00:00
|
|
|
(vectype (and (eq type 'vec) (nth 3 item)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(tail 3)
|
|
|
|
data)
|
|
|
|
(if (and type (consp type) (eq (car type) 'eval))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq type (eval (car (cdr type)) t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (and len (consp len) (eq (car len) 'eval))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq len (eval (car (cdr len)) t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (memq field '(eval fill align struct union))
|
|
|
|
(setq tail 2
|
|
|
|
len type
|
|
|
|
type field
|
|
|
|
field nil))
|
2021-02-15 23:22:09 -05:00
|
|
|
(if (and (consp field) (eq (car field) 'eval))
|
|
|
|
(setq field (eval (car (cdr field)) t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (and (consp len) (not (eq type 'eval)))
|
2020-10-21 16:09:12 +02:00
|
|
|
(setq len (apply #'bindat-get-field struct len)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (not len)
|
|
|
|
(setq len 1))
|
2021-02-15 23:22:09 -05:00
|
|
|
(pcase type
|
|
|
|
('eval
|
2002-07-01 22:01:13 +00:00
|
|
|
(if field
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq data (eval len t))
|
|
|
|
(eval len t)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('fill
|
2006-05-28 22:19:52 +00:00
|
|
|
(setq bindat-idx (+ bindat-idx len)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('align
|
2021-03-05 13:31:16 -05:00
|
|
|
(setq bindat-idx (bindat--align bindat-idx len)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('struct
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq data (bindat--unpack-group (eval len t))))
|
2021-02-15 23:22:09 -05:00
|
|
|
('repeat
|
|
|
|
(dotimes (_ len)
|
|
|
|
(push (bindat--unpack-group (nthcdr tail item)) data))
|
|
|
|
(setq data (nreverse data)))
|
|
|
|
('union
|
2021-01-28 14:42:21 -05:00
|
|
|
(with-suppressed-warnings ((lexical tag))
|
|
|
|
(defvar tag))
|
2002-07-01 22:01:13 +00:00
|
|
|
(let ((tag len) (cases (nthcdr tail item)) case cc)
|
|
|
|
(while cases
|
|
|
|
(setq case (car cases)
|
|
|
|
cases (cdr cases)
|
|
|
|
cc (car case))
|
|
|
|
(if (or (equal cc tag) (equal cc t)
|
2021-01-28 14:42:21 -05:00
|
|
|
(and (consp cc) (eval cc t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(setq data (bindat--unpack-group (cdr case))
|
|
|
|
cases nil)))))
|
2021-02-15 23:22:09 -05:00
|
|
|
((pred integerp) (debug t))
|
|
|
|
(_
|
2020-10-24 14:22:58 +02:00
|
|
|
(setq data (bindat--unpack-item type len vectype)
|
|
|
|
last data)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if data
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq struct (if field
|
|
|
|
(cons (cons field data) struct)
|
|
|
|
(append data struct))))))
|
2002-07-01 22:01:13 +00:00
|
|
|
struct))
|
2003-02-04 13:24:35 +00:00
|
|
|
|
2021-01-28 14:42:21 -05:00
|
|
|
(defun bindat-unpack (spec raw &optional idx)
|
|
|
|
"Return structured data according to SPEC for binary data in RAW.
|
|
|
|
RAW is a unibyte string or vector.
|
|
|
|
Optional third arg IDX specifies the starting offset in RAW."
|
|
|
|
(when (multibyte-string-p raw)
|
2006-05-25 08:51:31 +00:00
|
|
|
(error "String is multibyte"))
|
2021-01-28 14:42:21 -05:00
|
|
|
(let ((bindat-idx (or idx 0))
|
|
|
|
(bindat-raw raw))
|
|
|
|
(bindat--unpack-group spec)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat-get-field (struct &rest field)
|
|
|
|
"In structured data STRUCT, return value of field named FIELD.
|
|
|
|
If multiple field names are specified, use the field names to
|
|
|
|
lookup nested sub-structures in STRUCT, corresponding to the
|
|
|
|
C-language syntax STRUCT.FIELD1.FIELD2.FIELD3...
|
|
|
|
An integer value in the field list is taken as an array index,
|
|
|
|
e.g. corresponding to STRUCT.FIELD1[INDEX2].FIELD3..."
|
|
|
|
(while (and struct field)
|
|
|
|
(setq struct (if (integerp (car field))
|
2021-03-05 13:31:16 -05:00
|
|
|
(elt struct (car field))
|
|
|
|
(cdr (assq (car field) struct))))
|
2002-07-01 22:01:13 +00:00
|
|
|
(setq field (cdr field)))
|
|
|
|
struct)
|
|
|
|
|
2021-02-15 21:25:15 -05:00
|
|
|
;;;; Calculate bindat-raw length of structured data
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defvar bindat--fixed-length-alist
|
|
|
|
'((u8 . 1) (byte . 1)
|
|
|
|
(u16 . 2) (u16r . 2) (word . 2) (short . 2)
|
|
|
|
(u24 . 3) (u24r . 3)
|
|
|
|
(u32 . 4) (u32r . 4) (dword . 4) (long . 4)
|
2021-02-15 23:54:45 -05:00
|
|
|
(u64 . 8) (u64r . 8)
|
2002-07-01 22:01:13 +00:00
|
|
|
(ip . 4)))
|
|
|
|
|
|
|
|
(defun bindat--length-group (struct spec)
|
2021-02-15 10:50:07 -05:00
|
|
|
(with-suppressed-warnings ((lexical struct last))
|
|
|
|
(defvar struct) (defvar last))
|
|
|
|
(let ((struct struct) last)
|
2021-02-15 23:22:09 -05:00
|
|
|
(dolist (item spec)
|
|
|
|
(let* ((field (car item))
|
2020-10-24 14:22:58 +02:00
|
|
|
(type (nth 1 item))
|
|
|
|
(len (nth 2 item))
|
|
|
|
(vectype (and (eq type 'vec) (nth 3 item)))
|
|
|
|
(tail 3))
|
|
|
|
(if (and type (consp type) (eq (car type) 'eval))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq type (eval (car (cdr type)) t)))
|
2020-10-24 14:22:58 +02:00
|
|
|
(if (and len (consp len) (eq (car len) 'eval))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq len (eval (car (cdr len)) t)))
|
2020-10-24 14:22:58 +02:00
|
|
|
(if (memq field '(eval fill align struct union))
|
|
|
|
(setq tail 2
|
|
|
|
len type
|
|
|
|
type field
|
|
|
|
field nil))
|
2021-02-15 23:22:09 -05:00
|
|
|
(if (and (consp field) (eq (car field) 'eval))
|
|
|
|
(setq field (eval (car (cdr field)) t)))
|
2020-10-24 14:22:58 +02:00
|
|
|
(if (and (consp len) (not (eq type 'eval)))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq len (apply #'bindat-get-field struct len)))
|
2020-10-24 14:22:58 +02:00
|
|
|
(if (not len)
|
|
|
|
(setq len 1))
|
|
|
|
(while (eq type 'vec)
|
2021-01-28 14:42:21 -05:00
|
|
|
(if (consp vectype)
|
|
|
|
(setq len (* len (nth 1 vectype))
|
|
|
|
type (nth 2 vectype))
|
|
|
|
(setq type (or vectype 'u8)
|
|
|
|
vectype nil)))
|
2021-02-15 23:22:09 -05:00
|
|
|
(pcase type
|
|
|
|
('eval
|
2020-10-24 14:22:58 +02:00
|
|
|
(if field
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq struct (cons (cons field (eval len t)) struct))
|
|
|
|
(eval len t)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('fill
|
2020-10-24 14:22:58 +02:00
|
|
|
(setq bindat-idx (+ bindat-idx len)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('align
|
2021-03-05 13:31:16 -05:00
|
|
|
(setq bindat-idx (bindat--align bindat-idx len)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('struct
|
2020-10-24 14:22:58 +02:00
|
|
|
(bindat--length-group
|
2021-01-28 14:42:21 -05:00
|
|
|
(if field (bindat-get-field struct field) struct) (eval len t)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('repeat
|
|
|
|
(dotimes (index len)
|
|
|
|
(bindat--length-group
|
|
|
|
(nth index (bindat-get-field struct field))
|
|
|
|
(nthcdr tail item))))
|
|
|
|
('union
|
2021-01-28 14:42:21 -05:00
|
|
|
(with-suppressed-warnings ((lexical tag))
|
|
|
|
(defvar tag))
|
2020-10-24 14:22:58 +02:00
|
|
|
(let ((tag len) (cases (nthcdr tail item)) case cc)
|
|
|
|
(while cases
|
|
|
|
(setq case (car cases)
|
|
|
|
cases (cdr cases)
|
|
|
|
cc (car case))
|
|
|
|
(if (or (equal cc tag) (equal cc t)
|
2021-01-28 14:42:21 -05:00
|
|
|
(and (consp cc) (eval cc t)))
|
2020-10-24 14:22:58 +02:00
|
|
|
(progn
|
|
|
|
(bindat--length-group struct (cdr case))
|
|
|
|
(setq cases nil))))))
|
2021-02-15 23:22:09 -05:00
|
|
|
(_
|
2020-10-24 14:22:58 +02:00
|
|
|
(if (setq type (assq type bindat--fixed-length-alist))
|
|
|
|
(setq len (* len (cdr type))))
|
|
|
|
(if field
|
|
|
|
(setq last (bindat-get-field struct field)))
|
|
|
|
(setq bindat-idx (+ bindat-idx len))))))))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat-length (spec struct)
|
2021-02-15 21:25:15 -05:00
|
|
|
"Calculate `bindat-raw' length for STRUCT according to bindat SPEC."
|
2006-05-28 22:19:52 +00:00
|
|
|
(let ((bindat-idx 0))
|
2002-07-01 22:01:13 +00:00
|
|
|
(bindat--length-group struct spec)
|
2006-05-28 22:19:52 +00:00
|
|
|
bindat-idx))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
|
2021-02-15 21:25:15 -05:00
|
|
|
;;;; Pack structured data into bindat-raw
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-03-05 13:31:16 -05:00
|
|
|
(defsubst bindat--pack-u8 (v)
|
2006-05-28 22:19:52 +00:00
|
|
|
(aset bindat-raw bindat-idx (logand v 255))
|
|
|
|
(setq bindat-idx (1+ bindat-idx)))
|
2003-02-04 13:24:35 +00:00
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
(defun bindat--pack-u16 (v)
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(aset bindat-raw bindat-idx (logand (ash v -8) 255))
|
2006-05-28 22:19:52 +00:00
|
|
|
(aset bindat-raw (1+ bindat-idx) (logand v 255))
|
|
|
|
(setq bindat-idx (+ bindat-idx 2)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--pack-u24 (v)
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(bindat--pack-u8 (ash v -16))
|
2002-07-01 22:01:13 +00:00
|
|
|
(bindat--pack-u16 v))
|
|
|
|
|
|
|
|
(defun bindat--pack-u32 (v)
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(bindat--pack-u16 (ash v -16))
|
2002-07-01 22:01:13 +00:00
|
|
|
(bindat--pack-u16 v))
|
|
|
|
|
2021-02-15 23:54:45 -05:00
|
|
|
(defun bindat--pack-u64 (v)
|
|
|
|
(bindat--pack-u32 (ash v -32))
|
|
|
|
(bindat--pack-u32 v))
|
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
(defun bindat--pack-u16r (v)
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(aset bindat-raw (1+ bindat-idx) (logand (ash v -8) 255))
|
2006-05-28 22:19:52 +00:00
|
|
|
(aset bindat-raw bindat-idx (logand v 255))
|
|
|
|
(setq bindat-idx (+ bindat-idx 2)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--pack-u24r (v)
|
|
|
|
(bindat--pack-u16r v)
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(bindat--pack-u8 (ash v -16)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--pack-u32r (v)
|
|
|
|
(bindat--pack-u16r v)
|
Audit use of lsh and fix glitches
I audited use of lsh in the Lisp source code, and fixed the
glitches that I found. While I was at it, I replaced uses of lsh
with ash when either will do. Replacement is OK when either
argument is known to be nonnegative, or when only the low-order
bits of the result matter, and is a (minor) win since ash is a bit
more solid than lsh nowadays, and is a bit faster.
* lisp/calc/calc-ext.el (math-check-fixnum):
Prefer most-positive-fixnum to (lsh -1 -1).
* lisp/vc/vc-hg.el (vc-hg-state-fast): When testing fixnum width,
prefer (zerop (ash most-positive-fixnum -32)) to (zerop (lsh -1
32)) (Bug#32485#11).
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode):
Tighten sanity-check for bytecode overflow, by checking that the
result of (ash pc -8) is nonnegative. Formerly this check was not
needed since lsh was used and the number overflowed differently.
* lisp/net/dns.el (dns-write): Fix some obvious sign typos in
shift counts. Evidently this part of the code has never been
exercised.
* lisp/progmodes/hideif.el (hif-shiftleft, hif-shiftright):
* lisp/term/common-win.el (x-setup-function-keys):
Simplify.
* admin/unidata/unidata-gen.el, admin/unidata/uvs.el:
* doc/lispref/keymaps.texi, doc/lispref/syntax.texi:
* doc/misc/calc.texi, doc/misc/cl.texi, etc/NEWS.19:
* lisp/arc-mode.el, lisp/calc/calc-bin.el, lisp/calc/calc-comb.el:
* lisp/calc/calc-ext.el, lisp/calc/calc-math.el:
* lisp/cedet/semantic/wisent/comp.el, lisp/composite.el:
* lisp/disp-table.el, lisp/dos-fns.el, lisp/edmacro.el:
* lisp/emacs-lisp/bindat.el, lisp/emacs-lisp/byte-opt.el:
* lisp/emacs-lisp/bytecomp.el, lisp/emacs-lisp/cl-extra.el:
* lisp/erc/erc-dcc.el, lisp/facemenu.el, lisp/gnus/message.el:
* lisp/gnus/nndoc.el, lisp/gnus/nnmaildir.el, lisp/image.el:
* lisp/international/ccl.el, lisp/international/fontset.el:
* lisp/international/mule-cmds.el, lisp/international/mule.el:
* lisp/json.el, lisp/mail/binhex.el, lisp/mail/rmail.el:
* lisp/mail/uudecode.el, lisp/md4.el, lisp/net/dns.el:
* lisp/net/ntlm.el, lisp/net/sasl.el, lisp/net/socks.el:
* lisp/net/tramp.el, lisp/obsolete/levents.el:
* lisp/obsolete/pgg-parse.el, lisp/org/org.el:
* lisp/org/ox-publish.el, lisp/progmodes/cc-defs.el:
* lisp/progmodes/ebnf2ps.el, lisp/progmodes/hideif.el:
* lisp/ps-bdf.el, lisp/ps-print.el, lisp/simple.el:
* lisp/tar-mode.el, lisp/term/common-win.el:
* lisp/term/tty-colors.el, lisp/term/xterm.el, lisp/vc/vc-git.el:
* lisp/vc/vc-hg.el, lisp/x-dnd.el, test/src/data-tests.el:
Prefer ash to lsh when either will do.
2018-08-21 13:44:03 -07:00
|
|
|
(bindat--pack-u16r (ash v -16)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-02-15 23:54:45 -05:00
|
|
|
(defun bindat--pack-u64r (v)
|
|
|
|
(bindat--pack-u32r v)
|
|
|
|
(bindat--pack-u32r (ash v -32)))
|
|
|
|
|
2021-03-05 13:31:16 -05:00
|
|
|
(defun bindat--pack-str (len v)
|
|
|
|
(dotimes (i (min len (length v)))
|
|
|
|
(aset bindat-raw (+ bindat-idx i) (aref v i)))
|
|
|
|
(setq bindat-idx (+ bindat-idx len)))
|
|
|
|
|
|
|
|
(defun bindat--pack-bits (len v)
|
|
|
|
(let ((bnum (1- (* 8 len))) j m)
|
|
|
|
(while (>= bnum 0)
|
|
|
|
(setq m 0)
|
|
|
|
(if (null v)
|
|
|
|
(setq bnum (- bnum 8))
|
|
|
|
(setq j 128)
|
|
|
|
(while (> j 0)
|
|
|
|
(if (memq bnum v)
|
|
|
|
(setq m (logior m j)))
|
|
|
|
(setq bnum (1- bnum)
|
|
|
|
j (ash j -1))))
|
|
|
|
(bindat--pack-u8 m))))
|
|
|
|
|
2007-02-17 22:02:25 +00:00
|
|
|
(defun bindat--pack-item (v type len &optional vectype)
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (eq type 'ip)
|
|
|
|
(setq type 'vec len 4))
|
2021-02-15 23:22:09 -05:00
|
|
|
(pcase type
|
2021-03-05 13:31:16 -05:00
|
|
|
((guard (null v)) (setq bindat-idx (+ bindat-idx len)))
|
|
|
|
((or 'u8 'byte) (bindat--pack-u8 v))
|
|
|
|
((or 'u16 'word 'short) (bindat--pack-u16 v))
|
|
|
|
('u24 (bindat--pack-u24 v))
|
|
|
|
((or 'u32 'dword 'long) (bindat--pack-u32 v))
|
2021-02-15 23:54:45 -05:00
|
|
|
('u64 (bindat--pack-u64 v))
|
|
|
|
('u16r (bindat--pack-u16r v))
|
|
|
|
('u24r (bindat--pack-u24r v))
|
|
|
|
('u32r (bindat--pack-u32r v))
|
|
|
|
('u64r (bindat--pack-u64r v))
|
2021-03-05 13:31:16 -05:00
|
|
|
('bits (bindat--pack-bits len v))
|
|
|
|
((or 'str 'strz) (bindat--pack-str len v))
|
2021-02-15 23:22:09 -05:00
|
|
|
('vec
|
|
|
|
(let ((l (length v)) (vlen 1))
|
2007-02-17 22:02:25 +00:00
|
|
|
(if (consp vectype)
|
|
|
|
(setq vlen (nth 1 vectype)
|
|
|
|
vectype (nth 2 vectype))
|
|
|
|
(setq type (or vectype 'u8)
|
|
|
|
vectype nil))
|
|
|
|
(if (> l len) (setq l len))
|
2021-02-15 23:22:09 -05:00
|
|
|
(dotimes (i l)
|
|
|
|
(bindat--pack-item (aref v i) type vlen vectype))))
|
|
|
|
(_
|
2006-05-28 22:19:52 +00:00
|
|
|
(setq bindat-idx (+ bindat-idx len)))))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat--pack-group (struct spec)
|
2021-02-15 10:50:07 -05:00
|
|
|
(with-suppressed-warnings ((lexical struct last))
|
|
|
|
(defvar struct) (defvar last))
|
|
|
|
(let ((struct struct) last)
|
2021-02-15 23:22:09 -05:00
|
|
|
(dolist (item spec)
|
|
|
|
(let* ((field (car item))
|
2002-07-01 22:01:13 +00:00
|
|
|
(type (nth 1 item))
|
|
|
|
(len (nth 2 item))
|
2007-02-17 22:02:25 +00:00
|
|
|
(vectype (and (eq type 'vec) (nth 3 item)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(tail 3))
|
|
|
|
(if (and type (consp type) (eq (car type) 'eval))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq type (eval (car (cdr type)) t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (and len (consp len) (eq (car len) 'eval))
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq len (eval (car (cdr len)) t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (memq field '(eval fill align struct union))
|
|
|
|
(setq tail 2
|
|
|
|
len type
|
|
|
|
type field
|
|
|
|
field nil))
|
2021-02-15 23:22:09 -05:00
|
|
|
(if (and (consp field) (eq (car field) 'eval))
|
|
|
|
(setq field (eval (car (cdr field)) t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (and (consp len) (not (eq type 'eval)))
|
2020-10-21 16:09:12 +02:00
|
|
|
(setq len (apply #'bindat-get-field struct len)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(if (not len)
|
|
|
|
(setq len 1))
|
2021-02-15 23:22:09 -05:00
|
|
|
(pcase type
|
|
|
|
('eval
|
2002-07-01 22:01:13 +00:00
|
|
|
(if field
|
2021-01-28 14:42:21 -05:00
|
|
|
(setq struct (cons (cons field (eval len t)) struct))
|
|
|
|
(eval len t)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('fill
|
2006-05-28 22:19:52 +00:00
|
|
|
(setq bindat-idx (+ bindat-idx len)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('align
|
2021-03-05 13:31:16 -05:00
|
|
|
(setq bindat-idx (bindat--align bindat-idx len)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('struct
|
2002-07-01 22:01:13 +00:00
|
|
|
(bindat--pack-group
|
2021-01-28 14:42:21 -05:00
|
|
|
(if field (bindat-get-field struct field) struct) (eval len t)))
|
2021-02-15 23:22:09 -05:00
|
|
|
('repeat
|
|
|
|
(dotimes (index len)
|
|
|
|
(bindat--pack-group
|
|
|
|
(nth index (bindat-get-field struct field))
|
|
|
|
(nthcdr tail item))))
|
|
|
|
('union
|
2021-01-28 14:42:21 -05:00
|
|
|
(with-suppressed-warnings ((lexical tag))
|
|
|
|
(defvar tag))
|
2002-07-01 22:01:13 +00:00
|
|
|
(let ((tag len) (cases (nthcdr tail item)) case cc)
|
|
|
|
(while cases
|
|
|
|
(setq case (car cases)
|
|
|
|
cases (cdr cases)
|
|
|
|
cc (car case))
|
|
|
|
(if (or (equal cc tag) (equal cc t)
|
2021-01-28 14:42:21 -05:00
|
|
|
(and (consp cc) (eval cc t)))
|
2002-07-01 22:01:13 +00:00
|
|
|
(progn
|
|
|
|
(bindat--pack-group struct (cdr case))
|
|
|
|
(setq cases nil))))))
|
2021-02-15 23:22:09 -05:00
|
|
|
(_
|
2002-07-01 22:01:13 +00:00
|
|
|
(setq last (bindat-get-field struct field))
|
2007-02-17 22:02:25 +00:00
|
|
|
(bindat--pack-item last type len vectype)
|
2002-07-01 22:01:13 +00:00
|
|
|
))))))
|
|
|
|
|
2021-01-28 14:42:21 -05:00
|
|
|
(defun bindat-pack (spec struct &optional raw idx)
|
2002-10-27 21:58:18 +00:00
|
|
|
"Return binary data packed according to SPEC for structured data STRUCT.
|
2021-01-28 14:42:21 -05:00
|
|
|
Optional third arg RAW is a pre-allocated unibyte string or vector to
|
2020-10-24 14:22:58 +02:00
|
|
|
pack into.
|
2021-01-28 14:42:21 -05:00
|
|
|
Optional fourth arg IDX is the starting offset into RAW."
|
|
|
|
(when (multibyte-string-p raw)
|
2006-05-25 08:51:31 +00:00
|
|
|
(error "Pre-allocated string is multibyte"))
|
2021-01-28 14:42:21 -05:00
|
|
|
(let* ((bindat-idx (or idx 0))
|
|
|
|
(bindat-raw
|
|
|
|
(or raw
|
|
|
|
(make-string (+ bindat-idx (bindat-length spec struct)) 0))))
|
2002-07-01 22:01:13 +00:00
|
|
|
(bindat--pack-group struct spec)
|
2021-01-28 14:42:21 -05:00
|
|
|
(if raw nil bindat-raw)))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-02-15 21:25:15 -05:00
|
|
|
;;;; Debugging support
|
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-spec '(&rest bindat-item))
|
|
|
|
|
2021-02-15 23:22:09 -05:00
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat--item-aux
|
|
|
|
;; Field types which can come without a field label.
|
|
|
|
'(&or ["eval" form]
|
|
|
|
["fill" bindat-len]
|
|
|
|
["align" bindat-len]
|
|
|
|
["struct" form] ;A reference to another bindat-spec.
|
|
|
|
["union" bindat-tag-val &rest (bindat-tag bindat-spec)]))
|
|
|
|
|
2021-02-15 21:25:15 -05:00
|
|
|
(def-edebug-elem-spec 'bindat-item
|
2021-02-15 23:22:09 -05:00
|
|
|
'((&or bindat--item-aux ;Without label..
|
|
|
|
[bindat-field ;..or with label
|
|
|
|
&or bindat--item-aux
|
|
|
|
["repeat" bindat-arg bindat-spec]
|
|
|
|
bindat-type])))
|
2021-02-15 21:25:15 -05:00
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-type
|
|
|
|
'(&or ("eval" form)
|
|
|
|
["str" bindat-len]
|
|
|
|
["strz" bindat-len]
|
|
|
|
["vec" bindat-len &optional bindat-type]
|
|
|
|
["bits" bindat-len]
|
|
|
|
symbolp))
|
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-field
|
|
|
|
'(&or ("eval" form) symbolp))
|
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-len '(&or [] "nil" bindat-arg))
|
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-tag-val '(bindat-arg))
|
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-tag '(&or ("eval" form) atom))
|
|
|
|
|
|
|
|
(def-edebug-elem-spec 'bindat-arg
|
|
|
|
'(&or ("eval" form) integerp (&rest symbolp integerp)))
|
|
|
|
|
|
|
|
(defmacro bindat-spec (&rest fields)
|
|
|
|
"Build the bindat spec described by FIELDS."
|
|
|
|
(declare (indent 0) (debug (bindat-spec)))
|
|
|
|
;; FIXME: We should really "compile" this to a triplet of functions!
|
|
|
|
`',fields)
|
2002-07-01 22:01:13 +00:00
|
|
|
|
2021-02-15 21:25:15 -05:00
|
|
|
;;;; Misc. format conversions
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(defun bindat-format-vector (vect fmt sep &optional len)
|
|
|
|
"Format vector VECT using element format FMT and separator SEP.
|
|
|
|
Result is a string with each element of VECT formatted using FMT and
|
|
|
|
separated by the string SEP. If optional fourth arg LEN is given, use
|
|
|
|
only that many elements from VECT."
|
2021-02-15 23:22:09 -05:00
|
|
|
(when len (setq vect (substring vect 0 len)))
|
|
|
|
(mapconcat (lambda (x) (format fmt x)) vect sep))
|
2003-02-04 13:24:35 +00:00
|
|
|
|
2002-07-01 22:01:13 +00:00
|
|
|
(defun bindat-vector-to-dec (vect &optional sep)
|
|
|
|
"Format vector VECT in decimal format separated by dots.
|
|
|
|
If optional second arg SEP is a string, use that as separator."
|
|
|
|
(bindat-format-vector vect "%d" (if (stringp sep) sep ".")))
|
|
|
|
|
|
|
|
(defun bindat-vector-to-hex (vect &optional sep)
|
2020-04-29 09:52:34 +02:00
|
|
|
"Format vector VECT in hex format separated by colons.
|
2002-07-01 22:01:13 +00:00
|
|
|
If optional second arg SEP is a string, use that as separator."
|
|
|
|
(bindat-format-vector vect "%02x" (if (stringp sep) sep ":")))
|
|
|
|
|
|
|
|
(defun bindat-ip-to-string (ip)
|
2006-08-11 09:28:44 +00:00
|
|
|
"Format vector IP as an ip address in dotted notation.
|
|
|
|
The port (if any) is omitted. IP can be a string, as well."
|
|
|
|
(if (vectorp ip)
|
|
|
|
(format-network-address ip t)
|
|
|
|
(format "%d.%d.%d.%d"
|
|
|
|
(aref ip 0) (aref ip 1) (aref ip 2) (aref ip 3))))
|
2002-07-01 22:01:13 +00:00
|
|
|
|
|
|
|
(provide 'bindat)
|
|
|
|
|
|
|
|
;;; bindat.el ends here
|