El siguiente código lisp coloca una entrada "Modo de búsqueda Hexl" en el menú "Hexl".
Ese elemento del menú (des) activa el modo menor hexl-isearch-mode
. Si activa ese modo, isearch
busca en los datos binarios en lugar del búfer hexl.
La cadena de búsqueda se lee con read
. Entonces, todas las secuencias de escape para cadenas de lisp funcionan. Como ejemplo, puede buscar \x0a\x0d
o \^M\n
buscar extremos de línea dos.
El código no es perfecto.
Supongamos que busca una cadena ELF\x01
que solo ocurre al comienzo de un archivo. Además, suponga que hay una cadena ELf\x00
más adelante en el binario. Luego, cuando llegues a ELF\x0
escribir, Emacs encontrará la coincidencia posterior y si continúas escribiendo, ELF\x01
Emacs piensa que no hay ocurrencias de esa cadena porque ya llegó a la ELF\x0
que aparece más tarde en el archivo ELF\x01
. Vale la pena hacer una búsqueda superpuesta en tal caso. (Ese problema ya está solucionado en la versión git del paquete ).
Solo la secuencia de bytes se resalta correctamente en el búfer hexl, no la representación de cadena en el lado derecho.
Si la cadena de búsqueda abarca dos líneas en el búfer hexl, la representación de la cadena al final de la línea y la dirección al comienzo de la línea también se resaltan. Eso no se debe a que pertenecen a la coincidencia, sino a que están en el camino al resaltar la secuencia de bytes.
(require 'hexl)
(defvar-local hexl-isearch-raw-buffer nil
"Buffer with the dehexlified content of the hexl buffer for hexl-isearch-mode.
This variable is set in the original hexl-mode buffer.")
(defvar-local hexl-isearch-original-buffer nil
"This variable is set in the buffer with the dehexlified content.
It points to the corresponding hexl buffer.")
(defun hexl-address (position)
"Return address of hexl buffer POSITION."
(save-excursion
(goto-char position)
(hexl-current-address)))
(defun hexl-isearch-startup ()
"Prepare hexl buffer for `hexl-isearch'."
(let ((original-buf (current-buffer)))
(setq-local hexl-isearch-raw-buffer (generate-new-buffer " hexl"))
(setq-local isearch-search-fun-function (lambda () #'hexl-isearch-fun))
(with-current-buffer hexl-isearch-raw-buffer
(set-buffer-multibyte nil)
(setq-local hexl-isearch-original-buffer original-buf)
(insert-buffer-substring original-buf 1 (buffer-size original-buf))
(dehexlify-buffer))))
(defun hexl-isearch-end ()
"Cleanup after `hexl-isearch'."
(let ((isearch-raw-buffer hexl-isearch-raw-buffer))
(setq-local hexl-isearch-raw-buffer nil)
(when (buffer-live-p isearch-raw-buffer)
(kill-buffer isearch-raw-buffer))))
(defun hexl-isearch-fun (string &optional bound noerror count)
"Search for byte sequence of STRING in hexl buffer.
The arguments BOUND and NOERROR work like in `search-forward'."
(when bound (setq bound (1+ (hexl-address bound))))
(setq string (read (concat "\"" string "\"")))
(let ((point (1+ (hexl-current-address)))
match-data)
(with-current-buffer hexl-isearch-raw-buffer
(goto-char point)
(setq point (funcall (if isearch-forward #'re-search-forward #'re-search-backward)
(if isearch-regexp
string
(regexp-quote string))
bound noerror count))
(setq match-data (match-data t nil t)))
(when point
(prog1
(hexl-goto-address (1- point))
(set-match-data
(mapcar (lambda (el)
(if (integerp el)
(hexl-address-to-marker (1- el))
el))
match-data))))))
(define-minor-mode hexl-isearch-mode
"Search for binary string with isearch in hexl buffer."
:lighter " hi"
(if hexl-isearch-mode
(progn
(setq-local isearch-search-fun-function #'hexl-isearch-fun)
(add-hook 'isearch-mode-hook #'hexl-isearch-startup t t)
(add-hook 'isearch-mode-end-hook #'hexl-isearch-end t t))
(setq-local isearch-search-fun-function #'isearch-search-fun-default)
(remove-hook 'isearch-mode-hook #'hexl-isearch-startup t)
(remove-hook 'isearch-mode-end-hook #'hexl-isearch-end t)))
(easy-menu-add-item hexl-mode-map '(menu-bar Hexl)
["Hexl Isearch Mode" (if hexl-isearch-mode (hexl-isearch-mode -1) (hexl-isearch-mode)) :style toggle :selected hexl-isearch-mode] "Go to address")