File: decode.lisp

package info (click to toggle)
acl2 7.2dfsg-3
  • links: PTS
  • area: main
  • in suites: stretch
  • size: 198,968 kB
  • ctags: 182,300
  • sloc: lisp: 2,415,261; ansic: 5,675; perl: 5,577; xml: 3,576; sh: 3,255; cpp: 2,835; makefile: 2,440; ruby: 2,402; python: 778; ml: 763; yacc: 709; csh: 355; php: 171; lex: 162; tcl: 44; java: 24; asm: 23; haskell: 17
file content (256 lines) | stat: -rw-r--r-- 10,475 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          encode.lisp
;;;; Purpose:       cl-base64 encoding routines
;;;; Programmer:    Kevin M. Rosenberg
;;;; Date Started:  Dec 2002
;;;;
;;;; $Id$
;;;;
;;;; This file implements the Base64 transfer encoding algorithm as
;;;; defined in RFC 1521 by Borensten & Freed, September 1993.
;;;; See: http://www.ietf.org/rfc/rfc1521.txt
;;;;
;;;; Based on initial public domain code by Juri Pakaste <juri@iki.fi>
;;;;
;;;; Copyright 2002-2003 Kevin M. Rosenberg
;;;; Permission to use with BSD-style license included in the COPYING file
;;;; *************************************************************************

