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