1 /* $Id: Base64.xs,v 1.18 2001/02/24 06:27:01 gisle Exp $
3 Copyright 1997-1999,2001 Gisle Aas
5 This library is free software; you can redistribute it and/or
6 modify it under the same terms as Perl itself.
9 The tables and some of the code that used to be here was borrowed from
10 metamail, which comes with this message:
12 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
14 Permission to use, copy, modify, and distribute this material
15 for any purpose and without fee is hereby granted, provided
16 that the above copyright notice and this permission notice
17 appear in all copies, and that the name of Bellcore not be
18 used in advertising or publicity pertaining to this
19 material without the specific, prior written permission
20 of an authorized representative of Bellcore. BELLCORE
21 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
22 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
23 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
38 #include "patchlevel.h"
39 #if PATCHLEVEL <= 4 && !defined(PL_dowarn)
40 #define PL_dowarn dowarn
43 #define MAX_LINE 76 /* size of encoded lines */
45 static char basis_64[] =
46 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
48 #define XX 255 /* illegal base64 char */
49 #define EQ 254 /* padding */
52 static unsigned char index_64[256] = {
53 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
54 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
55 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
56 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
57 XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
58 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
59 XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
60 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
62 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
63 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
64 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
65 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
66 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
67 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
68 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
69 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
74 MODULE = MIME::Base64 PACKAGE = MIME::Base64
82 char *str; /* string to encode */
83 SSize_t len; /* length of the string */
84 char *eol; /* the end-of-line sequence to use */
85 STRLEN eollen; /* length of the EOL sequence */
86 char *r; /* result string */
87 STRLEN rlen; /* length of result string */
88 unsigned char c1, c2, c3;
92 #ifdef sv_utf8_downgrade
93 sv_utf8_downgrade(sv, FALSE);
95 str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
98 /* set up EOL from the second argument if present, default to "\n" */
99 if (items > 1 && SvOK(ST(1))) {
100 eol = SvPV(ST(1), eollen);
106 /* calculate the length of the result */
107 rlen = (len+2) / 3 * 4; /* encoded bytes */
109 /* add space for EOL */
110 rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
113 /* allocate a result buffer */
114 RETVAL = newSV(rlen ? rlen : 1);
116 SvCUR_set(RETVAL, rlen);
120 for (chunk=0; len > 0; len -= 3, chunk++) {
121 if (chunk == (MAX_LINE/4)) {
123 char *e = eol + eollen;
130 *r++ = basis_64[c1>>2];
131 *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
134 *r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
135 *r++ = basis_64[c3 & 0x3F];
136 } else if (len == 2) {
137 *r++ = basis_64[(c2 & 0xF) << 2];
139 } else { /* len == 1 */
145 /* append eol to the result string */
147 char *e = eol + eollen;
151 *r = '\0'; /* every SV in perl should be NUL-terminated */
163 register unsigned char *str = (unsigned char*)SvPV(sv, len);
164 unsigned char const* end = str + len;
170 /* always enough, but might be too much */
171 STRLEN rlen = len * 3 / 4;
172 RETVAL = newSV(rlen ? rlen : 1);
180 unsigned char uc = index_64[*str++];
187 warn("Premature end of base64 data");
188 if (i < 2) goto thats_it;
189 if (i == 2) c[2] = EQ;
196 if (c[0] == EQ || c[1] == EQ) {
197 if (PL_dowarn) warn("Premature padding of base64 data");
200 /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);/**/
202 *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
206 *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
210 *r++ = ((c[2] & 0x03) << 6) | c[3];
214 SvCUR_set(RETVAL, r - SvPVX(RETVAL));