summaryrefslogtreecommitdiff
path: root/ext/MIME-Base64/Base64.xs
diff options
context:
space:
mode:
Diffstat (limited to 'ext/MIME-Base64/Base64.xs')
-rw-r--r--ext/MIME-Base64/Base64.xs457
1 files changed, 457 insertions, 0 deletions
diff --git a/ext/MIME-Base64/Base64.xs b/ext/MIME-Base64/Base64.xs
new file mode 100644
index 0000000000..afbad93c52
--- /dev/null
+++ b/ext/MIME-Base64/Base64.xs
@@ -0,0 +1,457 @@
+/* $Id: Base64.xs,v 3.5 2005/11/26 10:44:14 gisle Exp $
+
+Copyright 1997-2004 Gisle Aas
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+
+The tables and some of the code that used to be here was borrowed from
+metamail, which comes with this message:
+
+ Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
+
+ Permission to use, copy, modify, and distribute this material
+ for any purpose and without fee is hereby granted, provided
+ that the above copyright notice and this permission notice
+ appear in all copies, and that the name of Bellcore not be
+ used in advertising or publicity pertaining to this
+ material without the specific, prior written permission
+ of an authorized representative of Bellcore. BELLCORE
+ MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
+ OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
+ WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
+
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define PERL_NO_GET_CONTEXT /* we want efficiency */
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#ifdef __cplusplus
+}
+#endif
+
+#ifndef PATCHLEVEL
+# include <patchlevel.h>
+# if !(defined(PERL_VERSION) || (SUBVERSION > 0 && defined(PATCHLEVEL)))
+# include <could_not_find_Perl_patchlevel.h>
+# endif
+#endif
+
+#if PATCHLEVEL <= 4 && !defined(PL_dowarn)
+ #define PL_dowarn dowarn
+#endif
+
+#ifdef G_WARN_ON
+ #define DOWARN (PL_dowarn & G_WARN_ON)
+#else
+ #define DOWARN PL_dowarn
+#endif
+
+
+#define MAX_LINE 76 /* size of encoded lines */
+
+static const char basis_64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define XX 255 /* illegal base64 char */
+#define EQ 254 /* padding */
+#define INVALID XX
+
+static const unsigned char index_64[256] = {
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
+ 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
+ XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
+ XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
+
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+ XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
+};
+
+#ifdef SvPVbyte
+# if PERL_REVISION == 5 && PERL_VERSION < 7
+ /* SvPVbyte does not work in perl-5.6.1, borrowed version for 5.7.3 */
+# undef SvPVbyte
+# define SvPVbyte(sv, lp) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : my_sv_2pvbyte(aTHX_ sv, &lp))
+ static char *
+ my_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+ {
+ sv_utf8_downgrade(sv,0);
+ return SvPV(sv,*lp);
+ }
+# endif
+#else
+# define SvPVbyte SvPV
+#endif
+
+#ifndef isXDIGIT
+# define isXDIGIT isxdigit
+#endif
+
+#ifndef NATIVE_TO_ASCII
+# define NATIVE_TO_ASCII(ch) (ch)
+#endif
+
+MODULE = MIME::Base64 PACKAGE = MIME::Base64
+
+SV*
+encode_base64(sv,...)
+ SV* sv
+ PROTOTYPE: $;$
+
+ PREINIT:
+ char *str; /* string to encode */
+ SSize_t len; /* length of the string */
+ char *eol; /* the end-of-line sequence to use */
+ STRLEN eollen; /* length of the EOL sequence */
+ char *r; /* result string */
+ STRLEN rlen; /* length of result string */
+ unsigned char c1, c2, c3;
+ int chunk;
+
+ CODE:
+#if PERL_REVISION == 5 && PERL_VERSION >= 6
+ sv_utf8_downgrade(sv, FALSE);
+#endif
+ str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
+ len = (SSize_t)rlen;
+
+ /* set up EOL from the second argument if present, default to "\n" */
+ if (items > 1 && SvOK(ST(1))) {
+ eol = SvPV(ST(1), eollen);
+ } else {
+ eol = "\n";
+ eollen = 1;
+ }
+
+ /* calculate the length of the result */
+ rlen = (len+2) / 3 * 4; /* encoded bytes */
+ if (rlen) {
+ /* add space for EOL */
+ rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
+ }
+
+ /* allocate a result buffer */
+ RETVAL = newSV(rlen ? rlen : 1);
+ SvPOK_on(RETVAL);
+ SvCUR_set(RETVAL, rlen);
+ r = SvPVX(RETVAL);
+
+ /* encode */
+ for (chunk=0; len > 0; len -= 3, chunk++) {
+ if (chunk == (MAX_LINE/4)) {
+ char *c = eol;
+ char *e = eol + eollen;
+ while (c < e)
+ *r++ = *c++;
+ chunk = 0;
+ }
+ c1 = *str++;
+ c2 = len > 1 ? *str++ : '\0';
+ *r++ = basis_64[c1>>2];
+ *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
+ if (len > 2) {
+ c3 = *str++;
+ *r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
+ *r++ = basis_64[c3 & 0x3F];
+ } else if (len == 2) {
+ *r++ = basis_64[(c2 & 0xF) << 2];
+ *r++ = '=';
+ } else { /* len == 1 */
+ *r++ = '=';
+ *r++ = '=';
+ }
+ }
+ if (rlen) {
+ /* append eol to the result string */
+ char *c = eol;
+ char *e = eol + eollen;
+ while (c < e)
+ *r++ = *c++;
+ }
+ *r = '\0'; /* every SV in perl should be NUL-terminated */
+
+ OUTPUT:
+ RETVAL
+
+SV*
+decode_base64(sv)
+ SV* sv
+ PROTOTYPE: $
+
+ PREINIT:
+ STRLEN len;
+ register unsigned char *str = (unsigned char*)SvPVbyte(sv, len);
+ unsigned char const* end = str + len;
+ char *r;
+ unsigned char c[4];
+
+ CODE:
+ {
+ /* always enough, but might be too much */
+ STRLEN rlen = len * 3 / 4;
+ RETVAL = newSV(rlen ? rlen : 1);
+ }
+ SvPOK_on(RETVAL);
+ r = SvPVX(RETVAL);
+
+ while (str < end) {
+ int i = 0;
+ do {
+ unsigned char uc = index_64[NATIVE_TO_ASCII(*str++)];
+ if (uc != INVALID)
+ c[i++] = uc;
+
+ if (str == end) {
+ if (i < 4) {
+ if (i && DOWARN)
+ warn("Premature end of base64 data");
+ if (i < 2) goto thats_it;
+ if (i == 2) c[2] = EQ;
+ c[3] = EQ;
+ }
+ break;
+ }
+ } while (i < 4);
+
+ if (c[0] == EQ || c[1] == EQ) {
+ if (DOWARN) warn("Premature padding of base64 data");
+ break;
+ }
+ /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);*/
+
+ *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
+
+ if (c[2] == EQ)
+ break;
+ *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
+
+ if (c[3] == EQ)
+ break;
+ *r++ = ((c[2] & 0x03) << 6) | c[3];
+ }
+
+ thats_it:
+ SvCUR_set(RETVAL, r - SvPVX(RETVAL));
+ *r = '\0';
+
+ OUTPUT:
+ RETVAL
+
+
+MODULE = MIME::Base64 PACKAGE = MIME::QuotedPrint
+
+#ifdef EBCDIC
+#define qp_isplain(c) ((c) == '\t' || ((!isprint(c) && (c) != '=')))
+#else
+#define qp_isplain(c) ((c) == '\t' || (((c) >= ' ' && (c) <= '~') && (c) != '='))
+#endif
+
+SV*
+encode_qp(sv,...)
+ SV* sv
+ PROTOTYPE: $;$$
+
+ PREINIT:
+ char *eol;
+ STRLEN eol_len;
+ int binary;
+ STRLEN sv_len;
+ STRLEN linelen;
+ char *beg;
+ char *end;
+ char *p;
+ char *p_beg;
+ STRLEN p_len;
+
+ CODE:
+#if PERL_REVISION == 5 && PERL_VERSION >= 6
+ sv_utf8_downgrade(sv, FALSE);
+#endif
+ /* set up EOL from the second argument if present, default to "\n" */
+ if (items > 1 && SvOK(ST(1))) {
+ eol = SvPV(ST(1), eol_len);
+ } else {
+ eol = "\n";
+ eol_len = 1;
+ }
+
+ binary = (items > 2 && SvTRUE(ST(2)));
+
+ beg = SvPV(sv, sv_len);
+ end = beg + sv_len;
+
+ RETVAL = newSV(sv_len + 1);
+ sv_setpv(RETVAL, "");
+ linelen = 0;
+
+ p = beg;
+ while (1) {
+ p_beg = p;
+
+ /* skip past as much plain text as possible */
+ while (p < end && qp_isplain(*p)) {
+ p++;
+ }
+ if (p == end || *p == '\n') {
+ /* whitespace at end of line must be encoded */
+ while (p > p_beg && (*(p - 1) == '\t' || *(p - 1) == ' '))
+ p--;
+ }
+
+ p_len = p - p_beg;
+ if (p_len) {
+ /* output plain text (with line breaks) */
+ if (eol_len) {
+ STRLEN max_last_line = (p == end || *p == '\n')
+ ? MAX_LINE /* .......\n */
+ : ((p + 1) == end || *(p + 1) == '\n')
+ ? MAX_LINE - 3 /* ....=XX\n */
+ : MAX_LINE - 4; /* ...=XX=\n */
+ while (p_len + linelen > max_last_line) {
+ STRLEN len = MAX_LINE - 1 - linelen;
+ if (len > p_len)
+ len = p_len;
+ sv_catpvn(RETVAL, p_beg, len);
+ p_beg += len;
+ p_len -= len;
+ sv_catpvn(RETVAL, "=", 1);
+ sv_catpvn(RETVAL, eol, eol_len);
+ linelen = 0;
+ }
+ }
+ if (p_len) {
+ sv_catpvn(RETVAL, p_beg, p_len);
+ linelen += p_len;
+ }
+ }
+
+ if (p == end) {
+ break;
+ }
+ else if (*p == '\n' && eol_len && !binary) {
+ sv_catpvn(RETVAL, eol, eol_len);
+ p++;
+ linelen = 0;
+ }
+ else {
+ /* output escaped char (with line breaks) */
+ assert(p < end);
+ if (eol_len && linelen > MAX_LINE - 4) {
+ sv_catpvn(RETVAL, "=", 1);
+ sv_catpvn(RETVAL, eol, eol_len);
+ linelen = 0;
+ }
+ sv_catpvf(RETVAL, "=%02X", (unsigned char)*p);
+ p++;
+ linelen += 3;
+ }
+
+ /* optimize reallocs a bit */
+ if (SvLEN(RETVAL) > 80 && SvLEN(RETVAL) - SvCUR(RETVAL) < 3) {
+ STRLEN expected_len = (SvCUR(RETVAL) * sv_len) / (p - beg);
+ SvGROW(RETVAL, expected_len);
+ }
+ }
+
+ if (SvCUR(RETVAL) && eol_len && linelen) {
+ sv_catpvn(RETVAL, "=", 1);
+ sv_catpvn(RETVAL, eol, eol_len);
+ }
+
+ OUTPUT:
+ RETVAL
+
+SV*
+decode_qp(sv)
+ SV* sv
+ PROTOTYPE: $
+
+ PREINIT:
+ STRLEN len;
+ char *str = SvPVbyte(sv, len);
+ char const* end = str + len;
+ char *r;
+ char *whitespace = 0;
+
+ CODE:
+ RETVAL = newSV(len ? len : 1);
+ SvPOK_on(RETVAL);
+ r = SvPVX(RETVAL);
+ while (str < end) {
+ if (*str == ' ' || *str == '\t') {
+ if (!whitespace)
+ whitespace = str;
+ str++;
+ }
+ else if (*str == '\r' && (str + 1) < end && str[1] == '\n') {
+ str++;
+ }
+ else if (*str == '\n') {
+ whitespace = 0;
+ *r++ = *str++;
+ }
+ else {
+ if (whitespace) {
+ while (whitespace < str) {
+ *r++ = *whitespace++;
+ }
+ whitespace = 0;
+ }
+ if (*str == '=') {
+ if ((str + 2) < end && isXDIGIT(str[1]) && isXDIGIT(str[2])) {
+ char buf[3];
+ str++;
+ buf[0] = *str++;
+ buf[1] = *str++;
+ buf[2] = '\0';
+ *r++ = (char)strtol(buf, 0, 16);
+ }
+ else {
+ /* look for soft line break */
+ char *p = str + 1;
+ while (p < end && (*p == ' ' || *p == '\t'))
+ p++;
+ if (p < end && *p == '\n')
+ str = p + 1;
+ else if ((p + 1) < end && *p == '\r' && *(p + 1) == '\n')
+ str = p + 2;
+ else
+ *r++ = *str++; /* give up */
+ }
+ }
+ else {
+ *r++ = *str++;
+ }
+ }
+ }
+ if (whitespace) {
+ while (whitespace < str) {
+ *r++ = *whitespace++;
+ }
+ }
+ *r = '\0';
+ SvCUR_set(RETVAL, r - SvPVX(RETVAL));
+
+ OUTPUT:
+ RETVAL
+
+
+MODULE = MIME::Base64 PACKAGE = MIME::Base64