Various EBCDIC fixes:
[p5sagit/p5-mst-13.2.git] / ext / MIME / Base64 / Base64.xs
CommitLineData
6fba102d 1/* $Id: Base64.xs,v 1.18 2001/02/24 06:27:01 gisle Exp $
2
3Copyright 1997-1999,2001 Gisle Aas
4
5This library is free software; you can redistribute it and/or
6modify it under the same terms as Perl itself.
7
8
9The tables and some of the code that used to be here was borrowed from
10metamail, which comes with this message:
11
12 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
13
5ad8ef52 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",
6fba102d 23 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
24
25*/
26
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31#include "EXTERN.h"
32#include "perl.h"
33#include "XSUB.h"
34#ifdef __cplusplus
35}
36#endif
37
38#include "patchlevel.h"
39#if PATCHLEVEL <= 4 && !defined(PL_dowarn)
40 #define PL_dowarn dowarn
41#endif
42
43#define MAX_LINE 76 /* size of encoded lines */
44
45static char basis_64[] =
46 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
47
48#define XX 255 /* illegal base64 char */
49#define EQ 254 /* padding */
50#define INVALID XX
51
52static 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,
61
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,
70};
71
72
73
74MODULE = MIME::Base64 PACKAGE = MIME::Base64
75
76SV*
77encode_base64(sv,...)
78 SV* sv
79 PROTOTYPE: $;$
80
81 PREINIT:
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;
89 int chunk;
90
91 CODE:
92#ifdef sv_utf8_downgrade
93 sv_utf8_downgrade(sv, FALSE);
94#endif
95 str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
96 len = (SSize_t)rlen;
97
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);
101 } else {
102 eol = "\n";
103 eollen = 1;
104 }
105
106 /* calculate the length of the result */
107 rlen = (len+2) / 3 * 4; /* encoded bytes */
108 if (rlen) {
109 /* add space for EOL */
110 rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
111 }
112
113 /* allocate a result buffer */
114 RETVAL = newSV(rlen ? rlen : 1);
115 SvPOK_on(RETVAL);
116 SvCUR_set(RETVAL, rlen);
117 r = SvPVX(RETVAL);
118
119 /* encode */
120 for (chunk=0; len > 0; len -= 3, chunk++) {
121 if (chunk == (MAX_LINE/4)) {
122 char *c = eol;
123 char *e = eol + eollen;
124 while (c < e)
125 *r++ = *c++;
126 chunk = 0;
127 }
128 c1 = *str++;
129 c2 = *str++;
130 *r++ = basis_64[c1>>2];
131 *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
132 if (len > 2) {
133 c3 = *str++;
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];
138 *r++ = '=';
139 } else { /* len == 1 */
140 *r++ = '=';
141 *r++ = '=';
142 }
143 }
144 if (rlen) {
145 /* append eol to the result string */
146 char *c = eol;
147 char *e = eol + eollen;
148 while (c < e)
149 *r++ = *c++;
150 }
151 *r = '\0'; /* every SV in perl should be NUL-terminated */
152
153 OUTPUT:
154 RETVAL
155
156SV*
157decode_base64(sv)
158 SV* sv
159 PROTOTYPE: $
160
161 PREINIT:
162 STRLEN len;
5ad8ef52 163 register unsigned char *str = (unsigned char*)SvPVbyte(sv, len);
6fba102d 164 unsigned char const* end = str + len;
165 char *r;
166 unsigned char c[4];
167
168 CODE:
169 {
170 /* always enough, but might be too much */
171 STRLEN rlen = len * 3 / 4;
172 RETVAL = newSV(rlen ? rlen : 1);
173 }
174 SvPOK_on(RETVAL);
175 r = SvPVX(RETVAL);
176
177 while (str < end) {
178 int i = 0;
179 do {
5ad8ef52 180 unsigned char uc = index_64[NATIVE_TO_ASCII(*str++)];
6fba102d 181 if (uc != INVALID)
182 c[i++] = uc;
183
184 if (str == end) {
185 if (i < 4) {
186 if (i && PL_dowarn)
187 warn("Premature end of base64 data");
188 if (i < 2) goto thats_it;
189 if (i == 2) c[2] = EQ;
190 c[3] = EQ;
191 }
192 break;
193 }
194 } while (i < 4);
5ad8ef52 195
6fba102d 196 if (c[0] == EQ || c[1] == EQ) {
197 if (PL_dowarn) warn("Premature padding of base64 data");
198 break;
199 }
200 /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);/**/
201
202 *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
203
204 if (c[2] == EQ)
205 break;
206 *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
207
208 if (c[3] == EQ)
209 break;
210 *r++ = ((c[2] & 0x03) << 6) | c[3];
211 }
212
213 thats_it:
214 SvCUR_set(RETVAL, r - SvPVX(RETVAL));
215 *r = '\0';
216
217 OUTPUT:
218 RETVAL