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 /* ASCII85Decode filter */
18 #include "std.h"
19 #include "strimpl.h"
20 #include "sa85d.h"
21 #include "scanchar.h"
22
23 /* ------ ASCII85Decode ------ */
24
25 private_st_A85D_state();
26
27 /* Initialize the state */
28 static int
s_A85D_init(stream_state * st)29 s_A85D_init(stream_state * st)
30 {
31 stream_A85D_state *const ss = (stream_A85D_state *) st;
32
33 s_A85D_init_inline(ss);
34 return 0;
35 }
36
37 /* Process a buffer */
38 static int a85d_finish(int, ulong, stream_cursor_write *);
39 static int
s_A85D_process(stream_state * st,stream_cursor_read * pr,stream_cursor_write * pw,bool last)40 s_A85D_process(stream_state * st, stream_cursor_read * pr,
41 stream_cursor_write * pw, bool last)
42 {
43 stream_A85D_state *const ss = (stream_A85D_state *) st;
44 register const byte *p = pr->ptr;
45 register byte *q = pw->ptr;
46 /* stop processing early unless the target is empty (last == true) */
47 /* to make sure we consume the EOD marker correctly. The EOD marker */
48 /* might be as many as 6 characters after the last valid data char */
49 /* D <cr> <lf> '~' <cr> <lf> '>' where 'D' is a data character. */
50 const byte *rlimit = pr->limit - (last ? 0 : 7); /* max EOD len + 1 */
51 const byte *r = max(p, rlimit);
52 byte *wlimit = pw->limit;
53 int ccount = ss->odd;
54 ulong word = ss->word;
55 int status = 0;
56
57 /* scan to make sure that an EOD isn't fully contained in the */
58 /* last part of the buffer (between rlimit and pr->limit). */
59 while (r < pr->limit) {
60 if (*++r == '~')
61 while (r < pr->limit)
62 if (*++r == '>') {
63 /* we have both characters of a complete EOD. */
64 rlimit = pr->limit; /* go ahead and process everything */
65 r = rlimit; /* break out of the while loops */
66 break;
67 }
68 }
69 while (p < rlimit) {
70 int ch = *++p;
71 uint ccode = ch - '!';
72
73 if (ccode < 85) { /* catches ch < '!' as well */
74 if (ccount == 4) {
75 /*
76 * We've completed a 32-bit group. Make sure we have
77 * room for it in the output.
78 */
79 if (wlimit - q < 4) {
80 p--;
81 status = 1;
82 break;
83 }
84 /* Check for overflow condition, throw ioerror if so */
85 if (word >= 0x03030303 && ccode > 0) {
86 status = ERRC;
87 break;
88 }
89 word = word * 85 + ccode;
90 q[1] = (byte) (word >> 24);
91 q[2] = (byte) (word >> 16);
92 q[3] = (byte) ((uint) word >> 8);
93 q[4] = (byte) word;
94 q += 4;
95 word = 0;
96 ccount = 0;
97 } else {
98 word = word * 85 + ccode;
99 ++ccount;
100 }
101 } else if (ch == 'z' && ccount == 0) {
102 if (wlimit - q < 4) {
103 p--;
104 status = 1;
105 break;
106 }
107 q[1] = q[2] = q[3] = q[4] = 0,
108 q += 4;
109 } else if (scan_char_decoder[ch] == ctype_space)
110 DO_NOTHING;
111 else if (ch == '~') {
112 int i = 1;
113
114 rlimit = pr->limit; /* Here we use the real "limit" */
115 /* Handle odd bytes. */
116 if (p == rlimit) {
117 if (!last)
118 p--;
119 else if (ss->pdf_rules)
120 goto finish;
121 else
122 status = ERRC;
123 break;
124 }
125 if ((int)(wlimit - q) < ccount - 1) {
126 status = 1;
127 p--;
128 break;
129 }
130
131 /* According to PLRM 3rd, if the A85 filter encounters '~',
132 * the next character must be '>'.
133 * And any other characters should raise an ioerror.
134 * But Adobe Acrobat allows CR/LF between ~ and >.
135 * So we allow CR/LF between them. */
136 /* PDF further relaxes the requirements and accepts bare '~'.
137 */
138 while ((p[i] == 13 || p[i] == 10) && (p+i <= rlimit))
139 i++;
140 if (p[i] != '>') {
141 if (ss->pdf_rules) {
142 if (p[i] == 13 || p[i] == 10) {
143 if (!last)
144 break;
145 } else {
146 p--;
147 }
148 } else {
149 if (p+i == rlimit) {
150 if (last)
151 status = ERRC;
152 else
153 p--; /* we'll see the '~' after filling the buffer */
154 }
155 break;
156 }
157 }
158 finish:
159 p += i; /* advance to the '>' */
160 pw->ptr = q;
161 status = a85d_finish(ccount, word, pw);
162 q = pw->ptr;
163 break;
164 } else { /* syntax error or exception */
165 status = ERRC;
166 break;
167 }
168 }
169 pw->ptr = q;
170 if (status == 0 && last) {
171 if ((int)(wlimit - q) < ccount - 1)
172 status = 1;
173 else if (ss->require_eod)
174 status = ERRC;
175 else
176 status = a85d_finish(ccount, word, pw);
177 }
178 pr->ptr = p;
179 ss->odd = ccount;
180 ss->word = word;
181 return status;
182 }
183 /* Handle the end of input data. */
184 static int
a85d_finish(int ccount,ulong word,stream_cursor_write * pw)185 a85d_finish(int ccount, ulong word, stream_cursor_write * pw)
186 {
187 /* Assume there is enough room in the output buffer! */
188 byte *q = pw->ptr;
189 int status = EOFC;
190
191 switch (ccount) {
192 case 0:
193 break;
194 case 1: /* syntax error */
195 status = ERRC;
196 break;
197 case 2: /* 1 odd byte */
198 word = word * (85L * 85 * 85) + 85L * 85 * 85 - 1L;
199 goto o1;
200 case 3: /* 2 odd bytes */
201 word = word * (85L * 85) + 85L * 85L - 1L;
202 goto o2;
203 case 4: /* 3 odd bytes */
204 word = word * 85L + 84L;
205 q[3] = (byte) (word >> 8);
206 o2: q[2] = (byte) (word >> 16);
207 o1: q[1] = (byte) (word >> 24);
208 q += ccount - 1;
209 pw->ptr = q;
210 }
211 return status;
212 }
213
214 /* Stream template */
215 const stream_template s_A85D_template = {
216 &st_A85D_state, s_A85D_init, s_A85D_process, 2, 4
217 };
218