From 6f1edcb56b8aaaee593552172242d78ec0a81cf2 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 13 Apr 2015 03:01:44 -0700 Subject: [PATCH] Initial import. --- LICENSE | 19 ++++++++ README.txt | 26 +++++++++++ binary.asd | 10 ++++ binary.lisp | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 LICENSE create mode 100644 README.txt create mode 100644 binary.asd create mode 100644 binary.lisp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..45499ee --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Kyle Isom + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..6ae92b1 --- /dev/null +++ b/README.txt @@ -0,0 +1,26 @@ +#:BINARY + +These are various utilities I wrote to read and write integers from +binary streams while working on a common lisp interface to the 9P +protocol. The following sets of functions are provided: + + - read-{u32,u16,u8}: read unsigned 32-, 16-, and 8-bit integers + from a stream. + - write-{u32,u16,u8}: write unsigned 32-, 16-, and 8-bit integers + from a stream. + - read-{i32,i16,i8}: read signed 32-, 16-, and 8-bit integers + from a stream. + - write-{i32,i16,u8}: write signed 32-, 16-, and 8-bit integers + from a stream. + + - octets: read binary data from a stream + - {int,uint}-from-bytes: read a signed or unsigned integer from + a byte array. + - {int,uint}-to-bytes: produce a byte array from a signed or + unsigned integer. + +Most of these functions take an endian specifier. Valid endians are +:little for little endian (the default) and :big for big endian. + + +kyle@metacircular.net diff --git a/binary.asd b/binary.asd new file mode 100644 index 0000000..0b93279 --- /dev/null +++ b/binary.asd @@ -0,0 +1,10 @@ +;;;; binary.asd + +(asdf:defsystem #:binary + :description "Describe binary here" + :author "Kyle Isom " + :license "MIT License" + :serial t + :components ((:file "package") + (:file "binary"))) + diff --git a/binary.lisp b/binary.lisp new file mode 100644 index 0000000..34f432a --- /dev/null +++ b/binary.lisp @@ -0,0 +1,129 @@ +;;;; binary.lisp + +(in-package #:binary) + +;;; "binary" goes here. Hacks and glory await! + + +(defconstant U32 4) +(defconstant I32 4) +(defconstant U16 2) +(defconstant I16 2) +(defconstant U8 1) +(defconstant I8 1) + +(defun octets (stream length) + "Read length bytes from the stream." + (let ((bin (make-array length :element-type '(unsigned-byte 8)))) + (read-sequence bin stream) + bin)) + +(defun uint-from-bytes (bin &key (endian :little)) + "Produce an unsigned integer from the binary array input." + (let ((bin (cond + ((eql endian :little) bin) + ((eql endian :big) (reverse bin)) + (t (error "Invalid endian specification.")))) + (n 0)) + (dotimes (i (length bin)) + (setf n (+ n (ash (aref bin i) (* i 8))))) + n)) + +(defun uint-to-bytes (n size &key (endian :little)) + "Produce a binary array of size bytes from the unsigned integer +provided." + (let ((bin (make-array size :element-type '(unsigned-byte 8)))) + (dotimes (i size) + (setf (aref bin i) + (logand 255 (ash n (- 0 (* i 8)))))) + (cond + ((eql endian :little) bin) + ((eql endian :big) (nreverse bin)) + (t (error "Invalid endian specification."))))) + +(defun read-uint (stream size &key (endian :little)) + (uint-from-bytes (octets stream size) :endian endian)) + +(defun write-uint (stream n size &key (endian :little)) + (write-sequence (uint-to-bytes n size :endian endian) stream)) + +(defmacro define-unsigned-reader (const-name) + (let ((docstring + (format nil + "Read an unsigned ~A-bit integer from a stream." + (subseq (format nil "~A" const-name) 1)))) + `(defun ,(intern (format nil "READ-~A" const-name)) + (stream &key (endian :little)) + ,docstring + (read-uint stream ,const-name :endian endian)))) + +(defmacro define-unsigned-writer (const-name) + (let ((docstring + (format nil + "Write an unsigned ~A-bit integer to a stream." + (subseq (format nil "~A" const-name) 1)))) + `(defun ,(intern (format nil "WRITE-~A" const-name)) + (stream n &key (endian :little)) + ,docstring + (write-uint stream n ,const-name :endian endian)))) + +(defmacro defunsigned (const-name) + `(progn + (define-unsigned-reader ,const-name) + (define-unsigned-writer ,const-name))) + +(defunsigned U32) +(defunsigned U16) +(defunsigned U8) + +(defun twos-complement (n size) + (if (zerop (logand (ash 1 (* (- size 1) 8)) n)) + n + (- n (ash 1 (* size 8))))) + +(defun int-from-bytes (bin &key (endian :little)) + "Produce a signed integer from the binary array input." + (twos-complement (uint-from-bytes bin :endian endian) + (length bin))) + +(defun int-to-bytes (n size &key (endian :little)) + "Produce a binary array of size bytes from the provided signed +integer." + (uint-to-bytes (twos-complement n size) size :endian endian)) + +(defun read-int (stream size &key (endian :little)) + (int-from-bytes (octets stream size) + :endian endian)) + +(defun write-int (stream n size &key (endian :little)) + (write-sequence (int-to-bytes n size :endian endian) + stream)) + +(defmacro define-signed-reader (const-name) + (let ((docstring + (format nil + "Read a signed ~A-bit integer from a stream." + (subseq (format nil "~A" const-name) 1)))) + `(defun ,(intern (format nil "READ-~A" const-name)) + (stream &key (endian :little)) + ,docstring + (read-int stream ,const-name :endian endian)))) + +(defmacro define-signed-writer (const-name) + (let ((docstring + (format nil + "Write a signed ~A-bit integer to a stream." + (subseq (format nil "~A" const-name) 1)))) + `(defun ,(intern (format nil "WRITE-~A" const-name)) + (stream n &key (endian :little)) + ,docstring + (write-int stream n ,const-name :endian endian)))) + +(defmacro defsigned (const-name) + `(progn + (define-signed-reader ,const-name) + (define-signed-writer ,const-name))) + +(defsigned I32) +(defsigned I16) +(defsigned I8)