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