1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
30 #include "Stream-CCITT.h"
33 static GBool setDJSYSFLAGS
= gFalse
;
37 #if (__VMS_VER < 70000000)
38 extern "C" int unlink(char *filename
);
48 #include "StuffItEngineLib.h"
51 //------------------------------------------------------------------------
52 // Stream (base class)
53 //------------------------------------------------------------------------
62 int Stream::getRawChar() {
63 error(-1, "Internal: called getRawChar() on non-predictor stream");
67 char *Stream::getLine(char *buf
, int size
) {
71 if (lookChar() == EOF
)
73 for (i
= 0; i
< size
- 1; ++i
) {
75 if (c
== EOF
|| c
== '\n')
78 if ((c
= lookChar()) == '\n')
88 GString
*Stream::getPSFilter(const char *indent
) {
94 Stream
*Stream::addFilters(Object
*dict
) {
96 Object params
, params2
;
101 dict
->dictLookup("Filter", &obj
);
104 dict
->dictLookup("F", &obj
);
106 dict
->dictLookup("DecodeParms", ¶ms
);
107 if (params
.isNull()) {
109 dict
->dictLookup("DP", ¶ms
);
112 str
= makeFilter(obj
.getName(), str
, ¶ms
);
113 } else if (obj
.isArray()) {
114 for (i
= 0; i
< obj
.arrayGetLength(); ++i
) {
115 obj
.arrayGet(i
, &obj2
);
116 if (params
.isArray())
117 params
.arrayGet(i
, ¶ms2
);
121 str
= makeFilter(obj2
.getName(), str
, ¶ms2
);
123 error(getPos(), "Bad filter name");
124 str
= new EOFStream(str
);
129 } else if (!obj
.isNull()) {
130 error(getPos(), "Bad 'Filter' attribute in stream");
138 Stream
*Stream::makeFilter(const char *name
, Stream
*str
, Object
*params
) {
139 int pred
; // parameters
144 GBool endOfLine
, byteAlign
, endOfBlock
, black
;
148 if (!strcmp(name
, "ASCIIHexDecode") || !strcmp(name
, "AHx")) {
149 str
= new ASCIIHexStream(str
);
150 } else if (!strcmp(name
, "ASCII85Decode") || !strcmp(name
, "A85")) {
151 str
= new ASCII85Stream(str
);
152 } else if (!strcmp(name
, "LZWDecode") || !strcmp(name
, "LZW")) {
158 if (params
->isDict()) {
159 params
->dictLookup("Predictor", &obj
);
163 params
->dictLookup("Columns", &obj
);
165 columns
= obj
.getInt();
167 params
->dictLookup("Colors", &obj
);
169 colors
= obj
.getInt();
171 params
->dictLookup("BitsPerComponent", &obj
);
175 params
->dictLookup("EarlyChange", &obj
);
177 early
= obj
.getInt();
180 str
= new LZWStream(str
, pred
, columns
, colors
, bits
, early
);
181 } else if (!strcmp(name
, "RunLengthDecode") || !strcmp(name
, "RL")) {
182 str
= new RunLengthStream(str
);
183 } else if (!strcmp(name
, "CCITTFaxDecode") || !strcmp(name
, "CCF")) {
191 if (params
->isDict()) {
192 params
->dictLookup("K", &obj
);
194 encoding
= obj
.getInt();
197 params
->dictLookup("EndOfLine", &obj
);
199 endOfLine
= obj
.getBool();
202 params
->dictLookup("EncodedByteAlign", &obj
);
204 byteAlign
= obj
.getBool();
207 params
->dictLookup("Columns", &obj
);
209 columns
= obj
.getInt();
212 params
->dictLookup("Rows", &obj
);
217 params
->dictLookup("EndOfBlock", &obj
);
219 endOfBlock
= obj
.getBool();
222 params
->dictLookup("BlackIs1", &obj
);
224 black
= obj
.getBool();
228 str
= new CCITTFaxStream(str
, encoding
, endOfLine
, byteAlign
,
229 columns
, rows
, endOfBlock
, black
);
230 } else if (!strcmp(name
, "DCTDecode") || !strcmp(name
, "DCT")) {
231 str
= new DCTStream(str
);
232 } else if (!strcmp(name
, "FlateDecode") || !strcmp(name
, "Fl")) {
237 if (params
->isDict()) {
238 params
->dictLookup("Predictor", &obj
);
242 params
->dictLookup("Columns", &obj
);
244 columns
= obj
.getInt();
246 params
->dictLookup("Colors", &obj
);
248 colors
= obj
.getInt();
250 params
->dictLookup("BitsPerComponent", &obj
);
255 str
= new FlateStream(str
, pred
, columns
, colors
, bits
);
257 error(getPos(), "Unknown filter '%s'", name
);
258 str
= new EOFStream(str
);
263 //------------------------------------------------------------------------
265 //------------------------------------------------------------------------
267 BaseStream::BaseStream(Object
*ndict
) {
269 #ifndef NO_DECRYPTION
274 BaseStream::~BaseStream() {
276 #ifndef NO_DECRYPTION
282 #ifndef NO_DECRYPTION
283 void BaseStream::doDecryption(Guchar
*fileKey
, int objNum
, int objGen
) {
284 decrypt
= new Decrypt(fileKey
, objNum
, objGen
);
288 //------------------------------------------------------------------------
290 //------------------------------------------------------------------------
292 FilterStream::FilterStream(Stream
*nstr
) {
296 FilterStream::~FilterStream() {
299 void FilterStream::setPos(int pos
) {
302 error(-1, "Internal: called setPos() on FilterStream");
305 //------------------------------------------------------------------------
307 //------------------------------------------------------------------------
309 ImageStream::ImageStream(Stream
*nstr
, int nwidth
, int nnComps
, int nnBits
) {
317 nVals
= width
* nComps
;
319 imgLineSize
= (nVals
+ 7) & ~7;
323 imgLine
= (Guchar
*)gmalloc(imgLineSize
* sizeof(Guchar
));
327 ImageStream::~ImageStream() {
331 void ImageStream::reset() {
335 GBool
ImageStream::getPixel(Guchar
*pix
) {
341 if (imgIdx
>= nVals
) {
343 // read one line of image pixels
345 for (i
= 0; i
< nVals
; i
+= 8) {
347 imgLine
[i
+0] = (Guchar
)((c
>> 7) & 1);
348 imgLine
[i
+1] = (Guchar
)((c
>> 6) & 1);
349 imgLine
[i
+2] = (Guchar
)((c
>> 5) & 1);
350 imgLine
[i
+3] = (Guchar
)((c
>> 4) & 1);
351 imgLine
[i
+4] = (Guchar
)((c
>> 3) & 1);
352 imgLine
[i
+5] = (Guchar
)((c
>> 2) & 1);
353 imgLine
[i
+6] = (Guchar
)((c
>> 1) & 1);
354 imgLine
[i
+7] = (Guchar
)(c
& 1);
356 } else if (nBits
== 8) {
357 for (i
= 0; i
< nVals
; ++i
) {
358 imgLine
[i
] = str
->getChar();
361 bitMask
= (1 << nBits
) - 1;
364 for (i
= 0; i
< nVals
; ++i
) {
366 buf
= (buf
<< 8) | (str
->getChar() & 0xff);
369 imgLine
[i
] = (Guchar
)((buf
>> (bits
- nBits
)) & bitMask
);
374 // reset to start of line
378 for (i
= 0; i
< nComps
; ++i
)
379 pix
[i
] = imgLine
[imgIdx
++];
383 void ImageStream::skipLine() {
386 n
= (nVals
* nBits
+ 7) >> 3;
387 for (i
= 0; i
< n
; ++i
) {
392 //------------------------------------------------------------------------
394 //------------------------------------------------------------------------
396 StreamPredictor::StreamPredictor(Stream
*nstr
, int npredictor
,
397 int nwidth
, int nnComps
, int nnBits
) {
399 predictor
= npredictor
;
404 nVals
= width
* nComps
;
405 pixBytes
= (nComps
* nBits
+ 7) >> 3;
406 rowBytes
= ((nVals
* nBits
+ 7) >> 3) + pixBytes
;
407 predLine
= (Guchar
*)gmalloc(rowBytes
);
408 memset(predLine
, 0, rowBytes
);
412 StreamPredictor::~StreamPredictor() {
416 int StreamPredictor::lookChar() {
417 if (predIdx
>= rowBytes
) {
418 if (!getNextLine()) {
422 return predLine
[predIdx
];
425 int StreamPredictor::getChar() {
426 if (predIdx
>= rowBytes
) {
427 if (!getNextLine()) {
431 return predLine
[predIdx
++];
434 GBool
StreamPredictor::getNextLine() {
437 int left
, up
, upLeft
, p
, pa
, pb
, pc
;
439 Gulong inBuf
, outBuf
, bitMask
;
443 // get PNG optimum predictor number
444 if (predictor
== 15) {
445 if ((curPred
= str
->getRawChar()) == EOF
) {
453 // read the raw line, apply PNG (byte) predictor
454 upLeftBuf
[0] = upLeftBuf
[1] = upLeftBuf
[2] = upLeftBuf
[3] = 0;
455 for (i
= pixBytes
; i
< rowBytes
; ++i
) {
456 upLeftBuf
[3] = upLeftBuf
[2];
457 upLeftBuf
[2] = upLeftBuf
[1];
458 upLeftBuf
[1] = upLeftBuf
[0];
459 upLeftBuf
[0] = predLine
[i
];
460 if ((c
= str
->getRawChar()) == EOF
) {
465 predLine
[i
] = predLine
[i
- pixBytes
] + (Guchar
)c
;
468 predLine
[i
] = predLine
[i
] + (Guchar
)c
;
470 case 13: // PNG average
471 predLine
[i
] = ((predLine
[i
- pixBytes
] + predLine
[i
]) >> 1) +
474 case 14: // PNG Paeth
475 left
= predLine
[i
- pixBytes
];
477 upLeft
= upLeftBuf
[pixBytes
];
478 p
= left
+ up
- upLeft
;
479 if ((pa
= p
- left
) < 0)
481 if ((pb
= p
- up
) < 0)
483 if ((pc
= p
- upLeft
) < 0)
485 if (pa
<= pb
&& pa
<= pc
)
486 predLine
[i
] = pa
+ (Guchar
)c
;
488 predLine
[i
] = pb
+ (Guchar
)c
;
490 predLine
[i
] = pc
+ (Guchar
)c
;
493 default: // no predictor or TIFF predictor
494 predLine
[i
] = (Guchar
)c
;
499 // apply TIFF (component) predictor
500 //~ this is completely untested
501 if (predictor
== 2) {
503 inBuf
= predLine
[pixBytes
- 1];
504 for (i
= pixBytes
; i
< rowBytes
; i
+= 8) {
505 // 1-bit add is just xor
506 inBuf
= (inBuf
<< 8) | predLine
[i
];
507 predLine
[i
] ^= inBuf
>> nComps
;
509 } else if (nBits
== 8) {
510 for (i
= pixBytes
; i
< rowBytes
; ++i
) {
511 predLine
[i
] += predLine
[i
- nComps
];
514 upLeftBuf
[0] = upLeftBuf
[1] = upLeftBuf
[2] = upLeftBuf
[3] = 0;
515 bitMask
= (1 << nBits
) - 1;
517 inBits
= outBits
= 0;
519 for (i
= 0; i
< nVals
; ++i
) {
520 if (inBits
< nBits
) {
521 inBuf
= (inBuf
<< 8) | (predLine
[j
++] & 0xff);
524 upLeftBuf
[3] = upLeftBuf
[2];
525 upLeftBuf
[2] = upLeftBuf
[1];
526 upLeftBuf
[1] = upLeftBuf
[0];
527 upLeftBuf
[0] = (upLeftBuf
[nComps
] +
528 (inBuf
>> (inBits
- nBits
))) & bitMask
;
529 outBuf
= (outBuf
<< nBits
) | upLeftBuf
[0];
533 predLine
[k
++] = (Guchar
)(outBuf
>> (outBits
- 8));
537 predLine
[k
++] = (Guchar
)(outBuf
<< (8 - outBits
));
542 // reset to start of line
548 //------------------------------------------------------------------------
550 //------------------------------------------------------------------------
552 FileStream::FileStream(FILE *nf
, int nstart
, int nlength
, Object
*dict
):
557 bufPtr
= bufEnd
= buf
;
562 FileStream::~FileStream() {
564 fseek(f
, savePos
, SEEK_SET
);
568 Stream
*FileStream::makeSubStream(int nstart
, int nlength
, Object
*ndict
) {
569 return new FileStream(f
, nstart
, nlength
, ndict
);
572 void FileStream::reset() {
573 savePos
= (int)ftell(f
);
574 fseek(f
, start
, SEEK_SET
);
575 bufPtr
= bufEnd
= buf
;
577 #ifndef NO_DECRYPTION
583 GBool
FileStream::fillBuf() {
585 #ifndef NO_DECRYPTION
589 bufPos
+= bufEnd
- buf
;
590 bufPtr
= bufEnd
= buf
;
591 if (length
>= 0 && bufPos
>= start
+ length
)
593 if (length
>= 0 && bufPos
+ 256 > start
+ length
)
594 n
= start
+ length
- bufPos
;
597 n
= fread(buf
, 1, n
, f
);
599 if (bufPtr
>= bufEnd
)
601 #ifndef NO_DECRYPTION
603 for (p
= buf
; p
< bufEnd
; ++p
)
604 *p
= (char)decrypt
->decryptByte((Guchar
)*p
);
610 void FileStream::setPos(int pos1
) {
614 fseek(f
, pos1
, SEEK_SET
);
617 fseek(f
, 0, SEEK_END
);
621 fseek(f
, pos1
, SEEK_END
);
622 bufPos
= (int)ftell(f
);
624 bufPtr
= bufEnd
= buf
;
627 void FileStream::moveStart(int delta
) {
628 this->start
+= delta
;
629 bufPtr
= bufEnd
= buf
;
633 //------------------------------------------------------------------------
635 //------------------------------------------------------------------------
637 EmbedStream::EmbedStream(Stream
*nstr
, Object
*ndict
):
642 EmbedStream::~EmbedStream() {
645 Stream
*EmbedStream::makeSubStream(int start
, int length
, Object
*ndict
) {
650 error(-1, "Internal: called makeSubStream() on EmbedStream");
654 void EmbedStream::setPos(int pos
) {
657 error(-1, "Internal: called setPos() on EmbedStream");
660 int EmbedStream::getStart() {
661 error(-1, "Internal: called getStart() on EmbedStream");
665 void EmbedStream::moveStart(int start
) {
668 error(-1, "Internal: called moveStart() on EmbedStream");
671 //------------------------------------------------------------------------
673 //------------------------------------------------------------------------
675 ASCIIHexStream::ASCIIHexStream(Stream
*str
):
681 ASCIIHexStream::~ASCIIHexStream() {
685 void ASCIIHexStream::reset() {
691 int ASCIIHexStream::lookChar() {
702 } while (isspace(c1
));
710 } while (isspace(c2
));
715 if (c1
>= '0' && c1
<= '9') {
717 } else if (c1
>= 'A' && c1
<= 'F') {
718 x
= (c1
- 'A' + 10) << 4;
719 } else if (c1
>= 'a' && c1
<= 'f') {
720 x
= (c1
- 'a' + 10) << 4;
721 } else if (c1
== EOF
) {
725 error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1
);
728 if (c2
>= '0' && c2
<= '9') {
730 } else if (c2
>= 'A' && c2
<= 'F') {
732 } else if (c2
>= 'a' && c2
<= 'f') {
734 } else if (c2
== EOF
) {
738 error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2
);
744 GString
*ASCIIHexStream::getPSFilter(const char *indent
) {
747 s
= str
->getPSFilter(indent
);
748 s
->append(indent
)->append("/ASCIIHexDecode filter\n");
752 GBool
ASCIIHexStream::isBinary(GBool last
) {
755 return str
->isBinary(gFalse
);
758 //------------------------------------------------------------------------
760 //------------------------------------------------------------------------
762 ASCII85Stream::ASCII85Stream(Stream
*str
):
768 ASCII85Stream::~ASCII85Stream() {
772 void ASCII85Stream::reset() {
778 int ASCII85Stream::lookChar() {
787 c
[0] = str
->getChar();
788 } while (c
[0] == '\n' || c
[0] == '\r');
789 if (c
[0] == '~' || c
[0] == EOF
) {
793 } else if (c
[0] == 'z') {
794 b
[0] = b
[1] = b
[2] = b
[3] = 0;
797 for (k
= 1; k
< 5; ++k
) {
799 c
[k
] = str
->getChar();
800 } while (c
[k
] == '\n' || c
[k
] == '\r');
801 if (c
[k
] == '~' || c
[k
] == EOF
)
805 if (k
< 5 && (c
[k
] == '~' || c
[k
] == EOF
)) {
806 for (++k
; k
< 5; ++k
)
811 for (k
= 0; k
< 5; ++k
)
812 t
= t
* 85 + (c
[k
] - 0x21);
813 for (k
= 3; k
>= 0; --k
) {
814 b
[k
] = (int)(t
& 0xff);
822 GString
*ASCII85Stream::getPSFilter(const char *indent
) {
825 s
= str
->getPSFilter(indent
);
826 s
->append(indent
)->append("/ASCII85Decode filter\n");
830 GBool
ASCII85Stream::isBinary(GBool last
) {
833 return str
->isBinary(gFalse
);
836 //------------------------------------------------------------------------
838 //------------------------------------------------------------------------
840 LZWStream::LZWStream(Stream
*str
, int predictor1
, int columns1
, int colors1
,
841 int bits1
, int early1
):
843 if (predictor1
!= 1) {
844 pred
= new StreamPredictor(this, predictor1
, columns1
, colors1
, bits1
);
850 bufPtr
= bufEnd
= buf
;
853 LZWStream::~LZWStream() {
861 unlink(zName
->getCString());
870 int LZWStream::getChar() {
872 return pred
->getChar();
874 return (bufPtr
>= bufEnd
&& !fillBuf()) ? EOF
: (*bufPtr
++ & 0xff);
877 int LZWStream::lookChar() {
879 return pred
->lookChar();
881 return (bufPtr
>= bufEnd
&& !fillBuf()) ? EOF
: (*bufPtr
& 0xff);
884 int LZWStream::getRawChar() {
885 return (bufPtr
>= bufEnd
&& !fillBuf()) ? EOF
: (*bufPtr
++ & 0xff);
888 void LZWStream::reset() {
892 //----- close old LZW stream
900 unlink(zName
->getCString());
904 //----- tell Delorie runtime to spawn a new instance of COMMAND.COM
907 if (!setDJSYSFLAGS
) {
908 setenv("DJSYSFLAGS", "0x0002", 0);
909 setDJSYSFLAGS
= gTrue
;
913 //----- create the .Z file
914 if (!openTempFile(&zName
, &f
, "wb", ".Z")) {
915 error(getPos(), "Couldn't create temporary file for LZW stream");
921 //----- execute uncompress / gzip
922 zCmd
= new GString(uncompressCmd
);
927 // first we open the engine up
928 OSErr err
= OpenSITEngine(kUseExternalEngine
, &magicCookie
);
929 // if we found it - let's use it!
930 if (!err
&& magicCookie
) {
931 // make sure we have the correct version of the Engine
932 if (GetSITEngineVersion(magicCookie
) >= kFirstSupportedEngine
) {
935 strcpy((char *)pName
, zName
->getCString());
936 c2pstr((char *)pName
);
937 FSMakeFSSpec(0, 0, pName
, &myFSS
);
938 short ftype
= DetermineFileType(magicCookie
, &myFSS
);
939 OSErr expandErr
= ExpandFSSpec(magicCookie
, ftype
, &myFSS
,
940 NULL
, NULL
, kCreateFolderNever
,
941 kDeleteOriginal
, kTextConvertSmart
);
944 #elif defined(HAVE_POPEN)
945 if (!(zPipe
= popen(zCmd
->getCString(), POPEN_READ_MODE
))) {
946 error(getPos(), "Couldn't popen '%s'", zCmd
->getCString());
947 unlink(zName
->getCString());
953 if (!system(zCmd
->getCString())) {
955 if (system(zCmd
->getCString())) {
957 error(getPos(), "Couldn't execute '%s'", zCmd
->getCString());
958 unlink(zName
->getCString());
962 zName
->del(zName
->getLength() - 2, 2);
963 if (!(zPipe
= fopen(zName
->getCString(), "rb"))) {
964 error(getPos(), "Couldn't open uncompress file '%s'", zName
->getCString());
965 unlink(zName
->getCString());
974 //----- initialize buffer
975 bufPtr
= bufEnd
= buf
;
978 void LZWStream::dumpFile(FILE *f
) {
979 int outCodeBits
; // size of output code
980 int outBits
; // max output code
981 int outBuf
[8]; // output buffer
982 int outData
; // temporary output buffer
983 int inCode
, outCode
; // input and output codes
984 int nextCode
; // next code index
985 GBool eof
; // set when EOF is reached
986 GBool clear
; // set if table needs to be cleared
987 GBool first
; // indicates first code word after clear
996 // max code length, block mode flag
1014 for (i
= 0; i
< 8; ++i
) {
1015 // check for table overflow
1016 if (nextCode
+ early
> 0x1001) {
1023 if (inCode
== EOF
) {
1027 } while (first
&& inCode
== 256);
1030 // compute output code
1033 } else if (inCode
== 256) {
1036 } else if (inCode
== 257) {
1040 outCode
= inCode
- 1;
1042 outBuf
[i
] = outCode
;
1050 // check input code size
1051 if (nextCode
+ early
== 0x200)
1053 else if (nextCode
+ early
== 0x400) {
1055 } else if (nextCode
+ early
== 0x800) {
1059 // check for eof/clear
1068 // write output block
1072 while (j
< i
|| outBits
> 0) {
1073 if (outBits
< 8 && j
< i
) {
1074 outData
= outData
| (outBuf
[j
++] << outBits
);
1075 outBits
+= outCodeBits
;
1077 fputc(outData
& 0xff, f
);
1082 // check output code size
1083 if (nextCode
- 1 == 512 ||
1084 nextCode
- 1 == 1024 ||
1085 nextCode
- 1 == 2048 ||
1086 nextCode
- 1 == 4096) {
1087 outCodeBits
= inCodeBits
;
1090 // clear table if necessary
1101 int LZWStream::getCode() {
1105 while (inputBits
< inCodeBits
) {
1106 if ((c
= str
->getChar()) == EOF
)
1108 inputBuf
= (inputBuf
<< 8) | (c
& 0xff);
1111 code
= (inputBuf
>> (inputBits
- inCodeBits
)) & ((1 << inCodeBits
) - 1);
1112 inputBits
-= inCodeBits
;
1116 GBool
LZWStream::fillBuf() {
1121 if ((n
= fread(buf
, 1, 256, zPipe
)) < 256) {
1128 unlink(zName
->getCString());
1136 GString
*LZWStream::getPSFilter(const char *indent
) {
1142 s
= str
->getPSFilter(indent
);
1143 s
->append(indent
)->append("/LZWDecode filter\n");
1147 GBool
LZWStream::isBinary(GBool last
) {
1150 return str
->isBinary(gTrue
);
1153 //------------------------------------------------------------------------
1155 //------------------------------------------------------------------------
1157 RunLengthStream::RunLengthStream(Stream
*str
):
1159 bufPtr
= bufEnd
= buf
;
1163 RunLengthStream::~RunLengthStream() {
1167 void RunLengthStream::reset() {
1169 bufPtr
= bufEnd
= buf
;
1173 GString
*RunLengthStream::getPSFilter(const char *indent
) {
1176 s
= str
->getPSFilter(indent
);
1177 s
->append(indent
)->append("/RunLengthDecode filter\n");
1181 GBool
RunLengthStream::isBinary(GBool last
) {
1184 return str
->isBinary(gTrue
);
1187 GBool
RunLengthStream::fillBuf() {
1194 if (c
== 0x80 || c
== EOF
) {
1200 for (i
= 0; i
< n
; ++i
)
1201 buf
[i
] = (char)str
->getChar();
1205 for (i
= 0; i
< n
; ++i
)
1213 //------------------------------------------------------------------------
1215 //------------------------------------------------------------------------
1217 CCITTFaxStream::CCITTFaxStream(Stream
*str
, int nencoding
, GBool nendOfLine
,
1218 GBool nbyteAlign
, int ncolumns
, int nrows
,
1219 GBool nendOfBlock
, GBool nblack
):
1221 encoding
= nencoding
;
1222 endOfLine
= nendOfLine
;
1223 byteAlign
= nbyteAlign
;
1226 endOfBlock
= nendOfBlock
;
1228 refLine
= (short *)gmalloc((columns
+ 3) * sizeof(short));
1229 codingLine
= (short *)gmalloc((columns
+ 2) * sizeof(short));
1233 nextLine2D
= encoding
< 0;
1236 codingLine
[1] = refLine
[2] = columns
;
1242 CCITTFaxStream::~CCITTFaxStream() {
1248 void CCITTFaxStream::reset() {
1254 nextLine2D
= encoding
< 0;
1257 codingLine
[1] = refLine
[2] = columns
;
1261 // get initial end-of-line marker and 2D encoding tag
1263 if (lookBits(12) == 0x001) {
1267 for (n
= 0; n
< 11 && lookBits(n
) == 0; ++n
) ;
1268 if (n
== 11 && lookBits(12) == 0x001) {
1273 nextLine2D
= !lookBits(1);
1278 int CCITTFaxStream::lookChar() {
1279 short code1
, code2
, code3
;
1287 // if at eof just return EOF
1288 if (eof
&& codingLine
[a0
] >= columns
) {
1292 // read the next row
1296 if (codingLine
[a0
] >= columns
) {
1300 for (i
= 0; codingLine
[i
] < columns
; ++i
)
1301 refLine
[i
] = codingLine
[i
];
1302 refLine
[i
] = refLine
[i
+ 1] = columns
;
1304 a0New
= codingLine
[a0
= 0] = 0;
1306 code1
= getTwoDimCode();
1309 if (refLine
[b1
] < columns
) {
1310 a0New
= refLine
[b1
+ 1];
1315 if ((a0
& 1) == 0) {
1318 code1
+= code3
= getWhiteCode();
1319 } while (code3
>= 64);
1321 code2
+= code3
= getBlackCode();
1322 } while (code3
>= 64);
1326 code1
+= code3
= getBlackCode();
1327 } while (code3
>= 64);
1329 code2
+= code3
= getWhiteCode();
1330 } while (code3
>= 64);
1332 codingLine
[a0
+ 1] = a0New
+ code1
;
1334 a0New
= codingLine
[a0
+ 1] = codingLine
[a0
] + code2
;
1336 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1340 a0New
= codingLine
[++a0
] = refLine
[b1
];
1341 if (refLine
[b1
] < columns
) {
1343 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1348 a0New
= codingLine
[++a0
] = refLine
[b1
] + 1;
1349 if (refLine
[b1
] < columns
) {
1351 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1356 a0New
= codingLine
[++a0
] = refLine
[b1
] - 1;
1358 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1362 a0New
= codingLine
[++a0
] = refLine
[b1
] + 2;
1363 if (refLine
[b1
] < columns
) {
1365 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1370 a0New
= codingLine
[++a0
] = refLine
[b1
] - 2;
1372 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1376 a0New
= codingLine
[++a0
] = refLine
[b1
] + 3;
1377 if (refLine
[b1
] < columns
) {
1379 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1384 a0New
= codingLine
[++a0
] = refLine
[b1
] - 3;
1386 while (refLine
[b1
] <= codingLine
[a0
] && refLine
[b1
] < columns
)
1391 codingLine
[a0
= 0] = columns
;
1394 error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1
);
1403 } while (codingLine
[a0
] < columns
);
1407 codingLine
[a0
= 0] = 0;
1411 code1
+= code3
= getWhiteCode();
1412 } while (code3
>= 64);
1413 codingLine
[a0
+1] = codingLine
[a0
] + code1
;
1415 if (codingLine
[a0
] >= columns
)
1419 code2
+= code3
= getBlackCode();
1420 } while (code3
>= 64);
1421 codingLine
[a0
+1] = codingLine
[a0
] + code2
;
1423 if (codingLine
[a0
] >= columns
)
1428 if (codingLine
[a0
] != columns
) {
1429 error(getPos(), "CCITTFax row is wrong length (%d)", codingLine
[a0
]);
1435 // byte-align the row
1440 // check for end-of-line marker, end-of-block marker, and
1443 code1
= lookBits(12);
1446 } else if (code1
== 0x001) {
1449 nextLine2D
= !lookBits(1);
1452 code1
= lookBits(12);
1453 if (code1
== 0x001) {
1459 if (encoding
>= 0) {
1460 for (i
= 0; i
< 4; ++i
) {
1461 code1
= lookBits(12);
1462 if (code1
!= 0x001) {
1463 error(getPos(), "Bad RTC code in CCITTFax stream");
1476 nextLine2D
= !lookBits(1);
1481 if (row
== rows
- 1) {
1484 for (n
= 0; n
< 11 && lookBits(n
) == 0; ++n
) ;
1485 if (n
== 11 && lookBits(12) == 0x001) {
1489 nextLine2D
= !lookBits(1);
1496 // This looks for an end-of-line marker after an error, however
1497 // some (most?) CCITT streams in PDF files don't use end-of-line
1498 // markers, and the just-plow-on technique works better in those
1507 code1
= look13Bits();
1508 } while ((code1
>> 1) != 0x001);
1510 codingLine
[++a0
] = columns
;
1513 nextLine2D
= !(code1
& 1);
1519 outputBits
= codingLine
[1] - codingLine
[0];
1520 if (outputBits
== 0) {
1522 outputBits
= codingLine
[2] - codingLine
[1];
1529 if (outputBits
>= 8) {
1530 ret
= ((a0
& 1) == 0) ? 0xff : 0x00;
1531 if ((outputBits
-= 8) == 0) {
1533 if (codingLine
[a0
] < columns
) {
1534 outputBits
= codingLine
[a0
+ 1] - codingLine
[a0
];
1541 if (outputBits
> bits
) {
1544 if ((a0
& 1) == 0) {
1545 ret
|= 0xff >> (8 - i
);
1551 if ((a0
& 1) == 0) {
1552 ret
|= (0xff >> (8 - i
)) << bits
;
1556 if (codingLine
[a0
] < columns
) {
1557 outputBits
= codingLine
[a0
+ 1] - codingLine
[a0
];
1560 } while (bits
> 0 && codingLine
[a0
] < columns
);
1562 buf
= black
? (ret
^ 0xff) : ret
;
1566 short CCITTFaxStream::getTwoDimCode() {
1571 code
= 0; // make gcc happy
1574 p
= &twoDimTab1
[code
];
1580 for (n
= 1; n
<= 7; ++n
) {
1585 p
= &twoDimTab1
[code
];
1592 error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code
);
1596 short CCITTFaxStream::getWhiteCode() {
1601 code
= 0; // make gcc happy
1603 code
= lookBits(12);
1604 if ((code
>> 5) == 0)
1605 p
= &whiteTab1
[code
];
1607 p
= &whiteTab2
[code
>> 3];
1613 for (n
= 1; n
<= 9; ++n
) {
1618 p
= &whiteTab2
[code
];
1624 for (n
= 11; n
<= 12; ++n
) {
1629 p
= &whiteTab1
[code
];
1636 error(getPos(), "Bad white code (%04x) in CCITTFax stream", code
);
1640 short CCITTFaxStream::getBlackCode() {
1645 code
= 0; // make gcc happy
1647 code
= lookBits(13);
1648 if ((code
>> 7) == 0)
1649 p
= &blackTab1
[code
];
1650 else if ((code
>> 9) == 0)
1651 p
= &blackTab2
[(code
>> 1) - 64];
1653 p
= &blackTab3
[code
>> 7];
1659 for (n
= 2; n
<= 6; ++n
) {
1664 p
= &blackTab3
[code
];
1670 for (n
= 7; n
<= 12; ++n
) {
1676 p
= &blackTab2
[code
- 64];
1683 for (n
= 10; n
<= 13; ++n
) {
1688 p
= &blackTab1
[code
];
1695 error(getPos(), "Bad black code (%04x) in CCITTFax stream", code
);
1699 short CCITTFaxStream::lookBits(int n
) {
1702 while (inputBits
< n
) {
1703 if ((c
= str
->getChar()) == EOF
) {
1708 inputBuf
= (inputBuf
<< 8) + c
;
1711 return (inputBuf
>> (inputBits
- n
)) & (0xffff >> (16 - n
));
1714 GString
*CCITTFaxStream::getPSFilter(const char *indent
) {
1718 s
= str
->getPSFilter(indent
);
1719 s
->append(indent
)->append("<< ");
1720 if (encoding
!= 0) {
1721 sprintf(s1
, "/K %d ", encoding
);
1725 s
->append("/EndOfLine true ");
1728 s
->append("/EncodedByteAlign true ");
1730 sprintf(s1
, "/Columns %d ", columns
);
1733 sprintf(s1
, "/Rows %d ", rows
);
1737 s
->append("/EndOfBlock false ");
1740 s
->append("/BlackIs1 true ");
1742 s
->append(">> /CCITTFaxDecode filter\n");
1746 GBool
CCITTFaxStream::isBinary(GBool last
) {
1749 return str
->isBinary(gTrue
);
1752 //------------------------------------------------------------------------
1754 //------------------------------------------------------------------------
1756 // IDCT constants (20.12 fixed point format)
1758 #define dctCos1 4017 // cos(pi/16)
1759 #define dctSin1 799 // sin(pi/16)
1760 #define dctCos3 3406 // cos(3*pi/16)
1761 #define dctSin3 2276 // sin(3*pi/16)
1762 #define dctCos6 1567 // cos(6*pi/16)
1763 #define dctSin6 3784 // sin(6*pi/16)
1764 #define dctSqrt2 5793 // sqrt(2)
1765 #define dctSqrt1d2 2896 // sqrt(2) / 2
1770 #define dctCos1 0.98078528 // cos(pi/16)
1771 #define dctSin1 0.19509032 // sin(pi/16)
1772 #define dctCos3 0.83146961 // cos(3*pi/16)
1773 #define dctSin3 0.55557023 // sin(3*pi/16)
1774 #define dctCos6 0.38268343 // cos(6*pi/16)
1775 #define dctSin6 0.92387953 // sin(6*pi/16)
1776 #define dctSqrt2 1.41421356 // sqrt(2)
1777 #define dctSqrt1d2 0.70710678 // sqrt(2) / 2
1780 // color conversion parameters (16.16 fixed point format)
1781 #define dctCrToR 91881 // 1.4020
1782 #define dctCbToG -22553 // -0.3441363
1783 #define dctCrToG -46802 // -0.71413636
1784 #define dctCbToB 116130 // 1.772
1786 // clip [-256,511] --> [0,255]
1787 #define dctClipOffset 256
1788 static Guchar dctClip
[768];
1789 static int dctClipInit
= 0;
1791 // zig zag decode map
1792 static int dctZigZag
[64] = {
1798 5, 12, 19, 26, 33, 40,
1799 48, 41, 34, 27, 20, 13, 6,
1800 7, 14, 21, 28, 35, 42, 49, 56,
1801 57, 50, 43, 36, 29, 22, 15,
1802 23, 30, 37, 44, 51, 58,
1810 DCTStream::DCTStream(Stream
*str
):
1815 mcuWidth
= mcuHeight
= 0;
1819 for (i
= 0; i
< 4; ++i
)
1820 for (j
= 0; j
< 32; ++j
)
1821 rowBuf
[i
][j
] = NULL
;
1824 for (i
= -256; i
< 0; ++i
)
1825 dctClip
[dctClipOffset
+ i
] = 0;
1826 for (i
= 0; i
< 256; ++i
)
1827 dctClip
[dctClipOffset
+ i
] = i
;
1828 for (i
= 256; i
< 512; ++i
)
1829 dctClip
[dctClipOffset
+ i
] = 255;
1834 DCTStream::~DCTStream() {
1838 for (i
= 0; i
< numComps
; ++i
)
1839 for (j
= 0; j
< mcuHeight
; ++j
)
1840 gfree(rowBuf
[i
][j
]);
1843 void DCTStream::reset() {
1845 if (!readHeader()) {
1849 restartMarker
= 0xd0;
1853 int DCTStream::getChar() {
1859 if (++comp
== numComps
) {
1872 int DCTStream::lookChar() {
1875 if (dy
>= mcuHeight
) {
1876 if (!readMCURow()) {
1884 return rowBuf
[comp
][dy
][x
];
1887 void DCTStream::restart() {
1891 restartCtr
= restartInterval
;
1892 for (i
= 0; i
< numComps
; ++i
)
1893 compInfo
[i
].prevDC
= 0;
1896 GBool
DCTStream::readMCURow() {
1899 int pY
, pCb
, pCr
, pR
, pG
, pB
;
1900 int h
, v
, horiz
, vert
, hSub
, vSub
;
1901 int x1
, x2
, y2
, x3
, y3
, x4
, y4
, x5
, y5
, cc
, i
;
1904 for (x1
= 0; x1
< width
; x1
+= mcuWidth
) {
1906 // deal with restart marker
1907 if (restartInterval
> 0 && restartCtr
== 0) {
1909 if (c
!= restartMarker
) {
1910 error(getPos(), "Bad DCT data: incorrect restart marker");
1913 if (++restartMarker
== 0xd8)
1914 restartMarker
= 0xd0;
1919 for (cc
= 0; cc
< numComps
; ++cc
) {
1920 h
= compInfo
[cc
].hSample
;
1921 v
= compInfo
[cc
].vSample
;
1922 horiz
= mcuWidth
/ h
;
1923 vert
= mcuHeight
/ v
;
1926 for (y2
= 0; y2
< mcuHeight
; y2
+= vert
) {
1927 for (x2
= 0; x2
< mcuWidth
; x2
+= horiz
) {
1928 if (!readDataUnit(&dcHuffTables
[compInfo
[cc
].dcHuffTable
],
1929 &acHuffTables
[compInfo
[cc
].acHuffTable
],
1930 quantTables
[compInfo
[cc
].quantTable
],
1931 &compInfo
[cc
].prevDC
,
1934 if (hSub
== 1 && vSub
== 1) {
1935 for (y3
= 0, i
= 0; y3
< 8; ++y3
, i
+= 8) {
1936 p1
= &rowBuf
[cc
][y2
+y3
][x1
+x2
];
1946 } else if (hSub
== 2 && vSub
== 2) {
1947 for (y3
= 0, i
= 0; y3
< 16; y3
+= 2, i
+= 8) {
1948 p1
= &rowBuf
[cc
][y2
+y3
][x1
+x2
];
1949 p2
= &rowBuf
[cc
][y2
+y3
+1][x1
+x2
];
1950 p1
[0] = p1
[1] = p2
[0] = p2
[1] = data
[i
];
1951 p1
[2] = p1
[3] = p2
[2] = p2
[3] = data
[i
+1];
1952 p1
[4] = p1
[5] = p2
[4] = p2
[5] = data
[i
+2];
1953 p1
[6] = p1
[7] = p2
[6] = p2
[7] = data
[i
+3];
1954 p1
[8] = p1
[9] = p2
[8] = p2
[9] = data
[i
+4];
1955 p1
[10] = p1
[11] = p2
[10] = p2
[11] = data
[i
+5];
1956 p1
[12] = p1
[13] = p2
[12] = p2
[13] = data
[i
+6];
1957 p1
[14] = p1
[15] = p2
[14] = p2
[15] = data
[i
+7];
1961 for (y3
= 0, y4
= 0; y3
< 8; ++y3
, y4
+= vSub
) {
1962 for (x3
= 0, x4
= 0; x3
< 8; ++x3
, x4
+= hSub
) {
1963 for (y5
= 0; y5
< vSub
; ++y5
)
1964 for (x5
= 0; x5
< hSub
; ++x5
)
1965 rowBuf
[cc
][y2
+y4
+y5
][x1
+x2
+x4
+x5
] = data
[i
];
1975 // color space conversion
1977 // convert YCbCr to RGB
1978 if (numComps
== 3) {
1979 for (y2
= 0; y2
< mcuHeight
; ++y2
) {
1980 for (x2
= 0; x2
< mcuWidth
; ++x2
) {
1981 pY
= rowBuf
[0][y2
][x1
+x2
];
1982 pCb
= rowBuf
[1][y2
][x1
+x2
] - 128;
1983 pCr
= rowBuf
[2][y2
][x1
+x2
] - 128;
1984 pR
= ((pY
<< 16) + dctCrToR
* pCr
+ 32768) >> 16;
1985 rowBuf
[0][y2
][x1
+x2
] = dctClip
[dctClipOffset
+ pR
];
1986 pG
= ((pY
<< 16) + dctCbToG
* pCb
+ dctCrToG
* pCr
+ 32768) >> 16;
1987 rowBuf
[1][y2
][x1
+x2
] = dctClip
[dctClipOffset
+ pG
];
1988 pB
= ((pY
<< 16) + dctCbToB
* pCb
+ 32768) >> 16;
1989 rowBuf
[2][y2
][x1
+x2
] = dctClip
[dctClipOffset
+ pB
];
1992 // convert YCbCrK to CMYK (K is passed through unchanged)
1993 } else if (numComps
== 4) {
1994 for (y2
= 0; y2
< mcuHeight
; ++y2
) {
1995 for (x2
= 0; x2
< mcuWidth
; ++x2
) {
1996 pY
= rowBuf
[0][y2
][x1
+x2
];
1997 pCb
= rowBuf
[1][y2
][x1
+x2
] - 128;
1998 pCr
= rowBuf
[2][y2
][x1
+x2
] - 128;
1999 pR
= ((pY
<< 16) + dctCrToR
* pCr
+ 32768) >> 16;
2000 rowBuf
[0][y2
][x1
+x2
] = 255 - dctClip
[dctClipOffset
+ pR
];
2001 pG
= ((pY
<< 16) + dctCbToG
* pCb
+ dctCrToG
* pCr
+ 32678) >> 16;
2002 rowBuf
[1][y2
][x1
+x2
] = 255 - dctClip
[dctClipOffset
+ pG
];
2003 pB
= ((pY
<< 16) + dctCbToB
* pCb
+ 32768) >> 16;
2004 rowBuf
[2][y2
][x1
+x2
] = 255 - dctClip
[dctClipOffset
+ pB
];
2013 // This IDCT algorithm is taken from:
2014 // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
2015 // "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
2016 // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
2018 // The stage numbers mentioned in the comments refer to Figure 1 in this
2021 GBool
DCTStream::readDataUnit(DCTHuffTable
*dcHuffTable
,
2022 DCTHuffTable
*acHuffTable
,
2023 Guchar quantTable
[64], int *prevDC
,
2026 int v0
, v1
, v2
, v3
, v4
, v5
, v6
, v7
, t
;
2031 // Huffman decode and dequantize
2032 size
= readHuffSym(dcHuffTable
);
2036 amp
= readAmp(size
);
2042 tmp1
[0] = (*prevDC
+= amp
) * quantTable
[0];
2043 for (i
= 1; i
< 64; ++i
)
2048 while ((c
= readHuffSym(acHuffTable
)) == 0xf0 && run
< 0x30)
2055 run
+= (c
>> 4) & 0x0f;
2057 amp
= readAmp(size
);
2062 tmp1
[j
] = amp
* quantTable
[j
];
2066 // inverse DCT on rows
2067 for (i
= 0; i
< 64; i
+= 8) {
2070 v0
= (dctSqrt2
* tmp1
[i
+0] + 128) >> 8;
2071 v1
= (dctSqrt2
* tmp1
[i
+4] + 128) >> 8;
2074 v4
= (dctSqrt1d2
* (tmp1
[i
+1] - tmp1
[i
+7]) + 128) >> 8;
2075 v7
= (dctSqrt1d2
* (tmp1
[i
+1] + tmp1
[i
+7]) + 128) >> 8;
2076 v5
= tmp1
[i
+3] << 4;
2077 v6
= tmp1
[i
+5] << 4;
2080 t
= (v0
- v1
+ 1) >> 1;
2081 v0
= (v0
+ v1
+ 1) >> 1;
2083 t
= (v2
* dctSin6
+ v3
* dctCos6
+ 128) >> 8;
2084 v2
= (v2
* dctCos6
- v3
* dctSin6
+ 128) >> 8;
2086 t
= (v4
- v6
+ 1) >> 1;
2087 v4
= (v4
+ v6
+ 1) >> 1;
2089 t
= (v7
+ v5
+ 1) >> 1;
2090 v5
= (v7
- v5
+ 1) >> 1;
2094 t
= (v0
- v3
+ 1) >> 1;
2095 v0
= (v0
+ v3
+ 1) >> 1;
2097 t
= (v1
- v2
+ 1) >> 1;
2098 v1
= (v1
+ v2
+ 1) >> 1;
2100 t
= (v4
* dctSin3
+ v7
* dctCos3
+ 2048) >> 12;
2101 v4
= (v4
* dctCos3
- v7
* dctSin3
+ 2048) >> 12;
2103 t
= (v5
* dctSin1
+ v6
* dctCos1
+ 2048) >> 12;
2104 v5
= (v5
* dctCos1
- v6
* dctSin1
+ 2048) >> 12;
2108 tmp1
[i
+0] = v0
+ v7
;
2109 tmp1
[i
+7] = v0
- v7
;
2110 tmp1
[i
+1] = v1
+ v6
;
2111 tmp1
[i
+6] = v1
- v6
;
2112 tmp1
[i
+2] = v2
+ v5
;
2113 tmp1
[i
+5] = v2
- v5
;
2114 tmp1
[i
+3] = v3
+ v4
;
2115 tmp1
[i
+4] = v3
- v4
;
2118 // inverse DCT on columns
2119 for (i
= 0; i
< 8; ++i
) {
2122 v0
= (dctSqrt2
* tmp1
[0*8+i
] + 2048) >> 12;
2123 v1
= (dctSqrt2
* tmp1
[4*8+i
] + 2048) >> 12;
2126 v4
= (dctSqrt1d2
* (tmp1
[1*8+i
] - tmp1
[7*8+i
]) + 2048) >> 12;
2127 v7
= (dctSqrt1d2
* (tmp1
[1*8+i
] + tmp1
[7*8+i
]) + 2048) >> 12;
2132 t
= (v0
- v1
+ 1) >> 1;
2133 v0
= (v0
+ v1
+ 1) >> 1;
2135 t
= (v2
* dctSin6
+ v3
* dctCos6
+ 2048) >> 12;
2136 v2
= (v2
* dctCos6
- v3
* dctSin6
+ 2048) >> 12;
2138 t
= (v4
- v6
+ 1) >> 1;
2139 v4
= (v4
+ v6
+ 1) >> 1;
2141 t
= (v7
+ v5
+ 1) >> 1;
2142 v5
= (v7
- v5
+ 1) >> 1;
2146 t
= (v0
- v3
+ 1) >> 1;
2147 v0
= (v0
+ v3
+ 1) >> 1;
2149 t
= (v1
- v2
+ 1) >> 1;
2150 v1
= (v1
+ v2
+ 1) >> 1;
2152 t
= (v4
* dctSin3
+ v7
* dctCos3
+ 2048) >> 12;
2153 v4
= (v4
* dctCos3
- v7
* dctSin3
+ 2048) >> 12;
2155 t
= (v5
* dctSin1
+ v6
* dctCos1
+ 2048) >> 12;
2156 v5
= (v5
* dctCos1
- v6
* dctSin1
+ 2048) >> 12;
2160 tmp1
[0*8+i
] = v0
+ v7
;
2161 tmp1
[7*8+i
] = v0
- v7
;
2162 tmp1
[1*8+i
] = v1
+ v6
;
2163 tmp1
[6*8+i
] = v1
- v6
;
2164 tmp1
[2*8+i
] = v2
+ v5
;
2165 tmp1
[5*8+i
] = v2
- v5
;
2166 tmp1
[3*8+i
] = v3
+ v4
;
2167 tmp1
[4*8+i
] = v3
- v4
;
2170 // convert to 8-bit integers
2171 for (i
= 0; i
< 64; ++i
)
2172 data
[i
] = dctClip
[dctClipOffset
+ 128 + ((tmp1
[i
] + 8) >> 4)];
2179 GBool
DCTStream::readDataUnit(DCTHuffTable
*dcHuffTable
,
2180 DCTHuffTable
*acHuffTable
,
2181 Guchar quantTable
[64], int *prevDC
,
2184 double v0
, v1
, v2
, v3
, v4
, v5
, v6
, v7
, t
;
2189 // Huffman decode and dequantize
2190 size
= readHuffSym(dcHuffTable
);
2194 amp
= readAmp(size
);
2200 tmp1
[0] = (*prevDC
+= amp
) * quantTable
[0];
2201 for (i
= 1; i
< 64; ++i
)
2206 while ((c
= readHuffSym(acHuffTable
)) == 0xf0 && run
< 0x30)
2213 run
+= (c
>> 4) & 0x0f;
2215 amp
= readAmp(size
);
2220 tmp1
[j
] = amp
* quantTable
[j
];
2224 // inverse DCT on rows
2225 for (i
= 0; i
< 64; i
+= 8) {
2228 v0
= dctSqrt2
* tmp1
[i
+0];
2229 v1
= dctSqrt2
* tmp1
[i
+4];
2232 v4
= dctSqrt1d2
* (tmp1
[i
+1] - tmp1
[i
+7]);
2233 v7
= dctSqrt1d2
* (tmp1
[i
+1] + tmp1
[i
+7]);
2238 t
= 0.5 * (v0
- v1
);
2239 v0
= 0.5 * (v0
+ v1
);
2241 t
= v2
* dctSin6
+ v3
* dctCos6
;
2242 v2
= v2
* dctCos6
- v3
* dctSin6
;
2244 t
= 0.5 * (v4
- v6
);
2245 v4
= 0.5 * (v4
+ v6
);
2247 t
= 0.5 * (v7
+ v5
);
2248 v5
= 0.5 * (v7
- v5
);
2252 t
= 0.5 * (v0
- v3
);
2253 v0
= 0.5 * (v0
+ v3
);
2255 t
= 0.5 * (v1
- v2
);
2256 v1
= 0.5 * (v1
+ v2
);
2258 t
= v4
* dctSin3
+ v7
* dctCos3
;
2259 v4
= v4
* dctCos3
- v7
* dctSin3
;
2261 t
= v5
* dctSin1
+ v6
* dctCos1
;
2262 v5
= v5
* dctCos1
- v6
* dctSin1
;
2266 tmp1
[i
+0] = v0
+ v7
;
2267 tmp1
[i
+7] = v0
- v7
;
2268 tmp1
[i
+1] = v1
+ v6
;
2269 tmp1
[i
+6] = v1
- v6
;
2270 tmp1
[i
+2] = v2
+ v5
;
2271 tmp1
[i
+5] = v2
- v5
;
2272 tmp1
[i
+3] = v3
+ v4
;
2273 tmp1
[i
+4] = v3
- v4
;
2276 // inverse DCT on columns
2277 for (i
= 0; i
< 8; ++i
) {
2280 v0
= dctSqrt2
* tmp1
[0*8+i
];
2281 v1
= dctSqrt2
* tmp1
[4*8+i
];
2284 v4
= dctSqrt1d2
* (tmp1
[1*8+i
] - tmp1
[7*8+i
]);
2285 v7
= dctSqrt1d2
* (tmp1
[1*8+i
] + tmp1
[7*8+i
]);
2290 t
= 0.5 * (v0
- v1
);
2291 v0
= 0.5 * (v0
+ v1
);
2293 t
= v2
* dctSin6
+ v3
* dctCos6
;
2294 v2
= v2
* dctCos6
- v3
* dctSin6
;
2296 t
= 0.5 * (v4
- v6
);
2297 v4
= 0.5 * (v4
+ v6
);
2299 t
= 0.5 * (v7
+ v5
);
2300 v5
= 0.5 * (v7
- v5
);
2304 t
= 0.5 * (v0
- v3
);
2305 v0
= 0.5 * (v0
+ v3
);
2307 t
= 0.5 * (v1
- v2
);
2308 v1
= 0.5 * (v1
+ v2
);
2310 t
= v4
* dctSin3
+ v7
* dctCos3
;
2311 v4
= v4
* dctCos3
- v7
* dctSin3
;
2313 t
= v5
* dctSin1
+ v6
* dctCos1
;
2314 v5
= v5
* dctCos1
- v6
* dctSin1
;
2318 tmp1
[0*8+i
] = v0
+ v7
;
2319 tmp1
[7*8+i
] = v0
- v7
;
2320 tmp1
[1*8+i
] = v1
+ v6
;
2321 tmp1
[6*8+i
] = v1
- v6
;
2322 tmp1
[2*8+i
] = v2
+ v5
;
2323 tmp1
[5*8+i
] = v2
- v5
;
2324 tmp1
[3*8+i
] = v3
+ v4
;
2325 tmp1
[4*8+i
] = v3
- v4
;
2328 // convert to 8-bit integers
2329 for (i
= 0; i
< 64; ++i
)
2330 data
[i
] = dctClip
[dctClipOffset
+ (int)(tmp1
[i
] + 128.5)];
2336 int DCTStream::readHuffSym(DCTHuffTable
*table
) {
2344 // add a bit to the code
2345 if ((bit
= readBit()) == EOF
)
2347 code
= (code
<< 1) + bit
;
2351 if (code
- table
->firstCode
[codeBits
] < table
->numCodes
[codeBits
]) {
2352 code
-= table
->firstCode
[codeBits
];
2353 return table
->sym
[table
->firstSym
[codeBits
] + code
];
2355 } while (codeBits
< 16);
2357 error(getPos(), "Bad Huffman code in DCT stream");
2361 int DCTStream::readAmp(int size
) {
2366 for (bits
= 0; bits
< size
; ++bits
) {
2367 if ((bit
= readBit()) == EOF
)
2369 amp
= (amp
<< 1) + bit
;
2371 if (amp
< (1 << (size
- 1)))
2372 amp
-= (1 << size
) - 1;
2376 int DCTStream::readBit() {
2380 if (inputBits
== 0) {
2381 if ((c
= str
->getChar()) == EOF
)
2385 c2
= str
->getChar();
2386 } while (c2
== 0xff);
2388 error(getPos(), "Bad DCT data: missing 00 after ff");
2395 bit
= (inputBuf
>> (inputBits
- 1)) & 1;
2400 GBool
DCTStream::readHeader() {
2402 int minHSample
, minVSample
;
2411 numDCHuffTables
= 0;
2412 numACHuffTables
= 0;
2414 gotAdobeMarker
= gFalse
;
2415 restartInterval
= 0;
2423 if (!readFrameInfo())
2427 if (!readHuffmanTables())
2433 if (!readScanInfo())
2438 if (!readQuantTables())
2442 if (!readRestartInterval())
2446 if (!readAdobeMarker())
2450 error(getPos(), "Bad DCT header");
2453 // skip APPn / COM / etc.
2456 for (i
= 0; i
< n
; ++i
)
2459 error(getPos(), "Unknown DCT marker <%02x>", c
);
2467 mcuWidth
= minHSample
= compInfo
[0].hSample
;
2468 mcuHeight
= minVSample
= compInfo
[0].vSample
;
2469 for (i
= 1; i
< numComps
; ++i
) {
2470 if (compInfo
[i
].hSample
< minHSample
)
2471 minHSample
= compInfo
[i
].hSample
;
2472 if (compInfo
[i
].vSample
< minVSample
)
2473 minVSample
= compInfo
[i
].vSample
;
2474 if (compInfo
[i
].hSample
> mcuWidth
)
2475 mcuWidth
= compInfo
[i
].hSample
;
2476 if (compInfo
[i
].vSample
> mcuHeight
)
2477 mcuHeight
= compInfo
[i
].vSample
;
2479 for (i
= 0; i
< numComps
; ++i
) {
2480 compInfo
[i
].hSample
/= minHSample
;
2481 compInfo
[i
].vSample
/= minVSample
;
2483 mcuWidth
= (mcuWidth
/ minHSample
) * 8;
2484 mcuHeight
= (mcuHeight
/ minVSample
) * 8;
2487 bufWidth
= ((width
+ mcuWidth
- 1) / mcuWidth
) * mcuWidth
;
2488 for (i
= 0; i
< numComps
; ++i
)
2489 for (j
= 0; j
< mcuHeight
; ++j
)
2490 rowBuf
[i
][j
] = (Guchar
*)gmalloc(bufWidth
* sizeof(Guchar
));
2492 // figure out color transform
2493 if (!gotAdobeMarker
&& numComps
== 3) {
2494 if (compInfo
[0].id
== 1 && compInfo
[1].id
== 2 && compInfo
[2].id
== 3) {
2499 // initialize counters
2508 GBool
DCTStream::readFrameInfo() {
2514 length
= read16() - 2;
2515 prec
= str
->getChar();
2518 numComps
= str
->getChar();
2521 error(getPos(), "Bad DCT precision %d", prec
);
2524 for (i
= 0; i
< numComps
; ++i
) {
2525 compInfo
[i
].id
= str
->getChar();
2526 compInfo
[i
].inScan
= gFalse
;
2528 compInfo
[i
].hSample
= (c
>> 4) & 0x0f;
2529 compInfo
[i
].vSample
= c
& 0x0f;
2530 compInfo
[i
].quantTable
= str
->getChar();
2531 compInfo
[i
].dcHuffTable
= 0;
2532 compInfo
[i
].acHuffTable
= 0;
2537 GBool
DCTStream::readScanInfo() {
2539 int scanComps
, id
, c
;
2542 length
= read16() - 2;
2543 scanComps
= str
->getChar();
2545 if (length
!= 2 * scanComps
+ 3) {
2546 error(getPos(), "Bad DCT scan info block");
2549 for (i
= 0; i
< scanComps
; ++i
) {
2550 id
= str
->getChar();
2551 for (j
= 0; j
< numComps
; ++j
) {
2552 if (id
== compInfo
[j
].id
)
2555 if (j
== numComps
) {
2556 error(getPos(), "Bad DCT component ID in scan info block");
2559 compInfo
[j
].inScan
= gTrue
;
2561 compInfo
[j
].dcHuffTable
= (c
>> 4) & 0x0f;
2562 compInfo
[j
].acHuffTable
= c
& 0x0f;
2570 GBool
DCTStream::readQuantTables() {
2575 length
= read16() - 2;
2576 while (length
> 0) {
2577 index
= str
->getChar();
2578 if ((index
& 0xf0) || index
>= 4) {
2579 error(getPos(), "Bad DCT quantization table");
2582 if (index
== numQuantTables
)
2583 numQuantTables
= index
+ 1;
2584 for (i
= 0; i
< 64; ++i
)
2585 quantTables
[index
][dctZigZag
[i
]] = str
->getChar();
2591 GBool
DCTStream::readHuffmanTables() {
2600 length
= read16() - 2;
2601 while (length
> 0) {
2602 index
= str
->getChar();
2604 if ((index
& 0x0f) >= 4) {
2605 error(getPos(), "Bad DCT Huffman table");
2610 if (index
>= numACHuffTables
)
2611 numACHuffTables
= index
+1;
2612 tbl
= &acHuffTables
[index
];
2614 if (index
>= numDCHuffTables
)
2615 numDCHuffTables
= index
+1;
2616 tbl
= &dcHuffTables
[index
];
2620 for (i
= 1; i
<= 16; ++i
) {
2622 tbl
->firstSym
[i
] = sym
;
2623 tbl
->firstCode
[i
] = code
;
2624 tbl
->numCodes
[i
] = c
;
2626 code
= (code
+ c
) << 1;
2629 for (i
= 0; i
< sym
; ++i
)
2630 tbl
->sym
[i
] = str
->getChar();
2636 GBool
DCTStream::readRestartInterval() {
2641 error(getPos(), "Bad DCT restart interval");
2644 restartInterval
= read16();
2648 GBool
DCTStream::readAdobeMarker() {
2656 for (i
= 0; i
< 12; ++i
) {
2657 if ((c
= str
->getChar()) == EOF
)
2661 if (strncmp(buf
, "Adobe", 5))
2663 colorXform
= buf
[11];
2664 gotAdobeMarker
= gTrue
;
2668 error(getPos(), "Bad DCT Adobe APP14 marker");
2672 GBool
DCTStream::readTrailer() {
2676 if (c
!= 0xd9) { // EOI
2677 error(getPos(), "Bad DCT trailer");
2683 int DCTStream::readMarker() {
2689 } while (c
!= 0xff);
2692 } while (c
== 0xff);
2693 } while (c
== 0x00);
2697 int DCTStream::read16() {
2700 if ((c1
= str
->getChar()) == EOF
)
2702 if ((c2
= str
->getChar()) == EOF
)
2704 return (c1
<< 8) + c2
;
2707 GString
*DCTStream::getPSFilter(const char *indent
) {
2710 s
= str
->getPSFilter(indent
);
2711 s
->append(indent
)->append("<< >> /DCTDecode filter\n");
2715 GBool
DCTStream::isBinary(GBool last
) {
2718 return str
->isBinary(gTrue
);
2721 //------------------------------------------------------------------------
2723 //------------------------------------------------------------------------
2725 int FlateStream::codeLenCodeMap
[flateMaxCodeLenCodes
] = {
2726 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
2729 FlateDecode
FlateStream::lengthDecode
[flateMaxLitCodes
-257] = {
2761 FlateDecode
FlateStream::distDecode
[flateMaxDistCodes
] = {
2794 FlateStream::FlateStream(Stream
*str
, int predictor1
, int columns1
,
2795 int colors1
, int bits1
):
2797 if (predictor1
!= 1) {
2798 pred
= new StreamPredictor(this, predictor1
, columns1
, colors1
, bits1
);
2804 FlateStream::~FlateStream() {
2811 void FlateStream::reset() {
2817 //~ need to look at window size?
2818 endOfBlock
= eof
= gTrue
;
2819 cmf
= str
->getChar();
2820 flg
= str
->getChar();
2821 if (cmf
== EOF
|| flg
== EOF
)
2823 if ((cmf
& 0x0f) != 0x08) {
2824 error(getPos(), "Unknown compression method in flate stream");
2827 if ((((cmf
<< 8) + flg
) % 31) != 0) {
2828 error(getPos(), "Bad FCHECK in flate stream");
2832 error(getPos(), "FDICT bit set in flate stream");
2841 compressedBlock
= gFalse
;
2846 int FlateStream::getChar() {
2850 return pred
->getChar();
2852 while (remain
== 0) {
2853 if (endOfBlock
&& eof
)
2858 index
= (index
+ 1) & flateMask
;
2863 int FlateStream::lookChar() {
2867 return pred
->lookChar();
2869 while (remain
== 0) {
2870 if (endOfBlock
&& eof
)
2878 int FlateStream::getRawChar() {
2881 while (remain
== 0) {
2882 if (endOfBlock
&& eof
)
2887 index
= (index
+ 1) & flateMask
;
2892 GString
*FlateStream::getPSFilter(const char *indent
) {
2898 GBool
FlateStream::isBinary(GBool last
) {
2901 return str
->isBinary(gTrue
);
2904 void FlateStream::readSome() {
2915 if (compressedBlock
) {
2916 if ((code1
= getHuffmanCodeWord(&litCodeTab
)) == EOF
)
2921 } else if (code1
== 256) {
2926 code2
= lengthDecode
[code1
].bits
;
2927 if (code2
> 0 && (code2
= getCodeWord(code2
)) == EOF
)
2929 len
= lengthDecode
[code1
].first
+ code2
;
2930 if ((code1
= getHuffmanCodeWord(&distCodeTab
)) == EOF
)
2932 code2
= distDecode
[code1
].bits
;
2933 if (code2
> 0 && (code2
= getCodeWord(code2
)) == EOF
)
2935 dist
= distDecode
[code1
].first
+ code2
;
2937 j
= (index
- dist
) & flateMask
;
2938 for (k
= 0; k
< len
; ++k
) {
2940 i
= (i
+ 1) & flateMask
;
2941 j
= (j
+ 1) & flateMask
;
2947 len
= (blockLen
< flateWindow
) ? blockLen
: flateWindow
;
2948 for (i
= 0, j
= index
; i
< len
; ++i
, j
= (j
+ 1) & flateMask
) {
2949 if ((c
= str
->getChar()) == EOF
) {
2950 endOfBlock
= eof
= gTrue
;
2964 error(getPos(), "Unexpected end of file in flate stream");
2965 endOfBlock
= eof
= gTrue
;
2969 GBool
FlateStream::startBlock() {
2974 // read block header
2975 blockHdr
= getCodeWord(3);
2980 // uncompressed block
2981 if (blockHdr
== 0) {
2982 compressedBlock
= gFalse
;
2983 if ((c
= str
->getChar()) == EOF
)
2985 blockLen
= c
& 0xff;
2986 if ((c
= str
->getChar()) == EOF
)
2988 blockLen
|= (c
& 0xff) << 8;
2989 if ((c
= str
->getChar()) == EOF
)
2992 if ((c
= str
->getChar()) == EOF
)
2994 check
|= (c
& 0xff) << 8;
2995 if (check
!= (~blockLen
& 0xffff))
2996 error(getPos(), "Bad uncompressed block length in flate stream");
3000 // compressed block with fixed codes
3001 } else if (blockHdr
== 1) {
3002 compressedBlock
= gTrue
;
3005 // compressed block with dynamic codes
3006 } else if (blockHdr
== 2) {
3007 compressedBlock
= gTrue
;
3008 if (!readDynamicCodes())
3011 // unknown block type
3016 endOfBlock
= gFalse
;
3020 error(getPos(), "Bad block header in flate stream");
3021 endOfBlock
= eof
= gTrue
;
3025 void FlateStream::loadFixedCodes() {
3028 // set up code arrays
3029 litCodeTab
.codes
= allCodes
;
3030 distCodeTab
.codes
= allCodes
+ flateMaxLitCodes
;
3032 // initialize literal code table
3033 for (i
= 0; i
<= 143; ++i
)
3034 litCodeTab
.codes
[i
].len
= 8;
3035 for (i
= 144; i
<= 255; ++i
)
3036 litCodeTab
.codes
[i
].len
= 9;
3037 for (i
= 256; i
<= 279; ++i
)
3038 litCodeTab
.codes
[i
].len
= 7;
3039 for (i
= 280; i
<= 287; ++i
)
3040 litCodeTab
.codes
[i
].len
= 8;
3041 compHuffmanCodes(&litCodeTab
, flateMaxLitCodes
);
3043 // initialize distance code table
3044 for (i
= 0; i
<= 5; ++i
) {
3045 distCodeTab
.start
[i
] = 0;
3047 for (i
= 6; i
<= flateMaxHuffman
+1; ++i
) {
3048 distCodeTab
.start
[i
] = flateMaxDistCodes
;
3050 for (i
= 0; i
< flateMaxDistCodes
; ++i
) {
3051 distCodeTab
.codes
[i
].len
= 5;
3052 distCodeTab
.codes
[i
].code
= i
;
3053 distCodeTab
.codes
[i
].val
= i
;
3057 GBool
FlateStream::readDynamicCodes() {
3058 int numCodeLenCodes
;
3061 FlateCode codeLenCodes
[flateMaxCodeLenCodes
];
3062 FlateHuffmanTab codeLenCodeTab
;
3063 int len
, repeat
, code
;
3067 if ((numLitCodes
= getCodeWord(5)) == EOF
)
3070 if ((numDistCodes
= getCodeWord(5)) == EOF
)
3073 if ((numCodeLenCodes
= getCodeWord(4)) == EOF
)
3075 numCodeLenCodes
+= 4;
3076 if (numLitCodes
> flateMaxLitCodes
||
3077 numDistCodes
> flateMaxDistCodes
||
3078 numCodeLenCodes
> flateMaxCodeLenCodes
)
3081 // read code length code table
3082 codeLenCodeTab
.codes
= codeLenCodes
;
3083 for (i
= 0; i
< flateMaxCodeLenCodes
; ++i
)
3084 codeLenCodes
[i
].len
= 0;
3085 for (i
= 0; i
< numCodeLenCodes
; ++i
) {
3086 if ((codeLenCodes
[codeLenCodeMap
[i
]].len
= getCodeWord(3)) == -1)
3089 compHuffmanCodes(&codeLenCodeTab
, flateMaxCodeLenCodes
);
3091 // set up code arrays
3092 litCodeTab
.codes
= allCodes
;
3093 distCodeTab
.codes
= allCodes
+ numLitCodes
;
3095 // read literal and distance code tables
3099 while (i
< numLitCodes
+ numDistCodes
) {
3100 if ((code
= getHuffmanCodeWord(&codeLenCodeTab
)) == EOF
)
3103 if ((repeat
= getCodeWord(2)) == EOF
)
3105 for (repeat
+= 3; repeat
> 0; --repeat
)
3106 allCodes
[i
++].len
= len
;
3107 } else if (code
== 17) {
3108 if ((repeat
= getCodeWord(3)) == EOF
)
3111 for (repeat
+= 3; repeat
> 0; --repeat
)
3112 allCodes
[i
++].len
= 0;
3113 } else if (code
== 18) {
3114 if ((repeat
= getCodeWord(7)) == EOF
)
3117 for (repeat
+= 11; repeat
> 0; --repeat
)
3118 allCodes
[i
++].len
= 0;
3120 allCodes
[i
++].len
= len
= code
;
3123 compHuffmanCodes(&litCodeTab
, numLitCodes
);
3124 compHuffmanCodes(&distCodeTab
, numDistCodes
);
3129 error(getPos(), "Bad dynamic code table in flate stream");
3133 // On entry, the <tab->codes> array contains the lengths of each code,
3134 // stored in code value order. This function computes the code words.
3135 // The result is sorted in order of (1) code length and (2) code word.
3136 // The length values are no longer valid. The <tab->start> array is
3137 // filled with the indexes of the first code of each length.
3138 void FlateStream::compHuffmanCodes(FlateHuffmanTab
*tab
, int n
) {
3139 int numLengths
[flateMaxHuffman
+1];
3140 int nextCode
[flateMaxHuffman
+1];
3141 int nextIndex
[flateMaxHuffman
+2];
3145 // count number of codes for each code length
3146 for (i
= 0; i
<= flateMaxHuffman
; ++i
)
3148 for (i
= 0; i
< n
; ++i
)
3149 ++numLengths
[tab
->codes
[i
].len
];
3151 // compute first index for each length
3152 tab
->start
[0] = nextIndex
[0] = 0;
3153 for (i
= 1; i
<= flateMaxHuffman
+ 1; ++i
)
3154 tab
->start
[i
] = nextIndex
[i
] = tab
->start
[i
-1] + numLengths
[i
-1];
3156 // compute first code for each length
3159 for (i
= 1; i
<= flateMaxHuffman
; ++i
) {
3160 code
= (code
+ numLengths
[i
-1]) << 1;
3164 // compute the codes -- this permutes the codes array from value
3165 // order to length/code order
3166 for (i
= 0; i
< n
; ++i
) {
3167 j
= nextIndex
[tab
->codes
[i
].len
]++;
3168 if (tab
->codes
[i
].len
== 0)
3169 tab
->codes
[j
].code
= 0;
3171 tab
->codes
[j
].code
= nextCode
[tab
->codes
[i
].len
]++;
3172 tab
->codes
[j
].val
= i
;
3176 int FlateStream::getHuffmanCodeWord(FlateHuffmanTab
*tab
) {
3183 for (len
= 1; len
<= flateMaxHuffman
; ++len
) {
3185 // add a bit to the code
3186 if (codeSize
== 0) {
3187 if ((c
= str
->getChar()) == EOF
)
3192 code
= (code
<< 1) | (codeBuf
& 1);
3197 i
= tab
->start
[len
];
3198 j
= tab
->start
[len
+ 1];
3199 if (i
< j
&& code
>= tab
->codes
[i
].code
&& code
<= tab
->codes
[j
-1].code
) {
3200 i
+= code
- tab
->codes
[i
].code
;
3201 return tab
->codes
[i
].val
;
3206 error(getPos(), "Bad code (%04x) in flate stream", code
);
3210 int FlateStream::getCodeWord(int bits
) {
3213 while (codeSize
< bits
) {
3214 if ((c
= str
->getChar()) == EOF
)
3216 codeBuf
|= (c
& 0xff) << codeSize
;
3219 c
= codeBuf
& ((1 << bits
) - 1);
3225 //------------------------------------------------------------------------
3227 //------------------------------------------------------------------------
3229 EOFStream::EOFStream(Stream
*str
):
3233 EOFStream::~EOFStream() {
3237 //------------------------------------------------------------------------
3238 // FixedLengthEncoder
3239 //------------------------------------------------------------------------
3241 FixedLengthEncoder::FixedLengthEncoder(Stream
*str
, int length1
):
3247 FixedLengthEncoder::~FixedLengthEncoder() {
3248 if (str
->isEncoder())
3252 void FixedLengthEncoder::reset() {
3257 int FixedLengthEncoder::getChar() {
3258 if (length
>= 0 && count
>= length
)
3261 return str
->getChar();
3264 int FixedLengthEncoder::lookChar() {
3265 if (length
>= 0 && count
>= length
)
3267 return str
->getChar();
3270 //------------------------------------------------------------------------
3272 //------------------------------------------------------------------------
3274 ASCII85Encoder::ASCII85Encoder(Stream
*str
):
3276 bufPtr
= bufEnd
= buf
;
3281 ASCII85Encoder::~ASCII85Encoder() {
3282 if (str
->isEncoder())
3286 void ASCII85Encoder::reset() {
3288 bufPtr
= bufEnd
= buf
;
3293 GBool
ASCII85Encoder::fillBuf() {
3302 for (n
= 0; n
< 4; ++n
) {
3303 if ((c
= str
->getChar()) == EOF
)
3307 bufPtr
= bufEnd
= buf
;
3309 if (n
== 4 && t
== 0) {
3311 if (++lineLen
== 65) {
3318 for (i
= 4; i
>= 0; --i
) {
3319 buf1
[i
] = (char)(t
% 85 + 0x21);
3322 for (i
= 0; i
<= n
; ++i
) {
3323 *bufEnd
++ = buf1
[i
];
3324 if (++lineLen
== 65) {
3336 return bufPtr
< bufEnd
;
3339 //------------------------------------------------------------------------
3341 //------------------------------------------------------------------------
3343 RunLengthEncoder::RunLengthEncoder(Stream
*str
):
3345 bufPtr
= bufEnd
= nextEnd
= buf
;
3349 RunLengthEncoder::~RunLengthEncoder() {
3350 if (str
->isEncoder())
3354 void RunLengthEncoder::reset() {
3356 bufPtr
= bufEnd
= nextEnd
= buf
;
3361 // When fillBuf finishes, buf[] looks like this:
3362 // +-----+--------------+-----------------+--
3363 // + tag | ... data ... | next 0, 1, or 2 |
3364 // +-----+--------------+-----------------+--
3366 // bufPtr bufEnd nextEnd
3368 GBool
RunLengthEncoder::fillBuf() {
3377 if (nextEnd
< bufEnd
+ 1) {
3378 if ((c1
= str
->getChar()) == EOF
) {
3383 c1
= bufEnd
[0] & 0xff;
3385 if (nextEnd
< bufEnd
+ 2) {
3386 if ((c2
= str
->getChar()) == EOF
) {
3395 c2
= bufEnd
[1] & 0xff;
3399 c
= 0; // make gcc happy
3402 c
= 0; // suppress bogus compiler warning
3403 while (n
< 128 && (c
= str
->getChar()) == c1
)
3405 buf
[0] = (char)(257 - n
);
3410 } else if (n
< 128) {
3417 // get up to 128 chars
3423 if ((c
= str
->getChar()) == EOF
) {
3429 if (buf
[n
] == buf
[n
-1])
3432 if (buf
[n
] == buf
[n
-1]) {
3433 buf
[0] = (char)(n
-2-1);
3435 nextEnd
= &buf
[n
+1];
3437 buf
[0] = (char)(n
-1);
3438 bufEnd
= nextEnd
= &buf
[n
+1];