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