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