1 /*
2 * "streamable kanji code filter and converter"
3 * Copyright (c) 1998-2002 HappySize, Inc. All rights reserved.
4 *
5 * LICENSE NOTICES
6 *
7 * This file is part of "streamable kanji code filter and converter",
8 * which is distributed under the terms of GNU Lesser General Public
9 * License (version 2) as published by the Free Software Foundation.
10 *
11 * This software is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with "streamable kanji code filter and converter";
18 * if not, write to the Free Software Foundation, Inc., 59 Temple Place,
19 * Suite 330, Boston, MA 02111-1307 USA
20 *
21 * The author of this file:
22 *
23 */
24 /*
25 * The source code included in this files was separated from mbfilter.c
26 * by Moriyoshi Koizumi <moriyoshi@php.net> on 4 Dec 2002. The file
27 * mbfilter.c is included in this package .
28 *
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "mbfilter.h"
36 #include "mbfilter_base64.h"
37
38 const mbfl_encoding mbfl_encoding_base64 = {
39 mbfl_no_encoding_base64,
40 "BASE64",
41 "BASE64",
42 NULL,
43 NULL,
44 MBFL_ENCTYPE_ENC_STRM | MBFL_ENCTYPE_GL_UNSAFE,
45 NULL,
46 NULL
47 };
48
49 const struct mbfl_convert_vtbl vtbl_8bit_b64 = {
50 mbfl_no_encoding_8bit,
51 mbfl_no_encoding_base64,
52 mbfl_filt_conv_common_ctor,
53 mbfl_filt_conv_common_dtor,
54 mbfl_filt_conv_base64enc,
55 mbfl_filt_conv_base64enc_flush
56 };
57
58 const struct mbfl_convert_vtbl vtbl_b64_8bit = {
59 mbfl_no_encoding_base64,
60 mbfl_no_encoding_8bit,
61 mbfl_filt_conv_common_ctor,
62 mbfl_filt_conv_common_dtor,
63 mbfl_filt_conv_base64dec,
64 mbfl_filt_conv_base64dec_flush
65 };
66
67
68 #define CK(statement) do { if ((statement) < 0) return (-1); } while (0)
69
70 /*
71 * any => BASE64
72 */
73 static const unsigned char mbfl_base64_table[] = {
74 /* 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', */
75 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,
76 /* 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', */
77 0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,
78 /* 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', */
79 0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,
80 /* 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', */
81 0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,
82 /* '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' */
83 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x2b,0x2f,0x00
84 };
85
mbfl_filt_conv_base64enc(int c,mbfl_convert_filter * filter)86 int mbfl_filt_conv_base64enc(int c, mbfl_convert_filter *filter)
87 {
88 int n;
89
90 n = (filter->status & 0xff);
91 if (n == 0) {
92 filter->status++;
93 filter->cache = (c & 0xff) << 16;
94 } else if (n == 1) {
95 filter->status++;
96 filter->cache |= (c & 0xff) << 8;
97 } else {
98 filter->status &= ~0xff;
99 if ((filter->status & MBFL_BASE64_STS_MIME_HEADER) == 0) {
100 n = (filter->status & 0xff00) >> 8;
101 if (n > 72) {
102 CK((*filter->output_function)(0x0d, filter->data)); /* CR */
103 CK((*filter->output_function)(0x0a, filter->data)); /* LF */
104 filter->status &= ~0xff00;
105 }
106 filter->status += 0x400;
107 }
108 n = filter->cache | (c & 0xff);
109 CK((*filter->output_function)(mbfl_base64_table[(n >> 18) & 0x3f], filter->data));
110 CK((*filter->output_function)(mbfl_base64_table[(n >> 12) & 0x3f], filter->data));
111 CK((*filter->output_function)(mbfl_base64_table[(n >> 6) & 0x3f], filter->data));
112 CK((*filter->output_function)(mbfl_base64_table[n & 0x3f], filter->data));
113 }
114
115 return c;
116 }
117
mbfl_filt_conv_base64enc_flush(mbfl_convert_filter * filter)118 int mbfl_filt_conv_base64enc_flush(mbfl_convert_filter *filter)
119 {
120 int status, cache, len;
121
122 status = filter->status & 0xff;
123 cache = filter->cache;
124 len = (filter->status & 0xff00) >> 8;
125 filter->status &= ~0xffff;
126 filter->cache = 0;
127 /* flush fragments */
128 if (status >= 1) {
129 if ((filter->status & MBFL_BASE64_STS_MIME_HEADER) == 0) {
130 if (len > 72){
131 CK((*filter->output_function)(0x0d, filter->data)); /* CR */
132 CK((*filter->output_function)(0x0a, filter->data)); /* LF */
133 }
134 }
135 CK((*filter->output_function)(mbfl_base64_table[(cache >> 18) & 0x3f], filter->data));
136 CK((*filter->output_function)(mbfl_base64_table[(cache >> 12) & 0x3f], filter->data));
137 if (status == 1) {
138 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
139 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
140 } else {
141 CK((*filter->output_function)(mbfl_base64_table[(cache >> 6) & 0x3f], filter->data));
142 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
143 }
144 }
145 return 0;
146 }
147
148 /*
149 * BASE64 => any
150 */
mbfl_filt_conv_base64dec(int c,mbfl_convert_filter * filter)151 int mbfl_filt_conv_base64dec(int c, mbfl_convert_filter *filter)
152 {
153 int n;
154
155 if (c == 0x0d || c == 0x0a || c == 0x20 || c == 0x09 || c == 0x3d) { /* CR or LF or SPACE or HTAB or '=' */
156 return c;
157 }
158
159 n = 0;
160 if (c >= 0x41 && c <= 0x5a) { /* A - Z */
161 n = c - 65;
162 } else if (c >= 0x61 && c <= 0x7a) { /* a - z */
163 n = c - 71;
164 } else if (c >= 0x30 && c <= 0x39) { /* 0 - 9 */
165 n = c + 4;
166 } else if (c == 0x2b) { /* '+' */
167 n = 62;
168 } else if (c == 0x2f) { /* '/' */
169 n = 63;
170 }
171 n &= 0x3f;
172
173 switch (filter->status) {
174 case 0:
175 filter->status = 1;
176 filter->cache = n << 18;
177 break;
178 case 1:
179 filter->status = 2;
180 filter->cache |= n << 12;
181 break;
182 case 2:
183 filter->status = 3;
184 filter->cache |= n << 6;
185 break;
186 default:
187 filter->status = 0;
188 n |= filter->cache;
189 CK((*filter->output_function)((n >> 16) & 0xff, filter->data));
190 CK((*filter->output_function)((n >> 8) & 0xff, filter->data));
191 CK((*filter->output_function)(n & 0xff, filter->data));
192 break;
193 }
194
195 return c;
196 }
197
mbfl_filt_conv_base64dec_flush(mbfl_convert_filter * filter)198 int mbfl_filt_conv_base64dec_flush(mbfl_convert_filter *filter)
199 {
200 int status, cache;
201
202 status = filter->status;
203 cache = filter->cache;
204 filter->status = 0;
205 filter->cache = 0;
206 /* flush fragments */
207 if (status >= 2) {
208 CK((*filter->output_function)((cache >> 16) & 0xff, filter->data));
209 if (status >= 3) {
210 CK((*filter->output_function)((cache >> 8) & 0xff, filter->data));
211 }
212 }
213 return 0;
214 }
215