3 Copyright 1997-2004 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.
28 #define PERL_NO_GET_CONTEXT /* we want efficiency */
33 #define MAX_LINE 76 /* size of encoded lines */
35 static const char basis_64[] =
36 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
38 #define XX 255 /* illegal base64 char */
39 #define EQ 254 /* padding */
42 static const unsigned char index_64[256] = {
43 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
44 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
45 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
46 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
47 XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
48 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
49 XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
50 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
52 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
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,XX, XX,XX,XX,XX,
56 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
57 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
58 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
59 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
63 # if PERL_REVISION == 5 && PERL_VERSION < 7
64 /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
66 # define SvPVbyte(sv, lp) \
67 ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
68 ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
70 my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
72 sv_utf8_downgrade(sv,0);
77 # define SvPVbyte SvPV
81 # define isXDIGIT isxdigit
84 #ifndef NATIVE_TO_ASCII
85 # define NATIVE_TO_ASCII(ch) (ch)
88 MODULE = MIME::Base64 PACKAGE = MIME::Base64
96 char *str; /* string to encode */
97 SSize_t len; /* length of the string */
98 const char*eol;/* the end-of-line sequence to use */
99 STRLEN eollen; /* length of the EOL sequence */
100 char *r; /* result string */
101 STRLEN rlen; /* length of result string */
102 unsigned char c1, c2, c3;
107 #if PERL_REVISION == 5 && PERL_VERSION >= 6
108 had_utf8 = SvUTF8(sv);
109 sv_utf8_downgrade(sv, FALSE);
111 str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
114 /* set up EOL from the second argument if present, default to "\n" */
115 if (items > 1 && SvOK(ST(1))) {
116 eol = SvPV(ST(1), eollen);
122 /* calculate the length of the result */
123 rlen = (len+2) / 3 * 4; /* encoded bytes */
125 /* add space for EOL */
126 rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
129 /* allocate a result buffer */
130 RETVAL = newSV(rlen ? rlen : 1);
132 SvCUR_set(RETVAL, rlen);
136 for (chunk=0; len > 0; len -= 3, chunk++) {
137 if (chunk == (MAX_LINE/4)) {
139 const char *e = eol + eollen;
145 c2 = len > 1 ? *str++ : '\0';
146 *r++ = basis_64[c1>>2];
147 *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
150 *r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
151 *r++ = basis_64[c3 & 0x3F];
152 } else if (len == 2) {
153 *r++ = basis_64[(c2 & 0xF) << 2];
155 } else { /* len == 1 */
161 /* append eol to the result string */
163 const char *e = eol + eollen;
167 *r = '\0'; /* every SV in perl should be NUL-terminated */
168 #if PERL_REVISION == 5 && PERL_VERSION >= 6
183 register unsigned char *str = (unsigned char*)SvPV(sv, len);
184 unsigned char const* end = str + len;
190 /* always enough, but might be too much */
191 STRLEN rlen = len * 3 / 4;
192 RETVAL = newSV(rlen ? rlen : 1);
200 unsigned char uc = index_64[NATIVE_TO_ASCII(*str++)];
206 if (i < 2) goto thats_it;
207 if (i == 2) c[2] = EQ;
214 if (c[0] == EQ || c[1] == EQ) {
217 /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);*/
219 *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
223 *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
227 *r++ = ((c[2] & 0x03) << 6) | c[3];
231 SvCUR_set(RETVAL, r - SvPVX(RETVAL));
238 encoded_base64_length(sv,...)
243 SSize_t len; /* length of the string */
244 STRLEN eollen; /* length of the EOL sequence */
248 #if PERL_REVISION == 5 && PERL_VERSION >= 6
249 had_utf8 = SvUTF8(sv);
250 sv_utf8_downgrade(sv, FALSE);
253 #if PERL_REVISION == 5 && PERL_VERSION >= 6
258 if (items > 1 && SvOK(ST(1))) {
259 eollen = SvCUR(ST(1));
264 RETVAL = (len+2) / 3 * 4; /* encoded bytes */
266 RETVAL += ((RETVAL-1) / MAX_LINE + 1) * eollen;
273 decoded_base64_length(sv)
279 register unsigned char *str = (unsigned char*)SvPV(sv, len);
280 unsigned char const* end = str + len;
286 unsigned char uc = index_64[NATIVE_TO_ASCII(*str++)];
302 MODULE = MIME::Base64 PACKAGE = MIME::QuotedPrint
305 #define qp_isplain(c) ((c) == '\t' || ((!isprint(c) && (c) != '=')))
307 #define qp_isplain(c) ((c) == '\t' || (((c) >= ' ' && (c) <= '~') && (c) != '='))
329 #if PERL_REVISION == 5 && PERL_VERSION >= 6
330 had_utf8 = SvUTF8(sv);
331 sv_utf8_downgrade(sv, FALSE);
333 /* set up EOL from the second argument if present, default to "\n" */
334 if (items > 1 && SvOK(ST(1))) {
335 eol = SvPV(ST(1), eol_len);
341 binary = (items > 2 && SvTRUE(ST(2)));
343 beg = SvPV(sv, sv_len);
346 RETVAL = newSV(sv_len + 1);
347 sv_setpv(RETVAL, "");
354 /* skip past as much plain text as possible */
355 while (p < end && qp_isplain(*p)) {
358 if (p == end || *p == '\n') {
359 /* whitespace at end of line must be encoded */
360 while (p > p_beg && (*(p - 1) == '\t' || *(p - 1) == ' '))
366 /* output plain text (with line breaks) */
368 while (p_len > MAX_LINE - 1 - linelen) {
369 STRLEN len = MAX_LINE - 1 - linelen;
370 sv_catpvn(RETVAL, p_beg, len);
373 sv_catpvn(RETVAL, "=", 1);
374 sv_catpvn(RETVAL, eol, eol_len);
379 sv_catpvn(RETVAL, p_beg, p_len);
387 else if (*p == '\n' && eol_len && !binary) {
388 if (linelen == 1 && SvCUR(RETVAL) > eol_len + 1 && (SvEND(RETVAL)-eol_len)[-2] == '=') {
389 /* fixup useless soft linebreak */
390 (SvEND(RETVAL)-eol_len)[-2] = SvEND(RETVAL)[-1];
391 SvCUR_set(RETVAL, SvCUR(RETVAL) - 1);
394 sv_catpvn(RETVAL, eol, eol_len);
400 /* output escaped char (with line breaks) */
402 if (eol_len && linelen > MAX_LINE - 4 && !(linelen == MAX_LINE - 3 && p + 1 < end && p[1] == '\n' && !binary)) {
403 sv_catpvn(RETVAL, "=", 1);
404 sv_catpvn(RETVAL, eol, eol_len);
407 sv_catpvf(RETVAL, "=%02X", (unsigned char)*p);
412 /* optimize reallocs a bit */
413 if (SvLEN(RETVAL) > 80 && SvLEN(RETVAL) - SvCUR(RETVAL) < 3) {
414 STRLEN expected_len = (SvCUR(RETVAL) * sv_len) / (p - beg);
415 SvGROW(RETVAL, expected_len);
419 if (SvCUR(RETVAL) && eol_len && linelen) {
420 sv_catpvn(RETVAL, "=", 1);
421 sv_catpvn(RETVAL, eol, eol_len);
423 #if PERL_REVISION == 5 && PERL_VERSION >= 6
438 char *str = SvPVbyte(sv, len);
439 char const* end = str + len;
441 char *whitespace = 0;
444 RETVAL = newSV(len ? len : 1);
448 if (*str == ' ' || *str == '\t') {
453 else if (*str == '\r' && (str + 1) < end && str[1] == '\n') {
456 else if (*str == '\n') {
462 while (whitespace < str) {
463 *r++ = *whitespace++;
468 if ((str + 2) < end && isXDIGIT(str[1]) && isXDIGIT(str[2])) {
474 *r++ = (char)strtol(buf, 0, 16);
477 /* look for soft line break */
479 while (p < end && (*p == ' ' || *p == '\t'))
481 if (p < end && *p == '\n')
483 else if ((p + 1) < end && *p == '\r' && *(p + 1) == '\n')
486 *r++ = *str++; /* give up */
495 while (whitespace < str) {
496 *r++ = *whitespace++;
500 SvCUR_set(RETVAL, r - SvPVX(RETVAL));
506 MODULE = MIME::Base64 PACKAGE = MIME::Base64