(in-package #:cl-base64)

(declaim (inline whitespace-p))
(defun whitespace-p (c)
  "Returns T for a whitespace character."
  (or (char= c #\Newline) (char= c #\Linefeed)
      (char= c #\Return) (char= c #\Space)
      (char= c #\Tab)))


;;; Decoding

#+ignore
(defmacro def-base64-stream-to-* (output-type)
  `(defun ,(intern (concatenate 'string (symbol-name :base64-stream-to-)
                                (symbol-name output-type)))
    (input &key (uri nil)
        ,@(when (eq output-type :stream)
                '(stream)))
     ,(concatenate 'string "Decode base64 stream to " (string-downcase
                                                       (symbol-name output-type)))
     (declare (stream input)
              (optimize (speed 3) (space 0) (safety 0)))
     (let ((pad (if uri *uri-pad-char* *pad-char*))
           (decode-table (if uri *uri-decode-table* *decode-table*)))
       (declare (type decode-table decode-table)
                (type character pad))
       (let (,@(case output-type
                     (:string
                      '((result (make-string (* 3 (truncate (length string) 4))))))
                     (:usb8-array
                      '((result (make-array (* 3 (truncate (length string) 4))
                                 :element-type '(unsigned-byte 8)
                                 :fill-pointer nil
                                 :adjustable nil)))))
               (ridx 0))
         (declare ,@(case output-type
                          (:string
                           '((simple-string result)))
                          (:usb8-array
                           '((type (simple-array (unsigned-byte 8) (*)) result))))
                  (fixnum ridx))
         (do* ((bitstore 0)
               (bitcount 0)
               (char (read-char stream nil #\null)
                     (read-char stream nil #\null)))
              ((eq char #\null)
               ,(case output-type
                      (:stream
                       'stream)
                      ((:string :usb8-array)
                       'result)
                      ;; ((:stream :string)
                      ;; '(subseq result 0 ridx))))
                      ))
           (declare (fixnum bitstore bitcount)
                    (character char))
           (let ((svalue (aref decode-table (the fixnum (char-code char)))))
             (declare (fixnum svalue))
             (cond
               ((>= svalue 0)
                (setf bitstore (logior
                                (the fixnum (ash bitstore 6))
                                svalue))
                (incf bitcount 6)
                (when (>= bitcount 8)
                  (decf bitcount 8)
                  (let ((ovalue (the fixnum
                                  (logand
                                   (the fixnum
                                     (ash bitstore
                                          (the fixnum (- bitcount))))
                                   #xFF))))
                    (declare (fixnum ovalue))
                    ,(case output-type
                           (:string
                            '(setf (char result ridx) (code-char ovalue)))
                           (:usb8-array
                            '(setf (aref result ridx) ovalue))
                           (:stream
                            '(write-char (code-char ovalue) stream)))
                    (incf ridx)
                    (setf bitstore (the fixnum (logand bitstore #xFF))))))
               ((char= char pad)
                ;; Could add checks to make sure padding is correct
                ;; Currently, padding is ignored
                )
               ((whitespace-p char)
                ;; Ignore whitespace
                )
               ((minusp svalue)
                (warn "Bad character ~W in base64 decode" char))
               )))))))

;;(def-base64-stream-to-* :string)
;;(def-base64-stream-to-* :stream)
;;(def-base64-stream-to-* :usb8-array)

(defmacro def-base64-string-to-* (output-type)
  `(defun ,(intern (concatenate 'string (symbol-name :base64-string-to-)
                                (symbol-name output-type)))
    (input &key (uri nil)
        ,@(when (eq output-type :stream)
                '(stream)))
     ,(concatenate 'string "Decode base64 string to " (string-downcase
                                                       (symbol-name output-type)))
     (declare (string input)
              (optimize (speed 3) (safety 0) (space 0)))
     (let ((pad (if uri *uri-pad-char* *pad-char*))
           (decode-table (if uri *uri-decode-table* *decode-table*)))
       (declare (type decode-table decode-table)
                (type character pad))
       (let (,@(case output-type
                     (:string
                      '((result (make-string (* 3 (truncate (length input) 4))))))
                     (:usb8-array
                      '((result (make-array (* 3 (truncate (length input) 4))
                                 :element-type '(unsigned-byte 8)
                                 :fill-pointer nil
                                 :adjustable nil)))))
               (ridx 0))
         (declare ,@(case output-type
                          (:string
                           '((simple-string result)))
                          (:usb8-array
                           '((type (simple-array (unsigned-byte 8) (*)) result))))
                  (fixnum ridx))
         (loop
            for char of-type character across input
            for svalue of-type fixnum = (aref decode-table
                                              (the fixnum (char-code char)))
            with bitstore of-type fixnum = 0
            with bitcount of-type fixnum = 0
            do
              (cond
                ((>= svalue 0)
                 (setf bitstore (logior
                                 (the fixnum (ash bitstore 6))
                                 svalue))
                 (incf bitcount 6)
                 (when (>= bitcount 8)
                   (decf bitcount 8)
                   (let ((ovalue (the fixnum
                                   (logand
                                    (the fixnum
                                      (ash bitstore
                                           (the fixnum (- bitcount))))
                                    #xFF))))
                     (declare (fixnum ovalue))
                     ,(case output-type
                            (:string
                             '(setf (char result ridx) (code-char ovalue)))
                            (:usb8-array
                             '(setf (aref result ridx) ovalue))
                            (:stream
                             '(write-char (code-char ovalue) stream)))
                     (incf ridx)
                     (setf bitstore (the fixnum (logand bitstore #xFF))))))
                 ((char= char pad)
                  ;; Could add checks to make sure padding is correct
                  ;; Currently, padding is ignored
                  )
                 ((whitespace-p char)
                  ;; Ignore whitespace
                  )
                 ((minusp svalue)
                  (warn "Bad character ~W in base64 decode" char))
                 ))
         ,(case output-type
                (:stream
                 'stream)
                ((:usb8-array :string)
                 '(subseq result 0 ridx)))))))

(def-base64-string-to-* :string)
(def-base64-string-to-* :stream)
(def-base64-string-to-* :usb8-array)

;; input-mode can be :string or :stream
;; input-format can be :character or :usb8

(defun base64-string-to-integer (string &key (uri nil))
  "Decodes a base64 string to an integer"
  (declare (string string)
           (optimize (speed 3) (safety 0) (space 0)))
  (let ((pad (if uri *uri-pad-char* *pad-char*))
        (decode-table (if uri *uri-decode-table* *decode-table*)))
    (declare (type decode-table decode-table)
             (character pad))
    (let ((value 0))
      (declare (integer value))
      (loop
         for char of-type character across string
         for svalue of-type fixnum =
           (aref decode-table (the fixnum (char-code char)))
         do
           (cond
             ((>= svalue 0)
              (setq value (+ svalue (ash value 6))))
             ((char= char pad)
              (setq value (ash value -2)))
             ((whitespace-p char)
              ; ignore whitespace
              )
             ((minusp svalue)
              (warn "Bad character ~W in base64 decode" char))))
      value)))


(defun base64-stream-to-integer (stream &key (uri nil))
  "Decodes a base64 string to an integer"
  (declare (stream stream)
           (optimize (speed 3) (space 0) (safety 0)))
  (let ((pad (if uri *uri-pad-char* *pad-char*))
        (decode-table (if uri *uri-decode-table* *decode-table*)))
    (declare (type decode-table decode-table)
             (character pad))
    (do* ((value 0)
          (char (read-char stream nil #\null)
                (read-char stream nil #\null)))
         ((eq char #\null)
          value)
      (declare (integer value)
               (character char))
      (let ((svalue (aref decode-table (the fixnum (char-code char)))))
           (declare (fixnum svalue))
           (cond
             ((>= svalue 0)
              (setq value (+ svalue (ash value 6))))
             ((char= char pad)
              (setq value (ash value -2)))
             ((whitespace-p char)               ; ignore whitespace
              )
             ((minusp svalue)
              (warn "Bad character ~W in base64 decode" char)))))))