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.
27 *
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include "mbfilter.h"
35 #include "mbfilter_qprint.h"
36 #include "unicode_prop.h"
37
38 static const char *mbfl_encoding_qprint_aliases[] = {"qprint", NULL};
39
40 const mbfl_encoding mbfl_encoding_qprint = {
41 mbfl_no_encoding_qprint,
42 "Quoted-Printable",
43 "Quoted-Printable",
44 (const char *(*)[])&mbfl_encoding_qprint_aliases,
45 NULL,
46 MBFL_ENCTYPE_ENC_STRM | MBFL_ENCTYPE_GL_UNSAFE
47 };
48
49 const struct mbfl_convert_vtbl vtbl_8bit_qprint = {
50 mbfl_no_encoding_8bit,
51 mbfl_no_encoding_qprint,
52 mbfl_filt_conv_common_ctor,
53 mbfl_filt_conv_common_dtor,
54 mbfl_filt_conv_qprintenc,
55 mbfl_filt_conv_qprintenc_flush };
56
57 const struct mbfl_convert_vtbl vtbl_qprint_8bit = {
58 mbfl_no_encoding_qprint,
59 mbfl_no_encoding_8bit,
60 mbfl_filt_conv_common_ctor,
61 mbfl_filt_conv_common_dtor,
62 mbfl_filt_conv_qprintdec,
63 mbfl_filt_conv_qprintdec_flush };
64
65
66 #define CK(statement) do { if ((statement) < 0) return (-1); } while (0)
67
68 /*
69 * any => Quoted-Printable
70 */
71
mbfl_filt_conv_qprintenc(int c,mbfl_convert_filter * filter)72 int mbfl_filt_conv_qprintenc(int c, mbfl_convert_filter *filter)
73 {
74 int s, n;
75
76 switch (filter->status & 0xff) {
77 case 0:
78 filter->cache = c;
79 filter->status++;
80 break;
81 default:
82 s = filter->cache;
83 filter->cache = c;
84 n = (filter->status & 0xff00) >> 8;
85
86 if (s == 0) { /* null */
87 CK((*filter->output_function)(s, filter->data));
88 filter->status &= ~0xff00;
89 break;
90 }
91
92 if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0) {
93 if (s == 0x0a || (s == 0x0d && c != 0x0a)) { /* line feed */
94 CK((*filter->output_function)(0x0d, filter->data)); /* CR */
95 CK((*filter->output_function)(0x0a, filter->data)); /* LF */
96 filter->status &= ~0xff00;
97 break;
98 } else if (s == 0x0d) {
99 break;
100 }
101 }
102
103 if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0 && n >= 72) { /* soft line feed */
104 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
105 CK((*filter->output_function)(0x0d, filter->data)); /* CR */
106 CK((*filter->output_function)(0x0a, filter->data)); /* LF */
107 filter->status &= ~0xff00;
108 }
109
110 if (s <= 0 || s >= 0x80 || s == 0x3d /* not ASCII or '=' */
111 || ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) != 0 &&
112 (mbfl_charprop_table[s] & MBFL_CHP_MMHQENC) != 0)) {
113 /* hex-octet */
114 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
115 n = (s >> 4) & 0xf;
116 if (n < 10) {
117 n += 48; /* '0' */
118 } else {
119 n += 55; /* 'A' - 10 */
120 }
121 CK((*filter->output_function)(n, filter->data));
122 n = s & 0xf;
123 if (n < 10) {
124 n += 48;
125 } else {
126 n += 55;
127 }
128 CK((*filter->output_function)(n, filter->data));
129 if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0) {
130 filter->status += 0x300;
131 }
132 } else {
133 CK((*filter->output_function)(s, filter->data));
134 if ((filter->status & MBFL_QPRINT_STS_MIME_HEADER) == 0) {
135 filter->status += 0x100;
136 }
137 }
138 break;
139 }
140
141 return c;
142 }
143
mbfl_filt_conv_qprintenc_flush(mbfl_convert_filter * filter)144 int mbfl_filt_conv_qprintenc_flush(mbfl_convert_filter *filter)
145 {
146 /* flush filter cache */
147 (*filter->filter_function)('\0', filter);
148 filter->status &= ~0xffff;
149 filter->cache = 0;
150 return 0;
151 }
152
153 /*
154 * Quoted-Printable => any
155 */
mbfl_filt_conv_qprintdec(int c,mbfl_convert_filter * filter)156 int mbfl_filt_conv_qprintdec(int c, mbfl_convert_filter *filter)
157 {
158 int n, m;
159
160 static int hex2code_map[] = {
161 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
162 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
163 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
164 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
165 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
166 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
167 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
168 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
169 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
170 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
171 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
172 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
173 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
174 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
175 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
176 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
177 };
178
179 switch (filter->status) {
180 case 1:
181 if (hex2code_map[c & 0xff] >= 0) {
182 filter->cache = c;
183 filter->status = 2;
184 } else if (c == 0x0d) { /* soft line feed */
185 filter->status = 3;
186 } else if (c == 0x0a) { /* soft line feed */
187 filter->status = 0;
188 } else {
189 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
190 CK((*filter->output_function)(c, filter->data));
191 filter->status = 0;
192 }
193 break;
194 case 2:
195 m = hex2code_map[c & 0xff];
196 if (m < 0) {
197 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
198 CK((*filter->output_function)(filter->cache, filter->data));
199 n = c;
200 } else {
201 n = hex2code_map[filter->cache] << 4 | m;
202 }
203 CK((*filter->output_function)(n, filter->data));
204 filter->status = 0;
205 break;
206 case 3:
207 if (c != 0x0a) { /* LF */
208 CK((*filter->output_function)(c, filter->data));
209 }
210 filter->status = 0;
211 break;
212 default:
213 if (c == 0x3d) { /* '=' */
214 filter->status = 1;
215 } else {
216 CK((*filter->output_function)(c, filter->data));
217 }
218 break;
219 }
220
221 return c;
222 }
223
mbfl_filt_conv_qprintdec_flush(mbfl_convert_filter * filter)224 int mbfl_filt_conv_qprintdec_flush(mbfl_convert_filter *filter)
225 {
226 int status, cache;
227
228 status = filter->status;
229 cache = filter->cache;
230 filter->status = 0;
231 filter->cache = 0;
232 /* flush fragments */
233 if (status == 1) {
234 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
235 } else if (status == 2) {
236 CK((*filter->output_function)(0x3d, filter->data)); /* '=' */
237 CK((*filter->output_function)(cache, filter->data));
238 }
239
240 return 0;
241 }
242