This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
ext/ + -Wall
[perl5.git] / ext / MIME / Base64 / Base64.xs
CommitLineData
2c1098f1 1/*
6fba102d
JH
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
7d85a32c
JH
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
JH
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
6fba102d
JH
38
39#define MAX_LINE 76 /* size of encoded lines */
40
41static char basis_64[] =
42 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
43
44#define XX 255 /* illegal base64 char */
45#define EQ 254 /* padding */
46#define INVALID XX
47
48static unsigned char index_64[256] = {
49 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
50 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
51 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63,
52 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,EQ,XX,XX,
53 XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
54 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX,
55 XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
56 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX,
57
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,
60 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
61 XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX,
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};
67
68
69
70MODULE = MIME::Base64 PACKAGE = MIME::Base64
71
72SV*
73encode_base64(sv,...)
74 SV* sv
75 PROTOTYPE: $;$
76
77 PREINIT:
78 char *str; /* string to encode */
79 SSize_t len; /* length of the string */
80 char *eol; /* the end-of-line sequence to use */
81 STRLEN eollen; /* length of the EOL sequence */
82 char *r; /* result string */
83 STRLEN rlen; /* length of result string */
84 unsigned char c1, c2, c3;
85 int chunk;
86
87 CODE:
6fba102d 88 sv_utf8_downgrade(sv, FALSE);
6fba102d
JH
89 str = SvPV(sv, rlen); /* SvPV(sv, len) gives warning for signed len */
90 len = (SSize_t)rlen;
91
92 /* set up EOL from the second argument if present, default to "\n" */
93 if (items > 1 && SvOK(ST(1))) {
94 eol = SvPV(ST(1), eollen);
95 } else {
96 eol = "\n";
97 eollen = 1;
98 }
99
100 /* calculate the length of the result */
101 rlen = (len+2) / 3 * 4; /* encoded bytes */
102 if (rlen) {
103 /* add space for EOL */
104 rlen += ((rlen-1) / MAX_LINE + 1) * eollen;
105 }
106
107 /* allocate a result buffer */
108 RETVAL = newSV(rlen ? rlen : 1);
109 SvPOK_on(RETVAL);
110 SvCUR_set(RETVAL, rlen);
111 r = SvPVX(RETVAL);
112
113 /* encode */
114 for (chunk=0; len > 0; len -= 3, chunk++) {
115 if (chunk == (MAX_LINE/4)) {
116 char *c = eol;
117 char *e = eol + eollen;
118 while (c < e)
119 *r++ = *c++;
120 chunk = 0;
121 }
122 c1 = *str++;
123 c2 = *str++;
124 *r++ = basis_64[c1>>2];
125 *r++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)];
126 if (len > 2) {
127 c3 = *str++;
128 *r++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)];
129 *r++ = basis_64[c3 & 0x3F];
130 } else if (len == 2) {
131 *r++ = basis_64[(c2 & 0xF) << 2];
132 *r++ = '=';
133 } else { /* len == 1 */
134 *r++ = '=';
135 *r++ = '=';
136 }
137 }
138 if (rlen) {
139 /* append eol to the result string */
140 char *c = eol;
141 char *e = eol + eollen;
142 while (c < e)
143 *r++ = *c++;
144 }
145 *r = '\0'; /* every SV in perl should be NUL-terminated */
146
147 OUTPUT:
148 RETVAL
149
150SV*
151decode_base64(sv)
152 SV* sv
153 PROTOTYPE: $
154
155 PREINIT:
156 STRLEN len;
7d85a32c 157 register unsigned char *str = (unsigned char*)SvPVbyte(sv, len);
6fba102d
JH
158 unsigned char const* end = str + len;
159 char *r;
160 unsigned char c[4];
161
162 CODE:
163 {
164 /* always enough, but might be too much */
165 STRLEN rlen = len * 3 / 4;
166 RETVAL = newSV(rlen ? rlen : 1);
167 }
168 SvPOK_on(RETVAL);
169 r = SvPVX(RETVAL);
170
171 while (str < end) {
172 int i = 0;
173 do {
7d85a32c 174 unsigned char uc = index_64[NATIVE_TO_ASCII(*str++)];
6fba102d
JH
175 if (uc != INVALID)
176 c[i++] = uc;
177
178 if (str == end) {
179 if (i < 4) {
180 if (i && PL_dowarn)
181 warn("Premature end of base64 data");
182 if (i < 2) goto thats_it;
183 if (i == 2) c[2] = EQ;
184 c[3] = EQ;
185 }
186 break;
187 }
188 } while (i < 4);
7d85a32c 189
6fba102d
JH
190 if (c[0] == EQ || c[1] == EQ) {
191 if (PL_dowarn) warn("Premature padding of base64 data");
192 break;
193 }
c6c619a9 194 /* printf("c0=%d,c1=%d,c2=%d,c3=%d\n", c[0],c[1],c[2],c[3]);*/
6fba102d
JH
195
196 *r++ = (c[0] << 2) | ((c[1] & 0x30) >> 4);
197
198 if (c[2] == EQ)
199 break;
200 *r++ = ((c[1] & 0x0F) << 4) | ((c[2] & 0x3C) >> 2);
201
202 if (c[3] == EQ)
203 break;
204 *r++ = ((c[2] & 0x03) << 6) | c[3];
205 }
206
207 thats_it:
208 SvCUR_set(RETVAL, r - SvPVX(RETVAL));
209 *r = '\0';
210
211 OUTPUT:
212 RETVAL