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 }