1 /* base64 interface for XEmacs.
2 Copyright (C) 1998, 1999 Free Software Foundation, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Not in FSF. */
23 /* Author: William Perry <wmperry@aventail.com> */
27 unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 DEFUN ("base64-encode", Fbase64_encode, 1, 5, 0, /*
30 Return the base64 encoding of an object.
31 OBJECT is either a string or a buffer.
32 Optional arguments START and END denote buffer positions for computing the
33 hash of a portion of OBJECT. The optional CODING argument specifies the coding
34 system the text is to be represented in while computing the digest. This only
35 has meaning with MULE, and defaults to the current format of the data.
36 If ERROR-ME-NOT is nil, report an error if the coding system can't be
37 determined. Else assume binary coding if all else fails.
39 (object, start, end, coding, error_me_not))
41 int cols,bits,char_count;
42 Lisp_Object instream, outstream,deststream;
43 Lstream *istr, *ostr, *dstr;
44 static Extbyte_dynarr *conversion_out_dynarr;
45 static Extbyte_dynarr *out_dynarr;
46 char tempbuf[1024]; /* some random amount */
47 struct gcpro gcpro1, gcpro2;
49 Lisp_Object conv_out_stream, coding_system;
54 if (!conversion_out_dynarr)
55 conversion_out_dynarr = Dynarr_new (Extbyte);
57 Dynarr_reset (conversion_out_dynarr);
60 out_dynarr = Dynarr_new(Extbyte);
62 Dynarr_reset (out_dynarr);
64 char_count = bits = cols = 0;
66 /* set up the in stream */
69 struct buffer *b = XBUFFER (object);
71 /* Figure out where we need to get info from */
72 get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL);
74 instream = make_lisp_buffer_input_stream (b, begv, endv, 0);
78 Bytecount bstart, bend;
79 CHECK_STRING (object);
80 get_string_range_byte (object, start, end, &bstart, &bend,
81 GB_HISTORICAL_STRING_BEHAVIOR);
82 instream = make_lisp_string_input_stream (object, bstart, bend);
84 istr = XLSTREAM (instream);
87 /* Find out what format the buffer will be saved in, so we can make
88 the digest based on what it will look like on disk */
93 /* Use the file coding for this buffer by default */
94 coding_system = XBUFFER(object)->buffer_file_coding_system;
98 /* attempt to autodetect the coding of the string. Note: this VERY hit-and-miss */
99 enum eol_type eol = EOL_AUTODETECT;
100 coding_system = Fget_coding_system(Qundecided);
101 determine_real_coding_system(istr, &coding_system, &eol);
103 if (NILP(coding_system))
104 coding_system = Fget_coding_system(Qbinary);
107 coding_system = Ffind_coding_system (coding_system);
108 if (NILP(coding_system))
109 coding_system = Fget_coding_system(Qbinary);
114 coding_system = Ffind_coding_system (coding);
115 if (NILP(coding_system))
117 if (NILP(error_me_not))
118 signal_simple_error("No such coding system", coding);
120 coding_system = Fget_coding_system(Qbinary); /* default to binary */
125 /* setup the out stream */
126 outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
127 ostr = XLSTREAM (outstream);
128 deststream = make_dynarr_output_stream((unsigned_char_dynarr *)out_dynarr);
129 dstr = XLSTREAM (deststream);
131 /* setup the conversion stream */
132 conv_out_stream = make_encoding_output_stream (ostr, coding_system);
133 costr = XLSTREAM (conv_out_stream);
134 GCPRO3 (instream, outstream, conv_out_stream);
136 GCPRO2 (instream, outstream);
139 /* Get the data while doing the conversion */
141 int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
145 /* It does seem the flushes are necessary... */
147 Lstream_write (costr, tempbuf, size_in_bytes);
148 Lstream_flush (costr);
150 Lstream_write (ostr, tempbuf, size_in_bytes);
152 Lstream_flush (ostr);
154 /* Update the base64 output buffer */
155 for (l = 0; l < size_in_bytes; l++) {
156 bits += Dynarr_at(conversion_out_dynarr,l);
158 if (char_count == 3) {
160 obuf[0] = alphabet[(bits >> 18)];
161 obuf[1] = alphabet[(bits >> 12) & 0x3f];
162 obuf[2] = alphabet[(bits >> 6) & 0x3f];
163 obuf[3] = alphabet[bits & 0x3f];
165 Lstream_write(dstr,obuf,sizeof(obuf));
168 Lstream_write(dstr,"\n",sizeof(unsigned char));
171 bits = char_count = 0;
176 /* reset the dynarr */
177 Lstream_rewind(ostr);
179 Lstream_close (istr);
181 Lstream_close (costr);
183 Lstream_close (ostr);
185 if (char_count != 0) {
186 bits <<= 16 - (8 * char_count);
187 Lstream_write(dstr,&alphabet[bits >> 18],sizeof(unsigned char));
188 Lstream_write(dstr,&alphabet[(bits >> 12) & 0x3f],sizeof(unsigned char));
189 if (char_count == 1) {
190 Lstream_write(dstr,"==",2 * sizeof(unsigned char));
192 Lstream_write(dstr,&alphabet[(bits >> 6) & 0x3f],sizeof(unsigned char));
193 Lstream_write(dstr,"=",sizeof(unsigned char));
198 Lstream_write(dstr,"\n",sizeof(unsigned char));
202 Lstream_delete (istr);
203 Lstream_delete (ostr);
205 Lstream_delete (costr);
208 Lstream_delete(dstr);
210 return(make_string(Dynarr_atp(out_dynarr,0),Dynarr_length(out_dynarr)));
213 DEFUN ("base64-decode", Fbase64_decode, 1, 5, 0, /*
214 Undo the base64 encoding of an object.
215 OBJECT is either a string or a buffer.
216 Optional arguments START and END denote buffer positions for computing the
217 hash of a portion of OBJECT. The optional CODING argument specifies the coding
218 system the text is to be represented in while computing the digest. This only
219 has meaning with MULE, and defaults to the current format of the data.
220 If ERROR-ME-NOT is nil, report an error if the coding system can't be
221 determined. Else assume binary coding if all else fails.
223 (object, start, end, coding, error_me_not))
225 static char inalphabet[256], decoder[256];
226 int i,cols,bits,char_count,hit_eof;
227 Lisp_Object instream, outstream,deststream;
228 Lstream *istr, *ostr, *dstr;
229 static Extbyte_dynarr *conversion_out_dynarr;
230 static Extbyte_dynarr *out_dynarr;
231 char tempbuf[1024]; /* some random amount */
232 struct gcpro gcpro1, gcpro2;
234 Lisp_Object conv_out_stream, coding_system;
239 for (i = (sizeof alphabet) - 1; i >= 0 ; i--) {
240 inalphabet[alphabet[i]] = 1;
241 decoder[alphabet[i]] = i;
244 if (!conversion_out_dynarr)
245 conversion_out_dynarr = Dynarr_new (Extbyte);
247 Dynarr_reset (conversion_out_dynarr);
250 out_dynarr = Dynarr_new(Extbyte);
252 Dynarr_reset (out_dynarr);
254 char_count = bits = cols = hit_eof = 0;
256 /* set up the in stream */
257 if (BUFFERP (object))
259 struct buffer *b = XBUFFER (object);
261 /* Figure out where we need to get info from */
262 get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL);
264 instream = make_lisp_buffer_input_stream (b, begv, endv, 0);
268 Bytecount bstart, bend;
269 CHECK_STRING (object);
270 get_string_range_byte (object, start, end, &bstart, &bend,
271 GB_HISTORICAL_STRING_BEHAVIOR);
272 instream = make_lisp_string_input_stream (object, bstart, bend);
274 istr = XLSTREAM (instream);
277 /* Find out what format the buffer will be saved in, so we can make
278 the digest based on what it will look like on disk */
283 /* Use the file coding for this buffer by default */
284 coding_system = XBUFFER(object)->buffer_file_coding_system;
288 /* attempt to autodetect the coding of the string. Note: this VERY hit-and-miss */
289 enum eol_type eol = EOL_AUTODETECT;
290 coding_system = Fget_coding_system(Qundecided);
291 determine_real_coding_system(istr, &coding_system, &eol);
293 if (NILP(coding_system))
294 coding_system = Fget_coding_system(Qbinary);
297 coding_system = Ffind_coding_system (coding_system);
298 if (NILP(coding_system))
299 coding_system = Fget_coding_system(Qbinary);
304 coding_system = Ffind_coding_system (coding);
305 if (NILP(coding_system))
307 if (NILP(error_me_not))
308 signal_simple_error("No such coding system", coding);
310 coding_system = Fget_coding_system(Qbinary); /* default to binary */
315 /* setup the out stream */
316 outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
317 ostr = XLSTREAM (outstream);
318 deststream = make_dynarr_output_stream((unsigned_char_dynarr *)out_dynarr);
319 dstr = XLSTREAM (deststream);
321 /* setup the conversion stream */
322 conv_out_stream = make_encoding_output_stream (ostr, coding_system);
323 costr = XLSTREAM (conv_out_stream);
324 GCPRO3 (instream, outstream, conv_out_stream);
326 GCPRO2 (instream, outstream);
329 /* Get the data while doing the conversion */
331 int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
333 if (!size_in_bytes) {
337 /* It does seem the flushes are necessary... */
339 Lstream_write (costr, tempbuf, size_in_bytes);
340 Lstream_flush (costr);
342 Lstream_write (ostr, tempbuf, size_in_bytes);
344 Lstream_flush (ostr);
346 /* Update the base64 output buffer */
347 for (l = 0; l < size_in_bytes; l++) {
348 if (Dynarr_at(conversion_out_dynarr,l) == '=')
350 bits += decoder[Dynarr_at(conversion_out_dynarr,l)];
351 fprintf(stderr,"%d\n",bits);
353 if (char_count == 4) {
354 static unsigned char obuf[3];
355 obuf[0] = (bits >> 16);
356 obuf[1] = (bits >> 8) & 0xff;
357 obuf[2] = (bits & 0xff);
359 Lstream_write(dstr,obuf,sizeof(obuf));
360 bits = char_count = 0;
365 /* reset the dynarr */
366 Lstream_rewind(ostr);
369 Lstream_close (istr);
371 Lstream_close (costr);
373 Lstream_close (ostr);
377 error_with_frob(object,"base64-decode failed: at least %d bits truncated",((4 - char_count) * 6));
382 error_with_frob(object, "base64 encoding incomplete: at least 2 bits missing");
385 char_count = bits >> 10;
386 Lstream_write(dstr,&char_count,sizeof(char_count));
390 unsigned char buf[2];
391 buf[0] = (bits >> 16);
392 buf[1] = (bits >> 8) & 0xff;
393 Lstream_write(dstr,buf,sizeof(buf));
399 Lstream_delete (istr);
400 Lstream_delete (ostr);
402 Lstream_delete (costr);
405 Lstream_delete(dstr);
407 return(make_string(Dynarr_atp(out_dynarr,0),Dynarr_length(out_dynarr)));
411 syms_of_base64 (void)
413 DEFSUBR(Fbase64_encode);
414 DEFSUBR(Fbase64_decode);
418 vars_of_base64 (void)
420 Fprovide (intern ("base64"));