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_uuencode.h"
36
37 const mbfl_encoding mbfl_encoding_uuencode = {
38 mbfl_no_encoding_uuencode,
39 "UUENCODE",
40 "x-uuencode",
41 NULL,
42 NULL,
43 MBFL_ENCTYPE_SBCS
44 };
45
46 const struct mbfl_convert_vtbl vtbl_uuencode_8bit = {
47 mbfl_no_encoding_uuencode,
48 mbfl_no_encoding_8bit,
49 mbfl_filt_conv_common_ctor,
50 mbfl_filt_conv_common_dtor,
51 mbfl_filt_conv_uudec,
52 mbfl_filt_conv_common_flush
53 };
54
55 #define CK(statement) do { if ((statement) < 0) return (-1); } while (0)
56
57 /* uuencode => any */
58 #define UUDEC(c) (char)(((c)-' ')&077)
59 static const char * uuenc_begin_text = "begin ";
60 enum { uudec_state_ground=0, uudec_state_inbegin,
61 uudec_state_until_newline,
62 uudec_state_size, uudec_state_a, uudec_state_b, uudec_state_c, uudec_state_d,
63 uudec_state_skip_newline};
64
mbfl_filt_conv_uudec(int c,mbfl_convert_filter * filter)65 int mbfl_filt_conv_uudec(int c, mbfl_convert_filter * filter)
66 {
67 int n;
68
69 switch(filter->status) {
70 case uudec_state_ground:
71 /* looking for "begin 0666 filename\n" line */
72 if (filter->cache == 0 && c == 'b')
73 {
74 filter->status = uudec_state_inbegin;
75 filter->cache = 1; /* move to 'e' */
76 }
77 else if (c == '\n')
78 filter->cache = 0;
79 else
80 filter->cache++;
81 break;
82 case uudec_state_inbegin:
83 if (uuenc_begin_text[filter->cache++] != c) {
84 /* doesn't match pattern */
85 filter->status = uudec_state_ground;
86 break;
87 }
88 if (filter->cache == 5)
89 {
90 /* thats good enough - wait for a newline */
91 filter->status = uudec_state_until_newline;
92 filter->cache = 0;
93 }
94 break;
95 case uudec_state_until_newline:
96 if (c == '\n')
97 filter->status = uudec_state_size;
98 break;
99 case uudec_state_size:
100 /* get "size" byte */
101 n = UUDEC(c);
102 filter->cache = n << 24;
103 filter->status = uudec_state_a;
104 break;
105 case uudec_state_a:
106 /* get "a" byte */
107 n = UUDEC(c);
108 filter->cache |= (n << 16);
109 filter->status = uudec_state_b;
110 break;
111 case uudec_state_b:
112 /* get "b" byte */
113 n = UUDEC(c);
114 filter->cache |= (n << 8);
115 filter->status = uudec_state_c;
116 break;
117 case uudec_state_c:
118 /* get "c" byte */
119 n = UUDEC(c);
120 filter->cache |= n;
121 filter->status = uudec_state_d;
122 break;
123 case uudec_state_d:
124 /* get "d" byte */
125 {
126 int A, B, C, D = UUDEC(c);
127 A = (filter->cache >> 16) & 0xff;
128 B = (filter->cache >> 8) & 0xff;
129 C = (filter->cache) & 0xff;
130 n = (filter->cache >> 24) & 0xff;
131 if (n-- > 0)
132 CK((*filter->output_function)( (A << 2) | (B >> 4), filter->data));
133 if (n-- > 0)
134 CK((*filter->output_function)( (B << 4) | (C >> 2), filter->data));
135 if (n-- > 0)
136 CK((*filter->output_function)( (C << 6) | D, filter->data));
137 filter->cache = n << 24;
138
139 if (n == 0)
140 filter->status = uudec_state_skip_newline; /* skip next byte (newline) */
141 else
142 filter->status = uudec_state_a; /* go back to fetch "A" byte */
143 }
144 break;
145 case uudec_state_skip_newline:
146 /* skip newline */
147 filter->status = uudec_state_size;
148 }
149 return c;
150 }
151