1 /* Copyright (C) 2001-2017 Peter Selinger.
2 This file is part of Potrace. It is free software and it is covered
3 by the GNU General Public License. See the file COPYING for details. */
4
5
6 /* the PostScript compression module of Potrace. The basic interface
7 is through the *_xship function, which processes a byte array and
8 outputs it in compressed or verbatim form, depending on whether
9 filter is 1 or 0. To flush the output, simply call with the empty
10 string and filter=0. filter=2 is used to output encoded text but
11 without the PostScript header to turn on the encoding. Each
12 function has variants for shipping a single character, a
13 null-terminated string, or a byte array. */
14
15 /* different compression algorithms are available. There is
16 dummy_xship, which is just the identity, and flate_xship, which
17 uses zlib compression. Also, lzw_xship provides LZW compression
18 from the file lzw.c/h. a85_xship provides a85-encoding without
19 compression. Each function returns the actual number of characters
20 written. */
21
22 /* note: the functions provided here have global state and are not
23 reentrant */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <errno.h>
33
34 #ifdef HAVE_ZLIB
35 #include <zlib.h>
36 #endif
37
38 #include "flate.h"
39 #include "lzw.h"
40
41 #define OUTSIZE 1000
42
43 static int a85init(FILE *f);
44 static int a85finish(FILE *f);
45 static int a85write(FILE *f, const char *buf, int n);
46 static int a85out(FILE *f, int n);
47 static int a85spool(FILE *f, char c);
48
49 /* ---------------------------------------------------------------------- */
50 /* dummy interface: no encoding */
51
dummy_xship(FILE * f,int filter,const char * s,int len)52 int dummy_xship(FILE *f, int filter, const char *s, int len) {
53 fwrite(s, 1, len, f);
54 return len;
55 }
56
57 /* ---------------------------------------------------------------------- */
58 /* flate interface: zlib (=postscript level 3) compression and a85 */
59
60 #ifdef HAVE_ZLIB
61
pdf_xship(FILE * f,int filter,const char * s,int len)62 int pdf_xship(FILE *f, int filter, const char *s, int len) {
63 static int fstate = 0;
64 static z_stream c_stream;
65 char outbuf[OUTSIZE];
66 int err;
67 int n=0;
68
69 if (filter && !fstate) {
70 /* switch on filtering */
71 c_stream.zalloc = Z_NULL;
72 c_stream.zfree = Z_NULL;
73 c_stream.opaque = Z_NULL;
74 err = deflateInit(&c_stream, 9);
75 if (err != Z_OK) {
76 fprintf(stderr, "deflateInit: %s (%d)\n", c_stream.msg, err);
77 exit(2);
78 }
79 c_stream.avail_in = 0;
80 fstate = 1;
81 } else if (!filter && fstate) {
82 /* switch off filtering */
83 /* flush stream */
84 do {
85 c_stream.next_out = (Bytef*)outbuf;
86 c_stream.avail_out = OUTSIZE;
87
88 err = deflate(&c_stream, Z_FINISH);
89 if (err != Z_OK && err != Z_STREAM_END) {
90 fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
91 exit(2);
92 }
93 n += fwrite(outbuf, 1, OUTSIZE-c_stream.avail_out, f);
94 } while (err != Z_STREAM_END);
95
96 fstate = 0;
97 }
98 if (!fstate) {
99 fwrite(s, 1, len, f);
100 return n+len;
101 }
102
103 /* do the actual compression */
104 c_stream.next_in = (Bytef*) s;
105 c_stream.avail_in = len;
106
107 do {
108 c_stream.next_out = (Bytef*) outbuf;
109 c_stream.avail_out = OUTSIZE;
110
111 err = deflate(&c_stream, Z_NO_FLUSH);
112 if (err != Z_OK) {
113 fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
114 exit(2);
115 }
116 n += fwrite(outbuf, 1, OUTSIZE-c_stream.avail_out, f);
117 } while (!c_stream.avail_out);
118
119 return n;
120 }
121
122 /* ship len bytes from s using zlib compression. */
flate_xship(FILE * f,int filter,const char * s,int len)123 int flate_xship(FILE *f, int filter, const char *s, int len) {
124 static int fstate = 0;
125 static z_stream c_stream;
126 char outbuf[OUTSIZE];
127 int err;
128 int n=0;
129
130 if (filter && !fstate) {
131 /* switch on filtering */
132 if (filter == 1) {
133 n += fprintf(f, "currentfile /ASCII85Decode filter /FlateDecode filter cvx exec\n");
134 }
135 c_stream.zalloc = Z_NULL;
136 c_stream.zfree = Z_NULL;
137 c_stream.opaque = Z_NULL;
138 err = deflateInit(&c_stream, 9);
139 if (err != Z_OK) {
140 fprintf(stderr, "deflateInit: %s (%d)\n", c_stream.msg, err);
141 exit(2);
142 }
143 c_stream.avail_in = 0;
144 n += a85init(f);
145 fstate = 1;
146 } else if (!filter && fstate) {
147 /* switch off filtering */
148 /* flush stream */
149 do {
150 c_stream.next_out = (Bytef*)outbuf;
151 c_stream.avail_out = OUTSIZE;
152
153 err = deflate(&c_stream, Z_FINISH);
154 if (err != Z_OK && err != Z_STREAM_END) {
155 fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
156 exit(2);
157 }
158 n += a85write(f, outbuf, OUTSIZE-c_stream.avail_out);
159 } while (err != Z_STREAM_END);
160
161 n += a85finish(f);
162
163 fstate = 0;
164 }
165 if (!fstate) {
166 fwrite(s, 1, len, f);
167 return n+len;
168 }
169
170 /* do the actual compression */
171 c_stream.next_in = (Bytef*) s;
172 c_stream.avail_in = len;
173
174 do {
175 c_stream.next_out = (Bytef*) outbuf;
176 c_stream.avail_out = OUTSIZE;
177
178 err = deflate(&c_stream, Z_NO_FLUSH);
179 if (err != Z_OK) {
180 fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
181 exit(2);
182 }
183 n += a85write(f, outbuf, OUTSIZE-c_stream.avail_out);
184 } while (!c_stream.avail_out);
185
186 return n;
187 }
188
189 #else /* HAVE_ZLIB */
190
pdf_xship(FILE * f,int filter,const char * s,int len)191 int pdf_xship(FILE *f, int filter, const char *s, int len) {
192 return dummy_xship(f, filter, s, len);
193 }
194
flate_xship(FILE * f,int filter,const char * s,int len)195 int flate_xship(FILE *f, int filter, const char *s, int len) {
196 return dummy_xship(f, filter, s, len);
197 }
198
199 #endif /* HAVE_ZLIB */
200
201 /* ---------------------------------------------------------------------- */
202 /* lzw interface: LZW (=postscript level 2) compression with a85.
203 This relies on lzw.c/h to do the actual compression. */
204
205 /* use Postscript level 2 compression. Ship len bytes from str. */
lzw_xship(FILE * f,int filter,const char * str,int len)206 int lzw_xship(FILE *f, int filter, const char *str, int len) {
207 static int fstate = 0;
208 static lzw_stream_t *s = NULL;
209 char outbuf[OUTSIZE];
210 int err;
211 int n=0;
212
213 if (filter && !fstate) {
214 /* switch on filtering */
215 if (filter == 1) {
216 n += fprintf(f, "currentfile /ASCII85Decode filter /LZWDecode filter cvx exec\n");
217 }
218 s = lzw_init();
219 if (s == NULL) {
220 fprintf(stderr, "lzw_init: %s\n", strerror(errno));
221 exit(2);
222 }
223 n += a85init(f);
224 fstate = 1;
225 } else if (!filter && fstate) {
226 /* switch off filtering */
227 /* flush stream */
228 s->next_in = 0;
229 s->avail_in = 0;
230 do {
231 s->next_out = outbuf;
232 s->avail_out = OUTSIZE;
233
234 err = lzw_compress(s, LZW_EOD);
235 if (err) {
236 fprintf(stderr, "lzw_compress: %s\n", strerror(errno));
237 exit(2);
238 }
239 n += a85write(f, outbuf, OUTSIZE - s->avail_out);
240 } while (s->avail_out == 0);
241
242 n += a85finish(f);
243
244 lzw_free(s);
245 s = NULL;
246
247 fstate = 0;
248 }
249 if (!fstate) {
250 fwrite(str, 1, len, f);
251 return n+len;
252 }
253
254 /* do the actual compression */
255 s->next_in = str;
256 s->avail_in = len;
257
258 do {
259 s->next_out = outbuf;
260 s->avail_out = OUTSIZE;
261
262 err = lzw_compress(s, LZW_NORMAL);
263 if (err) {
264 fprintf(stderr, "lzw_compress: %s\n", strerror(errno));
265 exit(2);
266 }
267 n += a85write(f, outbuf, OUTSIZE - s->avail_out);
268 } while (s->avail_out == 0);
269
270 return n;
271 }
272
273 /* ---------------------------------------------------------------------- */
274 /* a85 interface: a85 encoding without compression */
275
276 /* ship len bytes from s using a85 encoding only. */
a85_xship(FILE * f,int filter,const char * s,int len)277 int a85_xship(FILE *f, int filter, const char *s, int len) {
278 static int fstate = 0;
279 int n=0;
280
281 if (filter && !fstate) {
282 /* switch on filtering */
283 if (filter == 1) {
284 n += fprintf(f, "currentfile /ASCII85Decode filter cvx exec\n");
285 }
286 n += a85init(f);
287 fstate = 1;
288 } else if (!filter && fstate) {
289 /* switch off filtering */
290 /* flush stream */
291 n += a85finish(f);
292 fstate = 0;
293 }
294 if (!fstate) {
295 fwrite(s, 1, len, f);
296 return n+len;
297 }
298
299 n += a85write(f, s, len);
300
301 return n;
302 }
303
304 /* ---------------------------------------------------------------------- */
305 /* low-level a85 backend */
306
307 static unsigned long a85buf[4];
308 static int a85n;
309 static int a85col;
310
a85init(FILE * f)311 static int a85init(FILE *f) {
312 a85n = 0;
313 a85col = 0;
314 return 0;
315 }
316
a85finish(FILE * f)317 static int a85finish(FILE *f) {
318 int r=0;
319
320 if (a85n) {
321 r+=a85out(f, a85n);
322 }
323 fputs("~>\n", f);
324 return r+2;
325 }
326
a85write(FILE * f,const char * buf,int n)327 static int a85write(FILE *f, const char *buf, int n) {
328 int i;
329 int r=0;
330
331 for (i=0; i<n; i++) {
332 a85buf[a85n] = (unsigned char)buf[i];
333 a85n++;
334
335 if (a85n == 4) {
336 r+=a85out(f, 4);
337 a85n = 0;
338 }
339 }
340 return r;
341 }
342
a85out(FILE * f,int n)343 static int a85out(FILE *f, int n) {
344 char out[5];
345 unsigned long s;
346 int r=0;
347 int i;
348
349 for (i=n; i<4; i++) {
350 a85buf[i] = 0;
351 }
352
353 s = (a85buf[0]<<24) + (a85buf[1]<<16) + (a85buf[2]<<8) + (a85buf[3]<<0);
354
355 if (!s) {
356 r+=a85spool(f, 'z');
357 } else {
358 for (i=4; i>=0; i--) {
359 out[i] = s % 85;
360 s /= 85;
361 }
362 for (i=0; i<n+1; i++) {
363 r+=a85spool(f, out[i]+33);
364 }
365 }
366 return r;
367 }
368
a85spool(FILE * f,char c)369 static int a85spool(FILE *f, char c) {
370 fputc(c, f);
371
372 a85col++;
373 if (a85col>70) {
374 fputc('\n', f);
375 a85col=0;
376 return 2;
377 }
378
379 return 1;
380 }
381