1 /* $Id: Base64.xs,v 1.32 2003/01/05 07:49:07 gisle Exp $
3 Copyright 1997-2003 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.
39 # include <patchlevel.h>
40 # if !(defined(PERL_VERSION) || (SUBVERSION > 0 && defined(PATCHLEVEL)))
41 # include <could_not_find_Perl_patchlevel.h>
45 #if PATCHLEVEL <= 4 && !defined(PL_dowarn)
46 #define PL_dowarn dowarn
49 #define MAX_LINE 76 /* size of encoded lines */
51 static char basis_64[] =
52 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
54 #define XX 255 /* illegal base64 char */
55 #define EQ 254 /* padding */
58 static unsigned char index_64[256] = {
59 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
60 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
61 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
62 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
63 XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
64 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
65 XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
66 41,42,43,44, 45,46,47,48, 49,50,51,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,
70 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
71 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
72 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
73 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
74 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
75 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
79 # if PERL_REVISION == 5 && PERL_VERSION < 7
80 /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
82 # define SvPVbyte(sv, lp) \
83 ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
84 ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
86 my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
88 sv_utf8_downgrade(sv,0);
93 # define SvPVbyte SvPV
96 #ifndef NATIVE_TO_ASCII
97 # define NATIVE_TO_ASCII(ch) (ch)
100 MODULE = MIME::Base64 PACKAGE = MIME::Base64
103 encode_base64(sv,...)
108 char *str; /* string to encode */
109 SSize_t len; /* length of the string */
110 char *eol; /* the end-of-line sequence to use */
111 STRLEN eollen; /* length of the EOL sequence */
112 char *r; /* result string */
113 STRLEN rlen; /* length of result string */
114 unsigned char c1, c2, c3;
118 #if PERL_REVISION == 5 && PERL_VERSION >= 6
119 sv_utf8_downgrade(sv, FALSE);
121 str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
124 /* set up EOL from the second argument if present, default to "\n" */
125 if (items > 1 && SvOK(ST(1))) {
126 eol = SvPV(ST(1), eollen);
132 /* calculate the length of the result */
133 rlen = (len+2) / 3 * 4; /* encoded bytes */
135 /* add space for EOL */
136 rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
139 /* allocate a result buffer */
140 RETVAL = newSV(rlen ? rlen : 1);
142 SvCUR_set(RETVAL, rlen);
146 for (chunk=0; len > 0; len -= 3, chunk++) {
147 if (chunk == (MAX_LINE/4)) {
149 char *e = eol + eollen;
156 *r++ = basis_64[c1>>2];
157 *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
160 *r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
161 *r++ = basis_64[c3 & 0x3F];
162 } else if (len == 2) {
163 *r++ = basis_64[(c2 & 0xF) << 2];
165 } else { /* len == 1 */
171 /* append eol to the result string */
173 char *e = eol + eollen;
177 *r = '\0'; /* every SV in perl should be NUL-terminated */
189 register unsigned char *str = (unsigned char*)SvPVbyte(sv, len);
190 unsigned char const* end = str + len;
196 /* always enough, but might be too much */
197 STRLEN rlen = len * 3 / 4;
198 RETVAL = newSV(rlen ? rlen : 1);
206 unsigned char uc = index_64[NATIVE_TO_ASCII(*str++)];
213 warn("Premature end of base64 data");
214 if (i < 2) goto thats_it;
215 if (i == 2) c[2] = EQ;
222 if (c[0] == EQ || c[1] == EQ) {
223 if (PL_dowarn) warn("Premature padding of base64 data");
226 /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);*/
228 *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
232 *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
236 *r++ = ((c[2] & 0x03) << 6) | c[3];
240 SvCUR_set(RETVAL, r - SvPVX(RETVAL));
247 MODULE = MIME::Base64 PACKAGE = MIME::QuotedPrint
249 #define qp_isplain(c) ((c) == '\t' || ((c) >= ' ' && (c) <= '~') && (c) != '=')
268 #if PERL_REVISION == 5 && PERL_VERSION >= 6
269 sv_utf8_downgrade(sv, FALSE);
271 /* set up EOL from the second argument if present, default to "\n" */
272 if (items > 1 && SvOK(ST(1))) {
273 eol = SvPV(ST(1), eol_len);
279 beg = SvPV(sv, sv_len);
282 RETVAL = newSV(sv_len + 1);
283 sv_setpv(RETVAL, "");
290 /* skip past as much plain text as possible */
291 while (p < end && qp_isplain(*p)) {
294 if (*p == '\n' || p == end) {
295 /* whitespace at end of line must be encoded */
296 while (p > p_beg && (*(p - 1) == '\t' || *(p - 1) == ' '))
302 /* output plain text (with line breaks) */
304 STRLEN max_last_line = (*p == '\n' || p == end)
305 ? MAX_LINE /* .......\n */
306 : (*(p + 1) == '\n' || (p + 1) == end)
307 ? MAX_LINE - 3 /* ....=XX\n */
308 : MAX_LINE - 4; /* ...=XX=\n */
309 while (p_len + linelen > max_last_line) {
310 STRLEN len = MAX_LINE - 1 - linelen;
313 sv_catpvn(RETVAL, p_beg, len);
316 sv_catpvn(RETVAL, "=", 1);
317 sv_catpvn(RETVAL, eol, eol_len);
322 sv_catpvn(RETVAL, p_beg, p_len);
328 sv_catpvn(RETVAL, eol, eol_len);
333 /* output escaped char (with line breaks) */
334 if (eol_len && linelen > MAX_LINE - 4) {
335 sv_catpvn(RETVAL, "=", 1);
336 sv_catpvn(RETVAL, eol, eol_len);
339 sv_catpvf(RETVAL, "=%02X", (unsigned char)*p);
348 /* optimize reallocs a bit */
349 if (SvLEN(RETVAL) > 80 && SvLEN(RETVAL) - SvCUR(RETVAL) < 3) {
350 STRLEN expected_len = (SvCUR(RETVAL) * sv_len) / (p - beg);
351 SvGROW(RETVAL, expected_len);
365 char *str = SvPVbyte(sv, len);
366 char const* end = str + len;
368 char *whitespace = 0;
371 RETVAL = newSV(len ? len : 1);
375 if (*str == ' ' || *str == '\t') {
380 else if (*str == '\r' && (str + 1) < end && str[1] == '\n') {
383 else if (*str == '\n') {
389 while (whitespace < str) {
390 *r++ = *whitespace++;
394 if (*str == '=' && (str + 2) < end && isxdigit(str[1]) && isxdigit(str[2])) {
400 *r++ = (char)strtol(buf, 0, 16);
402 else if (*str == '=' && (str + 1) < end && str[1] == '\n') {
405 else if (*str == '=' && (str + 2) < end && str[1] == '\r' && str[2] == '\n') {
414 SvCUR_set(RETVAL, r - SvPVX(RETVAL));
420 MODULE = MIME::Base64 PACKAGE = MIME::Base64