1 /* base64 interface for XEmacs.
2 Copyright (C) 1998 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> */
32 #include "file-coding.h"
35 unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
37 DEFUN ("base64-encode", Fbase64_encode, 1, 5, 0, /*
38 Return the base64 encoding of an object.
39 OBJECT is either a string or a buffer.
40 Optional arguments START and END denote buffer positions for computing the
41 hash of a portion of OBJECT. The optional CODING argument specifies the coding
42 system the text is to be represented in while computing the digest. This only
43 has meaning with MULE, and defaults to the current format of the data.
44 If ERROR-ME-NOT is nil, report an error if the coding system can't be
45 determined. Else assume binary coding if all else fails.
47 (object, start, end, coding, error_me_not))
49 int cols,bits,char_count;
50 Lisp_Object instream, outstream,deststream;
51 Lstream *istr, *ostr, *dstr;
52 static Extbyte_dynarr *conversion_out_dynarr;
53 static Extbyte_dynarr *out_dynarr;
54 char tempbuf[1024]; /* some random amount */
55 struct gcpro gcpro1, gcpro2;
57 Lisp_Object conv_out_stream, coding_system;
62 if (!conversion_out_dynarr)
63 conversion_out_dynarr = Dynarr_new (Extbyte);
65 Dynarr_reset (conversion_out_dynarr);
68 out_dynarr = Dynarr_new(Extbyte);
70 Dynarr_reset (out_dynarr);
72 char_count = bits = cols = 0;
74 /* set up the in stream */
77 struct buffer *b = decode_buffer (object, 1);
79 /* Figure out where we need to get info from */
80 get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL);
82 instream = make_lisp_buffer_input_stream (b, begv, endv, 0);
86 Bytecount bstart, bend;
87 CHECK_STRING (object);
88 get_string_range_byte (object, start, end, &bstart, &bend,
89 GB_HISTORICAL_STRING_BEHAVIOR);
90 instream = make_lisp_string_input_stream (object, bstart, bend);
92 istr = XLSTREAM (instream);
95 /* Find out what format the buffer will be saved in, so we can make
96 the digest based on what it will look like on disk */
101 /* Use the file coding for this buffer by default */
102 coding_system = XBUFFER(object)->buffer_file_coding_system;
106 /* attempt to autodetect the coding of the string. Note: this VERY hit-and-miss */
107 enum eol_type eol = EOL_AUTODETECT;
108 coding_system = Fget_coding_system(Qundecided);
109 determine_real_coding_system(istr, &coding_system, &eol);
111 if (NILP(coding_system))
112 coding_system = Fget_coding_system(Qbinary);
115 coding_system = Ffind_coding_system (coding_system);
116 if (NILP(coding_system))
117 coding_system = Fget_coding_system(Qbinary);
122 coding_system = Ffind_coding_system (coding);
123 if (NILP(coding_system))
125 if (NILP(error_me_not))
126 signal_simple_error("No such coding system", coding);
128 coding_system = Fget_coding_system(Qbinary); /* default to binary */
133 /* setup the out stream */
134 outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
135 ostr = XLSTREAM (outstream);
136 deststream = make_dynarr_output_stream((unsigned_char_dynarr *)out_dynarr);
137 dstr = XLSTREAM (deststream);
139 /* setup the conversion stream */
140 conv_out_stream = make_encoding_output_stream (ostr, coding_system);
141 costr = XLSTREAM (conv_out_stream);
142 GCPRO3 (instream, outstream, conv_out_stream);
144 GCPRO2 (instream, outstream);
147 /* Get the data while doing the conversion */
149 int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
153 /* It does seem the flushes are necessary... */
155 Lstream_write (costr, tempbuf, size_in_bytes);
156 Lstream_flush (costr);
158 Lstream_write (ostr, tempbuf, size_in_bytes);
160 Lstream_flush (ostr);
162 /* Update the base64 output buffer */
163 for (l = 0; l < size_in_bytes; l++) {
164 bits += Dynarr_at(conversion_out_dynarr,l);
166 if (char_count == 3) {
168 obuf[0] = alphabet[(bits >> 18)];
169 obuf[1] = alphabet[(bits >> 12) & 0x3f];
170 obuf[2] = alphabet[(bits >> 6) & 0x3f];
171 obuf[3] = alphabet[bits & 0x3f];
173 Lstream_write(dstr,obuf,sizeof(obuf));
176 Lstream_write(dstr,"\n",sizeof(unsigned char));
179 bits = char_count = 0;
184 /* reset the dynarr */
185 Lstream_rewind(ostr);
187 Lstream_close (istr);
189 Lstream_close (costr);
191 Lstream_close (ostr);
193 if (char_count != 0) {
194 bits <<= 16 - (8 * char_count);
195 Lstream_write(dstr,&alphabet[bits >> 18],sizeof(unsigned char));
196 Lstream_write(dstr,&alphabet[(bits >> 12) & 0x3f],sizeof(unsigned char));
197 if (char_count == 1) {
198 Lstream_write(dstr,"==",2 * sizeof(unsigned char));
200 Lstream_write(dstr,&alphabet[(bits >> 6) & 0x3f],sizeof(unsigned char));
201 Lstream_write(dstr,"=",sizeof(unsigned char));
206 Lstream_write(dstr,"\n",sizeof(unsigned char));
210 Lstream_delete (istr);
211 Lstream_delete (ostr);
213 Lstream_delete (costr);
216 Lstream_delete(dstr);
218 return(make_string(Dynarr_atp(out_dynarr,0),Dynarr_length(out_dynarr)));
221 DEFUN ("base64-decode", Fbase64_decode, 1, 5, 0, /*
222 Undo the base64 encoding of an object.
223 OBJECT is either a string or a buffer.
224 Optional arguments START and END denote buffer positions for computing the
225 hash of a portion of OBJECT. The optional CODING argument specifies the coding
226 system the text is to be represented in while computing the digest. This only
227 has meaning with MULE, and defaults to the current format of the data.
228 If ERROR-ME-NOT is nil, report an error if the coding system can't be
229 determined. Else assume binary coding if all else fails.
231 (object, start, end, coding, error_me_not))
233 static char inalphabet[256], decoder[256];
234 int i,cols,bits,char_count,hit_eof;
235 Lisp_Object instream, outstream,deststream;
236 Lstream *istr, *ostr, *dstr;
237 static Extbyte_dynarr *conversion_out_dynarr;
238 static Extbyte_dynarr *out_dynarr;
239 char tempbuf[1024]; /* some random amount */
240 struct gcpro gcpro1, gcpro2;
242 Lisp_Object conv_out_stream, coding_system;
247 for (i = (sizeof alphabet) - 1; i >= 0 ; i--) {
248 inalphabet[alphabet[i]] = 1;
249 decoder[alphabet[i]] = i;
252 if (!conversion_out_dynarr)
253 conversion_out_dynarr = Dynarr_new (Extbyte);
255 Dynarr_reset (conversion_out_dynarr);
258 out_dynarr = Dynarr_new(Extbyte);
260 Dynarr_reset (out_dynarr);
262 char_count = bits = cols = hit_eof = 0;
264 /* set up the in stream */
265 if (BUFFERP (object))
267 struct buffer *b = decode_buffer (object, 1);
269 /* Figure out where we need to get info from */
270 get_buffer_range_char (b, start, end, &begv, &endv, GB_ALLOW_NIL);
272 instream = make_lisp_buffer_input_stream (b, begv, endv, 0);
276 Bytecount bstart, bend;
277 CHECK_STRING (object);
278 get_string_range_byte (object, start, end, &bstart, &bend,
279 GB_HISTORICAL_STRING_BEHAVIOR);
280 instream = make_lisp_string_input_stream (object, bstart, bend);
282 istr = XLSTREAM (instream);
285 /* Find out what format the buffer will be saved in, so we can make
286 the digest based on what it will look like on disk */
291 /* Use the file coding for this buffer by default */
292 coding_system = XBUFFER(object)->buffer_file_coding_system;
296 /* attempt to autodetect the coding of the string. Note: this VERY hit-and-miss */
297 enum eol_type eol = EOL_AUTODETECT;
298 coding_system = Fget_coding_system(Qundecided);
299 determine_real_coding_system(istr, &coding_system, &eol);
301 if (NILP(coding_system))
302 coding_system = Fget_coding_system(Qbinary);
305 coding_system = Ffind_coding_system (coding_system);
306 if (NILP(coding_system))
307 coding_system = Fget_coding_system(Qbinary);
312 coding_system = Ffind_coding_system (coding);
313 if (NILP(coding_system))
315 if (NILP(error_me_not))
316 signal_simple_error("No such coding system", coding);
318 coding_system = Fget_coding_system(Qbinary); /* default to binary */
323 /* setup the out stream */
324 outstream = make_dynarr_output_stream((unsigned_char_dynarr *)conversion_out_dynarr);
325 ostr = XLSTREAM (outstream);
326 deststream = make_dynarr_output_stream((unsigned_char_dynarr *)out_dynarr);
327 dstr = XLSTREAM (deststream);
329 /* setup the conversion stream */
330 conv_out_stream = make_encoding_output_stream (ostr, coding_system);
331 costr = XLSTREAM (conv_out_stream);
332 GCPRO3 (instream, outstream, conv_out_stream);
334 GCPRO2 (instream, outstream);
337 /* Get the data while doing the conversion */
339 int size_in_bytes = Lstream_read (istr, tempbuf, sizeof (tempbuf));
341 if (!size_in_bytes) {
345 /* It does seem the flushes are necessary... */
347 Lstream_write (costr, tempbuf, size_in_bytes);
348 Lstream_flush (costr);
350 Lstream_write (ostr, tempbuf, size_in_bytes);
352 Lstream_flush (ostr);
354 /* Update the base64 output buffer */
355 for (l = 0; l < size_in_bytes; l++) {
356 if (Dynarr_at(conversion_out_dynarr,l) == '=')
358 bits += decoder[Dynarr_at(conversion_out_dynarr,l)];
359 fprintf(stderr,"%d\n",bits);
361 if (char_count == 4) {
362 static unsigned char obuf[3];
363 obuf[0] = (bits >> 16);
364 obuf[1] = (bits >> 8) & 0xff;
365 obuf[2] = (bits & 0xff);
367 Lstream_write(dstr,obuf,sizeof(obuf));
368 bits = char_count = 0;
373 /* reset the dynarr */
374 Lstream_rewind(ostr);
377 Lstream_close (istr);
379 Lstream_close (costr);
381 Lstream_close (ostr);
385 error_with_frob(object,"base64-decode failed: at least %d bits truncated",((4 - char_count) * 6));
390 error_with_frob(object, "base64 encoding incomplete: at least 2 bits missing");
393 char_count = bits >> 10;
394 Lstream_write(dstr,&char_count,sizeof(char_count));
398 unsigned char buf[2];
399 buf[0] = (bits >> 16);
400 buf[1] = (bits >> 8) & 0xff;
401 Lstream_write(dstr,buf,sizeof(buf));
407 Lstream_delete (istr);
408 Lstream_delete (ostr);
410 Lstream_delete (costr);
413 Lstream_delete(dstr);
415 return(make_string(Dynarr_atp(out_dynarr,0),Dynarr_length(out_dynarr)));
421 DEFSUBR(Fbase64_encode);
422 DEFSUBR(Fbase64_decode);
428 Fprovide (intern ("base64"));