xref: /potrace-1.14/src/flate.c (revision b3fce824)
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