File indexing completed on 2024-12-22 04:04:11

0001 /* Copyright (C) 2001-2019 Peter Selinger.
0002    This file is part of Potrace. It is free software and it is covered
0003    by the GNU General Public License. See the file COPYING for details. */
0004 
0005 
0006 /* the PostScript compression module of Potrace. The basic interface
0007    is through the *_xship function, which processes a byte array and
0008    outputs it in compressed or verbatim form, depending on whether
0009    filter is 1 or 0. To flush the output, simply call with the empty
0010    string and filter=0. filter=2 is used to output encoded text but
0011    without the PostScript header to turn on the encoding. Each
0012    function has variants for shipping a single character, a
0013    null-terminated string, or a byte array. */
0014 
0015 /* different compression algorithms are available. There is
0016    dummy_xship, which is just the identity, and flate_xship, which
0017    uses zlib compression. Also, lzw_xship provides LZW compression
0018    from the file lzw.c/h. a85_xship provides a85-encoding without
0019    compression. Each function returns the actual number of characters
0020    written. */
0021 
0022 /* note: the functions provided here have global state and are not
0023    reentrant */
0024 
0025 #ifdef HAVE_CONFIG_H
0026 #include <config.h>
0027 #endif
0028 
0029 #include <stdio.h>
0030 #include <string.h>
0031 #include <stdlib.h>
0032 #include <errno.h>
0033 
0034 #ifdef HAVE_ZLIB
0035 #include <zlib.h>
0036 #endif
0037 
0038 #include "flate.h"
0039 #include "lzw.h"
0040 
0041 #define OUTSIZE 1000
0042 
0043 static int a85init(FILE *f);
0044 static int a85finish(FILE *f);
0045 static int a85write(FILE *f, const char *buf, int n);
0046 static int a85out(FILE *f, int n);
0047 static int a85spool(FILE *f, char c);
0048 
0049 /* ---------------------------------------------------------------------- */
0050 /* dummy interface: no encoding */
0051 
0052 int dummy_xship(FILE *f, int filter, const char *s, int len) {
0053   fwrite(s, 1, len, f);
0054   return len;
0055 }
0056 
0057 /* ---------------------------------------------------------------------- */
0058 /* flate interface: zlib (=postscript level 3) compression and a85 */
0059 
0060 #ifdef HAVE_ZLIB
0061 
0062 int pdf_xship(FILE *f, int filter, const char *s, int len) {
0063     static int fstate = 0;
0064     static z_stream c_stream;
0065     char outbuf[OUTSIZE];
0066     int err;
0067     int n=0;
0068 
0069   if (filter && !fstate) {
0070     /* switch on filtering */
0071     c_stream.zalloc = Z_NULL;
0072     c_stream.zfree = Z_NULL;
0073     c_stream.opaque = Z_NULL;
0074     err = deflateInit(&c_stream, 9);
0075     if (err != Z_OK) {
0076       fprintf(stderr, "deflateInit: %s (%d)\n", c_stream.msg, err);
0077       exit(2);
0078     }
0079     c_stream.avail_in = 0;
0080     fstate = 1;
0081   } else if (!filter && fstate) {
0082     /* switch off filtering */
0083     /* flush stream */
0084     do {
0085       c_stream.next_out = (Bytef*)outbuf;
0086       c_stream.avail_out = OUTSIZE;
0087 
0088       err = deflate(&c_stream, Z_FINISH);
0089       if (err != Z_OK && err != Z_STREAM_END) {
0090     fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
0091     exit(2);
0092       }
0093       n += fwrite(outbuf, 1, OUTSIZE-c_stream.avail_out, f);
0094     } while (err != Z_STREAM_END);
0095 
0096     fstate = 0;
0097   }
0098   if (!fstate) {
0099     fwrite(s, 1, len, f);
0100     return n+len;
0101   }
0102   
0103   /* do the actual compression */
0104   c_stream.next_in = (Bytef*) s;
0105   c_stream.avail_in = len;
0106 
0107   do {
0108     c_stream.next_out = (Bytef*) outbuf;
0109     c_stream.avail_out = OUTSIZE;
0110 
0111     err = deflate(&c_stream, Z_NO_FLUSH);
0112     if (err != Z_OK) {
0113       fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
0114       exit(2);
0115     }
0116     n += fwrite(outbuf, 1, OUTSIZE-c_stream.avail_out, f);
0117   } while (!c_stream.avail_out);
0118   
0119   return n;
0120 }
0121 
0122 /* ship len bytes from s using zlib compression. */
0123 int flate_xship(FILE *f, int filter, const char *s, int len) {
0124   static int fstate = 0;
0125   static z_stream c_stream;
0126   char outbuf[OUTSIZE];
0127   int err;
0128   int n=0;
0129 
0130   if (filter && !fstate) {
0131     /* switch on filtering */
0132     if (filter == 1) {
0133       n += fprintf(f, "currentfile /ASCII85Decode filter /FlateDecode filter cvx exec\n");
0134     }
0135     c_stream.zalloc = Z_NULL;
0136     c_stream.zfree = Z_NULL;
0137     c_stream.opaque = Z_NULL;
0138     err = deflateInit(&c_stream, 9);
0139     if (err != Z_OK) {
0140       fprintf(stderr, "deflateInit: %s (%d)\n", c_stream.msg, err);
0141       exit(2);
0142     }
0143     c_stream.avail_in = 0;
0144     n += a85init(f);
0145     fstate = 1;
0146   } else if (!filter && fstate) {
0147     /* switch off filtering */
0148     /* flush stream */
0149     do {
0150       c_stream.next_out = (Bytef*)outbuf;
0151       c_stream.avail_out = OUTSIZE;
0152 
0153       err = deflate(&c_stream, Z_FINISH);
0154       if (err != Z_OK && err != Z_STREAM_END) {
0155     fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
0156     exit(2);
0157       }
0158       n += a85write(f, outbuf, OUTSIZE-c_stream.avail_out);
0159     } while (err != Z_STREAM_END);
0160 
0161     n += a85finish(f);
0162 
0163     fstate = 0;
0164   }
0165   if (!fstate) {
0166     fwrite(s, 1, len, f);
0167     return n+len;
0168   }
0169   
0170   /* do the actual compression */
0171   c_stream.next_in = (Bytef*) s;
0172   c_stream.avail_in = len;
0173 
0174   do {
0175     c_stream.next_out = (Bytef*) outbuf;
0176     c_stream.avail_out = OUTSIZE;
0177 
0178     err = deflate(&c_stream, Z_NO_FLUSH);
0179     if (err != Z_OK) {
0180       fprintf(stderr, "deflate: %s (%d)\n", c_stream.msg, err);
0181       exit(2);
0182     }
0183     n += a85write(f, outbuf, OUTSIZE-c_stream.avail_out);
0184   } while (!c_stream.avail_out);
0185   
0186   return n;
0187 }
0188 
0189 #else  /* HAVE_ZLIB */
0190 
0191 int pdf_xship(FILE *f, int filter, const char *s, int len) {
0192   return dummy_xship(f, filter, s, len);
0193 }
0194 
0195 int flate_xship(FILE *f, int filter, const char *s, int len) {
0196   return dummy_xship(f, filter, s, len);
0197 }
0198 
0199 #endif /* HAVE_ZLIB */
0200 
0201 /* ---------------------------------------------------------------------- */
0202 /* lzw interface: LZW (=postscript level 2) compression with a85.
0203    This relies on lzw.c/h to do the actual compression. */
0204 
0205 /* use Postscript level 2 compression. Ship len bytes from str. */
0206 int lzw_xship(FILE *f, int filter, const char *str, int len) {
0207   static int fstate = 0;
0208   static lzw_stream_t *s = NULL;
0209   char outbuf[OUTSIZE];
0210   int err;
0211   int n=0;
0212 
0213   if (filter && !fstate) {
0214     /* switch on filtering */
0215     if (filter == 1) {
0216       n += fprintf(f, "currentfile /ASCII85Decode filter /LZWDecode filter cvx exec\n");
0217     }
0218     s = lzw_init();
0219     if (s == NULL) {
0220       fprintf(stderr, "lzw_init: %s\n", strerror(errno));
0221       exit(2);
0222     }
0223     n += a85init(f);
0224     fstate = 1;
0225   } else if (!filter && fstate) {
0226     /* switch off filtering */
0227     /* flush stream */
0228     s->next_in = 0;
0229     s->avail_in = 0;
0230     do {
0231       s->next_out = outbuf;
0232       s->avail_out = OUTSIZE;
0233 
0234       err = lzw_compress(s, LZW_EOD);
0235       if (err) {
0236     fprintf(stderr, "lzw_compress: %s\n", strerror(errno));
0237     exit(2);
0238       }
0239       n += a85write(f, outbuf, OUTSIZE - s->avail_out);
0240     } while (s->avail_out == 0);
0241 
0242     n += a85finish(f);
0243 
0244     lzw_free(s);
0245     s = NULL;
0246 
0247     fstate = 0;
0248   }
0249   if (!fstate) {
0250     fwrite(str, 1, len, f);
0251     return n+len;
0252   }
0253   
0254   /* do the actual compression */
0255   s->next_in = str;
0256   s->avail_in = len;
0257 
0258   do {
0259     s->next_out = outbuf;
0260     s->avail_out = OUTSIZE;
0261 
0262     err = lzw_compress(s, LZW_NORMAL);
0263     if (err) {
0264       fprintf(stderr, "lzw_compress: %s\n", strerror(errno));
0265       exit(2);
0266     }
0267     n += a85write(f, outbuf, OUTSIZE - s->avail_out);
0268   } while (s->avail_out == 0);
0269   
0270   return n;
0271 }
0272 
0273 /* ---------------------------------------------------------------------- */
0274 /* a85 interface: a85 encoding without compression */
0275 
0276 /* ship len bytes from s using a85 encoding only. */
0277 int a85_xship(FILE *f, int filter, const char *s, int len) {
0278   static int fstate = 0;
0279   int n=0;
0280 
0281   if (filter && !fstate) {
0282     /* switch on filtering */
0283     if (filter == 1) {
0284       n += fprintf(f, "currentfile /ASCII85Decode filter cvx exec\n");
0285     }
0286     n += a85init(f);
0287     fstate = 1;
0288   } else if (!filter && fstate) {
0289     /* switch off filtering */
0290     /* flush stream */
0291     n += a85finish(f);
0292     fstate = 0;
0293   }
0294   if (!fstate) {
0295     fwrite(s, 1, len, f);
0296     return n+len;
0297   }
0298   
0299   n += a85write(f, s, len);
0300   
0301   return n;
0302 }
0303 
0304 /* ---------------------------------------------------------------------- */
0305 /* low-level a85 backend */
0306 
0307 static unsigned long a85buf[4];
0308 static int a85n;
0309 static int a85col;
0310 
0311 static int a85init(FILE *f) {
0312   a85n = 0;
0313   a85col = 0;
0314   return 0;
0315 }
0316 
0317 static int a85finish(FILE *f) {
0318   int r=0;
0319 
0320   if (a85n) {
0321     r+=a85out(f, a85n);
0322   }
0323   fputs("~>\n", f);
0324   return r+2;
0325 }
0326 
0327 static int a85write(FILE *f, const char *buf, int n) {
0328   int i;
0329   int r=0;
0330 
0331   for (i=0; i<n; i++) {
0332     a85buf[a85n] = (unsigned char)buf[i];
0333     a85n++;
0334     
0335     if (a85n == 4) {
0336       r+=a85out(f, 4);
0337       a85n = 0;
0338     }
0339   }
0340   return r;
0341 }
0342 
0343 static int a85out(FILE *f, int n) {
0344   char out[5];
0345   unsigned long s;
0346   int r=0;
0347   int i;
0348 
0349   for (i=n; i<4; i++) {
0350     a85buf[i] = 0;
0351   }
0352 
0353   s = (a85buf[0]<<24) + (a85buf[1]<<16) + (a85buf[2]<<8) + (a85buf[3]<<0);
0354 
0355   if (!s) {
0356     r+=a85spool(f, 'z');
0357   } else {
0358     for (i=4; i>=0; i--) {
0359       out[i] = s % 85;
0360       s /= 85;
0361     }
0362     for (i=0; i<n+1; i++) {
0363       r+=a85spool(f, out[i]+33);
0364     }
0365   } 
0366   return r;
0367 }
0368 
0369 static int a85spool(FILE *f, char c) {
0370   fputc(c, f);
0371 
0372   a85col++;
0373   if (a85col>70) {
0374     fputc('\n', f);
0375     a85col=0;
0376     return 2;
0377   }
0378   
0379   return 1;
0380 }