1 ;;; ascii-armor.el -- translate data into and from ascii-armor
4 ;; Copyright (C) 1998 Ray Jones
6 ;; Author: Ray Jones, rjones@pobox.com
7 ;; Keywords: base64, ascii-armor, radix64, oink
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program; if not, you can either send email to this
22 ;; program's maintainer or write to: The Free Software Foundation,
23 ;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
31 (defun ascii-armor-char (val)
32 (cond ((< val 26) (+ val ?A))
33 ((< val 52) (+ (- val 26) ?a))
34 ((< val 62) (+ (- val 52) ?0))
37 (t (error "no ascii-armor character for %d!" val))))
39 (defun ascii-armor-val (char)
40 (cond ((and (<= ?A char) (<= char ?Z)) (- char ?A))
41 ((and (<= ?a char) (<= char ?z)) (+ (- char ?a) 26))
42 ((and (<= ?0 char) (<= char ?9)) (+ (- char ?0) 52))
47 (defun ascii-armor-length (n)
48 "calculate the number of characters needed to encode N octets."
53 ;; ascii armor is 6 bits per symbol...
54 (n2 (car (ceiling* n1 6)))
55 ;; but always a multiple of 4 symbols
56 (n3 (* 4 (car (ceiling* n2 4)))))
59 (defun ascii-armor-data-length (str)
60 "calculate the number of octets stored in an ascii-armor string"
62 (let ((len (length str)))
64 (eq ?= (aref str (1- len))))
68 ;; translate a vector of 16-bit values into an ascii-armor string
69 (defun vec16-to-ascii-armor (vec)
70 (let* ((in-len (length vec))
71 (out-len (ascii-armor-length (* 2 in-len)))
72 (out-str (make-string out-len ?=))
76 (flet ((next-out (val)
82 (dotimes (in-idx in-len)
84 ;; read out as many bits from the current index as possible
85 (while (> bits-start 0)
86 ;; do the next 6 bits straddle a boundary in vec?
90 (let ((hi-val (aref vec in-idx))
92 (lo-val (if (< in-idx (1- in-len))
93 (aref vec (1+ in-idx))
96 (ash hi-val (- 6 bits-start))
97 (ash lo-val (- 6 bits-start 16)))))
99 ;; 6 bits all from the current entry in vec
100 (next-out (ash (aref vec in-idx) (- 6 bits-start))))
102 (decf bits-start 6))))
104 ;; pad with ?=, if out-str isn't full
105 (while (< out-idx out-len)
106 (aset out-str out-idx ?=)
111 ;; translate an ascii-armor string to a 16-bit vector
112 (defun ascii-armor-to-vec16 (string)
113 ;; ascii armor is padded, so this doesn't have to be rounded, just
115 (let* ((out-len (/ (ascii-armor-data-length string) 2))
116 (out-vec (make-vector out-len 0))
120 (dotimes (out-idx out-len)
121 ;; shift bits from the string until there are enough to stick
122 ;; into the output vector
123 (while (< bits-in-buf 16)
124 (let ((val (ascii-armor-val (aref string in-idx))))
126 (setq buf (logior (ash buf 6)
128 (incf bits-in-buf 6))
131 (aset out-vec out-idx (ash buf (- 16 bits-in-buf)))
132 (decf bits-in-buf 16)
133 ;; turn off the used bits
134 (setq buf (logand buf (lognot (ash #xffff bits-in-buf)))))
138 (provide 'ascii-armor)