Missing semi-colon
[p5sagit/p5-mst-13.2.git] / ext / MIME / Base64 / Base64.xs
index f77ba14..14c8bea 100644 (file)
@@ -1,6 +1,6 @@
-/* $Id: Base64.xs,v 1.18 2001/02/24 06:27:01 gisle Exp $
+/* $Id: Base64.xs,v 1.41 2004/01/08 14:07:26 gisle Exp $
 
-Copyright 1997-1999,2001 Gisle Aas
+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.
@@ -35,11 +35,24 @@ extern "C" {
 }
 #endif
 
-#include "patchlevel.h"
+#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 char basis_64[] =
@@ -69,7 +82,27 @@ static unsigned char index_64[256] = {
     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 NATIVE_TO_ASCII
+#   define NATIVE_TO_ASCII(ch) (ch)
+#endif
 
 MODULE = MIME::Base64          PACKAGE = MIME::Base64
 
@@ -89,7 +122,7 @@ encode_base64(sv,...)
        int chunk;
 
        CODE:
-#ifdef sv_utf8_downgrade
+#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 */
@@ -126,7 +159,7 @@ encode_base64(sv,...)
                chunk = 0;
            }
            c1 = *str++;
-           c2 = *str++;
+           c2 = len > 1 ? *str++ : '\0';
            *r++ = basis_64[c1>>2];
            *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
            if (len > 2) {
@@ -183,7 +216,7 @@ decode_base64(sv)
 
                if (str == end) {
                    if (i < 4) {
-                       if (i && PL_dowarn)
+                       if (i && DOWARN)
                            warn("Premature end of base64 data");
                        if (i < 2) goto thats_it;
                        if (i == 2) c[2] = EQ;
@@ -194,10 +227,10 @@ decode_base64(sv)
             } while (i < 4);
        
            if (c[0] == EQ || c[1] == EQ) {
-               if (PL_dowarn) warn("Premature padding of base64 data");
+               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]);/**/
+           /* 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);
 
@@ -216,3 +249,192 @@ decode_base64(sv)
 
        OUTPUT:
        RETVAL
+
+
+MODULE = MIME::Base64          PACKAGE = MIME::QuotedPrint
+
+#define qp_isplain(c) ((c) == '\t' || (((c) >= ' ' && (c) <= '~') && (c) != '='))
+
+SV*
+encode_qp(sv,...)
+       SV* sv
+       PROTOTYPE: $;$
+
+       PREINIT:
+       char *eol;
+       STRLEN eol_len;
+       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;
+       }
+
+       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) {
+               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);
+           }
+        }
+
+       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