Home My Page Projects Code Snippets Project Openings SML/NJ
Summary Activity Forums Tracker Lists Tasks Docs Surveys News SCM Files

SCM Repository

[smlnj] Diff of /smlnj-lib/trunk/Util/base64.sml
ViewVC logotype

Diff of /smlnj-lib/trunk/Util/base64.sml

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3760, Sun Sep 23 13:16:22 2012 UTC revision 3761, Mon Sep 24 13:21:03 2012 UTC
# Line 26  Line 26 
26      val padChar = #"="      val padChar = #"="
27      fun incByte b = UCV.sub(encTbl, Word8.toIntX b)      fun incByte b = UCV.sub(encTbl, Word8.toIntX b)
28    
29      (* return true if a character is in the base64 alphabet *)
30        val isBase64 = Char.contains encTbl
31    
32    (* encode a triple of bytes into four base-64 characters *)    (* encode a triple of bytes into four base-64 characters *)
33      fun encode3 (b1, b2, b3) = let      fun encode3 (b1, b2, b3) = let
34            val c1 = W8.>>(b1, 0w2)            val c1 = W8.>>(b1, 0w2)
# Line 54  Line 57 
57            end            end
58    
59      local      local
60        fun encode (vec, start, len) = let        fun encode64 (vec, start, len) = let
61              val outLen = 4 * Int.quot(len + 2, 3)              val outLen = 4 * Int.quot(len + 2, 3)
62              val outBuf = Unsafe.CharVector.create outLen              val outBuf = Unsafe.CharVector.create outLen
63              val nTriples = Int.quot(len, 3)              val nTriples = Int.quot(len, 3)
# Line 82  Line 85 
85              end              end
86      in      in
87    
88      fun encodeVec vec = encode (vec, 0, W8V.length vec)      fun encode vec = encode64 (vec, 0, W8V.length vec)
89    
90      fun encodeVecSlice slice = encode (Word8VectorSlice.base slice)      fun encodeSlice slice = encode64 (Word8VectorSlice.base slice)
91    
92      end (* local *)      end (* local *)
93    
94      (* raised if a Base64 string does not end in a complete encoding quantum (i.e., 4
95       * characters including padding characters).
96       *)
97        exception Incomplete
98    
99      (* raised if an invalid Base64 character is encountered during decode.  The int
100       * is the position of the character and the char is the invalid character.
101       *)
102        exception Invalid of (int * char)
103    
104    (* decoding tags *)    (* decoding tags *)
105      val errCode : W8.word = 0w255      val errCode : W8.word = 0w255
106      val padCode : W8.word = 0w65      val padCode : W8.word = 0w65
# Line 101  Line 114 
114              ins(spCode, #"\n");              ins(spCode, #"\n");
115              ins(spCode, #"\r");              ins(spCode, #"\r");
116              ins(spCode, #" ");              ins(spCode, #" ");
117              (* add pad code *)
118                ins(padCode, padChar);
119            (* add decoding codes *)            (* add decoding codes *)
120              CharVector.appi (fn (i, c) => ins(Word8.fromInt i, c)) encTbl;              CharVector.appi (fn (i, c) => ins(Word8.fromInt i, c)) encTbl;
121            (* convert to vector *)            (* convert to vector *)
122              W8V.tabulate (256, fn i => W8A.sub(tbl, i))              W8V.tabulate (256, fn i => W8A.sub(tbl, i))
123            end            end
124        val strictDecTbl = let
125              val tbl = W8A.array(256, errCode)
126              fun ins (w, c) = W8A.update(tbl, Char.ord c, w)
127              in
128              (* add pad code *)
129                ins(padCode, padChar);
130              (* add decoding codes *)
131                CharVector.appi (fn (i, c) => ins(Word8.fromInt i, c)) encTbl;
132              (* convert to vector *)
133                W8V.tabulate (256, fn i => W8A.sub(tbl, i))
134              end
135    
136        fun decode64 decTbl (s, start, len) = let
137              fun getc i = if (i < len)
138                    then let
139                      val c = String.sub(s, start+i)
140                      val b = W8V.sub(decTbl, Char.ord c)
141                      in
142                        if (b = errCode) then raise Invalid(i, c)
143                        else if (b = spCode) then getc (i+1)
144    (* FIXME: we need a better way to handle padding, which should only occur at the end of the string *)
145                        else if (b = padCode) then (0w0, i+1)
146                        else (b, i+1)
147                      end
148                    else raise Incomplete
149            (* compute upper bound on number of output bytes *)
150              val nBytes = 3 * Word.toIntX(Word.>>(Word.fromInt len + 0w3, 0w2))
151              val buffer = W8A.array(nBytes, 0w0)
152              fun cvt (inIdx, outIdx) = if (inIdx < len)
153                    then let
154                      val (c0, i) = getc inIdx
155                      val (c1, i) = getc inIdx
156                      val (c2, i) = getc inIdx
157                      val (c3, i) = getc inIdx
158                      val b0 = W8.orb(W8.<<(c0, 0w2), W8.>>(c1, 0w4))
159                      val b1 = W8.orb(W8.<<(c1, 0w4), W8.>>(c2, 0w2))
160                      val b2 = W8.orb(W8.<<(c2, 0w6), c3)
161                      in
162                        W8A.update(buffer, outIdx, b0);
163                        W8A.update(buffer, outIdx+1, b1);
164                        W8A.update(buffer, outIdx+2, b2);
165                        cvt (i, outIdx+3)
166                      end
167                    else outIdx
168              val outLen = cvt (0, 0) handle Subscript => raise Incomplete
169              in
170                Word8ArraySlice.vector(Word8ArraySlice.slice(buffer, 0, SOME outLen))
171              end
172    
173        fun decode s = decode64 decTbl (s, 0, size s)
174        fun decodeSlice ss = decode64 decTbl (Substring.base ss)
175    
176        fun decodeStrict s = decode64 strictDecTbl (s, 0, size s)
177        fun decodeSliceStrict ss = decode64 strictDecTbl (Substring.base ss)
178    
179    end    end

Legend:
Removed from v.3760  
changed lines
  Added in v.3761

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0