1 /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: sa85d.c,v 1.9 2003/04/24 19:42:13 ray Exp $ */
18 /* ASCII85Decode filter */
19 #include "std.h"
20 #include "strimpl.h"
21 #include "sa85d.h"
22 #include "scanchar.h"
23
24 /* ------ ASCII85Decode ------ */
25
26 private_st_A85D_state();
27
28 /* Initialize the state */
29 private int
s_A85D_init(stream_state * st)30 s_A85D_init(stream_state * st)
31 {
32 stream_A85D_state *const ss = (stream_A85D_state *) st;
33
34 return s_A85D_init_inline(ss);
35 }
36
37 /* Process a buffer */
38 private int a85d_finish(int, ulong, stream_cursor_write *);
39 private 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 const byte *rlimit = pr->limit;
47 byte *wlimit = pw->limit;
48 int ccount = ss->odd;
49 ulong word = ss->word;
50 int status = 0;
51
52 while (p < rlimit) {
53 int ch = *++p;
54 uint ccode = ch - '!';
55
56 if (ccode < 85) { /* catches ch < '!' as well */
57 if (ccount == 4) {
58 /*
59 * We've completed a 32-bit group. Make sure we have
60 * room for it in the output.
61 */
62 if (wlimit - q < 4) {
63 p--;
64 status = 1;
65 break;
66 }
67 /* Check for overflow condition, throw ioerror if so */
68 if (word >= 0x03030303 && ccode > 0) {
69 status = ERRC;
70 break;
71 }
72 word = word * 85 + ccode;
73 q[1] = (byte) (word >> 24);
74 q[2] = (byte) (word >> 16);
75 q[3] = (byte) ((uint) word >> 8);
76 q[4] = (byte) word;
77 q += 4;
78 word = 0;
79 ccount = 0;
80 } else {
81 word = word * 85 + ccode;
82 ++ccount;
83 }
84 } else if (ch == 'z' && ccount == 0) {
85 if (wlimit - q < 4) {
86 p--;
87 status = 1;
88 break;
89 }
90 q[1] = q[2] = q[3] = q[4] = 0,
91 q += 4;
92 } else if (scan_char_decoder[ch] == ctype_space)
93 DO_NOTHING;
94 else if (ch == '~') {
95 int i = 1;
96
97 /* Handle odd bytes. */
98 if (p == rlimit) {
99 if (last)
100 status = ERRC;
101 else
102 p--;
103 break;
104 }
105 if ((int)(wlimit - q) < ccount - 1) {
106 status = 1;
107 p--;
108 break;
109 }
110
111 /* According to PLRM 3rd, if the A85 filter encounters '~',
112 * the next character must be '>'.
113 * And any other characters should raise an ioerror.
114 * But Adobe Acrobat allows CR/LF between ~ and >.
115 * So we allow CR/LF between them. */
116 while ((p[i] == 13 || p[i] == 10) && (p+i <= rlimit))
117 i++;
118 if (p[i] != '>') {
119 if (p+i == rlimit) {
120 if (last)
121 status = ERRC;
122 else
123 p--; /* we'll see the '~' after filling the buffer */
124 }
125 break;
126 }
127 p += i; /* advance to the '>' */
128 pw->ptr = q;
129 status = a85d_finish(ccount, word, pw);
130 q = pw->ptr;
131 break;
132 } else { /* syntax error or exception */
133 status = ERRC;
134 break;
135 }
136 }
137 pw->ptr = q;
138 if (status == 0 && last) {
139 if ((int)(wlimit - q) < ccount - 1)
140 status = 1;
141 else
142 status = a85d_finish(ccount, word, pw);
143 }
144 pr->ptr = p;
145 ss->odd = ccount;
146 ss->word = word;
147 return status;
148 }
149 /* Handle the end of input data. */
150 private int
a85d_finish(int ccount,ulong word,stream_cursor_write * pw)151 a85d_finish(int ccount, ulong word, stream_cursor_write * pw)
152 {
153 /* Assume there is enough room in the output buffer! */
154 byte *q = pw->ptr;
155 int status = EOFC;
156
157 switch (ccount) {
158 case 0:
159 break;
160 case 1: /* syntax error */
161 status = ERRC;
162 break;
163 case 2: /* 1 odd byte */
164 word = word * (85L * 85 * 85) + 85L * 85 * 85 - 1L;
165 goto o1;
166 case 3: /* 2 odd bytes */
167 word = word * (85L * 85) + 85L * 85L - 1L;
168 goto o2;
169 case 4: /* 3 odd bytes */
170 word = word * 85L + 84L;
171 q[3] = (byte) (word >> 8);
172 o2: q[2] = (byte) (word >> 16);
173 o1: q[1] = (byte) (word >> 24);
174 q += ccount - 1;
175 pw->ptr = q;
176 }
177 return status;
178 }
179
180 /* Stream template */
181 const stream_template s_A85D_template = {
182 &st_A85D_state, s_A85D_init, s_A85D_process, 2, 4
183 };
184