1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* BCP and TBCP filters */
18 #include "stdio_.h"
19 #include "strimpl.h"
20 #include "sbcp.h"
21
22 #define CtrlA 0x01
23 #define CtrlC 0x03
24 #define CtrlD 0x04
25 #define CtrlE 0x05
26 #define CtrlQ 0x11
27 #define CtrlS 0x13
28 #define CtrlT 0x14
29 #define ESC 0x1b
30 #define CtrlBksl 0x1c
31
32 /* The following is not used yet. */
33 /*static const char *TBCP_end_protocol_string = "\033%-12345X";*/
34
35 /* ------ BCPEncode and TBCPEncode ------ */
36
37 /* Process a buffer */
38 static int
s_xBCPE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last,const byte * escaped)39 s_xBCPE_process(stream_state * st, stream_cursor_read * pr,
40 stream_cursor_write * pw, bool last, const byte * escaped)
41 {
42 const byte *p = pr->ptr;
43 const byte *rlimit = pr->limit;
44 uint rcount = rlimit - p;
45 byte *q = pw->ptr;
46 uint wcount = pw->limit - q;
47 const byte *end = p + min(rcount, wcount);
48
49 while (p < end) {
50 byte ch = *++p;
51
52 if (ch <= 31 && escaped[ch]) {
53 if (p == rlimit) {
54 p--;
55 break;
56 }
57 *++q = CtrlA;
58 ch ^= 0x40;
59 if (--wcount < rcount)
60 end--;
61 }
62 *++q = ch;
63 }
64 pr->ptr = p;
65 pw->ptr = q;
66 return (p == rlimit ? 0 : 1);
67 }
68
69 /* Actual process procedures */
70 static int
s_BCPE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)71 s_BCPE_process(stream_state * st, stream_cursor_read * pr,
72 stream_cursor_write * pw, bool last)
73 {
74 static const byte escaped[32] =
75 {
76 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
78 };
79
80 return s_xBCPE_process(st, pr, pw, last, escaped);
81 }
82 static int
s_TBCPE_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)83 s_TBCPE_process(stream_state * st, stream_cursor_read * pr,
84 stream_cursor_write * pw, bool last)
85 {
86 static const byte escaped[32] =
87 {
88 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0
90 };
91
92 return s_xBCPE_process(st, pr, pw, last, escaped);
93 }
94
95 /* Stream templates */
96 const stream_template s_BCPE_template =
97 {&st_stream_state, NULL, s_BCPE_process, 1, 2
98 };
99 const stream_template s_TBCPE_template =
100 {&st_stream_state, NULL, s_TBCPE_process, 1, 2
101 };
102
103 /* ------ BCPDecode and TBCPDecode ------ */
104
105 private_st_BCPD_state();
106
107 /* Initialize the state */
108 static int
s_BCPD_init(stream_state * st)109 s_BCPD_init(stream_state * st)
110 {
111 stream_BCPD_state *const ss = (stream_BCPD_state *) st;
112
113 ss->escaped = 0;
114 ss->matched = ss->copy_count = 0;
115 return 0;
116 }
117
118 /* Process a buffer */
119 static int
s_xBCPD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last,bool tagged)120 s_xBCPD_process(stream_state * st, stream_cursor_read * pr,
121 stream_cursor_write * pw, bool last, bool tagged)
122 {
123 stream_BCPD_state *const ss = (stream_BCPD_state *) st;
124 const byte *p = pr->ptr;
125 const byte *rlimit = pr->limit;
126 byte *q = pw->ptr;
127 byte *wlimit = pw->limit;
128 int copy_count = ss->copy_count;
129 int status;
130 bool escaped = ss->escaped;
131
132 for (;;) {
133 byte ch;
134
135 if (copy_count) {
136 if (q == wlimit) {
137 status = (p < rlimit ? 1 : 0);
138 break;
139 }
140 *++q = *++(ss->copy_ptr);
141 copy_count--;
142 continue;
143 }
144 if (p == rlimit) {
145 status = 0;
146 break;
147 }
148 ch = *++p;
149 if (ch <= 31)
150 switch (ch) {
151 case CtrlA:
152 if (escaped) {
153 status = ERRC;
154 goto out;
155 }
156 escaped = true;
157 continue;
158 case CtrlC:
159 status = (*ss->signal_interrupt) (st);
160 if (status < 0)
161 goto out;
162 continue;
163 case CtrlD:
164 if (escaped) {
165 status = ERRC;
166 goto out;
167 }
168 status = EOFC;
169 goto out;
170 case CtrlE:
171 continue;
172 case CtrlQ:
173 continue;
174 case CtrlS:
175 continue;
176 case CtrlT:
177 status = (*ss->request_status) (st);
178 if (status < 0)
179 goto out;
180 continue;
181 case CtrlBksl:
182 continue;
183 }
184 if (q == wlimit) {
185 p--;
186 status = 1;
187 break;
188 }
189 if (escaped) {
190 escaped = false;
191 switch (ch) {
192 case '[':
193 if (!tagged) {
194 status = ERRC;
195 goto out;
196 }
197 /* falls through */
198 case 'A':
199 case 'C':
200 case 'D':
201 case 'E':
202 case 'Q':
203 case 'S':
204 case 'T':
205 case '\\':
206 ch ^= 0x40;
207 break;
208 case 'M':
209 if (!tagged) {
210 status = ERRC;
211 goto out;
212 }
213 continue;
214 default:
215 status = ERRC;
216 goto out;
217 }
218 }
219 *++q = ch;
220 }
221 out:ss->copy_count = copy_count;
222 ss->escaped = escaped;
223 pr->ptr = p;
224 pw->ptr = q;
225 return status;
226 }
227
228 /* Actual process procedures */
229 static int
s_BCPD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)230 s_BCPD_process(stream_state * st, stream_cursor_read * pr,
231 stream_cursor_write * pw, bool last)
232 {
233 return s_xBCPD_process(st, pr, pw, last, false);
234 }
235 static int
s_TBCPD_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)236 s_TBCPD_process(stream_state * st, stream_cursor_read * pr,
237 stream_cursor_write * pw, bool last)
238 {
239 return s_xBCPD_process(st, pr, pw, last, true);
240 }
241
242 /* Stream templates */
243 const stream_template s_BCPD_template =
244 {&st_BCPD_state, s_BCPD_init, s_BCPD_process, 1, 1,
245 NULL, NULL, s_BCPD_init
246 };
247 const stream_template s_TBCPD_template =
248 {&st_BCPD_state, s_BCPD_init, s_TBCPD_process, 1, 1,
249 NULL, NULL, s_BCPD_init
250 };
251