1 | /* $Id: Base64.xs 718 1999-10-19 02:36:47Z davidb $
|
---|
2 |
|
---|
3 | Copyright 1997-1998 Gisle Aas
|
---|
4 |
|
---|
5 | This library is free software; you can redistribute it and/or
|
---|
6 | modify it under the same terms as Perl itself.
|
---|
7 |
|
---|
8 |
|
---|
9 | The tables and some of the code that used to be here was borrowed from
|
---|
10 | metamail, which comes with this message:
|
---|
11 |
|
---|
12 | Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
|
---|
13 |
|
---|
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.
|
---|
24 |
|
---|
25 | */
|
---|
26 |
|
---|
27 |
|
---|
28 | #ifdef __cplusplus
|
---|
29 | extern "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 |
|
---|
45 | static char basis_64[] =
|
---|
46 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
---|
47 |
|
---|
48 | #define XX 255 /* illegal base64 char */
|
---|
49 | #define EQ 254 /* padding */
|
---|
50 | #define INVALID XX
|
---|
51 |
|
---|
52 | static 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 |
|
---|
74 | MODULE = MIME::Base64 PACKAGE = MIME::Base64
|
---|
75 |
|
---|
76 | SV*
|
---|
77 | encode_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 | str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
|
---|
93 | len = (SSize_t)rlen;
|
---|
94 |
|
---|
95 | /* set up EOL from the second argument if present, default to "\n" */
|
---|
96 | if (items > 1 && SvOK(ST(1))) {
|
---|
97 | eol = SvPV(ST(1), eollen);
|
---|
98 | } else {
|
---|
99 | eol = "\n";
|
---|
100 | eollen = 1;
|
---|
101 | }
|
---|
102 |
|
---|
103 | /* calculate the length of the result */
|
---|
104 | rlen = (len+2) / 3 * 4; /* encoded bytes */
|
---|
105 | if (rlen) {
|
---|
106 | /* add space for EOL */
|
---|
107 | rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
|
---|
108 | }
|
---|
109 |
|
---|
110 | /* allocate a result buffer */
|
---|
111 | RETVAL = newSV(rlen ? rlen : 1);
|
---|
112 | SvPOK_on(RETVAL);
|
---|
113 | SvCUR_set(RETVAL, rlen);
|
---|
114 | r = SvPVX(RETVAL);
|
---|
115 |
|
---|
116 | /* encode */
|
---|
117 | for (chunk=0; len > 0; len -= 3, chunk++) {
|
---|
118 | if (chunk == (MAX_LINE/4)) {
|
---|
119 | char *c = eol;
|
---|
120 | char *e = eol + eollen;
|
---|
121 | while (c < e)
|
---|
122 | *r++ = *c++;
|
---|
123 | chunk = 0;
|
---|
124 | }
|
---|
125 | c1 = *str++;
|
---|
126 | c2 = *str++;
|
---|
127 | *r++ = basis_64[c1>>2];
|
---|
128 | *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
|
---|
129 | if (len > 2) {
|
---|
130 | c3 = *str++;
|
---|
131 | *r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
|
---|
132 | *r++ = basis_64[c3 & 0x3F];
|
---|
133 | } else if (len == 2) {
|
---|
134 | *r++ = basis_64[(c2 & 0xF) << 2];
|
---|
135 | *r++ = '=';
|
---|
136 | } else { /* len == 1 */
|
---|
137 | *r++ = '=';
|
---|
138 | *r++ = '=';
|
---|
139 | }
|
---|
140 | }
|
---|
141 | if (rlen) {
|
---|
142 | /* append eol to the result string */
|
---|
143 | char *c = eol;
|
---|
144 | char *e = eol + eollen;
|
---|
145 | while (c < e)
|
---|
146 | *r++ = *c++;
|
---|
147 | }
|
---|
148 | *r = '\0'; /* every SV in perl should be NUL-terminated */
|
---|
149 |
|
---|
150 | OUTPUT:
|
---|
151 | RETVAL
|
---|
152 |
|
---|
153 | SV*
|
---|
154 | decode_base64(sv)
|
---|
155 | SV* sv
|
---|
156 | PROTOTYPE: $
|
---|
157 |
|
---|
158 | PREINIT:
|
---|
159 | STRLEN len;
|
---|
160 | register unsigned char *str = (unsigned char*)SvPV(sv, len);
|
---|
161 | unsigned char const* end = str + len;
|
---|
162 | char *r;
|
---|
163 | unsigned char c[4];
|
---|
164 |
|
---|
165 | CODE:
|
---|
166 | {
|
---|
167 | /* always enough, but might be too much */
|
---|
168 | STRLEN rlen = len * 3 / 4;
|
---|
169 | RETVAL = newSV(rlen ? rlen : 1);
|
---|
170 | }
|
---|
171 | SvPOK_on(RETVAL);
|
---|
172 | r = SvPVX(RETVAL);
|
---|
173 |
|
---|
174 | while (str < end) {
|
---|
175 | int i = 0;
|
---|
176 | do {
|
---|
177 | unsigned char uc = index_64[*str++];
|
---|
178 | if (uc != INVALID)
|
---|
179 | c[i++] = uc;
|
---|
180 |
|
---|
181 | if (str == end) {
|
---|
182 | if (i < 4) {
|
---|
183 | if (i && PL_dowarn)
|
---|
184 | warn("Premature end of base64 data");
|
---|
185 | if (i < 2) goto thats_it;
|
---|
186 | if (i == 2) c[2] = EQ;
|
---|
187 | c[3] = EQ;
|
---|
188 | }
|
---|
189 | break;
|
---|
190 | }
|
---|
191 | } while (i < 4);
|
---|
192 |
|
---|
193 | if (c[0] == EQ || c[1] == EQ) {
|
---|
194 | if (PL_dowarn) warn("Premature padding of base64 data");
|
---|
195 | break;
|
---|
196 | }
|
---|
197 | /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);/**/
|
---|
198 |
|
---|
199 | *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
|
---|
200 |
|
---|
201 | if (c[2] == EQ)
|
---|
202 | break;
|
---|
203 | *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
|
---|
204 |
|
---|
205 | if (c[3] == EQ)
|
---|
206 | break;
|
---|
207 | *r++ = ((c[2] & 0x03) << 6) | c[3];
|
---|
208 | }
|
---|
209 |
|
---|
210 | thats_it:
|
---|
211 | SvCUR_set(RETVAL, r - SvPVX(RETVAL));
|
---|
212 | *r = '\0';
|
---|
213 |
|
---|
214 | OUTPUT:
|
---|
215 | RETVAL
|
---|