1 /* encoder.cpp -- various PostScript and PDF encoding filter implementations
2  * by pts@fazekas.hu at Sun Mar  3 14:16:00 CET 2002
3  * --- Mon Mar  4 00:00:20 CET 2002
4  */
5 
6 /* Imp: make built-in FlateEncode DYNALLOC */
7 /* Imp: add lzw_codec */
8 /* Imp: add gzip */
9 /* Imp: add zlib */
10 
11 #ifdef __GNUC__
12 #ifndef __clang__
13 #pragma implementation
14 #endif
15 #endif
16 
17 
18 #include "encoder.hpp"
19 #include "error.hpp"
20 #include "gensio.hpp"
21 #include <stdlib.h> /* getenv() */
22 #include <string.h>
23 
24 /* --- */
25 
26 /** Does output EOD (end-of-data) marker `>' */
27 class ASCIIHexEncode: public PSEncoder {
28  public:
29   /** @param maxcpl_: maximum # hex digits per line, should be even */
30   ASCIIHexEncode(GenBuffer::Writable &out_, unsigned maxcpl_);
31   virtual void vi_write(char const*buf, slen_t len);
32  protected:
33   unsigned maxcpl;
34   /** Number of hex digits already printed. */
35   unsigned curcpl;
36   GenBuffer::Writable &out;
37 };
38 
39 /** Does output EOD (end-of-data) marker `~>' */
40 class ASCII85Encode: public PSEncoder {
41  public:
42   /** @param maxcpl_: maximum # hex digits per line, should be even */
43   ASCII85Encode(GenBuffer::Writable &out_, unsigned maxcpl_);
44   virtual void vi_write(char const*buf, slen_t len);
45 
46  protected:
47   void wencoded(char const *encoded);
48   void wout(unsigned PTS_INT32_T buf_);
49   unsigned maxcpl;
50   /** Number of digits available in this line */
51   GenBuffer::Writable &out;
52   unsigned ascii85breaklen;
53   unsigned ascii85left;
54   unsigned PTS_INT32_T ascii85buf;
55   char *obuf, *obufend, *op;
56   char dscst;  /* For converting `%%' to `% %' to avoid DSC parser errors */
57 };
58 
59 /** Doesn't output EOD (end-of-data) marker `>' */
60 class RunLengthEncode: public PSEncoder {
61  public:
62   /** @param maxcpl_: maximum # hex digits per line, should be even */
63   RunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize_);
64   virtual void vi_write(char const*buf, slen_t len);
65 
66  protected:
67   slen_t recordsize;
68   GenBuffer::Writable &out;
69   // char *obuf, *obufend, *op;
70   slen_t record_left;
71   unsigned saved_c, saved_rep;
72   /** size == header+buffer+EOD */
73   char saved[130];
74 };
75 
76 static int gen_write(char *block, unsigned len, void *zfile);
77 
78 #if USE_BUILTIN_ZIP
79 #include "pts_defl.h" /* Imp: because pts_defl_interface :-( */
80 #if OBJDEP
81 #  warning REQUIRES: pts_defl
82 #endif
83 class FlateEncode: public PSEncoder {
84 #if PTS_DEFL_RIPPED_ZLIB /* Dat: defined in pts_defl.h */
85  public:
86   /** @param level: 1..9: 9==highest compression */
87   FlateEncode(GenBuffer::Writable &out_, unsigned level_);
~FlateEncode()88   virtual ~FlateEncode() { zlib_deflateEnd(&zs); } /* Dat: ==Z_OK check (for unflushed buffers) omitted */
89   virtual void vi_write(char const*buf, slen_t len);
90  protected:
91   /** Formerly only one instance of FlateEncode was allowed.
92    * It exists <=> loced==true
93    */
94   // static bool locked;
95   /** Writable that this filter writes to */
96   GenBuffer::Writable &out;
97   char workspace[ZLIB_DEFLATE_WORKSPACESIZE_MIN]; /* big, about 270k */
98   char obuf[4096];
99   /*struct*/ z_stream zs;
100 #else /* old, ripped from Info-ZIP 2.2 */
101  public:
102   /** @param level: 1..9: 9==highest compression */
103   FlateEncode(GenBuffer::Writable &out_, unsigned level_);
104   virtual ~FlateEncode() { if (fs!=NULLP) fs->delete2(fs); }
105   virtual void vi_write(char const*buf, slen_t len);
106   static void *gen_malloc(unsigned n);
107   static void gen_free(void *p);
108  protected:
109   /** Formerly only one instance of FlateEncode was allowed.
110    * It exists <=> loced==true
111    */
112   // static bool locked;
113   /** Writable that this filter writes to */
114   GenBuffer::Writable &out;
115   #if SIZEOF_INT>2
116     typedef unsigned s_t;
117   #else
118     typedef unsigned short s_t;
119   #endif
120   /** Adler32 checksum */
121   s_t s1, s2;
122   bool had_header;
123   struct pts_defl_interface* fs;
124 #endif /* else PTS_DEFL_RIPPED_ZLIB */
125 };
126 #endif
127 
128 /** Just store the data in Flate (ZLIB) format, no real compression. Adds
129  * about 3 bytes of overhead per 65535 bytes (compression ratio:
130  * 100.004578%)
131  */
132 class FlateStoreEncode: public PSEncoder {
133  public:
134   /** @param level: 1..9: 9==highest compression */
135   FlateStoreEncode(GenBuffer::Writable &out_);
~FlateStoreEncode()136   inline virtual ~FlateStoreEncode() {}
137   virtual void vi_write(char const*buf, slen_t len);
138  protected:
139   GenBuffer::Writable &out;
140   #if SIZEOF_INT>2
141     typedef unsigned s_t;
142   #else
143     typedef unsigned short s_t;
144   #endif
145   /** Adler32 checksum */
146   s_t s1, s2;
147   bool had_header;
148   /** Number of bytes already in buf */
149   unsigned abuflen;
150   /** Max: 65535 */
151   #if HAVE_STATIC_CONST
152     static const unsigned ABUFSIZE=65535;
153   #else
154     #define ABUFSIZE 65535
155   #endif
156   /** Should really not allocate a FlateStoreEncode on the stack. */
157   char abuf[ABUFSIZE+5];
158 };
159 
160 #if USE_BUILTIN_FAXE
161 
162 #include "pts_fax.h"
163 #if OBJDEP
164 #  warning REQUIRES: pts_faxe
165 #endif
166 class CCITTFaxEncode: public PSEncoder {
167  public:
168   CCITTFaxEncode(GenBuffer::Writable &out_, slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1);
169   virtual void vi_write(char const*buf, slen_t len);
170  protected:
171   GenBuffer::Writable &out;
172   stream_CFE_state sCFEs;
173   unsigned char rbuf[4096];
174   unsigned char wbuf[4096];
175   stream_cursor_read r;
176   stream_cursor_write w;
177   unsigned char *hard, *rlimit;
178 
179   static void*gen_xalloc(unsigned n);
180   static void gen_free(void *ptr);
181   static void gen_memset(void *s, int c, unsigned n);
182   static void gen_memcpy(void *dest, const void *src, unsigned n);
183 };
184 #endif
185 
186 #if USE_BUILTIN_LZW
187 #include "pts_lzw.h" /* Imp: because pts_lzw_state :-( */
188 #if OBJDEP
189 #  warning REQUIRES: pts_lzw
190 #endif
191 class LZWEncode: public PSEncoder {
192  public:
193   LZWEncode(GenBuffer::Writable &out_);
194   virtual void vi_write(char const*buf, slen_t len);
195  protected:
196   GenBuffer::Writable &out;
197   struct pts_lzw_state fs;
198 };
199 #endif
200 
201 /**
202  * Reporting of GS errors is somewhat dump: the actual message isn't reported,
203  * only the fact that something went wrong.
204  * Imp: force a no-error trailer output by gs, and check that
205  */
206 class GSEncode: public PSEncoder {
207  public:
208   /** @param filter_psname is a full-featured PostScript *Encode filter
209    * specification string, for example: "<</Effort 5>>/FlateEncode" or
210    * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
211    * `currentfile ... filter'
212    */
213   GSEncode(GenBuffer::Writable &out_, char const*filter_psname);
~GSEncode()214   inline virtual ~GSEncode() {}
215   /* vvv Imp: correct these */
216   virtual void vi_write(char const*buf, slen_t len);
217  protected:
218   class P: public Filter::PipeE {
219     protected: virtual void vi_check();
220     public: P(GenBuffer::Writable &out_, char const*filter_psname);
221   };
222   /** We need this delegator because `delete ...' won't work with multiple
223    * inheritance. (?? )
224    */
225   P p;
226 };
227 
228 class CjpegEncode: public PSEncoder {
229  public:
230   /** @param filter_psname is a full-featured PostScript *Encode filter
231    * specification string, for example: "<</Effort 5>>/FlateEncode" or
232    * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
233    * `currentfile ... filter'
234    */
235   CjpegEncode(GenBuffer::Writable &out_, char const*filter_psname, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality);
~CjpegEncode()236   inline virtual ~CjpegEncode() {}
237   virtual void vi_write(char const*buf, slen_t len);
238  protected:
239   class P: public Filter::PipeE { public:
240     // protected: virtual void vi_check();
241     P(GenBuffer::Writable &out_, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality);
242    protected: /* Not needed: protected -> public: pacify VC6.0 */
243     virtual void vi_copy(FILE *f);
244     bool rgbp;
245   };
246   /** We need this delegator because `delete ...' won't work with multiple
247    * inheritance. (?? )
248    */
249   P p;
250 };
251 
252 #if !USE_BUILTIN_LZW
253 class Lzw_codecEncode: public PSEncoder {
254  public:
255   /** @param filter_psname is a full-featured PostScript *Encode filter
256    * specification string, for example: "<</Effort 5>>/FlateEncode" or
257    * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
258    * `currentfile ... filter'
259    */
260   Lzw_codecEncode(GenBuffer::Writable &out_, char const*filter_psname);
~Lzw_codecEncode()261   inline virtual ~Lzw_codecEncode() {}
262   virtual void vi_write(char const*buf, slen_t len);
263  protected:
264   class P: public Filter::PipeE { public:
265     // protected: virtual void vi_check();
266     P(GenBuffer::Writable &out_);
267    protected:
268     // virtual void vi_copy(FILE *f);
269   };
270   /** We need this delegator because `delete ...' won't work with multiple
271    * inheritance. (?? )
272    */
273   P p;
274 };
275 #endif
276 
277 class TIFFPredictor2: public Encoder {
278  public:
279   /** @param maxcpl_: maximum # hex digits per line, should be even */
280   TIFFPredictor2(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
281   virtual void vi_write(char const*buf, slen_t len);
282  protected:
283   unsigned PTS_INT32_T h;
284   unsigned char *obuf, *op, bpc, cpp;
285   slen_t rlen;
286   GenBuffer::Writable &out;
287 };
288 
289 class PNGPredictorNone: public Encoder {
290  public:
291   /** @param maxcpl_: maximum # hex digits per line, should be even */
292   PNGPredictorNone(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
293   virtual void vi_write(char const*buf, slen_t len);
294  protected:
295   slen_t rlen, opleft;
296   GenBuffer::Writable &out;
297 };
298 
299 class PNGPredictorSub: public Encoder {
300  public:
301   /** @param maxcpl_: maximum # hex digits per line, should be even */
302   PNGPredictorSub(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
303   virtual void vi_write(char const*buf, slen_t len);
304  protected:
305   unsigned PTS_INT32_T h;
306   unsigned char *obuf, *op;
307   slen_t rlen;
308   GenBuffer::Writable &out;
309   unsigned char bpccpp;
310 };
311 
312 class PNGPredictorUp: public Encoder {
313  public:
314   /** @param maxcpl_: maximum # hex digits per line, should be even */
315   PNGPredictorUp(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
316   virtual void vi_write(char const*buf, slen_t len);
317  protected:
318   unsigned char *obuf, *op, *oq;
319   slen_t rlen;
320   GenBuffer::Writable &out;
321 };
322 
323 class PNGPredictorAverage: public Encoder {
324  public:
325   /** @param maxcpl_: maximum # hex digits per line, should be even */
326   PNGPredictorAverage(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
327   virtual void vi_write(char const*buf, slen_t len);
328  protected:
329   unsigned PTS_INT32_T h/*, g*/;
330   unsigned char *obuf, *op, *oq;
331   slen_t rlen;
332   GenBuffer::Writable &out;
333   unsigned char bpccpp;
334 };
335 
336 class PNGPredictorPaeth: public Encoder {
337  public:
338   /** @param maxcpl_: maximum # hex digits per line, should be even */
339   PNGPredictorPaeth(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
340   virtual void vi_write(char const*buf, slen_t len);
341  protected:
342   unsigned PTS_INT32_T h, g;
343   unsigned char *obuf, *op, *oq;
344   slen_t rlen;
345   GenBuffer::Writable &out;
346   unsigned char bpccpp;
347 };
348 
349 /** This class implements inferior predictor autoselection heuristics.
350  * Please use PNGPredictorAuto instead.
351  * Imp: code reuse with PNGPredictorAuto
352  */
353 class PNGPredictorAutoBadSigned: public Encoder {
354  public:
355   /** @param maxcpl_: maximum # hex digits per line, should be even */
356   PNGPredictorAutoBadSigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
357   virtual void vi_write(char const*buf, slen_t len);
358  protected:
359   unsigned PTS_INT32_T h, g;
360   unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
361   slen_t rlen;
362   GenBuffer::Writable &out;
363   unsigned char bpccpp;
364   slen_t opleft;
365 };
366 
367 /** This class implements inferior predictor autoselection heuristics.
368  * Please use PNGPredictorAuto instead.
369  * Imp: code reuse with PNGPredictorAuto
370  */
371 class PNGPredictorAutoBadUnsigned: public Encoder {
372  public:
373   /** @param maxcpl_: maximum # hex digits per line, should be even */
374   PNGPredictorAutoBadUnsigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
375   virtual void vi_write(char const*buf, slen_t len);
376  protected:
377   unsigned PTS_INT32_T h, g;
378   unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
379   slen_t rlen;
380   GenBuffer::Writable &out;
381   unsigned char bpccpp;
382   slen_t opleft;
383 };
384 
385 /** This class implements to so-called ``minimum sum of absolute differences''
386  * predictior autoselection heuristics, the same as what pngwutil.c
387  * contains in function png_write_find_filter() in libpng 1.2.20. (See that
388  * function for a discussion of other heuristics. A summary of this heuristics:
389  * we find which method provides the smallest value when summing the absolute
390  * values of the distances from zero, using anything >= 128 as negative
391  * numbers.
392  */
393 class PNGPredictorAuto: public Encoder {
394  public:
395   /** @param maxcpl_: maximum # hex digits per line, should be even */
396   PNGPredictorAuto(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
397   virtual void vi_write(char const*buf, slen_t len);
398  protected:
399   unsigned PTS_INT32_T h, g;
400   unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
401   slen_t rlen;
402   GenBuffer::Writable &out;
403   unsigned char bpccpp;
404   slen_t opleft;
405 };
406 
407 /* --- */
408 
FlateStoreEncode(GenBuffer::Writable & out_)409 FlateStoreEncode::FlateStoreEncode(GenBuffer::Writable &out_)
410  :out(out_)
411  ,s1(1)
412  ,s2(0)
413  ,had_header(false)
414  ,abuflen(0)
415  {}
416 
417 #if 0
418 /** 0x7801: ZLIB header signaling fastest compression
419  * 0: 2 bits: DEFLATE block header signaling stored (uncompressed) block +
420  *    6 bits of padding.
421  */
422 char FlateStoreEncode::header[3]= { 0x78, 1, 0 };
423 #endif
424 
vi_write(char const * buf,slen_t len)425 void FlateStoreEncode::vi_write(char const*buf, slen_t len) {
426   register s_t sold;
427   register char const*p=buf; char const*pend=p+len;
428   (void)sold;
429   if (len==0) { /* EOF: flush and send trailer */
430     /* Dat: Last block has to be written even if it's empty. */
431     if (!had_header) { out.vi_write("\x78\x01", 2); had_header=true; }
432     abuf[0]=(char)1; /* Last, stored block with padding */
433     abuf[1]=abuflen; abuf[2]=abuflen>>8;
434     abuf[3]=~(abuflen); abuf[4]=~(abuflen>>8);
435     out.vi_write(abuf, abuflen+5);
436     if (s1>=65521) s1-=65521;
437     if (s2>=65521) s2-=65521;
438     unsigned char trailer[4];
439     trailer[0]=s2>>8; trailer[1]=s2&255; trailer[2]=s1>>8; trailer[3]=s1&255;
440     out.vi_write((char const*)trailer,4);
441     out.vi_write(0,0); /* Signal EOF */
442     return;
443   }
444   /* From rfc1950.txt:
445            Adler-32 is composed of two sums accumulated per byte: s1 is
446            the sum of all bytes, s2 is the sum of all s1 values. Both sums
447            are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
448            Adler-32 checksum is stored as s2*65536 + s1 in most-
449            significant-byte first (network) order.
450   */
451   /* Update Adler-32 checksum */
452   while (p!=pend) {
453     #if SIZEOF_INT>2
454       if ((s1+=*(unsigned char const*)p)>=65521) s1-=65521;
455       if ((s2+=s1)>=65521) s2-=65521;
456     #elif SIZEOF_SHORT==2
457       sold=s1;
458       if ((s1+=*(unsigned char const*)p))<sold) s1+=15; /* 15==65536-21 */
459       sold=s2;
460       s2=(s2+s1)&0xffff;
461       if ((s2+=s1)<sold) s2+=15;
462     #else
463       /* vvv 0xffff is needed since unsigned short may be > 0..65535 */
464       sold=s1;
465       s1=(s1+*(unsigned char const*)p)&0xffff;
466       if (s1<sold) s1+=15; /* 15==65536-21 */
467       sold=s2;
468       s2=(s2+s1)&0xffff;
469       if (s2<sold) s2+=15;
470     #endif
471     p++;
472   }
473   // fprintf(stderr, "len=%u\n", len);
474   unsigned abufleft;
475   while ((abufleft=ABUFSIZE-abuflen)<len) {
476     // putchar('.');
477     // fprintf(stderr, "ABUFSIZE=%u abuflen=%u\n", ABUFSIZE, abuflen);
478     memcpy(abuf+abuflen+5, buf, abufleft);
479     abuf[0]=0; /* Stored block with padding */
480     abuf[1]=(char)ABUFSIZE; abuf[2]=(char)(ABUFSIZE>>8);
481     abuf[3]=(char)~(ABUFSIZE); abuf[4]=(char)~(ABUFSIZE>>8);
482     if (!had_header) { out.vi_write("\x78\x01", 2); had_header=true; }
483     /* fprintf(stderr,"%02x %02x", abuf[1], abuf[2]); */
484     out.vi_write(abuf, ABUFSIZE+5); /* emit next stored block with header */
485     abuflen=0;
486     len-=abufleft;
487     buf+=abufleft;
488   }
489   // putchar('X');
490   memcpy(abuf+abuflen+5, buf, len);
491   abuflen+=len;
492   /* Now abuf is possibly full. That is intentional, so we will be able to
493    * emit a full last block instead of an empty one.
494    */
495 }
496 
497 /* --- */
498 
ASCIIHexEncode(GenBuffer::Writable & out_,unsigned maxcpl_)499 ASCIIHexEncode::ASCIIHexEncode(GenBuffer::Writable &out_, unsigned maxcpl_)
500  :maxcpl(maxcpl_)
501  ,curcpl(0)
502  ,out(out_) {}
503 
vi_write(char const * buf,slen_t len)504 void ASCIIHexEncode::vi_write(char const*buf, slen_t len) {
505   /* Imp: buffering (1K etc.) */
506   static char const hextable []="0123456789abcdef";
507   char obuf[3];
508   obuf[0]='\n';
509   if (len==0) { out.vi_write(">",1); out.vi_write(0,0); }
510   else while (len--!=0) {
511     obuf[1]=hextable[(*(unsigned char const*)buf)>>4];
512     obuf[2]=hextable[(*(unsigned char const*)buf)&15];
513     if (curcpl>=maxcpl) { curcpl=2;  out.vi_write(obuf,   3); }
514                    else { curcpl+=2; out.vi_write(obuf+1, 2); }
515     buf++;
516   }
517 }
518 
519 /* --- */
520 
ASCII85Encode(GenBuffer::Writable & out_,unsigned maxcpl_)521 ASCII85Encode::ASCII85Encode(GenBuffer::Writable &out_, unsigned maxcpl_)
522  :maxcpl(maxcpl_)
523  ,out(out_)
524  ,ascii85breaklen(maxcpl_)
525  ,ascii85left(4)
526  ,dscst(1) {
527   obufend=(op=obuf=new char[4096])+4096;
528 }
529 
wencoded(char const * cp)530 void ASCII85Encode::wencoded(char const *cp) {
531   for (; *cp!='\0'; ) {
532     if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
533     // if (*cp<='!') { fprintf(stderr, "e=%d.\n", cp-encoded); }
534     assert(*cp>='!');
535     assert(*cp<='~');
536     if (dscst) {
537       if (dscst == 1) {
538         dscst = (*cp == '%') ? 2 : 0;
539       } else {  /* if (dscst == 2) { */
540         if (*cp == '%') {
541           if (--ascii85breaklen == 0) {
542             *op++ = '\n';
543             ascii85breaklen = maxcpl;
544           } else {
545             /* Add space for `% %' instead of `%%' at BOL. */
546             *op++ = ' ';
547           }
548           if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
549         }
550         dscst = 0;
551       }
552     }
553     *op++=*cp++;
554     if (--ascii85breaklen == 0) {
555       if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
556       *op++='\n';
557       ascii85breaklen = maxcpl;
558       dscst = 1;
559     }
560   } /* NEXT */
561 }
562 
vi_write(char const * buf,slen_t len)563 void ASCII85Encode::vi_write(char const*buf, slen_t len) {
564   if (len==0) {
565     char encoded[6];
566     assert(ascii85left<=4);
567     if (ascii85left!=4) {
568       unsigned PTS_INT32_T buf_=ascii85buf<<8*ascii85left;
569       unsigned PTS_INT32_T q;
570       unsigned w1;
571 
572       q = buf_ / ((unsigned PTS_INT32_T)85*85*85*85);  /* actually only a byte */
573       assert(q<=85);
574       encoded[0] = q + '!';
575 
576       buf_ -= q * ((unsigned PTS_INT32_T)85*85*85*85); q = buf_ / ((unsigned PTS_INT32_T)85*85*85);
577       encoded[1] = q + '!';
578 
579       buf_ -= q * ((unsigned PTS_INT32_T)85*85*85); q = buf_ / (85*85);
580       encoded[2] = q + '!';
581 
582       w1 = (unsigned) (buf_ - q*(unsigned PTS_INT32_T)(85*85));
583       assert(w1/85<85);
584       encoded[3] = (w1 / 85) + '!';
585       encoded[4] = (w1 % 85) + '!';
586       encoded[5-ascii85left] = '\0';
587       wencoded(encoded);
588     } /* IF */
589     if (op!=obuf) out.vi_write(obuf, op-obuf); /* flush buffer cache */
590     out.vi_write("~>",2); out.vi_write(0,0);
591     delete [] obuf;
592     obuf=(char*)NULLP;
593   } else {
594     assert(obuf!=NULLP);
595     register unsigned PTS_INT32_T abuf=ascii85buf;
596     register unsigned aleft=ascii85left;
597     assert(aleft>=1 && aleft<=4);
598     do {
599       while (len!=0 && aleft!=0) {
600         abuf=(abuf<<8)+*(unsigned char const*)buf++; len--; aleft--;
601       }
602       if (aleft!=0) break;
603       wout(abuf);
604       aleft=4;
605     } while (len!=0);
606     ascii85buf=abuf; ascii85left=aleft;
607   }
608 }
609 
wout(unsigned PTS_INT32_T buf_)610 void ASCII85Encode::wout(unsigned PTS_INT32_T buf_) {
611   char encoded[6];
612   if (buf_ != (unsigned PTS_INT32_T)0) {
613     unsigned PTS_INT32_T q;
614     unsigned w1;
615 
616     q = buf_ / ((unsigned PTS_INT32_T)85*85*85*85);  /* actually only a byte */
617     encoded[0] = q + '!';
618 
619     buf_ -= q * ((unsigned PTS_INT32_T)85*85*85*85); q = buf_ / ((unsigned PTS_INT32_T)85*85*85);
620     encoded[1] = q + '!';
621 
622     buf_ -= q * ((unsigned PTS_INT32_T)85*85*85); q = buf_ / (85*85);
623     encoded[2] = q + '!';
624 
625     w1 = (unsigned) (buf_ - q*(unsigned PTS_INT32_T)(85*85));
626     encoded[3] = (w1 / 85) + '!';
627     encoded[4] = (w1 % 85) + '!';
628     encoded[5] = '\0';
629   } else {
630     encoded[0] = 'z', encoded[1] = '\0';
631   }
632   wencoded(encoded);
633 }
634 
635 /* --- */
636 
RunLengthEncode(GenBuffer::Writable & out_,slen_t RecordSize_)637 RunLengthEncode::RunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize_)
638  :recordsize(RecordSize_==0?(slen_t)-1:RecordSize_)
639  ,out(out_) {
640   record_left=recordsize;
641   // obufend=(op=obuf=new char[4096])+4096; /* Imp: implement write buffering */
642   saved_c=saved_rep=0;
643 }
644 
vi_write(char const * buf,slen_t len)645 void RunLengthEncode::vi_write(char const*buf, slen_t len) {
646   unsigned j, umax;
647   char b;
648   if (len==0) { /* handle EOF */
649     if (saved_rep!=0) {
650       assert(saved_rep>=2);
651       (saved+1)[-1]=257-saved_rep;
652       (saved+1)[1]=(char)128; /* EOD */
653       out.vi_write((saved+1)-1,3);
654       // fprintf(stderr,"rd=%u\n",saved_rep);
655     } else if (saved_c!=0) {
656       (saved+1)[-1]=saved_c-1;
657       (saved+1)[saved_c]=(char)128; /* EOD */
658       out.vi_write((saved+1)-1, saved_c+2);
659       // fprintf(stderr,"re=%u\n",saved_c);
660     } else {
661       (saved+1)[-1]=(char)128;
662       out.vi_write((saved+1)-1, 1);
663     }
664     out.vi_write(0,0); /* propagate EOF */
665     record_left=0; /* signal that no further data will be accepted */
666     return;
667   }
668  again:
669   assert(record_left>=1);
670   assert(len>=1);
671   /* Imp: locally cache vars saved* */
672   j=0;
673   if (saved_c==0) {
674     saved_rep=0; saved_c=1; b=(saved+1)[0]=*buf++; len--;
675     if (0==--record_left) goto put_norep;
676     if (0==len) return;
677     goto yes;
678   }
679   if (saved_c==1 && saved_rep==0) { yes:
680     if (*buf++==(saved+1)[0]) {
681       saved_rep=2; len--;
682       if (0==--record_left) goto put_rep;
683     } else {
684       (saved+1)[1]=buf[-1]; saved_c=2; len--;
685       if (0==--record_left) goto put_norep;
686     }
687     if (0==len) return;
688   }
689   assert(record_left>=1);
690   assert(len>=1);
691   assert((saved_rep==0 && saved_c>=2) || (saved_rep>=2 && saved_c==1));
692   if (saved_rep!=0) { /* Try to increase the repeating sequence */
693     assert(saved_rep>=2);
694     assert(saved_c==1);
695     assert(len>=1);
696     b=(saved+1)[0];
697     umax=len>128?128:len; if (umax>record_left) umax=record_left;
698     /* fprintf(stderr,"um1=%u\n", umax); */
699     if (umax>128-saved_rep) umax=128-saved_rep;
700     assert(umax>=1);
701     j=0; while (j!=umax && buf[j]==b) { j++; saved_rep++; }
702     if (j!=len || saved_rep==128) {
703      put_rep: /* Found a maximal repeat width */
704       (saved+1)[-1]=257-saved_rep;
705       out.vi_write((saved+1)-1,2);
706       /* fprintf(stderr,"ra=%u\n",saved_rep); */
707       if ((record_left-=j)==0) record_left=recordsize;
708       buf+=j;
709       saved_c=saved_rep=0;
710       if (0==(len-=j)) return;
711       goto again;
712     } /* Current repeat width can be further increased */
713   } else { /* Try to increase the non-repeating sequence */
714     assert(saved_c>=2);
715     if (buf[0]==(saved+1)[saved_c-1]) { /* this decision might be sub-optimal */
716       saved_c--;
717       /* Now: saved_c: non-repeat length, >=1 */
718       (saved+1)[-1]=saved_c-1;
719       out.vi_write((saved+1)-1, saved_c+1);
720       /* fprintf(stderr,"rb=%u\n",saved_c); */
721       // record_left++; /* because of saved_c--; but we would increase it later anyway */
722       // buf+=saved_c;
723       (saved+1)[0]=buf[0]; /* first matching char-pair data */
724       saved_c=1; saved_rep=2; /* make the new block a >=2 repeat */
725       record_left--; buf++;
726       if (0==--len) return;
727       goto again;
728     }
729     (saved+1)[saved_c++]=buf[0];
730     //record_left--;
731     //buf++;
732     //len--;
733     //if (saved_c==128) goto put_norep;
734     //if (0==len) return;
735     umax=len>128?128:len; if (umax>record_left) umax=record_left;
736     if (umax>128-saved_c) umax=128-saved_c;
737     /* fprintf(stderr,"um2=%u\n", umax); */
738     assert(umax>=1);
739     j=1; while (j!=umax && buf[j]!=buf[j-1]) (saved+1)[saved_c++]=buf[j++];
740     if (j!=len || saved_c==128) {
741      put_norep: /* Found a maximal non-repeat width */
742       (saved+1)[-1]=saved_c-1;
743       out.vi_write((saved+1)-1, saved_c+1);
744       /* fprintf(stderr,"rc=%u\n",saved_c); */
745       if ((record_left-=j)==0) record_left=recordsize;
746       buf+=j;
747       saved_c=saved_rep=0;
748       if (0==(len-=j)) return;
749       goto again;
750     } /* Current non-repeat width can be further increased */
751   }
752   assert(j==len);
753   record_left-=j;
754   assert(saved_rep<128);
755   assert(saved_c<128);
756 }
757 
758 /* --- */
759 
760 #if USE_BUILTIN_ZIP
761 // bool FlateEncode::locked=false;
762 
763 #if PTS_DEFL_RIPPED_ZLIB
FlateEncode(GenBuffer::Writable & out_,unsigned level_)764 FlateEncode::FlateEncode(GenBuffer::Writable &out_, unsigned level_)
765  :out(out_) {
766   // assert(!locked); locked /* locking is not necessary anymore */
767   // pts_deflate_init(&fs); /* obsolete */
768   zs.total_in=0;
769   zs.total_out=0;
770   zs.workspace=workspace;
771   zs.msg=(char*)0;
772   zs.state=(struct zlib_internal_state*)0;
773   zs.data_type=Z_UNKNOWN; /* Imp: do we have to initialize it? */
774   assert(zlib_deflate_workspacesize()+(unsigned)0<sizeof(workspace) && "Flate workspace too small");
775   if (Z_OK!=zlib_deflateInit(&zs, level_))
776     Error::sev(Error::EERROR) << "Flate init error (out of memory?)" << (Error*)0;
777 }
778 
vi_write(char const * buf,slen_t len)779 void FlateEncode::vi_write(char const*buf, slen_t len) {
780   slen_t got, zgot;
781   /* fprintf(stderr,"wcall\n"); */
782   zs.next_in=(unsigned char*)const_cast<char*>(buf);   zs.avail_in=len;
783   if (len==0) { /* flush all output */
784     do { /* SUXX: C compiler should emit a warning: while (1) { ... } while(...); */
785       zs.next_out=(unsigned char*)obuf; zs.avail_out=sizeof(obuf);
786       /* fprintf(stderr,"wdone zai=%d zao=%d\n", zs.avail_in, zs.avail_out); */
787       if (Z_STREAM_END!=(zgot=zlib_deflate(&zs, Z_FINISH)) && Z_OK!=zgot)
788         Error::sev(Error::EERROR) << "Flate close error: " << zs.msg << (Error*)0;
789       got=sizeof(obuf)-zs.avail_out;
790       /* fprintf(stderr, "got=%u zgot=%d Z_OK=%d\n", got, zgot, Z_OK); */
791       if (got>0) out.vi_write(obuf, got);
792     } while (zgot==Z_OK);
793     /* Dat: zlib_deflateEnd() will be called in the destructur */
794     out.vi_write(0,0); /* Signal EOF */
795     /* Dat: zlib_deflate() adds RFC 1950 header and adler32 checksum automatically */
796   } else {
797     do {
798       /* fprintf(stderr,"writ\n"); */
799       zs.next_out=(unsigned char*)obuf;  zs.avail_out=sizeof(obuf);
800       if (Z_OK!=zlib_deflate(&zs, 0))
801         Error::sev(Error::EERROR) << "Flate write error: " << zs.msg << (Error*)0;
802       if (0<(got=sizeof(obuf)-zs.avail_out)) out.vi_write(obuf, got);
803     } while (0!=zs.avail_in);
804   }
805 }
806 #else
FlateEncode(GenBuffer::Writable & out_,unsigned level_)807 FlateEncode::FlateEncode(GenBuffer::Writable &out_, unsigned level_)
808  :out(out_)
809  ,s1(1)
810  ,s2(0)
811  ,had_header(false) {
812   // assert(!locked); locked /* locking is not necessary anymore */
813   // pts_deflate_init(&fs); /* obsolete */
814   fs=pts_defl_new(
815     /*zpfwrite=*/ gen_write,
816     /*zpfmalloc=*/ gen_malloc,
817     /*zpffree=*/ gen_free,
818     /*pack_level=*/ level_,
819     /*zfile=*/ (void*)&out_
820   );
821   if (fs==NULL) Error::sev(Error::EERROR) << "Flate init error (out of memory?)" << (Error*)0;
822 }
gen_malloc(unsigned n)823 void *FlateEncode::gen_malloc(unsigned n) {
824   return operator new(n);
825   // return new char[n];
826 }
gen_free(void * p)827 void FlateEncode::gen_free(void *p) {
828   /*return*/ operator delete(p);
829   // delete [] (char*)p;
830 }
831 
vi_write(char const * buf,slen_t len)832 void FlateEncode::vi_write(char const*buf, slen_t len) {
833   register s_t sold;
834   register char const*p=buf; char const*pend=p+len;
835   (void)sold;
836   if (!had_header) {
837     out.vi_write("\x78\xda",2); /* ZLIB (RFC 1950): max compression header */
838     had_header=true;
839   }
840   if (len==0) { /* EOF: send trailer */
841     fs->deflate2(0,0,fs); /* Let the compressor flush its buffers. */
842     if (fs->err!=0) Error::sev(Error::EERROR) << "Flate compression error" << (Error*)0;
843     fs->delete2(fs);
844     fs=(struct pts_defl_interface*)NULL;
845     if (s1>=65521) s1-=65521;
846     if (s2>=65521) s2-=65521;
847     unsigned char trailer[4];
848     trailer[0]=s2>>8; trailer[1]=s2&255; trailer[2]=s1>>8; trailer[3]=s1&255;
849     out.vi_write((char const*)trailer,4);
850     out.vi_write(0,0); /* Signal EOF */
851     return;
852   }
853   assert(fs!=NULL);
854 
855   /* From rfc1950.txt:
856            Adler-32 is composed of two sums accumulated per byte: s1 is
857            the sum of all bytes, s2 is the sum of all s1 values. Both sums
858            are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
859            Adler-32 checksum is stored as s2*65536 + s1 in most-
860            significant-byte first (network) order.
861   */
862   /* Update Adler-32 checksum */
863   while (p!=pend) {
864     #if SIZEOF_INT>2
865       if ((s1+=*(unsigned char const*)p)>=65521) s1-=65521;
866       if ((s2+=s1)>=65521) s2-=65521;
867     #elif SIZEOF_SHORT==2
868       sold=s1;
869       if ((s1+=*(unsigned char const*)p))<sold) s1+=15; /* 15==65536-21 */
870       sold=s2;
871       s2=(s2+s1)&0xffff;
872       if ((s2+=s1)<sold) s2+=15;
873     #else
874       /* vvv 0xffff is needed since unsigned short may be > 0..65535 */
875       sold=s1;
876       s1=(s1+*(unsigned char const*)p)&0xffff;
877       if (s1<sold) s1+=15; /* 15==65536-21 */
878       sold=s2;
879       s2=(s2+s1)&0xffff;
880       if (s2<sold) s2+=15;
881     #endif
882     p++;
883   }
884   while (len>=0x8000) { fs->deflate2(const_cast<char*>(buf),0x8000, fs); len-=0x8000; buf+=0x8000; }
885   if (len!=0) fs->deflate2(const_cast<char*>(buf),len, fs);
886 }
887 #endif /* PTS_DEFL_RIPPED_ZLIB */
888 #endif /* USE_BUILTIN_ZIP */
889 
gen_write(char * block,unsigned len,void * zfile)890 int /*FlateEncode::*/gen_write(char *block, unsigned len, void *zfile) {
891   static_cast<GenBuffer::Writable*>(zfile)->vi_write(block, len);
892   return 0;
893 }
894 
895 
896 /* --- */
897 
898 #if USE_BUILTIN_FAXE
gen_xalloc(unsigned n)899 void* CCITTFaxEncode::gen_xalloc(unsigned n) {
900   return operator new(n);
901   //  void *ret; if ((ret=malloc(n))==0) abort(); return ret;
902 }
gen_free(void * ptr)903 void CCITTFaxEncode::gen_free(void *ptr) {
904   /*return*/ operator delete(ptr);
905   // free(ptr);
906 }
gen_memset(void * s,int c,unsigned n)907 void CCITTFaxEncode::gen_memset(void *s, int c, unsigned n) {
908   /*return*/ memset(s,c,n);
909 }
gen_memcpy(void * dest,const void * src,unsigned n)910 void CCITTFaxEncode::gen_memcpy(void *dest, const void *src, unsigned n) {
911   /*return*/ memcpy(dest, src, n);
912 }
CCITTFaxEncode(GenBuffer::Writable & out_,slendiff_t K,slen_t Columns,bool EndOfLine,bool BlackIs1)913 CCITTFaxEncode::CCITTFaxEncode(GenBuffer::Writable &out_, slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1): out(out_) {
914   sCFEs.memset_=gen_memset;
915   sCFEs.xalloc_=gen_xalloc;
916   sCFEs.free_=gen_free;
917   sCFEs.memcpy_=gen_memcpy;
918   s_CFE_template.set_defaults((stream_state*)&sCFEs);
919   sCFEs.K=K;
920   sCFEs.Columns=Columns;
921   sCFEs.EndOfLine=EndOfLine;
922   sCFEs.BlackIs1=BlackIs1;
923   const int cf_max_height=(unsigned)-1/2-100; /* Dat: was slen_t */
924   if (sCFEs.K < -cf_max_height || sCFEs.K > cf_max_height /* Dat: .K is an int */
925    || sCFEs.Columns < 0 || sCFEs.Columns > cfe_max_width /* Dat: .Columns is an int */
926    || sCFEs.Rows < 0 || sCFEs.Rows > cf_max_height /* Dat: .Rows is an int */
927    || sCFEs.DamagedRowsBeforeError < 0
928    || sCFEs.DamagedRowsBeforeError > cf_max_height /* Dat: .DamagedRowsBeforeError is an int */
929    || sCFEs.DecodedByteAlign < 1 || sCFEs.DecodedByteAlign > 16
930    || (sCFEs.DecodedByteAlign & (sCFEs.DecodedByteAlign - 1)) != 0
931      ) Error::sev(Error::EERROR) << "pts_fax: invalid params" << (Error*)0;
932   if (0!=s_CFE_template.init((stream_state*)&sCFEs))
933     Error::sev(Error::EERROR) << "pts_fax: init failed" << (Error*)0;
934   #if __CHECKER__
935     memset(&r, 0, sizeof(r));
936     memset(&w, 0, sizeof(w));
937   #endif
938   r.ptr=rlimit=rbuf-1;
939   hard=rbuf+sizeof(rbuf)-1;
940   assert(hard-r.ptr>=(int)s_CFE_template.min_in_size);
941 }
942 
vi_write(char const * buf,slen_t len)943 void CCITTFaxEncode::vi_write(char const*buf, slen_t len) {
944   int pog;
945   // unsigned char *save_wptr;
946   if (len==0) {
947     r.limit=rlimit;
948     do {
949       w.ptr=wbuf-1;
950       w.limit=wbuf+sizeof(wbuf)-1;
951       assert(w.limit-w.ptr>=(int)s_CFE_template.min_out_size);
952       pog=s_CFE_template.process((stream_state*)&sCFEs, &r, &w, /*last:*/ true);
953       // fprintf(stderr, "pog=%d write=%d last=%d\n", pog, w.ptr-(wbuf-1), true);
954       assert(pog!=PTSFAX_ERRC); /* /CCITTFaxEncode filter must accept any input */
955       assert(pog!=PTSFAX_EOFC); /* /CCITTFaxEncode filter doesn't have EOD markers */
956       if (w.ptr!=wbuf-1) out.vi_write((char const*)wbuf, w.ptr-(wbuf-1));
957     } while (pog==1);
958     s_CFE_template.release((stream_state*)&sCFEs);
959     out.vi_write(0,0); /* propagate EOF */
960     return;
961   }
962 
963   while (len!=0) {
964     assert(r.ptr==rbuf-1);
965     assert(hard>rlimit);
966     unsigned clen=hard-rlimit;
967     if (clen>len) clen=len;
968     assert(clen>0);
969     // fprintf(stderr, "clen=%u\n", clen);
970     memcpy(rlimit+1, buf, clen);
971     rlimit+=clen;
972     buf+=clen;
973     len-=clen;
974     /* if (r.ptr==rlimit) break; */
975     r.limit=rlimit;
976     do {
977       w.ptr=wbuf-1;
978       w.limit=wbuf+sizeof(wbuf)-1;
979       assert(w.limit-w.ptr>=(int)s_CFE_template.min_out_size);
980       pog=s_CFE_template.process((stream_state*)&sCFEs, &r, &w, /*last:*/ false);
981       // fprintf(stderr, "len=%d pog=%d write=%d last=%d\n", len, pog, w.ptr-(wbuf-1), false);
982       assert(pog!=PTSFAX_ERRC); /* /CCITTFaxEncode filter must accept any input */
983       assert(pog!=PTSFAX_EOFC); /* /CCITTFaxEncode filter doesn't have EOD markers */
984       if (w.ptr!=wbuf-1) out.vi_write((char const*)wbuf, w.ptr-(wbuf-1));
985     } while (pog==1);
986     // assert(pog!=1); /* not true: output space is enough (sizeof(wbuf)>min_out_size) */
987     assert(pog==0); /* more input is needed */
988     if (r.ptr!=rbuf-1) {
989       // fprintf(stderr, "limit=%d\n", rlimit-r.ptr);
990       memmove(rbuf, r.ptr+1, rlimit-r.ptr);
991       rlimit=rbuf-1+(rlimit-r.ptr);
992       r.ptr=rbuf-1;
993     }
994   }
995   // fprintf(stderr, "done\n");
996 }
997 #endif /* USE_BUILTIN_FAXE */
998 
999 /* --- */
1000 
1001 #if USE_BUILTIN_LZW
LZWEncode(GenBuffer::Writable & out_)1002 LZWEncode::LZWEncode(GenBuffer::Writable &out_): out(out_) {
1003   fs.tif_writer=/*FlateEncode::*/gen_write;
1004   fs.tif_sout=(void*)&out_;
1005   if (0==pts_lzw_init(&fs)) Error::sev(Error::EERROR) << "LZW init error" << (Error*)0;
1006 }
1007 
vi_write(char const * buf,slen_t len)1008 void LZWEncode::vi_write(char const*buf, slen_t len) {
1009   /* Imp: report real error _reason_ (if appropriate?? ) */
1010   if (len==0) {
1011     if (0==fs.tif_feeder(0,0,&fs)) goto we;
1012     out.vi_write(0,0); /* propagate EOF */
1013     return;
1014   }
1015   while (len>=0x8000) {
1016     if (0==fs.tif_feeder(const_cast<char*>(buf),0x8000,&fs)) we:
1017       Error::sev(Error::EERROR) << "LZW write error" << (Error*)0;
1018     len-=0x8000; buf+=0x8000;
1019   }
1020   if (len!=0 && 0==fs.tif_feeder(const_cast<char*>(buf),len,&fs)) goto we;
1021 }
1022 #endif /* USE_BUILTIN_LZW */
1023 
1024 /* --- */
1025 
1026 #if !USE_BUILTIN_LZW
Lzw_codecEncode(GenBuffer::Writable & out_,char const * filter_psname)1027 Lzw_codecEncode::Lzw_codecEncode(GenBuffer::Writable &out_, char const*filter_psname)
1028   :p(out_) {
1029   (void)filter_psname;
1030 }
vi_write(char const * buf,slen_t len)1031 void Lzw_codecEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
1032 
1033 /* Imp: figure out path-to-gs: gs or gswin32c */
P(GenBuffer::Writable & out_)1034 Lzw_codecEncode::P::P(GenBuffer::Writable &out_)
1035  // :PipeEncoder(out_, ">/tmp/t cat - cjpeg quality %i", quality), rgbp(rgbp_) {
1036  // :Filter::PipeE(out_, "cjpeg -quality %i >%D", quality), rgbp(rgbp_) {
1037  :Filter::PipeE(out_, "lzw_codec encode >%D") {}
1038 #endif
1039 
1040 /* --- */
1041 
CjpegEncode(GenBuffer::Writable & out_,char const * filter_psname,slen_t Columns,slen_t Rows,bool rgbp_,unsigned char quality)1042 CjpegEncode::CjpegEncode(GenBuffer::Writable &out_, char const*filter_psname, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality)
1043   :p(out_, Columns, Rows, rgbp_, quality) {
1044   (void)filter_psname;
1045 }
vi_write(char const * buf,slen_t len)1046 void CjpegEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
1047 
1048 /* Imp: figure out path-to-gs: gs or gswin32c */
P(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,bool rgbp_,unsigned char quality)1049 CjpegEncode::P::P(GenBuffer::Writable &out_, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality)
1050  // :PipeEncoder(out_, ">/tmp/t cat - cjpeg quality %i", quality), rgbp(rgbp_) {
1051  :Filter::PipeE(out_, "cjpeg -quality %i >%D", quality), rgbp(rgbp_) {
1052   /* Dat: we're extremely lucky that cjpeg can read PGM or PPM files from stdin */
1053   // operator<<("P5 width height 255\n"); /* RAWBITS PGM */
1054   // operator<<("P6 width height 255\n"); /* RAWBITS PPM */
1055   *this << (rgbp_?"P6 ":"P5 ") << Columns << ' ' << Rows << " 255\n";
1056 }
vi_copy(FILE * f)1057 void CjpegEncode::P::vi_copy(FILE *f) {
1058   char r[10];
1059   static char jfif[9]="\377\340\000\020JFIF";
1060   static unsigned char adobe[16]= {
1061     0xff, /* marker */
1062     0xee, /* APP14 */
1063     0,    /* length-hi */
1064     14,   /* length-lo */
1065     'A', 'd', 'o', 'b', 'e', /* ID */
1066     1,    /* version-hi */
1067     0,    /* version-lo */
1068     0, 0, /* flags0 */
1069     0, 0, /* flags1 */
1070     0,    /* ColorTransform */
1071   };
1072   if (MACRO_GETC(f)!=0xff || MACRO_GETC(f)!=0xd8 || fread(r, 1, 8, f)!=8) {
1073     bad: Error::sev(Error::EERROR) << "CjpegEncode: cjpeg created bad JPEG" << (Error*)0;
1074   }
1075   out.vi_putcc((char)0xff);
1076   out.vi_putcc((char)0xd8);
1077   r[9]=r[3]; r[3]='\020';
1078   if ((unsigned char)r[9]>=6 && 0==memcmp(r, jfif, 8)) { /* JFIF marker */
1079     r[3]=r[9]; unsigned skip=r[9]-6;
1080     out.vi_write(r, 8);
1081     while (skip--!=0) out.vi_putcc(MACRO_GETC(f));
1082   }
1083   if (ferror(f) || feof(f)) goto bad;
1084   /* Now we can emit the Adobe marker. */
1085   adobe[sizeof(adobe)-1]=rgbp==true; /* ColorTransform value 0 for Gray, 1 for RGB->YCbCr */
1086   out.vi_write((char*)adobe, sizeof(adobe));
1087   /* vvv Dat: pacify VC6.0: Filter::PipeE::vi_copy(f); doesn't work */
1088   PipeE::vi_copy(f);
1089   /* ^^^ copy rest of file verbatim */
1090   // ((Filter::PipeE)*this).vi_copy(f);
1091 }
1092 
1093 /* --- */
1094 
GSEncode(GenBuffer::Writable & out_,char const * filter_psname)1095 GSEncode::GSEncode(GenBuffer::Writable &out_, char const*filter_psname)
1096   :p(out_, filter_psname) {}
vi_write(char const * buf,slen_t len)1097 void GSEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
1098 
1099 /* Imp: figure out path-to-gs: gs or gswin32c */
P(GenBuffer::Writable & out_,char const * filter_psname)1100 GSEncode::P::P(GenBuffer::Writable &out_, char const*filter_psname)
1101   :Filter::PipeE(out_, "gs -s_OFN=%D -dNODISPLAY -q - >%E")
1102   {
1103   operator<<("{/o _OFN(w)file ");
1104   operator<<(filter_psname);
1105   operator<<(" filter def/s 4096 string def"
1106              "{currentfile s readstring exch o exch writestring not{exit}if}loop "
1107              "o closefile quit}bind exec\n");
1108 }
vi_check()1109 void GSEncode::P::vi_check() {
1110   /* If STDOUT of gs is not empty, then it is very probably an error message. */
1111   // tmpename.term0(); /* already is */
1112   assert(tmpename.end_()[0]=='\0');
1113   if (0!=Files::statSize(tmpename())) Error::sev(Error::EERROR) << "GSEncode: GS runtime error" << (Error*)0;
1114   /* Imp: display a meaningful error message */
1115 }
1116 
1117 /* --- */
1118 
newASCIIHexEncode(GenBuffer::Writable & out_,unsigned maxcpl_)1119 PSEncoder* PSEncoder::newASCIIHexEncode(GenBuffer::Writable &out_,unsigned maxcpl_) {
1120   // SimBuffer::B fp; (fp << maxcpl_ << " pop/ASCIIHexEncode").term0();
1121   // PSEncoder *ret=new GSEncode(out_, fp());
1122   PSEncoder *ret=new ASCIIHexEncode(out_,maxcpl_);
1123   // ret->shortname="AHx";  ret->longname="ASCIIHex";
1124   // ret->filter_psname << fp;
1125   return ret;
1126 }
newASCII85Encode(GenBuffer::Writable & out_,unsigned maxcpl_)1127 PSEncoder* PSEncoder::newASCII85Encode(GenBuffer::Writable &out_,unsigned maxcpl_) {
1128   // SimBuffer::B fp; (fp << maxcpl_ << " pop/ASCII85Encode").term0();
1129   PSEncoder *ret=new ASCII85Encode(out_,maxcpl_);
1130   // PSEncoder *ret=new GSEncode(out_, fp());
1131   // ret->shortname="A85";  ret->longname="ASCII85";
1132   // ret->filter_psname << fp;
1133   return ret;
1134 }
newCCITTFaxEncode(GenBuffer::Writable & out_,slendiff_t K,slen_t Columns,bool EndOfLine,bool BlackIs1)1135 PSEncoder* PSEncoder::newCCITTFaxEncode(GenBuffer::Writable &out_,slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1) {
1136   #if USE_BUILTIN_FAXE
1137     return new CCITTFaxEncode(out_, K, Columns, EndOfLine, BlackIs1);
1138   #else
1139     // (void)out_; (void)K; (void)Columns;
1140     // assert(0 && "unimplemented");
1141     SimBuffer::B fp("<< /K ");
1142     fp << K << "/Columns " << Columns;
1143     if (EndOfLine) fp << "/EndOfLine true"; /* PS default: false */
1144     if (BlackIs1)  fp << "/BlackIs1 true";
1145     (fp << ">>/CCITTFaxEncode").term0();
1146     // fprintf(stderr, "fp=(%s)\n", fp());
1147     PSEncoder *ret=new GSEncode(out_, fp());
1148     // ret->shortname="CCF";  ret->longname="CCITTFax";
1149     // ret->filter_psname << fp; /* Dat: this could be made faster */
1150     return ret;
1151   #endif
1152 }
newLZWEncode(GenBuffer::Writable & out_)1153 PSEncoder* PSEncoder::newLZWEncode(GenBuffer::Writable &out_) {
1154 #if USE_BUILTIN_LZW
1155   SimBuffer::B fp("/LZWEncode");
1156   PSEncoder *ret=new LZWEncode(out_);
1157   // PSEncoder *ret=new GSEncode(out_, fp());
1158   // ret->shortname="LZW";  ret->longname="LZW";
1159   // ret->filter_psname << fp;
1160   return ret;
1161 #else
1162   (void)out_;
1163   #if 0
1164     Error::sev(Error::EERROR) << "LZW not supported in this compilation of sam2p" << (Error*)0;
1165   #endif
1166   Error::sev(Error::WARNING) << "LZW: please `configure --enable-lzw' for builtin /Compression/LZW support" << (Error*)0;
1167   #if 0
1168     /* This is useless, because gs 5.50--7.04 have dummy LZW compressor:
1169      * it emits a correct LZW stream, but does no real compression, and
1170      * the file size is often increased.
1171      */
1172     PSEncoder *ret=new GSEncode(out_, "/LZWEncode");
1173     // ret->shortname="LZW";  ret->longname="LZW";
1174     // ret->filter_psname << "/LZWEncode";
1175     return ret;
1176   #endif
1177   #if 1 /* ask lzw_codec from the author of sam2p */
1178     return new Lzw_codecEncode(out_, "/LZWEncode");
1179   #endif
1180   return 0;
1181 #endif
1182 }
newFlateEncode(GenBuffer::Writable & out_,signed Effort)1183 PSEncoder* PSEncoder::newFlateEncode(GenBuffer::Writable &out_, signed Effort) {
1184   // (void)out_; (void)K; (void)Columns;
1185   // assert(0 && "unimplemented");
1186   if (Effort==0) {
1187     PSEncoder *ret=new FlateStoreEncode(out_);
1188     // ret->shortname="Fla";    ret->longname="Flate";
1189     // ret->filter_psname << fp;
1190     return ret;
1191   }
1192   if (Effort<1 || Effort>9) Effort=5;
1193   #if USE_BUILTIN_ZIP
1194     PSEncoder *ret=new FlateEncode(out_, Effort);
1195   #else
1196     SimBuffer::B fp("<</Effort "); (fp << Effort << ">>/FlateEncode").term0();
1197     PSEncoder *ret=new GSEncode(out_, fp());
1198   #endif
1199   // ret->shortname="Fla";  ret->longname="Flate";
1200   // ret->filter_psname << fp;
1201   return ret;
1202 }
newRunLengthEncode(GenBuffer::Writable & out_,slen_t RecordSize)1203 PSEncoder* PSEncoder::newRunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize) {
1204   SimBuffer::B fp; (fp << RecordSize << "/RunLengthEncode").term0();
1205   PSEncoder *ret=new RunLengthEncode(out_, RecordSize);
1206   // PSEncoder *ret=new GSEncode(out_, fp());
1207   // ret->shortname="RL";  ret->longname="RunLength";
1208   // ret->filter_psname << fp;
1209   return ret;
1210 }
1211 
newDCTIJGEncode(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,unsigned char Colors,unsigned char quality)1212 PSEncoder* PSEncoder::newDCTIJGEncode(GenBuffer::Writable &out_,
1213   slen_t Columns,
1214   slen_t Rows,
1215   unsigned char Colors, /*1..4*/
1216   unsigned char quality /*libJPEG quality: 0..100 */
1217 ) {
1218   /* Dat: this supports only the Gray and RGB color spaces of JPEG */
1219   param_assert(Colors==1 || Colors==3);
1220   param_assert(/* quality>=0 && */ quality <=100);
1221   SimBuffer::B fp("<<IJG ");
1222   (fp<< "/Columns " << Columns
1223      << "/Rows " << Rows
1224      << "/Colors " << (unsigned)Colors
1225      << ">>/DCTEncode").term0();
1226   /* Dat: the default of /ColorTransform (defined in DCTEncode in
1227      subsubsection 3.13.3 in PLRM.pdf) is just perfect. */
1228   PSEncoder *ret=new CjpegEncode(out_, fp(), Columns, Rows, Colors==3, quality);
1229   // ret->longname=ret->shortname="DCT";  ret->filter_psname << fp;
1230   return ret;
1231 }
1232 
newDCTEncode(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,unsigned char Colors,unsigned char quality,unsigned char const * HSamples,unsigned char const * VSamples,unsigned char (* QuantTables)[64],double QFactor,unsigned numHuffTables,unsigned char ** HuffTables,unsigned char ColorTransform)1233 PSEncoder* PSEncoder::newDCTEncode(GenBuffer::Writable &out_,
1234   slen_t Columns,
1235   slen_t Rows,
1236   unsigned char Colors, /*1..4*/
1237   unsigned char quality, /*libJPEG quality: 0..100 */
1238   unsigned char const*HSamples, /*all 1..4, NULLP OK*/
1239   unsigned char const*VSamples, /*all 1..4, NULLP OK*/
1240   unsigned char (*QuantTables)[64], /*NULLP OK*/
1241   double        QFactor, /*0..1000000*/
1242   unsigned      numHuffTables,
1243   unsigned char **HuffTables, /*NULLP OK*/
1244   unsigned char ColorTransform /*0,1,2 3=default*/
1245 ) {
1246   (void)quality;
1247   (void)QuantTables;
1248   (void)QFactor;
1249   (void)numHuffTables;
1250   (void)HuffTables;
1251   SimBuffer::B tmp;
1252   /* Imp: respect quality */
1253   /* Imp: respect QFactor (double) */
1254   /* Imp: respect QuantTables */
1255   /* Imp: respect numHuffTables, HuffTables */
1256 
1257   SimBuffer::B fp("<<");
1258   fp << "/Columns " << Columns
1259      << "/Rows " << Rows
1260      << "/Colors " << (unsigned)Colors;
1261   if (HSamples!=(unsigned char const*)NULLP) {
1262     tmp.clear(); tmp.vi_write((char const*)HSamples, (unsigned)Colors);
1263     fp << "/HSamples "; fp.appendDumpPS(tmp,true);
1264   }
1265   if (VSamples!=(unsigned char const*)NULLP) {
1266     tmp.clear(); tmp.vi_write((char const*)VSamples, (unsigned)Colors);
1267     fp << "/VSamples "; fp.appendDumpPS(tmp,true);
1268   }
1269   if (ColorTransform!=3) fp << "/ColorTransform " << (unsigned)ColorTransform;
1270   (fp << ">>/DCTEncode").term0();
1271 
1272   // PSEncoder *ret=new DCTEncode(out_,? ? ?);
1273   PSEncoder *ret=new GSEncode(out_, fp());
1274   // ret->shortname="DCT";  ret->longname="DCT";
1275   // ret->filter_psname << fp;
1276   return ret;
1277 }
1278 
newDCTEncode(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,unsigned char Colors,unsigned char ColorTransform,SimBuffer::Flat const & other_parameters)1279 PSEncoder* PSEncoder::newDCTEncode(GenBuffer::Writable &out_,
1280   slen_t Columns,
1281   slen_t Rows,
1282   unsigned char Colors, /*1..4*/
1283   unsigned char ColorTransform, /*0,1,2 3=default*/
1284   SimBuffer::Flat const& other_parameters
1285 ) {
1286   SimBuffer::B fp("<<");
1287   fp << "/Columns " << Columns
1288      << "/Rows " << Rows
1289      << "/Colors " << (unsigned)Colors;
1290   if (ColorTransform!=3) fp << "/ColorTransform " << (unsigned)ColorTransform;
1291   (fp << other_parameters << ">>/DCTEncode").term0();
1292   PSEncoder *ret=new GSEncode(out_, fp());
1293   // ret->shortname="DCT";  ret->longname="DCT";
1294   // ret->filter_psname << fp;
1295   return ret;
1296 }
1297 
1298 /* --- */
1299 
TIFFPredictor2(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1300 TIFFPredictor2::TIFFPredictor2(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1301  : h(0), bpc(bpc_), cpp(cpp_), out(out_) {
1302   param_assert(cpp_*bpc_<=32);
1303   rlen=(columns_*cpp_*bpc_+7)>>3; /* BUGFIX at Tue Mar 12 12:09:51 CET 2002 */
1304   op=obuf=new unsigned char[rlen];
1305 }
1306 
vi_write(char const * buf,slen_t len)1307 void TIFFPredictor2::vi_write(char const*buf, slen_t len) {
1308   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1309   slen_t opleft=rlen-(op-obuf);
1310   register unsigned int i, d, o, bpccpp;
1311   if (len==0) {
1312     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1313     assert(obuf!=NULLP);
1314     delete [] obuf;
1315     obuf=(unsigned char*)NULLP;
1316     out.vi_write(0,0);
1317     return;
1318   }
1319   bpccpp=(cpp-1)*bpc;
1320   if (bpc==1) {
1321     while (p!=pend0) {
1322       i=*p++;
1323       d=(i>>7); o =((d-((h>>bpccpp)))&1)<<7; h=(h<<1)|d;
1324       d=(i>>6); o|=((d-((h>>bpccpp)))&1)<<6; h=(h<<1)|d;
1325       d=(i>>5); o|=((d-((h>>bpccpp)))&1)<<5; h=(h<<1)|d;
1326       d=(i>>4); o|=((d-((h>>bpccpp)))&1)<<4; h=(h<<1)|d;
1327       d=(i>>3); o|=((d-((h>>bpccpp)))&1)<<3; h=(h<<1)|d;
1328       d=(i>>2); o|=((d-((h>>bpccpp)))&1)<<2; h=(h<<1)|d;
1329       d=(i>>1); o|=((d-((h>>bpccpp)))&1)<<1; h=(h<<1)|d;
1330       d=(i   ); o|=((d-((h>>bpccpp)))&1)   ; h=(h<<1)|d;
1331       *op++=o;
1332       if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1333     }
1334   } else if (bpc==2) {
1335     while (p!=pend0) {
1336       i=*p++;
1337       d=(i>>6); o =((d-((h>>bpccpp)))&3)<<6; h=(h<<2)|d; // fprintf(stderr,"d=%#x\n", d);
1338       d=(i>>4); o|=((d-((h>>bpccpp)))&3)<<4; h=(h<<2)|d;
1339       d=(i>>2); o|=((d-((h>>bpccpp)))&3)<<2; h=(h<<2)|d;
1340       d=(i   ); o|=((d-((h>>bpccpp)))&3)   ; h=(h<<2)|d;
1341       *op++=o;
1342       if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1343     }
1344   } else if (bpc==4) {
1345     while (p!=pend0) {
1346       i=*p++;
1347       d=(i>>4); o =((d-((h>>bpccpp)))&15)<<4; h=(h<<4)|d;
1348       d=(i   ); o|=((d-((h>>bpccpp)))&15)   ; h=(h<<4)|d;
1349       *op++=o;
1350       if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1351     }
1352   } else if (bpc==8) {
1353     while (p!=pend0) {
1354       i=*p++; *op++=((i-((h>>bpccpp)))/*&255*/); h=(h<<8)|i;
1355       if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1356     }
1357   } else assert(0);
1358 }
1359 
1360 /* --- */
1361 
PNGPredictorNone(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1362 PNGPredictorNone::PNGPredictorNone(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1363  : opleft(0), out(out_) {
1364   rlen=(columns_*cpp_*bpc_+7)>>3;
1365 }
1366 
vi_write(char const * buf,slen_t len)1367 void PNGPredictorNone::vi_write(char const*buf, slen_t len) {
1368   if (len==0) {
1369     assert(opleft==0); /* unflushed (half-ready) row disallowed */
1370     out.vi_write(0,0);
1371     return;
1372   }
1373   /* The following code just inserts a '\0' in front of each scanline */
1374   /* Imp: make it faster by collapsing vi_writes */
1375   if (opleft==0) { opleft=rlen; out.vi_write("\0",1); } /* Scanline (row) header: describes predictor used */
1376   while (len>opleft) {
1377     out.vi_write(buf,opleft);
1378     buf+=opleft; len-=opleft;
1379     opleft=rlen; out.vi_write("\0",1); /* Scanline (row) header: describes predictor used */
1380   }
1381   if (len!=0) out.vi_write(buf,len);
1382   opleft-=len;
1383 }
1384 
1385 /* --- */
1386 
PNGPredictorSub(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1387 PNGPredictorSub::PNGPredictorSub(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1388  : h(0), out(out_) {
1389   param_assert(cpp_*bpc_<=32);
1390   rlen=(columns_*cpp_*bpc_+7)>>3;
1391   op=obuf=1+new unsigned char[rlen+1];
1392   obuf[-1]='\1'; /* Scanline (row) header: describes predictor used */
1393   bpccpp=((cpp_*bpc_+7)&~7)-8;
1394 }
1395 
vi_write(char const * buf,slen_t len)1396 void PNGPredictorSub::vi_write(char const*buf, slen_t len) {
1397   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1398   slen_t opleft=rlen-(op-obuf);
1399   register unsigned int i;
1400   if (len==0) {
1401     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1402     assert(obuf!=NULLP);
1403     delete [] (obuf-1);
1404     obuf=(unsigned char*)NULLP;
1405     out.vi_write(0,0);
1406     return;
1407   }
1408   while (p!=pend0) {
1409     i=*p++; *op++=((i-((h>>bpccpp)))/*&255*/); h=(h<<8)|i;
1410     if (--opleft==0) { h=0;
1411       out.vi_write((char*)obuf-1,rlen+1); op=obuf; opleft=rlen;
1412     }
1413   }
1414 }
1415 
1416 /* --- */
1417 
PNGPredictorUp(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1418 PNGPredictorUp::PNGPredictorUp(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1419  : out(out_) {
1420   rlen=(columns_*cpp_*bpc_+7)>>3;
1421   // fprintf(stderr, "rUp.rlen=%u cpp=%u bpc=%u\n", rlen, cpp_, bpc_);
1422   op=obuf=1+new unsigned char[2*rlen+1];
1423   oq=op+rlen; /* prev scanline */
1424   memset(oq, '\0', rlen);
1425   obuf[-1]='\2'; /* Scanline (row) header: describes predictor used */
1426 }
1427 
vi_write(char const * buf,slen_t len)1428 void PNGPredictorUp::vi_write(char const*buf, slen_t len) {
1429   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1430   slen_t opleft=rlen-(op-obuf);
1431   if (len==0) {
1432     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1433     assert(obuf!=NULLP);
1434     delete [] (obuf-1);
1435     obuf=(unsigned char*)NULLP;
1436     out.vi_write(0,0);
1437     return;
1438   }
1439   while (p!=pend0) {
1440     *op++=((*p-*oq)/*&255*/); *oq++=*p++;
1441     if (--opleft==0) {
1442       out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
1443       op=obuf; oq=obuf+rlen;
1444     }
1445   }
1446 }
1447 
1448 /* --- */
1449 
PNGPredictorAverage(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1450 PNGPredictorAverage::PNGPredictorAverage(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1451  : h(0), /*g(0),*/ out(out_) {
1452   param_assert(cpp_*bpc_<=32);
1453   rlen=(columns_*cpp_*bpc_+7)>>3;
1454   op=obuf=1+new unsigned char[2*rlen+1];
1455   oq=op+rlen; /* prev scanline */
1456   memset(oq, '\0', rlen);
1457   obuf[-1]='\3'; /* Scanline (row) header: describes predictor used */
1458   bpccpp=((cpp_*bpc_+7)&~7)-8;
1459 }
1460 
vi_write(char const * buf,slen_t len)1461 void PNGPredictorAverage::vi_write(char const*buf, slen_t len) {
1462   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1463   slen_t opleft=rlen-(op-obuf);
1464   register unsigned int i;
1465   if (len==0) {
1466     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1467     assert(obuf!=NULLP);
1468     delete [] (obuf-1);
1469     obuf=(unsigned char*)NULLP;
1470     out.vi_write(0,0);
1471     return;
1472   }
1473   while (p!=pend0) {
1474     /* vvv Data: *og+h can be 0..510 */
1475     i=*p; *op++=i-((((h>>bpccpp)&255)+*oq)>>1); h=(h<<8)|i; *oq++=*p++;
1476     // i=*p; *op++=(*p-((*oq+h)>>1)/*&255*/); h=i; *oq++=*p++;
1477     if (--opleft==0) {
1478       out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
1479       op=obuf; oq=obuf+rlen; h=0;
1480     }
1481   }
1482 }
1483 
1484 /* --- */
1485 
1486 /* Dat: egcs-2.91.60 is buggy */
1487 // static inline unsigned abs_(unsigned i) { return ((signed)i)<0 ? -i : i; }
abs_(unsigned i)1488 static inline unsigned abs_(unsigned i) { return ((signed)i)<0 ? (i*-1) : i; }
1489 
paeth_predictor(unsigned a,unsigned b,unsigned c)1490 static inline unsigned paeth_predictor(unsigned a, unsigned b, unsigned c) {
1491   /* Code ripped from RFC 2083 (PNG specification), which also says:
1492    * The calculations within the PaethPredictor function must be
1493    * performed exactly, without overflow.  Arithmetic modulo 256 is to
1494    * be used only for the final step of subtracting the function result
1495    * from the target byte value.
1496    */
1497   /* a = left, b = above, c = upper left */
1498   unsigned p  = a + b - c;       /* initial estimate */
1499   unsigned pa = abs_(p - a);     /* distances to a, b, c */
1500   unsigned pb = abs_(p - b);
1501   unsigned pc = abs_(p - c);
1502   // assert(abs_(3*(-1))==3);
1503   // fprintf(stderr, "b=%u c=%u %d %d\n", b, c, p-b, ((signed)(p-b))<0 ? (b-p) : (p-b) );
1504   // fprintf(stderr, "pa=%u pb=%u pc=%u\n", pa, pb, pc);
1505   assert(pa<=255);
1506   assert(pb<=255);
1507   assert(pc<=255*2);
1508   /* return nearest of a,b,c, breaking ties in order a,b,c. */
1509   return (pa <= pb && pa <= pc) ? a
1510        : pb <= pc ? b
1511        : c;
1512 }
1513 
PNGPredictorPaeth(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1514 PNGPredictorPaeth::PNGPredictorPaeth(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1515  : h(0), g(0), out(out_) {
1516   param_assert(cpp_*bpc_<=32);
1517   rlen=(columns_*cpp_*bpc_+7)>>3;
1518   op=obuf=1+new unsigned char[2*rlen+2];
1519   oq=obuf+rlen+1; /* prev scanline */
1520   memset(obuf+rlen, '\0', rlen+1);
1521   obuf[-1]='\4'; /* Scanline (row) header: describes predictor used */
1522   bpccpp=((cpp_*bpc_+7)&~7)-8;
1523 }
1524 
vi_write(char const * buf,slen_t len)1525 void PNGPredictorPaeth::vi_write(char const*buf, slen_t len) {
1526   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1527   slen_t opleft=rlen-(op-obuf);
1528   register unsigned int i;
1529   if (len==0) {
1530     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1531     assert(obuf!=NULLP);
1532     delete [] (obuf-1);
1533     obuf=(unsigned char*)NULLP;
1534     out.vi_write(0,0);
1535     return;
1536   }
1537   while (p!=pend0) {
1538     // assert(0==obuf[rlen] && 4==obuf[-1]);
1539     i=*p;  *op++=i-paeth_predictor((h>>bpccpp)&255, *oq, (g>>bpccpp)&255);
1540     h=(h<<8)|i; g=(g<<8)|*oq; *oq++=*p++;
1541     // i=*p; *op++=i-h; h=i; *oq++=*p++;
1542     if (--opleft==0) {
1543       out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
1544       op=obuf; oq=obuf+rlen+1; h=0; g=0;
1545     }
1546   }
1547 }
1548 
1549 /* --- */
1550 
1551 #if SIZEOF_INT >= 4
1552 typedef int weight_t;
1553 #else
1554 typedef long weight_t;
1555 #endif
1556 
PNGPredictorAutoBadSigned(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1557 PNGPredictorAutoBadSigned::PNGPredictorAutoBadSigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1558  : h(0), g(0), out(out_) {
1559   param_assert(cpp_*bpc_<=32);
1560   opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
1561   obuf=new unsigned char[6*rlen+6];
1562   o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
1563   obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
1564   obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
1565   obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
1566   obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
1567   obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
1568   oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
1569   memset(obuf, '\0', rlen+1);
1570   bpccpp=((cpp_*bpc_+7)&~7)-8;
1571 }
1572 
vi_write(char const * buf,slen_t len)1573 void PNGPredictorAutoBadSigned::vi_write(char const*buf, slen_t len) {
1574   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1575   register unsigned int i;
1576   register unsigned raw_x_bpp, prior_x, prior_x_bpp;
1577   if (len==0) {
1578     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1579     assert(obuf!=NULLP);
1580     delete [] obuf;
1581     obuf=(unsigned char*)NULLP;
1582     out.vi_write(0,0);
1583     return;
1584   }
1585   while (p!=pend0) {
1586     raw_x_bpp=(h>>bpccpp) &255;
1587     prior_x=*(o_prior-opleft);
1588     prior_x_bpp=(g>>bpccpp) &255;
1589     i=*p;
1590     *(o_0-opleft)=i;
1591     *(o_1-opleft)=i-raw_x_bpp;
1592     *(o_2-opleft)=i-prior_x;
1593     *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
1594     *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
1595     h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
1596     if (--opleft==0) {
1597       /* Select the predictor having the smallest signed sum of values. */
1598       weight_t min_weight, cur_weight;
1599       unsigned min_pred=0, cur_pred;
1600       register signed char *beg, *end;
1601       min_weight=0; beg=(end=(signed char*)o_0)-rlen; while (beg!=end) min_weight+=*beg++;
1602       if (min_weight<0) min_weight*=-1;
1603       for (cur_pred=1; cur_pred<=4; cur_pred++) {
1604         cur_weight=0; beg=(end=(signed char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=*beg++;
1605         if (cur_weight<0) cur_weight*=-1;
1606         if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
1607       }
1608       // fprintf(stderr, "cp=%u\n", min_pred);
1609 
1610       out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
1611       opleft=rlen; h=0; g=0;
1612     }
1613   }
1614 }
1615 
1616 /* --- */
1617 
PNGPredictorAutoBadUnsigned(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1618 PNGPredictorAutoBadUnsigned::PNGPredictorAutoBadUnsigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1619  : h(0), g(0), out(out_) {
1620   param_assert(cpp_*bpc_<=32);
1621   opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
1622   obuf=new unsigned char[6*rlen+6];
1623   o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
1624   obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
1625   obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
1626   obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
1627   obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
1628   obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
1629   oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
1630   memset(obuf, '\0', rlen+1);
1631   bpccpp=((cpp_*bpc_+7)&~7)-8;
1632 }
1633 
vi_write(char const * buf,slen_t len)1634 void PNGPredictorAutoBadUnsigned::vi_write(char const*buf, slen_t len) {
1635   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1636   register unsigned int i;
1637   register unsigned raw_x_bpp, prior_x, prior_x_bpp;
1638   // unsigned lines=0;
1639   if (len==0) {
1640     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1641     assert(obuf!=NULLP);
1642     delete [] obuf;
1643     obuf=(unsigned char*)NULLP;
1644     out.vi_write(0,0);
1645     return;
1646   }
1647   // fprintf(stderr, "rlen=%u len=%u opleft=%u\n", rlen, len, opleft);
1648   while (p!=pend0) {
1649     raw_x_bpp=(h>>bpccpp) &255;
1650     prior_x=*(o_prior-opleft);
1651     prior_x_bpp=(g>>bpccpp) &255;
1652     i=*p;
1653     *(o_0-opleft)=i;
1654     *(o_1-opleft)=i-raw_x_bpp;
1655     *(o_2-opleft)=i-prior_x;
1656     *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
1657     *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
1658     h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
1659     if (--opleft==0) {
1660       /* Select the predictor having the smallest unsigned sum of values. */
1661       weight_t min_weight, cur_weight;
1662       unsigned min_pred=0, cur_pred;
1663       register unsigned char *beg, *end;
1664       min_weight=0; beg=(end=(unsigned char*)o_0)-rlen; while (beg!=end) min_weight+=*beg++;
1665       for (cur_pred=1; cur_pred<=4; cur_pred++) {
1666         cur_weight=0; beg=(end=(unsigned char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=*beg++;
1667         if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
1668       }
1669       // fprintf(stderr, "cp=%u\n", min_pred);
1670 
1671       out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
1672       opleft=rlen; h=0; g=0;
1673       // lines++;
1674     }
1675   }
1676   // fprintf(stderr, "oen=%u opleft=%u lines=%u\n", len, opleft, lines);
1677 }
1678 
1679 /* --- */
1680 
PNGPredictorAuto(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1681 PNGPredictorAuto::PNGPredictorAuto(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1682  : h(0), g(0), out(out_) {
1683   param_assert(cpp_*bpc_<=32);
1684   opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
1685   obuf=new unsigned char[6*rlen+6];
1686   o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
1687   obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
1688   obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
1689   obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
1690   obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
1691   obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
1692   oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
1693   memset(obuf, '\0', rlen+1);
1694   bpccpp=((cpp_*bpc_+7)&~7)-8;
1695 }
1696 
vi_write(char const * buf,slen_t len)1697 void PNGPredictorAuto::vi_write(char const*buf, slen_t len) {
1698   unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1699   register unsigned int i;
1700   register unsigned raw_x_bpp, prior_x, prior_x_bpp;
1701   // unsigned lines=0;
1702   if (len==0) {
1703     assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1704     assert(obuf!=NULLP);
1705     delete [] obuf;
1706     obuf=(unsigned char*)NULLP;
1707     out.vi_write(0,0);
1708     return;
1709   }
1710   // fprintf(stderr, "rlen=%u len=%u opleft=%u\n", rlen, len, opleft);
1711   while (p!=pend0) {
1712     raw_x_bpp=(h>>bpccpp) &255;
1713     prior_x=*(o_prior-opleft);
1714     prior_x_bpp=(g>>bpccpp) &255;
1715     i=*p;
1716     *(o_0-opleft)=i;
1717     *(o_1-opleft)=i-raw_x_bpp;
1718     *(o_2-opleft)=i-prior_x;
1719     *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
1720     *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
1721     h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
1722     if (--opleft==0) {
1723       /* Select the predictor having the smallest unsigned sum of values. */
1724       weight_t min_weight, cur_weight;
1725       unsigned min_pred=0, cur_pred;
1726       register signed char *beg, *end;
1727       /* abs_(...) here converts '\xFF' to 1. Good. */
1728       min_weight=0; beg=(end=(signed char*)o_0)-rlen; while (beg!=end) min_weight+=abs_(*beg++);
1729       for (cur_pred=1; cur_pred<=4; cur_pred++) {
1730         cur_weight=0; beg=(end=(signed char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=abs_(*beg++);
1731         if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
1732       }
1733       // fprintf(stderr, "cp=%u\n", min_pred);
1734 
1735       out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
1736       opleft=rlen; h=0; g=0;
1737       // lines++;
1738     }
1739   }
1740   // fprintf(stderr, "oen=%u opleft=%u lines=%u\n", len, opleft, lines);
1741 }
1742 
1743 /* --- */
1744 
newPredictor(GenBuffer::Writable & out_,unsigned char type,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1745 Encoder* PSEncoder::newPredictor(GenBuffer::Writable &out_, unsigned char type, unsigned char bpc_, slen_t columns_, unsigned char cpp_) {
1746   switch ((unsigned)type) {
1747    /* Imp: make these faster with `register int' etc. tricks */
1748    /* See also better_predictor in rule.cpp for the list of predictor numbers */
1749    case 1:  return new Filter::VerbatimE(out_);
1750    case 2:  return new TIFFPredictor2(out_, bpc_, columns_, cpp_);
1751    case 10: return new PNGPredictorNone(out_, bpc_, columns_, cpp_);
1752    case 11: return new PNGPredictorSub(out_, bpc_, columns_, cpp_);
1753    case 12: return new PNGPredictorUp(out_, bpc_, columns_, cpp_);
1754    case 13: return new PNGPredictorAverage(out_, bpc_, columns_, cpp_);
1755    case 14: return new PNGPredictorPaeth(out_, bpc_, columns_, cpp_);
1756    case 15: return new PNGPredictorAuto(out_, bpc_, columns_, cpp_);
1757    case 45: return new PNGPredictorAutoBadUnsigned(out_, bpc_, columns_, cpp_); /* pts' extension */
1758    case 55: return new PNGPredictorAutoBadSigned(out_, bpc_, columns_, cpp_); /* pts' extension */
1759   }
1760   // fprintf(stderr, "pred=%d\n", type);
1761   param_assert(0 && "invalid predictor requested");
1762   return (Encoder*)0; /*notreached*/
1763 }
1764 
1765 /* __END__ */
1766