144 lines
5.3 KiB
Common Lisp
144 lines
5.3 KiB
Common Lisp
|
;; This file is free software: you can redistribute it and/or modify
|
|||
|
;; it under the terms of version 3 of the GNU General Public License
|
|||
|
;; as published by the Free Software Foundation.
|
|||
|
;;
|
|||
|
;; This program 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.
|
|||
|
|
|||
|
(defpackage :eksd
|
|||
|
(:use :cl)
|
|||
|
(:export :stream-to-hex
|
|||
|
:file-to-hex
|
|||
|
:hex-to-char
|
|||
|
:hex-to-file
|
|||
|
:hex-to-integer
|
|||
|
:integer-to-hex
|
|||
|
:hex-to-stream
|
|||
|
:read-hex
|
|||
|
*ascii-text-table*
|
|||
|
*fancy-text-table*))
|
|||
|
|
|||
|
(in-package :eksd)
|
|||
|
|
|||
|
;; —————————————————————————————————————
|
|||
|
|
|||
|
(defparameter *ascii-text-table*
|
|||
|
'(("20" #\space)("21" #\!)("22" #\")("23" #\#)("24" #\$) ("25" #\%)
|
|||
|
("26" #\&) ("27" #\') ("28" #\() ("29" #\)) ("2A" #\*) ("2B" #\+)
|
|||
|
("2C" #\,) ("2D" #\-) ("2E" #\.) ("2F" #\/) ("30" #\0) ("31" #\1)
|
|||
|
("32" #\2) ("33" #\3) ("34" #\4) ("35" #\5) ("36" #\6) ("37" #\7)
|
|||
|
("38" #\8) ("39" #\9) ("3A" #\:) ("3B" #\;) ("3C" #\<) ("3D" #\=)
|
|||
|
("3E" #\>) ("3F" #\?) ("40" #\@) ("41" #\A) ("42" #\B) ("43" #\C)
|
|||
|
("44" #\D) ("45" #\E) ("46" #\F) ("47" #\G) ("48" #\H) ("49" #\I)
|
|||
|
("4A" #\J) ("4B" #\K) ("4C" #\L) ("4D" #\M) ("4E" #\N) ("4F" #\O)
|
|||
|
("50" #\P) ("51" #\Q) ("52" #\R) ("53" #\S) ("54" #\T) ("55" #\U)
|
|||
|
("56" #\V) ("57" #\W) ("58" #\X) ("59" #\Y) ("5A" #\Z) ("5B" #\[)
|
|||
|
("5C" #\\) ("5D" #\]) ("5E" #\^) ("5F" #\_) ("60" #\`) ("61" #\a)
|
|||
|
("62" #\b) ("63" #\c) ("64" #\d) ("65" #\e) ("66" #\f) ("67" #\g)
|
|||
|
("68" #\h) ("69" #\i) ("6A" #\j) ("6B" #\k) ("6C" #\l) ("6D" #\m)
|
|||
|
("6E" #\n) ("6F" #\o) ("70" #\p) ("71" #\q) ("72" #\r) ("73" #\s)
|
|||
|
("74" #\t) ("75" #\u) ("76" #\v) ("77" #\w) ("78" #\x) ("79" #\y)
|
|||
|
("7A" #\z) ("7B" #\{) ("7C" #\|) ("7D" #\}) ("7E" #\~)))
|
|||
|
(defparameter *fancy-text-bits*
|
|||
|
'(("00" #\×) ("07" #\🔔)("08" "⬅️") ("09" #\↣) ("0A" #\↵) ("0B" #\↧)
|
|||
|
("0C" #\⇲) ("0D" #\↲) ("0E" #\⇪) ("0F" #\⇫) ("1B" #\↯) ("7F" #\⇐)))
|
|||
|
(defparameter *fancy-text-table* (append *ascii-text-table* *fancy-text-bits*))
|
|||
|
|
|||
|
|
|||
|
;; —————————————————————————————————————
|
|||
|
;; X → HEX
|
|||
|
|
|||
|
;; STREAM → LIST_OF_STRINGS
|
|||
|
(defun stream-to-hex (stream)
|
|||
|
"Return a stream's data as a list of hexadecimal strings."
|
|||
|
(loop :while (listen stream)
|
|||
|
:collect (read-hex stream)))
|
|||
|
|
|||
|
;; PATHNAME → LIST_OF_STRINGS
|
|||
|
(defun file-to-hex (pathname)
|
|||
|
"Return a list of a file's octets represented in hexadecimal strings."
|
|||
|
(with-open-file (fstream pathname
|
|||
|
:direction :input :element-type '(unsigned-byte 8))
|
|||
|
(stream-to-hex fstream)))
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; —————————————————————————————————————
|
|||
|
;; HEX → X
|
|||
|
|
|||
|
;; LIST_OF_STRINGS STREAM → NIL
|
|||
|
(defun hex-to-stream (hexes stream)
|
|||
|
"Write a list of bytes (in hex-string format) to a stream."
|
|||
|
(loop :for hex :in hexes
|
|||
|
:do (write-hex hex stream)))
|
|||
|
|
|||
|
;; LIST_OF_STRINGS PATHNAME → NIL
|
|||
|
(defun hex-to-file (hexes pathname)
|
|||
|
"Write a list of bytes (in hex-string format) to a file."
|
|||
|
(with-open-file (fstream pathname
|
|||
|
:direction :output :element-type '(unsigned-byte 8))
|
|||
|
(hex-to-stream hexes fstream)))
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; —————————————————————————————————————
|
|||
|
;; TEXT-TABLE FUN
|
|||
|
|
|||
|
(defgeneric hex-to-char (hex/es &optional text-table)
|
|||
|
(:documentation "Return a hexadecimal's respective character (as string)
|
|||
|
according to the given text-table."))
|
|||
|
|
|||
|
;; STRING LIST → STRING
|
|||
|
(defmethod hex-to-char ((hex string) &optional (text-table *ascii-text-table*))
|
|||
|
(or (cadr (assoc hex text-table :test #'equal)) #\.))
|
|||
|
|
|||
|
;; LIST_OF_STRINGS LIST → LIST_OF_STRINGS
|
|||
|
(defmethod hex-to-char ((hexes list) &optional (text-table *ascii-text-table*))
|
|||
|
(mapcar (lambda (hex) (hex-to-char hex text-table)) hexes))
|
|||
|
|
|||
|
|
|||
|
;; PATHNAME LIST → LIST_OF_STRINGS
|
|||
|
(defun file-to-char (pathname &optional (text-table *ascii-text-table*))
|
|||
|
"Print character representation of a file, as per the given character table."
|
|||
|
(hex-to-char (file-to-hex pathname) text-table))
|
|||
|
|
|||
|
|
|||
|
;; CHARACTER LIST → STRING
|
|||
|
(defun char-hex (char &optional text-table)
|
|||
|
"Return a character's hex, given a text-table."
|
|||
|
(if (not text-table)
|
|||
|
(integer-to-hex (char-code char))
|
|||
|
(cadr (assoc char (mapcar #'reverse text-table)))))
|
|||
|
|
|||
|
(defun string-hex (string &optional text-table)
|
|||
|
(loop :for char :across string
|
|||
|
:collect (char-hex char text-table)))
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;; —————————————————————————————————————
|
|||
|
;; MISC
|
|||
|
|
|||
|
;; STREAM → STRING
|
|||
|
(defun read-hex (stream)
|
|||
|
"Read a byte from a stream as a hexcode."
|
|||
|
(integer-to-hex (read-byte stream)))
|
|||
|
|
|||
|
;; STREAM → STRING
|
|||
|
(defun write-hex (hex stream)
|
|||
|
"Read a byte from a stream as a hexcode."
|
|||
|
(write-byte (hex-to-integer hex) stream))
|
|||
|
|
|||
|
|
|||
|
;; NUMBER → STRING
|
|||
|
(defun integer-to-hex (number)
|
|||
|
"Return the base-16 of a number."
|
|||
|
(format nil "~2,'0x" number))
|
|||
|
|
|||
|
;; STRING → NUMBER
|
|||
|
(defun hex-to-integer (hex)
|
|||
|
"Convert hex to a base-10 integer."
|
|||
|
(parse-integer hex :radix 16))
|