O código lisp a seguir coloca uma entrada "Hexl Isearch Mode" no menu "Hexl".
Esse item de menu (des-) ativa o modo secundário hexl-isearch-mode
. Se você ativar esse modo, isearch
procurará nos dados binários em vez do buffer hexl.
A cadeia de pesquisa é lida com read
. Portanto, todas as seqüências de escape para strings lisp funcionam. Como exemplo, você pode procurar \x0a\x0d
ou \^M\n
pesquisar por finais da linha dos.
O código não é perfeito.
Digamos que você pesquise uma string ELF\x01
que só ocorra no início de um arquivo. Além disso, suponha que exista uma string ELf\x00
posteriormente no binário. Então, quando você ELF\x0
digitar o Emacs, encontrará a correspondência posterior e, se continuar digitando, o ELF\x01
Emacs acha que não há ocorrências dessa string, porque ela já chegou ao ELF\x0
que vem depois no arquivo ELF\x01
. Vale a pena fazer uma pesquisa sobreposta nesse caso. (Esse problema já foi corrigido na versão git do pacote .)
Somente a sequência de bytes é iluminada corretamente no buffer hexl, e não na representação de string no lado direito.
Se a cadeia de pesquisa se estender por duas linhas no buffer hexl, a representação da cadeia no final da linha e o endereço no início da linha também serão destacados. Isso não ocorre porque eles pertencem à correspondência, mas porque eles estão no caminho ao destacar a sequência 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")