Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/Stream.cc') (more/less context) (show whitespace changes)
-rw-r--r-- | noncore/unsupported/qpdf/xpdf/Stream.cc | 3467 |
1 files changed, 3467 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/Stream.cc b/noncore/unsupported/qpdf/xpdf/Stream.cc new file mode 100644 index 0000000..18490d4 --- a/dev/null +++ b/noncore/unsupported/qpdf/xpdf/Stream.cc | |||
@@ -0,0 +1,3467 @@ | |||
1 | //======================================================================== | ||
2 | // | ||
3 | // Stream.cc | ||
4 | // | ||
5 | // Copyright 1996 Derek B. Noonburg | ||
6 | // | ||
7 | //======================================================================== | ||
8 | |||
9 | #ifdef __GNUC__ | ||
10 | #pragma implementation | ||
11 | #endif | ||
12 | |||
13 | #include <aconf.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <stddef.h> | ||
17 | #ifndef WIN32 | ||
18 | #include <unistd.h> | ||
19 | #endif | ||
20 | #include <string.h> | ||
21 | #include <ctype.h> | ||
22 | #include "gmem.h" | ||
23 | #include "gfile.h" | ||
24 | #include "config.h" | ||
25 | #include "Error.h" | ||
26 | #include "Object.h" | ||
27 | #ifndef NO_DECRYPTION | ||
28 | #include "Decrypt.h" | ||
29 | #endif | ||
30 | #include "Stream.h" | ||
31 | #include "Stream-CCITT.h" | ||
32 | |||
33 | #ifdef __DJGPP__ | ||
34 | static GBool setDJSYSFLAGS = gFalse; | ||
35 | #endif | ||
36 | |||
37 | #ifdef VMS | ||
38 | #if (__VMS_VER < 70000000) | ||
39 | extern "C" int unlink(char *filename); | ||
40 | #endif | ||
41 | #ifdef __GNUC__ | ||
42 | #define SEEK_SET 0 | ||
43 | #define SEEK_CUR 1 | ||
44 | #define SEEK_END 2 | ||
45 | #endif | ||
46 | #endif | ||
47 | |||
48 | #ifdef MACOS | ||
49 | #include "StuffItEngineLib.h" | ||
50 | #endif | ||
51 | |||
52 | //------------------------------------------------------------------------ | ||
53 | // Stream (base class) | ||
54 | //------------------------------------------------------------------------ | ||
55 | |||
56 | Stream::Stream() { | ||
57 | ref = 1; | ||
58 | } | ||
59 | |||
60 | Stream::~Stream() { | ||
61 | } | ||
62 | |||
63 | void Stream::close() { | ||
64 | } | ||
65 | |||
66 | int Stream::getRawChar() { | ||
67 | error(-1, "Internal: called getRawChar() on non-predictor stream"); | ||
68 | return EOF; | ||
69 | } | ||
70 | |||
71 | char *Stream::getLine(char *buf, int size) { | ||
72 | int i; | ||
73 | int c; | ||
74 | |||
75 | if (lookChar() == EOF) | ||
76 | return NULL; | ||
77 | for (i = 0; i < size - 1; ++i) { | ||
78 | c = getChar(); | ||
79 | if (c == EOF || c == '\n') | ||
80 | break; | ||
81 | if (c == '\r') { | ||
82 | if ((c = lookChar()) == '\n') | ||
83 | getChar(); | ||
84 | break; | ||
85 | } | ||
86 | buf[i] = c; | ||
87 | } | ||
88 | buf[i] = '\0'; | ||
89 | return buf; | ||
90 | } | ||
91 | |||
92 | GString *Stream::getPSFilter(char *indent) { | ||
93 | return new GString(); | ||
94 | } | ||
95 | |||
96 | Stream *Stream::addFilters(Object *dict) { | ||
97 | Object obj, obj2; | ||
98 | Object params, params2; | ||
99 | Stream *str; | ||
100 | int i; | ||
101 | |||
102 | str = this; | ||
103 | dict->dictLookup("Filter", &obj); | ||
104 | if (obj.isNull()) { | ||
105 | obj.free(); | ||
106 | dict->dictLookup("F", &obj); | ||
107 | } | ||
108 | dict->dictLookup("DecodeParms", ¶ms); | ||
109 | if (params.isNull()) { | ||
110 | params.free(); | ||
111 | dict->dictLookup("DP", ¶ms); | ||
112 | } | ||
113 | if (obj.isName()) { | ||
114 | str = makeFilter(obj.getName(), str, ¶ms); | ||
115 | } else if (obj.isArray()) { | ||
116 | for (i = 0; i < obj.arrayGetLength(); ++i) { | ||
117 | obj.arrayGet(i, &obj2); | ||
118 | if (params.isArray()) | ||
119 | params.arrayGet(i, ¶ms2); | ||
120 | else | ||
121 | params2.initNull(); | ||
122 | if (obj2.isName()) { | ||
123 | str = makeFilter(obj2.getName(), str, ¶ms2); | ||
124 | } else { | ||
125 | error(getPos(), "Bad filter name"); | ||
126 | str = new EOFStream(str); | ||
127 | } | ||
128 | obj2.free(); | ||
129 | params2.free(); | ||
130 | } | ||
131 | } else if (!obj.isNull()) { | ||
132 | error(getPos(), "Bad 'Filter' attribute in stream"); | ||
133 | } | ||
134 | obj.free(); | ||
135 | params.free(); | ||
136 | |||
137 | return str; | ||
138 | } | ||
139 | |||
140 | Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { | ||
141 | int pred; // parameters | ||
142 | int colors; | ||
143 | int bits; | ||
144 | int early; | ||
145 | int encoding; | ||
146 | GBool endOfLine, byteAlign, endOfBlock, black; | ||
147 | int columns, rows; | ||
148 | Object obj; | ||
149 | |||
150 | if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { | ||
151 | str = new ASCIIHexStream(str); | ||
152 | } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) { | ||
153 | str = new ASCII85Stream(str); | ||
154 | } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) { | ||
155 | pred = 1; | ||
156 | columns = 1; | ||
157 | colors = 1; | ||
158 | bits = 8; | ||
159 | early = 1; | ||
160 | if (params->isDict()) { | ||
161 | params->dictLookup("Predictor", &obj); | ||
162 | if (obj.isInt()) | ||
163 | pred = obj.getInt(); | ||
164 | obj.free(); | ||
165 | params->dictLookup("Columns", &obj); | ||
166 | if (obj.isInt()) | ||
167 | columns = obj.getInt(); | ||
168 | obj.free(); | ||
169 | params->dictLookup("Colors", &obj); | ||
170 | if (obj.isInt()) | ||
171 | colors = obj.getInt(); | ||
172 | obj.free(); | ||
173 | params->dictLookup("BitsPerComponent", &obj); | ||
174 | if (obj.isInt()) | ||
175 | bits = obj.getInt(); | ||
176 | obj.free(); | ||
177 | params->dictLookup("EarlyChange", &obj); | ||
178 | if (obj.isInt()) | ||
179 | early = obj.getInt(); | ||
180 | obj.free(); | ||
181 | } | ||
182 | str = new LZWStream(str, pred, columns, colors, bits, early); | ||
183 | } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) { | ||
184 | str = new RunLengthStream(str); | ||
185 | } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) { | ||
186 | encoding = 0; | ||
187 | endOfLine = gFalse; | ||
188 | byteAlign = gFalse; | ||
189 | columns = 1728; | ||
190 | rows = 0; | ||
191 | endOfBlock = gTrue; | ||
192 | black = gFalse; | ||
193 | if (params->isDict()) { | ||
194 | params->dictLookup("K", &obj); | ||
195 | if (obj.isInt()) { | ||
196 | encoding = obj.getInt(); | ||
197 | } | ||
198 | obj.free(); | ||
199 | params->dictLookup("EndOfLine", &obj); | ||
200 | if (obj.isBool()) { | ||
201 | endOfLine = obj.getBool(); | ||
202 | } | ||
203 | obj.free(); | ||
204 | params->dictLookup("EncodedByteAlign", &obj); | ||
205 | if (obj.isBool()) { | ||
206 | byteAlign = obj.getBool(); | ||
207 | } | ||
208 | obj.free(); | ||
209 | params->dictLookup("Columns", &obj); | ||
210 | if (obj.isInt()) { | ||
211 | columns = obj.getInt(); | ||
212 | } | ||
213 | obj.free(); | ||
214 | params->dictLookup("Rows", &obj); | ||
215 | if (obj.isInt()) { | ||
216 | rows = obj.getInt(); | ||
217 | } | ||
218 | obj.free(); | ||
219 | params->dictLookup("EndOfBlock", &obj); | ||
220 | if (obj.isBool()) { | ||
221 | endOfBlock = obj.getBool(); | ||
222 | } | ||
223 | obj.free(); | ||
224 | params->dictLookup("BlackIs1", &obj); | ||
225 | if (obj.isBool()) { | ||
226 | black = obj.getBool(); | ||
227 | } | ||
228 | obj.free(); | ||
229 | } | ||
230 | str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, | ||
231 | columns, rows, endOfBlock, black); | ||
232 | } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { | ||
233 | str = new DCTStream(str); | ||
234 | } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { | ||
235 | pred = 1; | ||
236 | columns = 1; | ||
237 | colors = 1; | ||
238 | bits = 8; | ||
239 | if (params->isDict()) { | ||
240 | params->dictLookup("Predictor", &obj); | ||
241 | if (obj.isInt()) | ||
242 | pred = obj.getInt(); | ||
243 | obj.free(); | ||
244 | params->dictLookup("Columns", &obj); | ||
245 | if (obj.isInt()) | ||
246 | columns = obj.getInt(); | ||
247 | obj.free(); | ||
248 | params->dictLookup("Colors", &obj); | ||
249 | if (obj.isInt()) | ||
250 | colors = obj.getInt(); | ||
251 | obj.free(); | ||
252 | params->dictLookup("BitsPerComponent", &obj); | ||
253 | if (obj.isInt()) | ||
254 | bits = obj.getInt(); | ||
255 | obj.free(); | ||
256 | } | ||
257 | str = new FlateStream(str, pred, columns, colors, bits); | ||
258 | } else { | ||
259 | error(getPos(), "Unknown filter '%s'", name); | ||
260 | str = new EOFStream(str); | ||
261 | } | ||
262 | return str; | ||
263 | } | ||
264 | |||
265 | //------------------------------------------------------------------------ | ||
266 | // BaseStream | ||
267 | //------------------------------------------------------------------------ | ||
268 | |||
269 | BaseStream::BaseStream(Object *dictA) { | ||
270 | dict = *dictA; | ||
271 | #ifndef NO_DECRYPTION | ||
272 | decrypt = NULL; | ||
273 | #endif | ||
274 | } | ||
275 | |||
276 | BaseStream::~BaseStream() { | ||
277 | dict.free(); | ||
278 | #ifndef NO_DECRYPTION | ||
279 | if (decrypt) | ||
280 | delete decrypt; | ||
281 | #endif | ||
282 | } | ||
283 | |||
284 | #ifndef NO_DECRYPTION | ||
285 | void BaseStream::doDecryption(Guchar *fileKey, int keyLength, | ||
286 | int objNum, int objGen) { | ||
287 | decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); | ||
288 | } | ||
289 | #endif | ||
290 | |||
291 | //------------------------------------------------------------------------ | ||
292 | // FilterStream | ||
293 | //------------------------------------------------------------------------ | ||
294 | |||
295 | FilterStream::FilterStream(Stream *strA) { | ||
296 | str = strA; | ||
297 | } | ||
298 | |||
299 | FilterStream::~FilterStream() { | ||
300 | } | ||
301 | |||
302 | void FilterStream::close() { | ||
303 | str->close(); | ||
304 | } | ||
305 | |||
306 | void FilterStream::setPos(int pos) { | ||
307 | error(-1, "Internal: called setPos() on FilterStream"); | ||
308 | } | ||
309 | |||
310 | //------------------------------------------------------------------------ | ||
311 | // ImageStream | ||
312 | //------------------------------------------------------------------------ | ||
313 | |||
314 | ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { | ||
315 | int imgLineSize; | ||
316 | |||
317 | str = strA; | ||
318 | width = widthA; | ||
319 | nComps = nCompsA; | ||
320 | nBits = nBitsA; | ||
321 | |||
322 | nVals = width * nComps; | ||
323 | if (nBits == 1) { | ||
324 | imgLineSize = (nVals + 7) & ~7; | ||
325 | } else { | ||
326 | imgLineSize = nVals; | ||
327 | } | ||
328 | imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar)); | ||
329 | imgIdx = nVals; | ||
330 | } | ||
331 | |||
332 | ImageStream::~ImageStream() { | ||
333 | gfree(imgLine); | ||
334 | } | ||
335 | |||
336 | void ImageStream::reset() { | ||
337 | str->reset(); | ||
338 | } | ||
339 | |||
340 | GBool ImageStream::getPixel(Guchar *pix) { | ||
341 | Gulong buf, bitMask; | ||
342 | int bits; | ||
343 | int c; | ||
344 | int i; | ||
345 | |||
346 | if (imgIdx >= nVals) { | ||
347 | |||
348 | // read one line of image pixels | ||
349 | if (nBits == 1) { | ||
350 | for (i = 0; i < nVals; i += 8) { | ||
351 | c = str->getChar(); | ||
352 | imgLine[i+0] = (Guchar)((c >> 7) & 1); | ||
353 | imgLine[i+1] = (Guchar)((c >> 6) & 1); | ||
354 | imgLine[i+2] = (Guchar)((c >> 5) & 1); | ||
355 | imgLine[i+3] = (Guchar)((c >> 4) & 1); | ||
356 | imgLine[i+4] = (Guchar)((c >> 3) & 1); | ||
357 | imgLine[i+5] = (Guchar)((c >> 2) & 1); | ||
358 | imgLine[i+6] = (Guchar)((c >> 1) & 1); | ||
359 | imgLine[i+7] = (Guchar)(c & 1); | ||
360 | } | ||
361 | } else if (nBits == 8) { | ||
362 | for (i = 0; i < nVals; ++i) { | ||
363 | imgLine[i] = str->getChar(); | ||
364 | } | ||
365 | } else { | ||
366 | bitMask = (1 << nBits) - 1; | ||
367 | buf = 0; | ||
368 | bits = 0; | ||
369 | for (i = 0; i < nVals; ++i) { | ||
370 | if (bits < nBits) { | ||
371 | buf = (buf << 8) | (str->getChar() & 0xff); | ||
372 | bits += 8; | ||
373 | } | ||
374 | imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); | ||
375 | bits -= nBits; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | // reset to start of line | ||
380 | imgIdx = 0; | ||
381 | } | ||
382 | |||
383 | for (i = 0; i < nComps; ++i) | ||
384 | pix[i] = imgLine[imgIdx++]; | ||
385 | return gTrue; | ||
386 | } | ||
387 | |||
388 | void ImageStream::skipLine() { | ||
389 | int n, i; | ||
390 | |||
391 | n = (nVals * nBits + 7) >> 3; | ||
392 | for (i = 0; i < n; ++i) { | ||
393 | str->getChar(); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | //------------------------------------------------------------------------ | ||
398 | // StreamPredictor | ||
399 | //------------------------------------------------------------------------ | ||
400 | |||
401 | StreamPredictor::StreamPredictor(Stream *strA, int predictorA, | ||
402 | int widthA, int nCompsA, int nBitsA) { | ||
403 | str = strA; | ||
404 | predictor = predictorA; | ||
405 | width = widthA; | ||
406 | nComps = nCompsA; | ||
407 | nBits = nBitsA; | ||
408 | |||
409 | nVals = width * nComps; | ||
410 | pixBytes = (nComps * nBits + 7) >> 3; | ||
411 | rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; | ||
412 | predLine = (Guchar *)gmalloc(rowBytes); | ||
413 | memset(predLine, 0, rowBytes); | ||
414 | predIdx = rowBytes; | ||
415 | } | ||
416 | |||
417 | StreamPredictor::~StreamPredictor() { | ||
418 | gfree(predLine); | ||
419 | } | ||
420 | |||
421 | int StreamPredictor::lookChar() { | ||
422 | if (predIdx >= rowBytes) { | ||
423 | if (!getNextLine()) { | ||
424 | return EOF; | ||
425 | } | ||
426 | } | ||
427 | return predLine[predIdx]; | ||
428 | } | ||
429 | |||
430 | int StreamPredictor::getChar() { | ||
431 | if (predIdx >= rowBytes) { | ||
432 | if (!getNextLine()) { | ||
433 | return EOF; | ||
434 | } | ||
435 | } | ||
436 | return predLine[predIdx++]; | ||
437 | } | ||
438 | |||
439 | GBool StreamPredictor::getNextLine() { | ||
440 | int curPred; | ||
441 | Guchar upLeftBuf[4]; | ||
442 | int left, up, upLeft, p, pa, pb, pc; | ||
443 | int c; | ||
444 | Gulong inBuf, outBuf, bitMask; | ||
445 | int inBits, outBits; | ||
446 | int i, j, k; | ||
447 | |||
448 | // get PNG optimum predictor number | ||
449 | if (predictor == 15) { | ||
450 | if ((curPred = str->getRawChar()) == EOF) { | ||
451 | return gFalse; | ||
452 | } | ||
453 | curPred += 10; | ||
454 | } else { | ||
455 | curPred = predictor; | ||
456 | } | ||
457 | |||
458 | // read the raw line, apply PNG (byte) predictor | ||
459 | upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; | ||
460 | for (i = pixBytes; i < rowBytes; ++i) { | ||
461 | upLeftBuf[3] = upLeftBuf[2]; | ||
462 | upLeftBuf[2] = upLeftBuf[1]; | ||
463 | upLeftBuf[1] = upLeftBuf[0]; | ||
464 | upLeftBuf[0] = predLine[i]; | ||
465 | if ((c = str->getRawChar()) == EOF) { | ||
466 | break; | ||
467 | } | ||
468 | switch (curPred) { | ||
469 | case 11: // PNG sub | ||
470 | predLine[i] = predLine[i - pixBytes] + (Guchar)c; | ||
471 | break; | ||
472 | case 12: // PNG up | ||
473 | predLine[i] = predLine[i] + (Guchar)c; | ||
474 | break; | ||
475 | case 13: // PNG average | ||
476 | predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + | ||
477 | (Guchar)c; | ||
478 | break; | ||
479 | case 14: // PNG Paeth | ||
480 | left = predLine[i - pixBytes]; | ||
481 | up = predLine[i]; | ||
482 | upLeft = upLeftBuf[pixBytes]; | ||
483 | p = left + up - upLeft; | ||
484 | if ((pa = p - left) < 0) | ||
485 | pa = -pa; | ||
486 | if ((pb = p - up) < 0) | ||
487 | pb = -pb; | ||
488 | if ((pc = p - upLeft) < 0) | ||
489 | pc = -pc; | ||
490 | if (pa <= pb && pa <= pc) | ||
491 | predLine[i] = left + (Guchar)c; | ||
492 | else if (pb <= pc) | ||
493 | predLine[i] = up + (Guchar)c; | ||
494 | else | ||
495 | predLine[i] = upLeft + (Guchar)c; | ||
496 | break; | ||
497 | case 10: // PNG none | ||
498 | default: // no predictor or TIFF predictor | ||
499 | predLine[i] = (Guchar)c; | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | // apply TIFF (component) predictor | ||
505 | //~ this is completely untested | ||
506 | if (predictor == 2) { | ||
507 | if (nBits == 1) { | ||
508 | inBuf = predLine[pixBytes - 1]; | ||
509 | for (i = pixBytes; i < rowBytes; i += 8) { | ||
510 | // 1-bit add is just xor | ||
511 | inBuf = (inBuf << 8) | predLine[i]; | ||
512 | predLine[i] ^= inBuf >> nComps; | ||
513 | } | ||
514 | } else if (nBits == 8) { | ||
515 | for (i = pixBytes; i < rowBytes; ++i) { | ||
516 | predLine[i] += predLine[i - nComps]; | ||
517 | } | ||
518 | } else { | ||
519 | upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; | ||
520 | bitMask = (1 << nBits) - 1; | ||
521 | inBuf = outBuf = 0; | ||
522 | inBits = outBits = 0; | ||
523 | j = k = pixBytes; | ||
524 | for (i = 0; i < nVals; ++i) { | ||
525 | if (inBits < nBits) { | ||
526 | inBuf = (inBuf << 8) | (predLine[j++] & 0xff); | ||
527 | inBits += 8; | ||
528 | } | ||
529 | upLeftBuf[3] = upLeftBuf[2]; | ||
530 | upLeftBuf[2] = upLeftBuf[1]; | ||
531 | upLeftBuf[1] = upLeftBuf[0]; | ||
532 | upLeftBuf[0] = (upLeftBuf[nComps] + | ||
533 | (inBuf >> (inBits - nBits))) & bitMask; | ||
534 | outBuf = (outBuf << nBits) | upLeftBuf[0]; | ||
535 | inBits -= nBits; | ||
536 | outBits += nBits; | ||
537 | if (outBits > 8) { | ||
538 | predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); | ||
539 | } | ||
540 | } | ||
541 | if (outBits > 0) { | ||
542 | predLine[k++] = (Guchar)(outBuf << (8 - outBits)); | ||
543 | } | ||
544 | } | ||
545 | } | ||
546 | |||
547 | // reset to start of line | ||
548 | predIdx = pixBytes; | ||
549 | |||
550 | return gTrue; | ||
551 | } | ||
552 | |||
553 | //------------------------------------------------------------------------ | ||
554 | // FileStream | ||
555 | //------------------------------------------------------------------------ | ||
556 | |||
557 | FileStream::FileStream(FILE *fA, int startA, int lengthA, Object *dictA): | ||
558 | BaseStream(dictA) { | ||
559 | f = fA; | ||
560 | start = startA; | ||
561 | length = lengthA; | ||
562 | bufPtr = bufEnd = buf; | ||
563 | bufPos = start; | ||
564 | savePos = -1; | ||
565 | } | ||
566 | |||
567 | FileStream::~FileStream() { | ||
568 | close(); | ||
569 | } | ||
570 | |||
571 | Stream *FileStream::makeSubStream(int startA, int lengthA, Object *dictA) { | ||
572 | return new FileStream(f, startA, lengthA, dictA); | ||
573 | } | ||
574 | |||
575 | void FileStream::reset() { | ||
576 | savePos = (int)ftell(f); | ||
577 | fseek(f, start, SEEK_SET); | ||
578 | bufPtr = bufEnd = buf; | ||
579 | bufPos = start; | ||
580 | #ifndef NO_DECRYPTION | ||
581 | if (decrypt) | ||
582 | decrypt->reset(); | ||
583 | #endif | ||
584 | } | ||
585 | |||
586 | void FileStream::close() { | ||
587 | if (savePos >= 0) { | ||
588 | fseek(f, savePos, SEEK_SET); | ||
589 | savePos = -1; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | GBool FileStream::fillBuf() { | ||
594 | int n; | ||
595 | #ifndef NO_DECRYPTION | ||
596 | char *p; | ||
597 | #endif | ||
598 | |||
599 | bufPos += bufEnd - buf; | ||
600 | bufPtr = bufEnd = buf; | ||
601 | if (length >= 0 && bufPos >= start + length) { | ||
602 | return gFalse; | ||
603 | } | ||
604 | if (length >= 0 && bufPos + fileStreamBufSize > start + length) { | ||
605 | n = start + length - bufPos; | ||
606 | } else { | ||
607 | n = fileStreamBufSize; | ||
608 | } | ||
609 | n = fread(buf, 1, n, f); | ||
610 | bufEnd = buf + n; | ||
611 | if (bufPtr >= bufEnd) { | ||
612 | return gFalse; | ||
613 | } | ||
614 | #ifndef NO_DECRYPTION | ||
615 | if (decrypt) { | ||
616 | for (p = buf; p < bufEnd; ++p) { | ||
617 | *p = (char)decrypt->decryptByte((Guchar)*p); | ||
618 | } | ||
619 | } | ||
620 | #endif | ||
621 | return gTrue; | ||
622 | } | ||
623 | |||
624 | void FileStream::setPos(int pos) { | ||
625 | long size; | ||
626 | |||
627 | if (pos >= 0) { | ||
628 | fseek(f, pos, SEEK_SET); | ||
629 | bufPos = pos; | ||
630 | } else { | ||
631 | fseek(f, 0, SEEK_END); | ||
632 | size = ftell(f); | ||
633 | if (pos < -size) | ||
634 | pos = (int)(-size); | ||
635 | #ifdef __CYGWIN32__ | ||
636 | //~ work around a bug in cygwin's implementation of fseek | ||
637 | rewind(f); | ||
638 | #endif | ||
639 | fseek(f, pos, SEEK_END); | ||
640 | bufPos = (int)ftell(f); | ||
641 | } | ||
642 | bufPtr = bufEnd = buf; | ||
643 | } | ||
644 | |||
645 | void FileStream::moveStart(int delta) { | ||
646 | start += delta; | ||
647 | bufPtr = bufEnd = buf; | ||
648 | bufPos = start; | ||
649 | } | ||
650 | |||
651 | //------------------------------------------------------------------------ | ||
652 | // EmbedStream | ||
653 | //------------------------------------------------------------------------ | ||
654 | |||
655 | EmbedStream::EmbedStream(Stream *strA, Object *dictA): | ||
656 | BaseStream(dictA) { | ||
657 | str = strA; | ||
658 | } | ||
659 | |||
660 | EmbedStream::~EmbedStream() { | ||
661 | } | ||
662 | |||
663 | Stream *EmbedStream::makeSubStream(int start, int length, Object *dictA) { | ||
664 | error(-1, "Internal: called makeSubStream() on EmbedStream"); | ||
665 | return NULL; | ||
666 | } | ||
667 | |||
668 | void EmbedStream::setPos(int pos) { | ||
669 | error(-1, "Internal: called setPos() on EmbedStream"); | ||
670 | } | ||
671 | |||
672 | int EmbedStream::getStart() { | ||
673 | error(-1, "Internal: called getStart() on EmbedStream"); | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | void EmbedStream::moveStart(int start) { | ||
678 | error(-1, "Internal: called moveStart() on EmbedStream"); | ||
679 | } | ||
680 | |||
681 | //------------------------------------------------------------------------ | ||
682 | // ASCIIHexStream | ||
683 | //------------------------------------------------------------------------ | ||
684 | |||
685 | ASCIIHexStream::ASCIIHexStream(Stream *strA): | ||
686 | FilterStream(strA) { | ||
687 | buf = EOF; | ||
688 | eof = gFalse; | ||
689 | } | ||
690 | |||
691 | ASCIIHexStream::~ASCIIHexStream() { | ||
692 | delete str; | ||
693 | } | ||
694 | |||
695 | void ASCIIHexStream::reset() { | ||
696 | str->reset(); | ||
697 | buf = EOF; | ||
698 | eof = gFalse; | ||
699 | } | ||
700 | |||
701 | int ASCIIHexStream::lookChar() { | ||
702 | int c1, c2, x; | ||
703 | |||
704 | if (buf != EOF) | ||
705 | return buf; | ||
706 | if (eof) { | ||
707 | buf = EOF; | ||
708 | return EOF; | ||
709 | } | ||
710 | do { | ||
711 | c1 = str->getChar(); | ||
712 | } while (isspace(c1)); | ||
713 | if (c1 == '>') { | ||
714 | eof = gTrue; | ||
715 | buf = EOF; | ||
716 | return buf; | ||
717 | } | ||
718 | do { | ||
719 | c2 = str->getChar(); | ||
720 | } while (isspace(c2)); | ||
721 | if (c2 == '>') { | ||
722 | eof = gTrue; | ||
723 | c2 = '0'; | ||
724 | } | ||
725 | if (c1 >= '0' && c1 <= '9') { | ||
726 | x = (c1 - '0') << 4; | ||
727 | } else if (c1 >= 'A' && c1 <= 'F') { | ||
728 | x = (c1 - 'A' + 10) << 4; | ||
729 | } else if (c1 >= 'a' && c1 <= 'f') { | ||
730 | x = (c1 - 'a' + 10) << 4; | ||
731 | } else if (c1 == EOF) { | ||
732 | eof = gTrue; | ||
733 | x = 0; | ||
734 | } else { | ||
735 | error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1); | ||
736 | x = 0; | ||
737 | } | ||
738 | if (c2 >= '0' && c2 <= '9') { | ||
739 | x += c2 - '0'; | ||
740 | } else if (c2 >= 'A' && c2 <= 'F') { | ||
741 | x += c2 - 'A' + 10; | ||
742 | } else if (c2 >= 'a' && c2 <= 'f') { | ||
743 | x += c2 - 'a' + 10; | ||
744 | } else if (c2 == EOF) { | ||
745 | eof = gTrue; | ||
746 | x = 0; | ||
747 | } else { | ||
748 | error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2); | ||
749 | } | ||
750 | buf = x & 0xff; | ||
751 | return buf; | ||
752 | } | ||
753 | |||
754 | GString *ASCIIHexStream::getPSFilter(char *indent) { | ||
755 | GString *s; | ||
756 | |||
757 | if (!(s = str->getPSFilter(indent))) { | ||
758 | return NULL; | ||
759 | } | ||
760 | s->append(indent)->append("/ASCIIHexDecode filter\n"); | ||
761 | return s; | ||
762 | } | ||
763 | |||
764 | GBool ASCIIHexStream::isBinary(GBool last) { | ||
765 | return str->isBinary(gFalse); | ||
766 | } | ||
767 | |||
768 | //------------------------------------------------------------------------ | ||
769 | // ASCII85Stream | ||
770 | //------------------------------------------------------------------------ | ||
771 | |||
772 | ASCII85Stream::ASCII85Stream(Stream *strA): | ||
773 | FilterStream(strA) { | ||
774 | index = n = 0; | ||
775 | eof = gFalse; | ||
776 | } | ||
777 | |||
778 | ASCII85Stream::~ASCII85Stream() { | ||
779 | delete str; | ||
780 | } | ||
781 | |||
782 | void ASCII85Stream::reset() { | ||
783 | str->reset(); | ||
784 | index = n = 0; | ||
785 | eof = gFalse; | ||
786 | } | ||
787 | |||
788 | int ASCII85Stream::lookChar() { | ||
789 | int k; | ||
790 | Gulong t; | ||
791 | |||
792 | if (index >= n) { | ||
793 | if (eof) | ||
794 | return EOF; | ||
795 | index = 0; | ||
796 | do { | ||
797 | c[0] = str->getChar(); | ||
798 | } while (c[0] == '\n' || c[0] == '\r'); | ||
799 | if (c[0] == '~' || c[0] == EOF) { | ||
800 | eof = gTrue; | ||
801 | n = 0; | ||
802 | return EOF; | ||
803 | } else if (c[0] == 'z') { | ||
804 | b[0] = b[1] = b[2] = b[3] = 0; | ||
805 | n = 4; | ||
806 | } else { | ||
807 | for (k = 1; k < 5; ++k) { | ||
808 | do { | ||
809 | c[k] = str->getChar(); | ||
810 | } while (c[k] == '\n' || c[k] == '\r'); | ||
811 | if (c[k] == '~' || c[k] == EOF) | ||
812 | break; | ||
813 | } | ||
814 | n = k - 1; | ||
815 | if (k < 5 && (c[k] == '~' || c[k] == EOF)) { | ||
816 | for (++k; k < 5; ++k) | ||
817 | c[k] = 0x21 + 84; | ||
818 | eof = gTrue; | ||
819 | } | ||
820 | t = 0; | ||
821 | for (k = 0; k < 5; ++k) | ||
822 | t = t * 85 + (c[k] - 0x21); | ||
823 | for (k = 3; k >= 0; --k) { | ||
824 | b[k] = (int)(t & 0xff); | ||
825 | t >>= 8; | ||
826 | } | ||
827 | } | ||
828 | } | ||
829 | return b[index]; | ||
830 | } | ||
831 | |||
832 | GString *ASCII85Stream::getPSFilter(char *indent) { | ||
833 | GString *s; | ||
834 | |||
835 | if (!(s = str->getPSFilter(indent))) { | ||
836 | return NULL; | ||
837 | } | ||
838 | s->append(indent)->append("/ASCII85Decode filter\n"); | ||
839 | return s; | ||
840 | } | ||
841 | |||
842 | GBool ASCII85Stream::isBinary(GBool last) { | ||
843 | return str->isBinary(gFalse); | ||
844 | } | ||
845 | |||
846 | //------------------------------------------------------------------------ | ||
847 | // LZWStream | ||
848 | //------------------------------------------------------------------------ | ||
849 | |||
850 | LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, | ||
851 | int bits, int earlyA): | ||
852 | FilterStream(strA) { | ||
853 | if (predictor != 1) { | ||
854 | pred = new StreamPredictor(this, predictor, columns, colors, bits); | ||
855 | } else { | ||
856 | pred = NULL; | ||
857 | } | ||
858 | early = earlyA; | ||
859 | zPipe = NULL; | ||
860 | bufPtr = bufEnd = buf; | ||
861 | } | ||
862 | |||
863 | LZWStream::~LZWStream() { | ||
864 | if (zPipe) { | ||
865 | #ifdef HAVE_POPEN | ||
866 | pclose(zPipe); | ||
867 | #else | ||
868 | fclose(zPipe); | ||
869 | #endif | ||
870 | zPipe = NULL; | ||
871 | unlink(zName->getCString()); | ||
872 | delete zName; | ||
873 | } | ||
874 | if (pred) { | ||
875 | delete pred; | ||
876 | } | ||
877 | delete str; | ||
878 | } | ||
879 | |||
880 | int LZWStream::getChar() { | ||
881 | if (pred) { | ||
882 | return pred->getChar(); | ||
883 | } | ||
884 | return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); | ||
885 | } | ||
886 | |||
887 | int LZWStream::lookChar() { | ||
888 | if (pred) { | ||
889 | return pred->lookChar(); | ||
890 | } | ||
891 | return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); | ||
892 | } | ||
893 | |||
894 | int LZWStream::getRawChar() { | ||
895 | return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); | ||
896 | } | ||
897 | |||
898 | void LZWStream::reset() { | ||
899 | FILE *f; | ||
900 | GString *zCmd; | ||
901 | |||
902 | //----- close old LZW stream | ||
903 | if (zPipe) { | ||
904 | #ifdef HAVE_POPEN | ||
905 | pclose(zPipe); | ||
906 | #else | ||
907 | fclose(zPipe); | ||
908 | #endif | ||
909 | zPipe = NULL; | ||
910 | unlink(zName->getCString()); | ||
911 | delete zName; | ||
912 | } | ||
913 | |||
914 | //----- tell Delorie runtime to spawn a new instance of COMMAND.COM | ||
915 | // to run gzip | ||
916 | #if __DJGPP__ | ||
917 | if (!setDJSYSFLAGS) { | ||
918 | setenv("DJSYSFLAGS", "0x0002", 0); | ||
919 | setDJSYSFLAGS = gTrue; | ||
920 | } | ||
921 | #endif | ||
922 | |||
923 | //----- create the .Z file | ||
924 | if (!openTempFile(&zName, &f, "wb", ".Z")) { | ||
925 | error(getPos(), "Couldn't create temporary file for LZW stream"); | ||
926 | return; | ||
927 | } | ||
928 | dumpFile(f); | ||
929 | fclose(f); | ||
930 | |||
931 | //----- execute uncompress / gzip | ||
932 | zCmd = new GString(uncompressCmd); | ||
933 | zCmd->append(' '); | ||
934 | zCmd->append(zName); | ||
935 | #if defined(MACOS) | ||
936 | long magicCookie; | ||
937 | // first we open the engine up | ||
938 | OSErr err = OpenSITEngine(kUseExternalEngine, &magicCookie); | ||
939 | // if we found it - let's use it! | ||
940 | if (!err && magicCookie) { | ||
941 | // make sure we have the correct version of the Engine | ||
942 | if (GetSITEngineVersion(magicCookie) >= kFirstSupportedEngine) { | ||
943 | FSSpec myFSS; | ||
944 | Str255 pName; | ||
945 | strcpy((char *)pName, zName->getCString()); | ||
946 | c2pstr((char *)pName); | ||
947 | FSMakeFSSpec(0, 0, pName, &myFSS); | ||
948 | short ftype = DetermineFileType(magicCookie, &myFSS); | ||
949 | OSErr expandErr = ExpandFSSpec(magicCookie, ftype, &myFSS, | ||
950 | NULL, NULL, kCreateFolderNever, | ||
951 | kDeleteOriginal, kTextConvertSmart); | ||
952 | } | ||
953 | } | ||
954 | #elif defined(HAVE_POPEN) | ||
955 | if (!(zPipe = popen(zCmd->getCString(), POPEN_READ_MODE))) { | ||
956 | error(getPos(), "Couldn't popen '%s'", zCmd->getCString()); | ||
957 | unlink(zName->getCString()); | ||
958 | delete zName; | ||
959 | return; | ||
960 | } | ||
961 | #else // HAVE_POPEN | ||
962 | #ifdef VMS | ||
963 | if (!system(zCmd->getCString())) { | ||
964 | #else | ||
965 | if (system(zCmd->getCString())) { | ||
966 | #endif | ||
967 | error(getPos(), "Couldn't execute '%s'", zCmd->getCString()); | ||
968 | unlink(zName->getCString()); | ||
969 | delete zName; | ||
970 | return; | ||
971 | } | ||
972 | zName->del(zName->getLength() - 2, 2); | ||
973 | if (!(zPipe = fopen(zName->getCString(), "rb"))) { | ||
974 | error(getPos(), "Couldn't open uncompress file '%s'", zName->getCString()); | ||
975 | unlink(zName->getCString()); | ||
976 | delete zName; | ||
977 | return; | ||
978 | } | ||
979 | #endif // HAVE_POPEN | ||
980 | |||
981 | //----- clean up | ||
982 | delete zCmd; | ||
983 | |||
984 | //----- initialize buffer | ||
985 | bufPtr = bufEnd = buf; | ||
986 | } | ||
987 | |||
988 | void LZWStream::dumpFile(FILE *f) { | ||
989 | int outCodeBits; // size of output code | ||
990 | int outBits; // max output code | ||
991 | int outBuf[8]; // output buffer | ||
992 | int outData; // temporary output buffer | ||
993 | int inCode, outCode; // input and output codes | ||
994 | int nextCode; // next code index | ||
995 | GBool eof; // set when EOF is reached | ||
996 | GBool clear; // set if table needs to be cleared | ||
997 | GBool first; // indicates first code word after clear | ||
998 | int i, j; | ||
999 | |||
1000 | str->reset(); | ||
1001 | |||
1002 | // magic number | ||
1003 | fputc(0x1f, f); | ||
1004 | fputc(0x9d, f); | ||
1005 | |||
1006 | // max code length, block mode flag | ||
1007 | fputc(0x8c, f); | ||
1008 | |||
1009 | // init input side | ||
1010 | inCodeBits = 9; | ||
1011 | inputBuf = 0; | ||
1012 | inputBits = 0; | ||
1013 | eof = gFalse; | ||
1014 | |||
1015 | // init output side | ||
1016 | outCodeBits = 9; | ||
1017 | |||
1018 | // clear table | ||
1019 | first = gTrue; | ||
1020 | nextCode = 258; | ||
1021 | |||
1022 | clear = gFalse; | ||
1023 | do { | ||
1024 | for (i = 0; i < 8; ++i) { | ||
1025 | // check for table overflow | ||
1026 | if (nextCode + early > 0x1001) { | ||
1027 | inCode = 256; | ||
1028 | |||
1029 | // read input code | ||
1030 | } else { | ||
1031 | do { | ||
1032 | inCode = getCode(); | ||
1033 | if (inCode == EOF) { | ||
1034 | eof = gTrue; | ||
1035 | inCode = 0; | ||
1036 | } | ||
1037 | } while (first && inCode == 256); | ||
1038 | } | ||
1039 | |||
1040 | // compute output code | ||
1041 | if (inCode < 256) { | ||
1042 | outCode = inCode; | ||
1043 | } else if (inCode == 256) { | ||
1044 | outCode = 256; | ||
1045 | clear = gTrue; | ||
1046 | } else if (inCode == 257) { | ||
1047 | outCode = 0; | ||
1048 | eof = gTrue; | ||
1049 | } else { | ||
1050 | outCode = inCode - 1; | ||
1051 | } | ||
1052 | outBuf[i] = outCode; | ||
1053 | |||
1054 | // next code index | ||
1055 | if (first) | ||
1056 | first = gFalse; | ||
1057 | else | ||
1058 | ++nextCode; | ||
1059 | |||
1060 | // check input code size | ||
1061 | if (nextCode + early == 0x200) | ||
1062 | inCodeBits = 10; | ||
1063 | else if (nextCode + early == 0x400) { | ||
1064 | inCodeBits = 11; | ||
1065 | } else if (nextCode + early == 0x800) { | ||
1066 | inCodeBits = 12; | ||
1067 | } | ||
1068 | |||
1069 | // check for eof/clear | ||
1070 | if (eof) | ||
1071 | break; | ||
1072 | if (clear) { | ||
1073 | i = 8; | ||
1074 | break; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | // write output block | ||
1079 | outData = 0; | ||
1080 | outBits = 0; | ||
1081 | j = 0; | ||
1082 | while (j < i || outBits > 0) { | ||
1083 | if (outBits < 8 && j < i) { | ||
1084 | outData = outData | (outBuf[j++] << outBits); | ||
1085 | outBits += outCodeBits; | ||
1086 | } | ||
1087 | fputc(outData & 0xff, f); | ||
1088 | outData >>= 8; | ||
1089 | outBits -= 8; | ||
1090 | } | ||
1091 | |||
1092 | // check output code size | ||
1093 | if (nextCode - 1 == 512 || | ||
1094 | nextCode - 1 == 1024 || | ||
1095 | nextCode - 1 == 2048 || | ||
1096 | nextCode - 1 == 4096) { | ||
1097 | outCodeBits = inCodeBits; | ||
1098 | } | ||
1099 | |||
1100 | // clear table if necessary | ||
1101 | if (clear) { | ||
1102 | inCodeBits = 9; | ||
1103 | outCodeBits = 9; | ||
1104 | first = gTrue; | ||
1105 | nextCode = 258; | ||
1106 | clear = gFalse; | ||
1107 | } | ||
1108 | } while (!eof); | ||
1109 | } | ||
1110 | |||
1111 | int LZWStream::getCode() { | ||
1112 | int c; | ||
1113 | int code; | ||
1114 | |||
1115 | while (inputBits < inCodeBits) { | ||
1116 | if ((c = str->getChar()) == EOF) | ||
1117 | return EOF; | ||
1118 | inputBuf = (inputBuf << 8) | (c & 0xff); | ||
1119 | inputBits += 8; | ||
1120 | } | ||
1121 | code = (inputBuf >> (inputBits - inCodeBits)) & ((1 << inCodeBits) - 1); | ||
1122 | inputBits -= inCodeBits; | ||
1123 | return code; | ||
1124 | } | ||
1125 | |||
1126 | GBool LZWStream::fillBuf() { | ||
1127 | int n; | ||
1128 | |||
1129 | if (!zPipe) | ||
1130 | return gFalse; | ||
1131 | if ((n = fread(buf, 1, 256, zPipe)) < 256) { | ||
1132 | #ifdef HAVE_POPEN | ||
1133 | pclose(zPipe); | ||
1134 | #else | ||
1135 | fclose(zPipe); | ||
1136 | #endif | ||
1137 | zPipe = NULL; | ||
1138 | unlink(zName->getCString()); | ||
1139 | delete zName; | ||
1140 | } | ||
1141 | bufPtr = buf; | ||
1142 | bufEnd = buf + n; | ||
1143 | return n > 0; | ||
1144 | } | ||
1145 | |||
1146 | GString *LZWStream::getPSFilter(char *indent) { | ||
1147 | GString *s; | ||
1148 | |||
1149 | if (pred) { | ||
1150 | return NULL; | ||
1151 | } | ||
1152 | if (!(s = str->getPSFilter(indent))) { | ||
1153 | return NULL; | ||
1154 | } | ||
1155 | s->append(indent)->append("/LZWDecode filter\n"); | ||
1156 | return s; | ||
1157 | } | ||
1158 | |||
1159 | GBool LZWStream::isBinary(GBool last) { | ||
1160 | return str->isBinary(gTrue); | ||
1161 | } | ||
1162 | |||
1163 | //------------------------------------------------------------------------ | ||
1164 | // RunLengthStream | ||
1165 | //------------------------------------------------------------------------ | ||
1166 | |||
1167 | RunLengthStream::RunLengthStream(Stream *strA): | ||
1168 | FilterStream(strA) { | ||
1169 | bufPtr = bufEnd = buf; | ||
1170 | eof = gFalse; | ||
1171 | } | ||
1172 | |||
1173 | RunLengthStream::~RunLengthStream() { | ||
1174 | delete str; | ||
1175 | } | ||
1176 | |||
1177 | void RunLengthStream::reset() { | ||
1178 | str->reset(); | ||
1179 | bufPtr = bufEnd = buf; | ||
1180 | eof = gFalse; | ||
1181 | } | ||
1182 | |||
1183 | GString *RunLengthStream::getPSFilter(char *indent) { | ||
1184 | GString *s; | ||
1185 | |||
1186 | if (!(s = str->getPSFilter(indent))) { | ||
1187 | return NULL; | ||
1188 | } | ||
1189 | s->append(indent)->append("/RunLengthDecode filter\n"); | ||
1190 | return s; | ||
1191 | } | ||
1192 | |||
1193 | GBool RunLengthStream::isBinary(GBool last) { | ||
1194 | return str->isBinary(gTrue); | ||
1195 | } | ||
1196 | |||
1197 | GBool RunLengthStream::fillBuf() { | ||
1198 | int c; | ||
1199 | int n, i; | ||
1200 | |||
1201 | if (eof) | ||
1202 | return gFalse; | ||
1203 | c = str->getChar(); | ||
1204 | if (c == 0x80 || c == EOF) { | ||
1205 | eof = gTrue; | ||
1206 | return gFalse; | ||
1207 | } | ||
1208 | if (c < 0x80) { | ||
1209 | n = c + 1; | ||
1210 | for (i = 0; i < n; ++i) | ||
1211 | buf[i] = (char)str->getChar(); | ||
1212 | } else { | ||
1213 | n = 0x101 - c; | ||
1214 | c = str->getChar(); | ||
1215 | for (i = 0; i < n; ++i) | ||
1216 | buf[i] = (char)c; | ||
1217 | } | ||
1218 | bufPtr = buf; | ||
1219 | bufEnd = buf + n; | ||
1220 | return gTrue; | ||
1221 | } | ||
1222 | |||
1223 | //------------------------------------------------------------------------ | ||
1224 | // CCITTFaxStream | ||
1225 | //------------------------------------------------------------------------ | ||
1226 | |||
1227 | CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, | ||
1228 | GBool byteAlignA, int columnsA, int rowsA, | ||
1229 | GBool endOfBlockA, GBool blackA): | ||
1230 | FilterStream(strA) { | ||
1231 | encoding = encodingA; | ||
1232 | endOfLine = endOfLineA; | ||
1233 | byteAlign = byteAlignA; | ||
1234 | columns = columnsA; | ||
1235 | rows = rowsA; | ||
1236 | endOfBlock = endOfBlockA; | ||
1237 | black = blackA; | ||
1238 | refLine = (short *)gmalloc((columns + 3) * sizeof(short)); | ||
1239 | codingLine = (short *)gmalloc((columns + 2) * sizeof(short)); | ||
1240 | |||
1241 | eof = gFalse; | ||
1242 | row = 0; | ||
1243 | nextLine2D = encoding < 0; | ||
1244 | inputBits = 0; | ||
1245 | codingLine[0] = 0; | ||
1246 | codingLine[1] = refLine[2] = columns; | ||
1247 | a0 = 1; | ||
1248 | |||
1249 | buf = EOF; | ||
1250 | } | ||
1251 | |||
1252 | CCITTFaxStream::~CCITTFaxStream() { | ||
1253 | delete str; | ||
1254 | gfree(refLine); | ||
1255 | gfree(codingLine); | ||
1256 | } | ||
1257 | |||
1258 | void CCITTFaxStream::reset() { | ||
1259 | int n; | ||
1260 | |||
1261 | str->reset(); | ||
1262 | eof = gFalse; | ||
1263 | row = 0; | ||
1264 | nextLine2D = encoding < 0; | ||
1265 | inputBits = 0; | ||
1266 | codingLine[0] = 0; | ||
1267 | codingLine[1] = refLine[2] = columns; | ||
1268 | a0 = 1; | ||
1269 | buf = EOF; | ||
1270 | |||
1271 | // get initial end-of-line marker and 2D encoding tag | ||
1272 | if (endOfBlock) { | ||
1273 | if (lookBits(12) == 0x001) { | ||
1274 | eatBits(12); | ||
1275 | } | ||
1276 | } else { | ||
1277 | for (n = 0; n < 11 && lookBits(n) == 0; ++n) ; | ||
1278 | if (n == 11 && lookBits(12) == 0x001) { | ||
1279 | eatBits(12); | ||
1280 | } | ||
1281 | } | ||
1282 | if (encoding > 0) { | ||
1283 | nextLine2D = !lookBits(1); | ||
1284 | eatBits(1); | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | int CCITTFaxStream::lookChar() { | ||
1289 | short code1, code2, code3; | ||
1290 | int a0New; | ||
1291 | #if 0 | ||
1292 | GBool err; | ||
1293 | #endif | ||
1294 | GBool gotEOL; | ||
1295 | int ret; | ||
1296 | int bits, i; | ||
1297 | |||
1298 | // if at eof just return EOF | ||
1299 | if (eof && codingLine[a0] >= columns) { | ||
1300 | return EOF; | ||
1301 | } | ||
1302 | |||
1303 | // read the next row | ||
1304 | #if 0 | ||
1305 | err = gFalse; | ||
1306 | #endif | ||
1307 | if (codingLine[a0] >= columns) { | ||
1308 | |||
1309 | // 2-D encoding | ||
1310 | if (nextLine2D) { | ||
1311 | for (i = 0; codingLine[i] < columns; ++i) | ||
1312 | refLine[i] = codingLine[i]; | ||
1313 | refLine[i] = refLine[i + 1] = columns; | ||
1314 | b1 = 1; | ||
1315 | a0New = codingLine[a0 = 0] = 0; | ||
1316 | do { | ||
1317 | code1 = getTwoDimCode(); | ||
1318 | switch (code1) { | ||
1319 | case twoDimPass: | ||
1320 | if (refLine[b1] < columns) { | ||
1321 | a0New = refLine[b1 + 1]; | ||
1322 | b1 += 2; | ||
1323 | } | ||
1324 | break; | ||
1325 | case twoDimHoriz: | ||
1326 | if ((a0 & 1) == 0) { | ||
1327 | code1 = code2 = 0; | ||
1328 | do { | ||
1329 | code1 += code3 = getWhiteCode(); | ||
1330 | } while (code3 >= 64); | ||
1331 | do { | ||
1332 | code2 += code3 = getBlackCode(); | ||
1333 | } while (code3 >= 64); | ||
1334 | } else { | ||
1335 | code1 = code2 = 0; | ||
1336 | do { | ||
1337 | code1 += code3 = getBlackCode(); | ||
1338 | } while (code3 >= 64); | ||
1339 | do { | ||
1340 | code2 += code3 = getWhiteCode(); | ||
1341 | } while (code3 >= 64); | ||
1342 | } | ||
1343 | codingLine[a0 + 1] = a0New + code1; | ||
1344 | ++a0; | ||
1345 | a0New = codingLine[a0 + 1] = codingLine[a0] + code2; | ||
1346 | ++a0; | ||
1347 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1348 | b1 += 2; | ||
1349 | break; | ||
1350 | case twoDimVert0: | ||
1351 | a0New = codingLine[++a0] = refLine[b1]; | ||
1352 | if (refLine[b1] < columns) { | ||
1353 | ++b1; | ||
1354 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1355 | b1 += 2; | ||
1356 | } | ||
1357 | break; | ||
1358 | case twoDimVertR1: | ||
1359 | a0New = codingLine[++a0] = refLine[b1] + 1; | ||
1360 | if (refLine[b1] < columns) { | ||
1361 | ++b1; | ||
1362 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1363 | b1 += 2; | ||
1364 | } | ||
1365 | break; | ||
1366 | case twoDimVertL1: | ||
1367 | a0New = codingLine[++a0] = refLine[b1] - 1; | ||
1368 | --b1; | ||
1369 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1370 | b1 += 2; | ||
1371 | break; | ||
1372 | case twoDimVertR2: | ||
1373 | a0New = codingLine[++a0] = refLine[b1] + 2; | ||
1374 | if (refLine[b1] < columns) { | ||
1375 | ++b1; | ||
1376 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1377 | b1 += 2; | ||
1378 | } | ||
1379 | break; | ||
1380 | case twoDimVertL2: | ||
1381 | a0New = codingLine[++a0] = refLine[b1] - 2; | ||
1382 | --b1; | ||
1383 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1384 | b1 += 2; | ||
1385 | break; | ||
1386 | case twoDimVertR3: | ||
1387 | a0New = codingLine[++a0] = refLine[b1] + 3; | ||
1388 | if (refLine[b1] < columns) { | ||
1389 | ++b1; | ||
1390 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1391 | b1 += 2; | ||
1392 | } | ||
1393 | break; | ||
1394 | case twoDimVertL3: | ||
1395 | a0New = codingLine[++a0] = refLine[b1] - 3; | ||
1396 | --b1; | ||
1397 | while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) | ||
1398 | b1 += 2; | ||
1399 | break; | ||
1400 | case EOF: | ||
1401 | eof = gTrue; | ||
1402 | codingLine[a0 = 0] = columns; | ||
1403 | return EOF; | ||
1404 | default: | ||
1405 | error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); | ||
1406 | #if 0 | ||
1407 | err = gTrue; | ||
1408 | break; | ||
1409 | #else | ||
1410 | eof = gTrue; | ||
1411 | return EOF; | ||
1412 | #endif | ||
1413 | } | ||
1414 | } while (codingLine[a0] < columns); | ||
1415 | |||
1416 | // 1-D encoding | ||
1417 | } else { | ||
1418 | codingLine[a0 = 0] = 0; | ||
1419 | while (1) { | ||
1420 | code1 = 0; | ||
1421 | do { | ||
1422 | code1 += code3 = getWhiteCode(); | ||
1423 | } while (code3 >= 64); | ||
1424 | codingLine[a0+1] = codingLine[a0] + code1; | ||
1425 | ++a0; | ||
1426 | if (codingLine[a0] >= columns) | ||
1427 | break; | ||
1428 | code2 = 0; | ||
1429 | do { | ||
1430 | code2 += code3 = getBlackCode(); | ||
1431 | } while (code3 >= 64); | ||
1432 | codingLine[a0+1] = codingLine[a0] + code2; | ||
1433 | ++a0; | ||
1434 | if (codingLine[a0] >= columns) | ||
1435 | break; | ||
1436 | } | ||
1437 | } | ||
1438 | |||
1439 | if (codingLine[a0] != columns) { | ||
1440 | error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); | ||
1441 | #if 0 | ||
1442 | err = gTrue; | ||
1443 | #endif | ||
1444 | } | ||
1445 | |||
1446 | // byte-align the row | ||
1447 | if (byteAlign) { | ||
1448 | inputBits &= ~7; | ||
1449 | } | ||
1450 | |||
1451 | // check for end-of-line marker, skipping over any extra zero bits | ||
1452 | gotEOL = gFalse; | ||
1453 | if (!endOfBlock && row == rows - 1) { | ||
1454 | eof = gTrue; | ||
1455 | } else { | ||
1456 | code1 = lookBits(12); | ||
1457 | while (code1 == 0) { | ||
1458 | eatBits(1); | ||
1459 | code1 = lookBits(12); | ||
1460 | } | ||
1461 | if (code1 == 0x001) { | ||
1462 | eatBits(12); | ||
1463 | gotEOL = gTrue; | ||
1464 | } else if (code1 == EOF) { | ||
1465 | eof = gTrue; | ||
1466 | } | ||
1467 | } | ||
1468 | |||
1469 | // get 2D encoding tag | ||
1470 | if (!eof && encoding > 0) { | ||
1471 | nextLine2D = !lookBits(1); | ||
1472 | eatBits(1); | ||
1473 | } | ||
1474 | |||
1475 | // check for end-of-block marker | ||
1476 | if (endOfBlock && gotEOL) { | ||
1477 | code1 = lookBits(12); | ||
1478 | if (code1 == 0x001) { | ||
1479 | eatBits(12); | ||
1480 | if (encoding > 0) { | ||
1481 | lookBits(1); | ||
1482 | eatBits(1); | ||
1483 | } | ||
1484 | if (encoding >= 0) { | ||
1485 | for (i = 0; i < 4; ++i) { | ||
1486 | code1 = lookBits(12); | ||
1487 | if (code1 != 0x001) { | ||
1488 | error(getPos(), "Bad RTC code in CCITTFax stream"); | ||
1489 | } | ||
1490 | eatBits(12); | ||
1491 | if (encoding > 0) { | ||
1492 | lookBits(1); | ||
1493 | eatBits(1); | ||
1494 | } | ||
1495 | } | ||
1496 | } | ||
1497 | eof = gTrue; | ||
1498 | } | ||
1499 | } | ||
1500 | |||
1501 | #if 0 | ||
1502 | // This looks for an end-of-line marker after an error, however | ||
1503 | // some (most?) CCITT streams in PDF files don't use end-of-line | ||
1504 | // markers, and the just-plow-on technique works better in those | ||
1505 | // cases. | ||
1506 | else if (err) { | ||
1507 | do { | ||
1508 | if (code1 == EOF) { | ||
1509 | eof = gTrue; | ||
1510 | return EOF; | ||
1511 | } | ||
1512 | eatBits(1); | ||
1513 | code1 = look13Bits(); | ||
1514 | } while ((code1 >> 1) != 0x001); | ||
1515 | eatBits(12); | ||
1516 | codingLine[++a0] = columns; | ||
1517 | if (encoding > 0) { | ||
1518 | eatBits(1); | ||
1519 | nextLine2D = !(code1 & 1); | ||
1520 | } | ||
1521 | } | ||
1522 | #endif | ||
1523 | |||
1524 | a0 = 0; | ||
1525 | outputBits = codingLine[1] - codingLine[0]; | ||
1526 | if (outputBits == 0) { | ||
1527 | a0 = 1; | ||
1528 | outputBits = codingLine[2] - codingLine[1]; | ||
1529 | } | ||
1530 | |||
1531 | ++row; | ||
1532 | } | ||
1533 | |||
1534 | // get a byte | ||
1535 | if (outputBits >= 8) { | ||
1536 | ret = ((a0 & 1) == 0) ? 0xff : 0x00; | ||
1537 | if ((outputBits -= 8) == 0) { | ||
1538 | ++a0; | ||
1539 | if (codingLine[a0] < columns) { | ||
1540 | outputBits = codingLine[a0 + 1] - codingLine[a0]; | ||
1541 | } | ||
1542 | } | ||
1543 | } else { | ||
1544 | bits = 8; | ||
1545 | ret = 0; | ||
1546 | do { | ||
1547 | if (outputBits > bits) { | ||
1548 | i = bits; | ||
1549 | bits = 0; | ||
1550 | if ((a0 & 1) == 0) { | ||
1551 | ret |= 0xff >> (8 - i); | ||
1552 | } | ||
1553 | outputBits -= i; | ||
1554 | } else { | ||
1555 | i = outputBits; | ||
1556 | bits -= outputBits; | ||
1557 | if ((a0 & 1) == 0) { | ||
1558 | ret |= (0xff >> (8 - i)) << bits; | ||
1559 | } | ||
1560 | outputBits = 0; | ||
1561 | ++a0; | ||
1562 | if (codingLine[a0] < columns) { | ||
1563 | outputBits = codingLine[a0 + 1] - codingLine[a0]; | ||
1564 | } | ||
1565 | } | ||
1566 | } while (bits > 0 && codingLine[a0] < columns); | ||
1567 | } | ||
1568 | buf = black ? (ret ^ 0xff) : ret; | ||
1569 | return buf; | ||
1570 | } | ||
1571 | |||
1572 | short CCITTFaxStream::getTwoDimCode() { | ||
1573 | short code; | ||
1574 | CCITTCode *p; | ||
1575 | int n; | ||
1576 | |||
1577 | code = 0; // make gcc happy | ||
1578 | if (endOfBlock) { | ||
1579 | code = lookBits(7); | ||
1580 | p = &twoDimTab1[code]; | ||
1581 | if (p->bits > 0) { | ||
1582 | eatBits(p->bits); | ||
1583 | return p->n; | ||
1584 | } | ||
1585 | } else { | ||
1586 | for (n = 1; n <= 7; ++n) { | ||
1587 | code = lookBits(n); | ||
1588 | if (n < 7) { | ||
1589 | code <<= 7 - n; | ||
1590 | } | ||
1591 | p = &twoDimTab1[code]; | ||
1592 | if (p->bits == n) { | ||
1593 | eatBits(n); | ||
1594 | return p->n; | ||
1595 | } | ||
1596 | } | ||
1597 | } | ||
1598 | error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code); | ||
1599 | return EOF; | ||
1600 | } | ||
1601 | |||
1602 | short CCITTFaxStream::getWhiteCode() { | ||
1603 | short code; | ||
1604 | CCITTCode *p; | ||
1605 | int n; | ||
1606 | |||
1607 | code = 0; // make gcc happy | ||
1608 | if (endOfBlock) { | ||
1609 | code = lookBits(12); | ||
1610 | if ((code >> 5) == 0) { | ||
1611 | p = &whiteTab1[code]; | ||
1612 | } else { | ||
1613 | p = &whiteTab2[code >> 3]; | ||
1614 | } | ||
1615 | if (p->bits > 0) { | ||
1616 | eatBits(p->bits); | ||
1617 | return p->n; | ||
1618 | } | ||
1619 | } else { | ||
1620 | for (n = 1; n <= 9; ++n) { | ||
1621 | code = lookBits(n); | ||
1622 | if (n < 9) { | ||
1623 | code <<= 9 - n; | ||
1624 | } | ||
1625 | p = &whiteTab2[code]; | ||
1626 | if (p->bits == n) { | ||
1627 | eatBits(n); | ||
1628 | return p->n; | ||
1629 | } | ||
1630 | } | ||
1631 | for (n = 11; n <= 12; ++n) { | ||
1632 | code = lookBits(n); | ||
1633 | if (n < 12) { | ||
1634 | code <<= 12 - n; | ||
1635 | } | ||
1636 | p = &whiteTab1[code]; | ||
1637 | if (p->bits == n) { | ||
1638 | eatBits(n); | ||
1639 | return p->n; | ||
1640 | } | ||
1641 | } | ||
1642 | } | ||
1643 | error(getPos(), "Bad white code (%04x) in CCITTFax stream", code); | ||
1644 | // eat a bit and return a positive number so that the caller doesn't | ||
1645 | // go into an infinite loop | ||
1646 | eatBits(1); | ||
1647 | return 1; | ||
1648 | } | ||
1649 | |||
1650 | short CCITTFaxStream::getBlackCode() { | ||
1651 | short code; | ||
1652 | CCITTCode *p; | ||
1653 | int n; | ||
1654 | |||
1655 | code = 0; // make gcc happy | ||
1656 | if (endOfBlock) { | ||
1657 | code = lookBits(13); | ||
1658 | if ((code >> 7) == 0) { | ||
1659 | p = &blackTab1[code]; | ||
1660 | } else if ((code >> 9) == 0) { | ||
1661 | p = &blackTab2[(code >> 1) - 64]; | ||
1662 | } else { | ||
1663 | p = &blackTab3[code >> 7]; | ||
1664 | } | ||
1665 | if (p->bits > 0) { | ||
1666 | eatBits(p->bits); | ||
1667 | return p->n; | ||
1668 | } | ||
1669 | } else { | ||
1670 | for (n = 2; n <= 6; ++n) { | ||
1671 | code = lookBits(n); | ||
1672 | if (n < 6) { | ||
1673 | code <<= 6 - n; | ||
1674 | } | ||
1675 | p = &blackTab3[code]; | ||
1676 | if (p->bits == n) { | ||
1677 | eatBits(n); | ||
1678 | return p->n; | ||
1679 | } | ||
1680 | } | ||
1681 | for (n = 7; n <= 12; ++n) { | ||
1682 | code = lookBits(n); | ||
1683 | if (n < 12) { | ||
1684 | code <<= 12 - n; | ||
1685 | } | ||
1686 | if (code >= 64) { | ||
1687 | p = &blackTab2[code - 64]; | ||
1688 | if (p->bits == n) { | ||
1689 | eatBits(n); | ||
1690 | return p->n; | ||
1691 | } | ||
1692 | } | ||
1693 | } | ||
1694 | for (n = 10; n <= 13; ++n) { | ||
1695 | code = lookBits(n); | ||
1696 | if (n < 13) { | ||
1697 | code <<= 13 - n; | ||
1698 | } | ||
1699 | p = &blackTab1[code]; | ||
1700 | if (p->bits == n) { | ||
1701 | eatBits(n); | ||
1702 | return p->n; | ||
1703 | } | ||
1704 | } | ||
1705 | } | ||
1706 | error(getPos(), "Bad black code (%04x) in CCITTFax stream", code); | ||
1707 | // eat a bit and return a positive number so that the caller doesn't | ||
1708 | // go into an infinite loop | ||
1709 | eatBits(1); | ||
1710 | return 1; | ||
1711 | } | ||
1712 | |||
1713 | short CCITTFaxStream::lookBits(int n) { | ||
1714 | int c; | ||
1715 | |||
1716 | while (inputBits < n) { | ||
1717 | if ((c = str->getChar()) == EOF) { | ||
1718 | if (inputBits == 0) { | ||
1719 | return EOF; | ||
1720 | } | ||
1721 | // near the end of the stream, the caller may ask for more bits | ||
1722 | // than are available, but there may still be a valid code in | ||
1723 | // however many bits are available -- we need to return correct | ||
1724 | // data in this case | ||
1725 | return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n)); | ||
1726 | } | ||
1727 | inputBuf = (inputBuf << 8) + c; | ||
1728 | inputBits += 8; | ||
1729 | } | ||
1730 | return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); | ||
1731 | } | ||
1732 | |||
1733 | GString *CCITTFaxStream::getPSFilter(char *indent) { | ||
1734 | GString *s; | ||
1735 | char s1[50]; | ||
1736 | |||
1737 | if (!(s = str->getPSFilter(indent))) { | ||
1738 | return NULL; | ||
1739 | } | ||
1740 | s->append(indent)->append("<< "); | ||
1741 | if (encoding != 0) { | ||
1742 | sprintf(s1, "/K %d ", encoding); | ||
1743 | s->append(s1); | ||
1744 | } | ||
1745 | if (endOfLine) { | ||
1746 | s->append("/EndOfLine true "); | ||
1747 | } | ||
1748 | if (byteAlign) { | ||
1749 | s->append("/EncodedByteAlign true "); | ||
1750 | } | ||
1751 | sprintf(s1, "/Columns %d ", columns); | ||
1752 | s->append(s1); | ||
1753 | if (rows != 0) { | ||
1754 | sprintf(s1, "/Rows %d ", rows); | ||
1755 | s->append(s1); | ||
1756 | } | ||
1757 | if (!endOfBlock) { | ||
1758 | s->append("/EndOfBlock false "); | ||
1759 | } | ||
1760 | if (black) { | ||
1761 | s->append("/BlackIs1 true "); | ||
1762 | } | ||
1763 | s->append(">> /CCITTFaxDecode filter\n"); | ||
1764 | return s; | ||
1765 | } | ||
1766 | |||
1767 | GBool CCITTFaxStream::isBinary(GBool last) { | ||
1768 | return str->isBinary(gTrue); | ||
1769 | } | ||
1770 | |||
1771 | //------------------------------------------------------------------------ | ||
1772 | // DCTStream | ||
1773 | //------------------------------------------------------------------------ | ||
1774 | |||
1775 | // IDCT constants (20.12 fixed point format) | ||
1776 | #ifndef FP_IDCT | ||
1777 | #define dctCos1 4017 // cos(pi/16) | ||
1778 | #define dctSin1 799 // sin(pi/16) | ||
1779 | #define dctCos3 3406 // cos(3*pi/16) | ||
1780 | #define dctSin3 2276 // sin(3*pi/16) | ||
1781 | #define dctCos6 1567 // cos(6*pi/16) | ||
1782 | #define dctSin6 3784 // sin(6*pi/16) | ||
1783 | #define dctSqrt2 5793 // sqrt(2) | ||
1784 | #define dctSqrt1d2 2896 // sqrt(2) / 2 | ||
1785 | #endif | ||
1786 | |||
1787 | // IDCT constants | ||
1788 | #ifdef FP_IDCT | ||
1789 | #define dctCos1 0.98078528// cos(pi/16) | ||
1790 | #define dctSin1 0.19509032// sin(pi/16) | ||
1791 | #define dctCos3 0.83146961// cos(3*pi/16) | ||
1792 | #define dctSin3 0.55557023// sin(3*pi/16) | ||
1793 | #define dctCos6 0.38268343// cos(6*pi/16) | ||
1794 | #define dctSin6 0.92387953// sin(6*pi/16) | ||
1795 | #define dctSqrt2 1.41421356// sqrt(2) | ||
1796 | #define dctSqrt1d2 0.70710678// sqrt(2) / 2 | ||
1797 | #endif | ||
1798 | |||
1799 | // color conversion parameters (16.16 fixed point format) | ||
1800 | #define dctCrToR 91881// 1.4020 | ||
1801 | #define dctCbToG -22553// -0.3441363 | ||
1802 | #define dctCrToG -46802// -0.71413636 | ||
1803 | #define dctCbToB 116130// 1.772 | ||
1804 | |||
1805 | // clip [-256,511] --> [0,255] | ||
1806 | #define dctClipOffset 256 | ||
1807 | static Guchar dctClip[768]; | ||
1808 | static int dctClipInit = 0; | ||
1809 | |||
1810 | // zig zag decode map | ||
1811 | static int dctZigZag[64] = { | ||
1812 | 0, | ||
1813 | 1, 8, | ||
1814 | 16, 9, 2, | ||
1815 | 3, 10, 17, 24, | ||
1816 | 32, 25, 18, 11, 4, | ||
1817 | 5, 12, 19, 26, 33, 40, | ||
1818 | 48, 41, 34, 27, 20, 13, 6, | ||
1819 | 7, 14, 21, 28, 35, 42, 49, 56, | ||
1820 | 57, 50, 43, 36, 29, 22, 15, | ||
1821 | 23, 30, 37, 44, 51, 58, | ||
1822 | 59, 52, 45, 38, 31, | ||
1823 | 39, 46, 53, 60, | ||
1824 | 61, 54, 47, | ||
1825 | 55, 62, | ||
1826 | 63 | ||
1827 | }; | ||
1828 | |||
1829 | DCTStream::DCTStream(Stream *strA): | ||
1830 | FilterStream(strA) { | ||
1831 | int i, j; | ||
1832 | |||
1833 | width = height = 0; | ||
1834 | mcuWidth = mcuHeight = 0; | ||
1835 | numComps = 0; | ||
1836 | comp = 0; | ||
1837 | x = y = dy = 0; | ||
1838 | for (i = 0; i < 4; ++i) | ||
1839 | for (j = 0; j < 32; ++j) | ||
1840 | rowBuf[i][j] = NULL; | ||
1841 | |||
1842 | if (!dctClipInit) { | ||
1843 | for (i = -256; i < 0; ++i) | ||
1844 | dctClip[dctClipOffset + i] = 0; | ||
1845 | for (i = 0; i < 256; ++i) | ||
1846 | dctClip[dctClipOffset + i] = i; | ||
1847 | for (i = 256; i < 512; ++i) | ||
1848 | dctClip[dctClipOffset + i] = 255; | ||
1849 | dctClipInit = 1; | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | DCTStream::~DCTStream() { | ||
1854 | int i, j; | ||
1855 | |||
1856 | delete str; | ||
1857 | for (i = 0; i < numComps; ++i) | ||
1858 | for (j = 0; j < mcuHeight; ++j) | ||
1859 | gfree(rowBuf[i][j]); | ||
1860 | } | ||
1861 | |||
1862 | void DCTStream::reset() { | ||
1863 | str->reset(); | ||
1864 | if (!readHeader()) { | ||
1865 | y = height; | ||
1866 | return; | ||
1867 | } | ||
1868 | restartMarker = 0xd0; | ||
1869 | restart(); | ||
1870 | } | ||
1871 | |||
1872 | int DCTStream::getChar() { | ||
1873 | int c; | ||
1874 | |||
1875 | c = lookChar(); | ||
1876 | if (c == EOF) | ||
1877 | return EOF; | ||
1878 | if (++comp == numComps) { | ||
1879 | comp = 0; | ||
1880 | if (++x == width) { | ||
1881 | x = 0; | ||
1882 | ++y; | ||
1883 | ++dy; | ||
1884 | } | ||
1885 | } | ||
1886 | if (y == height) | ||
1887 | readTrailer(); | ||
1888 | return c; | ||
1889 | } | ||
1890 | |||
1891 | int DCTStream::lookChar() { | ||
1892 | if (y >= height) | ||
1893 | return EOF; | ||
1894 | if (dy >= mcuHeight) { | ||
1895 | if (!readMCURow()) { | ||
1896 | y = height; | ||
1897 | return EOF; | ||
1898 | } | ||
1899 | comp = 0; | ||
1900 | x = 0; | ||
1901 | dy = 0; | ||
1902 | } | ||
1903 | return rowBuf[comp][dy][x]; | ||
1904 | } | ||
1905 | |||
1906 | void DCTStream::restart() { | ||
1907 | int i; | ||
1908 | |||
1909 | inputBits = 0; | ||
1910 | restartCtr = restartInterval; | ||
1911 | for (i = 0; i < numComps; ++i) | ||
1912 | compInfo[i].prevDC = 0; | ||
1913 | } | ||
1914 | |||
1915 | GBool DCTStream::readMCURow() { | ||
1916 | Guchar data[64]; | ||
1917 | Guchar *p1, *p2; | ||
1918 | int pY, pCb, pCr, pR, pG, pB; | ||
1919 | int h, v, horiz, vert, hSub, vSub; | ||
1920 | int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; | ||
1921 | int c; | ||
1922 | |||
1923 | for (x1 = 0; x1 < width; x1 += mcuWidth) { | ||
1924 | |||
1925 | // deal with restart marker | ||
1926 | if (restartInterval > 0 && restartCtr == 0) { | ||
1927 | c = readMarker(); | ||
1928 | if (c != restartMarker) { | ||
1929 | error(getPos(), "Bad DCT data: incorrect restart marker"); | ||
1930 | return gFalse; | ||
1931 | } | ||
1932 | if (++restartMarker == 0xd8) | ||
1933 | restartMarker = 0xd0; | ||
1934 | restart(); | ||
1935 | } | ||
1936 | |||
1937 | // read one MCU | ||
1938 | for (cc = 0; cc < numComps; ++cc) { | ||
1939 | h = compInfo[cc].hSample; | ||
1940 | v = compInfo[cc].vSample; | ||
1941 | horiz = mcuWidth / h; | ||
1942 | vert = mcuHeight / v; | ||
1943 | hSub = horiz / 8; | ||
1944 | vSub = vert / 8; | ||
1945 | for (y2 = 0; y2 < mcuHeight; y2 += vert) { | ||
1946 | for (x2 = 0; x2 < mcuWidth; x2 += horiz) { | ||
1947 | if (!readDataUnit(&dcHuffTables[compInfo[cc].dcHuffTable], | ||
1948 | &acHuffTables[compInfo[cc].acHuffTable], | ||
1949 | quantTables[compInfo[cc].quantTable], | ||
1950 | &compInfo[cc].prevDC, | ||
1951 | data)) | ||
1952 | return gFalse; | ||
1953 | if (hSub == 1 && vSub == 1) { | ||
1954 | for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { | ||
1955 | p1 = &rowBuf[cc][y2+y3][x1+x2]; | ||
1956 | p1[0] = data[i]; | ||
1957 | p1[1] = data[i+1]; | ||
1958 | p1[2] = data[i+2]; | ||
1959 | p1[3] = data[i+3]; | ||
1960 | p1[4] = data[i+4]; | ||
1961 | p1[5] = data[i+5]; | ||
1962 | p1[6] = data[i+6]; | ||
1963 | p1[7] = data[i+7]; | ||
1964 | } | ||
1965 | } else if (hSub == 2 && vSub == 2) { | ||
1966 | for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { | ||
1967 | p1 = &rowBuf[cc][y2+y3][x1+x2]; | ||
1968 | p2 = &rowBuf[cc][y2+y3+1][x1+x2]; | ||
1969 | p1[0] = p1[1] = p2[0] = p2[1] = data[i]; | ||
1970 | p1[2] = p1[3] = p2[2] = p2[3] = data[i+1]; | ||
1971 | p1[4] = p1[5] = p2[4] = p2[5] = data[i+2]; | ||
1972 | p1[6] = p1[7] = p2[6] = p2[7] = data[i+3]; | ||
1973 | p1[8] = p1[9] = p2[8] = p2[9] = data[i+4]; | ||
1974 | p1[10] = p1[11] = p2[10] = p2[11] = data[i+5]; | ||
1975 | p1[12] = p1[13] = p2[12] = p2[13] = data[i+6]; | ||
1976 | p1[14] = p1[15] = p2[14] = p2[15] = data[i+7]; | ||
1977 | } | ||
1978 | } else { | ||
1979 | i = 0; | ||
1980 | for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { | ||
1981 | for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { | ||
1982 | for (y5 = 0; y5 < vSub; ++y5) | ||
1983 | for (x5 = 0; x5 < hSub; ++x5) | ||
1984 | rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data[i]; | ||
1985 | ++i; | ||
1986 | } | ||
1987 | } | ||
1988 | } | ||
1989 | } | ||
1990 | } | ||
1991 | } | ||
1992 | --restartCtr; | ||
1993 | |||
1994 | // color space conversion | ||
1995 | if (colorXform) { | ||
1996 | // convert YCbCr to RGB | ||
1997 | if (numComps == 3) { | ||
1998 | for (y2 = 0; y2 < mcuHeight; ++y2) { | ||
1999 | for (x2 = 0; x2 < mcuWidth; ++x2) { | ||
2000 | pY = rowBuf[0][y2][x1+x2]; | ||
2001 | pCb = rowBuf[1][y2][x1+x2] - 128; | ||
2002 | pCr = rowBuf[2][y2][x1+x2] - 128; | ||
2003 | pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; | ||
2004 | rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR]; | ||
2005 | pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; | ||
2006 | rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG]; | ||
2007 | pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; | ||
2008 | rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB]; | ||
2009 | } | ||
2010 | } | ||
2011 | // convert YCbCrK to CMYK (K is passed through unchanged) | ||
2012 | } else if (numComps == 4) { | ||
2013 | for (y2 = 0; y2 < mcuHeight; ++y2) { | ||
2014 | for (x2 = 0; x2 < mcuWidth; ++x2) { | ||
2015 | pY = rowBuf[0][y2][x1+x2]; | ||
2016 | pCb = rowBuf[1][y2][x1+x2] - 128; | ||
2017 | pCr = rowBuf[2][y2][x1+x2] - 128; | ||
2018 | pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; | ||
2019 | rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR]; | ||
2020 | pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; | ||
2021 | rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG]; | ||
2022 | pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; | ||
2023 | rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB]; | ||
2024 | } | ||
2025 | } | ||
2026 | } | ||
2027 | } | ||
2028 | } | ||
2029 | return gTrue; | ||
2030 | } | ||
2031 | |||
2032 | // This IDCT algorithm is taken from: | ||
2033 | // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, | ||
2034 | // "Practical Fast 1-D DCT Algorithms with 11 Multiplications", | ||
2035 | // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, | ||
2036 | // 988-991. | ||
2037 | // The stage numbers mentioned in the comments refer to Figure 1 in this | ||
2038 | // paper. | ||
2039 | #ifndef FP_IDCT | ||
2040 | GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, | ||
2041 | DCTHuffTable *acHuffTable, | ||
2042 | Guchar quantTable[64], int *prevDC, | ||
2043 | Guchar data[64]) { | ||
2044 | int tmp1[64]; | ||
2045 | int v0, v1, v2, v3, v4, v5, v6, v7, t; | ||
2046 | int run, size, amp; | ||
2047 | int c; | ||
2048 | int i, j; | ||
2049 | |||
2050 | // Huffman decode and dequantize | ||
2051 | size = readHuffSym(dcHuffTable); | ||
2052 | if (size == 9999) | ||
2053 | return gFalse; | ||
2054 | if (size > 0) { | ||
2055 | amp = readAmp(size); | ||
2056 | if (amp == 9999) | ||
2057 | return gFalse; | ||
2058 | } else { | ||
2059 | amp = 0; | ||
2060 | } | ||
2061 | tmp1[0] = (*prevDC += amp) * quantTable[0]; | ||
2062 | for (i = 1; i < 64; ++i) | ||
2063 | tmp1[i] = 0; | ||
2064 | i = 1; | ||
2065 | while (i < 64) { | ||
2066 | run = 0; | ||
2067 | while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) | ||
2068 | run += 0x10; | ||
2069 | if (c == 9999) | ||
2070 | return gFalse; | ||
2071 | if (c == 0x00) { | ||
2072 | break; | ||
2073 | } else { | ||
2074 | run += (c >> 4) & 0x0f; | ||
2075 | size = c & 0x0f; | ||
2076 | amp = readAmp(size); | ||
2077 | if (amp == 9999) | ||
2078 | return gFalse; | ||
2079 | i += run; | ||
2080 | j = dctZigZag[i++]; | ||
2081 | tmp1[j] = amp * quantTable[j]; | ||
2082 | } | ||
2083 | } | ||
2084 | |||
2085 | // inverse DCT on rows | ||
2086 | for (i = 0; i < 64; i += 8) { | ||
2087 | |||
2088 | // stage 4 | ||
2089 | v0 = (dctSqrt2 * tmp1[i+0] + 128) >> 8; | ||
2090 | v1 = (dctSqrt2 * tmp1[i+4] + 128) >> 8; | ||
2091 | v2 = tmp1[i+2]; | ||
2092 | v3 = tmp1[i+6]; | ||
2093 | v4 = (dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]) + 128) >> 8; | ||
2094 | v7 = (dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]) + 128) >> 8; | ||
2095 | v5 = tmp1[i+3] << 4; | ||
2096 | v6 = tmp1[i+5] << 4; | ||
2097 | |||
2098 | // stage 3 | ||
2099 | t = (v0 - v1+ 1) >> 1; | ||
2100 | v0 = (v0 + v1 + 1) >> 1; | ||
2101 | v1 = t; | ||
2102 | t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; | ||
2103 | v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; | ||
2104 | v3 = t; | ||
2105 | t = (v4 - v6 + 1) >> 1; | ||
2106 | v4 = (v4 + v6 + 1) >> 1; | ||
2107 | v6 = t; | ||
2108 | t = (v7 + v5 + 1) >> 1; | ||
2109 | v5 = (v7 - v5 + 1) >> 1; | ||
2110 | v7 = t; | ||
2111 | |||
2112 | // stage 2 | ||
2113 | t = (v0 - v3 + 1) >> 1; | ||
2114 | v0 = (v0 + v3 + 1) >> 1; | ||
2115 | v3 = t; | ||
2116 | t = (v1 - v2 + 1) >> 1; | ||
2117 | v1 = (v1 + v2 + 1) >> 1; | ||
2118 | v2 = t; | ||
2119 | t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; | ||
2120 | v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; | ||
2121 | v7 = t; | ||
2122 | t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; | ||
2123 | v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; | ||
2124 | v6 = t; | ||
2125 | |||
2126 | // stage 1 | ||
2127 | tmp1[i+0] = v0 + v7; | ||
2128 | tmp1[i+7] = v0 - v7; | ||
2129 | tmp1[i+1] = v1 + v6; | ||
2130 | tmp1[i+6] = v1 - v6; | ||
2131 | tmp1[i+2] = v2 + v5; | ||
2132 | tmp1[i+5] = v2 - v5; | ||
2133 | tmp1[i+3] = v3 + v4; | ||
2134 | tmp1[i+4] = v3 - v4; | ||
2135 | } | ||
2136 | |||
2137 | // inverse DCT on columns | ||
2138 | for (i = 0; i < 8; ++i) { | ||
2139 | |||
2140 | // stage 4 | ||
2141 | v0 = (dctSqrt2 * tmp1[0*8+i] + 2048) >> 12; | ||
2142 | v1 = (dctSqrt2 * tmp1[4*8+i] + 2048) >> 12; | ||
2143 | v2 = tmp1[2*8+i]; | ||
2144 | v3 = tmp1[6*8+i]; | ||
2145 | v4 = (dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]) + 2048) >> 12; | ||
2146 | v7 = (dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]) + 2048) >> 12; | ||
2147 | v5 = tmp1[3*8+i]; | ||
2148 | v6 = tmp1[5*8+i]; | ||
2149 | |||
2150 | // stage 3 | ||
2151 | t = (v0 - v1 + 1) >> 1; | ||
2152 | v0 = (v0 + v1 + 1) >> 1; | ||
2153 | v1 = t; | ||
2154 | t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; | ||
2155 | v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; | ||
2156 | v3 = t; | ||
2157 | t = (v4 - v6 + 1) >> 1; | ||
2158 | v4 = (v4 + v6 + 1) >> 1; | ||
2159 | v6 = t; | ||
2160 | t = (v7 + v5 + 1) >> 1; | ||
2161 | v5 = (v7 - v5 + 1) >> 1; | ||
2162 | v7 = t; | ||
2163 | |||
2164 | // stage 2 | ||
2165 | t = (v0 - v3 + 1) >> 1; | ||
2166 | v0 = (v0 + v3 + 1) >> 1; | ||
2167 | v3 = t; | ||
2168 | t = (v1 - v2 + 1) >> 1; | ||
2169 | v1 = (v1 + v2 + 1) >> 1; | ||
2170 | v2 = t; | ||
2171 | t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; | ||
2172 | v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; | ||
2173 | v7 = t; | ||
2174 | t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; | ||
2175 | v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; | ||
2176 | v6 = t; | ||
2177 | |||
2178 | // stage 1 | ||
2179 | tmp1[0*8+i] = v0 + v7; | ||
2180 | tmp1[7*8+i] = v0 - v7; | ||
2181 | tmp1[1*8+i] = v1 + v6; | ||
2182 | tmp1[6*8+i] = v1 - v6; | ||
2183 | tmp1[2*8+i] = v2 + v5; | ||
2184 | tmp1[5*8+i] = v2 - v5; | ||
2185 | tmp1[3*8+i] = v3 + v4; | ||
2186 | tmp1[4*8+i] = v3 - v4; | ||
2187 | } | ||
2188 | |||
2189 | // convert to 8-bit integers | ||
2190 | for (i = 0; i < 64; ++i) | ||
2191 | data[i] = dctClip[dctClipOffset + 128 + ((tmp1[i] + 8) >> 4)]; | ||
2192 | |||
2193 | return gTrue; | ||
2194 | } | ||
2195 | #endif | ||
2196 | |||
2197 | #ifdef FP_IDCT | ||
2198 | GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, | ||
2199 | DCTHuffTable *acHuffTable, | ||
2200 | Guchar quantTable[64], int *prevDC, | ||
2201 | Guchar data[64]) { | ||
2202 | fouble tmp1[64]; | ||
2203 | fouble v0, v1, v2, v3, v4, v5, v6, v7, t; | ||
2204 | int run, size, amp; | ||
2205 | int c; | ||
2206 | int i, j; | ||
2207 | |||
2208 | // Huffman decode and dequantize | ||
2209 | size = readHuffSym(dcHuffTable); | ||
2210 | if (size == 9999) | ||
2211 | return gFalse; | ||
2212 | if (size > 0) { | ||
2213 | amp = readAmp(size); | ||
2214 | if (amp == 9999) | ||
2215 | return gFalse; | ||
2216 | } else { | ||
2217 | amp = 0; | ||
2218 | } | ||
2219 | tmp1[0] = (*prevDC += amp) * quantTable[0]; | ||
2220 | for (i = 1; i < 64; ++i) | ||
2221 | tmp1[i] = 0; | ||
2222 | i = 1; | ||
2223 | while (i < 64) { | ||
2224 | run = 0; | ||
2225 | while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) | ||
2226 | run += 0x10; | ||
2227 | if (c == 9999) | ||
2228 | return gFalse; | ||
2229 | if (c == 0x00) { | ||
2230 | break; | ||
2231 | } else { | ||
2232 | run += (c >> 4) & 0x0f; | ||
2233 | size = c & 0x0f; | ||
2234 | amp = readAmp(size); | ||
2235 | if (amp == 9999) | ||
2236 | return gFalse; | ||
2237 | i += run; | ||
2238 | j = dctZigZag[i++]; | ||
2239 | tmp1[j] = amp * quantTable[j]; | ||
2240 | } | ||
2241 | } | ||
2242 | |||
2243 | // inverse DCT on rows | ||
2244 | for (i = 0; i < 64; i += 8) { | ||
2245 | |||
2246 | // stage 4 | ||
2247 | v0 = dctSqrt2 * tmp1[i+0]; | ||
2248 | v1 = dctSqrt2 * tmp1[i+4]; | ||
2249 | v2 = tmp1[i+2]; | ||
2250 | v3 = tmp1[i+6]; | ||
2251 | v4 = dctSqrt1d2 * (tmp1[i+1] - tmp1[i+7]); | ||
2252 | v7 = dctSqrt1d2 * (tmp1[i+1] + tmp1[i+7]); | ||
2253 | v5 = tmp1[i+3]; | ||
2254 | v6 = tmp1[i+5]; | ||
2255 | |||
2256 | // stage 3 | ||
2257 | t = 0.5 * (v0 - v1); | ||
2258 | v0 = 0.5 * (v0 + v1); | ||
2259 | v1 = t; | ||
2260 | t = v2 * dctSin6 + v3 * dctCos6; | ||
2261 | v2 = v2 * dctCos6 - v3 * dctSin6; | ||
2262 | v3 = t; | ||
2263 | t = 0.5 * (v4 - v6); | ||
2264 | v4 = 0.5 * (v4 + v6); | ||
2265 | v6 = t; | ||
2266 | t = 0.5 * (v7 + v5); | ||
2267 | v5 = 0.5 * (v7 - v5); | ||
2268 | v7 = t; | ||
2269 | |||
2270 | // stage 2 | ||
2271 | t = 0.5 * (v0 - v3); | ||
2272 | v0 = 0.5 * (v0 + v3); | ||
2273 | v3 = t; | ||
2274 | t = 0.5 * (v1 - v2); | ||
2275 | v1 = 0.5 * (v1 + v2); | ||
2276 | v2 = t; | ||
2277 | t = v4 * dctSin3 + v7 * dctCos3; | ||
2278 | v4 = v4 * dctCos3 - v7 * dctSin3; | ||
2279 | v7 = t; | ||
2280 | t = v5 * dctSin1 + v6 * dctCos1; | ||
2281 | v5 = v5 * dctCos1 - v6 * dctSin1; | ||
2282 | v6 = t; | ||
2283 | |||
2284 | // stage 1 | ||
2285 | tmp1[i+0] = v0 + v7; | ||
2286 | tmp1[i+7] = v0 - v7; | ||
2287 | tmp1[i+1] = v1 + v6; | ||
2288 | tmp1[i+6] = v1 - v6; | ||
2289 | tmp1[i+2] = v2 + v5; | ||
2290 | tmp1[i+5] = v2 - v5; | ||
2291 | tmp1[i+3] = v3 + v4; | ||
2292 | tmp1[i+4] = v3 - v4; | ||
2293 | } | ||
2294 | |||
2295 | // inverse DCT on columns | ||
2296 | for (i = 0; i < 8; ++i) { | ||
2297 | |||
2298 | // stage 4 | ||
2299 | v0 = dctSqrt2 * tmp1[0*8+i]; | ||
2300 | v1 = dctSqrt2 * tmp1[4*8+i]; | ||
2301 | v2 = tmp1[2*8+i]; | ||
2302 | v3 = tmp1[6*8+i]; | ||
2303 | v4 = dctSqrt1d2 * (tmp1[1*8+i] - tmp1[7*8+i]); | ||
2304 | v7 = dctSqrt1d2 * (tmp1[1*8+i] + tmp1[7*8+i]); | ||
2305 | v5 = tmp1[3*8+i]; | ||
2306 | v6 = tmp1[5*8+i]; | ||
2307 | |||
2308 | // stage 3 | ||
2309 | t = 0.5 * (v0 - v1); | ||
2310 | v0 = 0.5 * (v0 + v1); | ||
2311 | v1 = t; | ||
2312 | t = v2 * dctSin6 + v3 * dctCos6; | ||
2313 | v2 = v2 * dctCos6 - v3 * dctSin6; | ||
2314 | v3 = t; | ||
2315 | t = 0.5 * (v4 - v6); | ||
2316 | v4 = 0.5 * (v4 + v6); | ||
2317 | v6 = t; | ||
2318 | t = 0.5 * (v7 + v5); | ||
2319 | v5 = 0.5 * (v7 - v5); | ||
2320 | v7 = t; | ||
2321 | |||
2322 | // stage 2 | ||
2323 | t = 0.5 * (v0 - v3); | ||
2324 | v0 = 0.5 * (v0 + v3); | ||
2325 | v3 = t; | ||
2326 | t = 0.5 * (v1 - v2); | ||
2327 | v1 = 0.5 * (v1 + v2); | ||
2328 | v2 = t; | ||
2329 | t = v4 * dctSin3 + v7 * dctCos3; | ||
2330 | v4 = v4 * dctCos3 - v7 * dctSin3; | ||
2331 | v7 = t; | ||
2332 | t = v5 * dctSin1 + v6 * dctCos1; | ||
2333 | v5 = v5 * dctCos1 - v6 * dctSin1; | ||
2334 | v6 = t; | ||
2335 | |||
2336 | // stage 1 | ||
2337 | tmp1[0*8+i] = v0 + v7; | ||
2338 | tmp1[7*8+i] = v0 - v7; | ||
2339 | tmp1[1*8+i] = v1 + v6; | ||
2340 | tmp1[6*8+i] = v1 - v6; | ||
2341 | tmp1[2*8+i] = v2 + v5; | ||
2342 | tmp1[5*8+i] = v2 - v5; | ||
2343 | tmp1[3*8+i] = v3 + v4; | ||
2344 | tmp1[4*8+i] = v3 - v4; | ||
2345 | } | ||
2346 | |||
2347 | // convert to 8-bit integers | ||
2348 | for (i = 0; i < 64; ++i) | ||
2349 | data[i] = dctClip[dctClipOffset + (int)(tmp1[i] + 128.5)]; | ||
2350 | |||
2351 | return gTrue; | ||
2352 | } | ||
2353 | #endif | ||
2354 | |||
2355 | int DCTStream::readHuffSym(DCTHuffTable *table) { | ||
2356 | Gushort code; | ||
2357 | int bit; | ||
2358 | int codeBits; | ||
2359 | |||
2360 | code = 0; | ||
2361 | codeBits = 0; | ||
2362 | do { | ||
2363 | // add a bit to the code | ||
2364 | if ((bit = readBit()) == EOF) | ||
2365 | return 9999; | ||
2366 | code = (code << 1) + bit; | ||
2367 | ++codeBits; | ||
2368 | |||
2369 | // look up code | ||
2370 | if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) { | ||
2371 | code -= table->firstCode[codeBits]; | ||
2372 | return table->sym[table->firstSym[codeBits] + code]; | ||
2373 | } | ||
2374 | } while (codeBits < 16); | ||
2375 | |||
2376 | error(getPos(), "Bad Huffman code in DCT stream"); | ||
2377 | return 9999; | ||
2378 | } | ||
2379 | |||
2380 | int DCTStream::readAmp(int size) { | ||
2381 | int amp, bit; | ||
2382 | int bits; | ||
2383 | |||
2384 | amp = 0; | ||
2385 | for (bits = 0; bits < size; ++bits) { | ||
2386 | if ((bit = readBit()) == EOF) | ||
2387 | return 9999; | ||
2388 | amp = (amp << 1) + bit; | ||
2389 | } | ||
2390 | if (amp < (1 << (size - 1))) | ||
2391 | amp -= (1 << size) - 1; | ||
2392 | return amp; | ||
2393 | } | ||
2394 | |||
2395 | int DCTStream::readBit() { | ||
2396 | int bit; | ||
2397 | int c, c2; | ||
2398 | |||
2399 | if (inputBits == 0) { | ||
2400 | if ((c = str->getChar()) == EOF) | ||
2401 | return EOF; | ||
2402 | if (c == 0xff) { | ||
2403 | do { | ||
2404 | c2 = str->getChar(); | ||
2405 | } while (c2 == 0xff); | ||
2406 | if (c2 != 0x00) { | ||
2407 | error(getPos(), "Bad DCT data: missing 00 after ff"); | ||
2408 | return EOF; | ||
2409 | } | ||
2410 | } | ||
2411 | inputBuf = c; | ||
2412 | inputBits = 8; | ||
2413 | } | ||
2414 | bit = (inputBuf >> (inputBits - 1)) & 1; | ||
2415 | --inputBits; | ||
2416 | return bit; | ||
2417 | } | ||
2418 | |||
2419 | GBool DCTStream::readHeader() { | ||
2420 | GBool doScan; | ||
2421 | int minHSample, minVSample; | ||
2422 | int bufWidth; | ||
2423 | int n; | ||
2424 | int c = 0; | ||
2425 | int i, j; | ||
2426 | |||
2427 | width = height = 0; | ||
2428 | numComps = 0; | ||
2429 | numQuantTables = 0; | ||
2430 | numDCHuffTables = 0; | ||
2431 | numACHuffTables = 0; | ||
2432 | colorXform = 0; | ||
2433 | gotAdobeMarker = gFalse; | ||
2434 | restartInterval = 0; | ||
2435 | |||
2436 | // read headers | ||
2437 | doScan = gFalse; | ||
2438 | while (!doScan) { | ||
2439 | c = readMarker(); | ||
2440 | switch (c) { | ||
2441 | case 0xc0: // SOF0 | ||
2442 | if (!readFrameInfo()) | ||
2443 | return gFalse; | ||
2444 | break; | ||
2445 | case 0xc4: // DHT | ||
2446 | if (!readHuffmanTables()) | ||
2447 | return gFalse; | ||
2448 | break; | ||
2449 | case 0xd8: // SOI | ||
2450 | break; | ||
2451 | case 0xda: // SOS | ||
2452 | if (!readScanInfo()) | ||
2453 | return gFalse; | ||
2454 | doScan = gTrue; | ||
2455 | break; | ||
2456 | case 0xdb: // DQT | ||
2457 | if (!readQuantTables()) | ||
2458 | return gFalse; | ||
2459 | break; | ||
2460 | case 0xdd: // DRI | ||
2461 | if (!readRestartInterval()) | ||
2462 | return gFalse; | ||
2463 | break; | ||
2464 | case 0xee: // APP14 | ||
2465 | if (!readAdobeMarker()) | ||
2466 | return gFalse; | ||
2467 | break; | ||
2468 | case EOF: | ||
2469 | error(getPos(), "Bad DCT header"); | ||
2470 | return gFalse; | ||
2471 | default: | ||
2472 | // skip APPn / COM / etc. | ||
2473 | if (c >= 0xe0) { | ||
2474 | n = read16() - 2; | ||
2475 | for (i = 0; i < n; ++i) | ||
2476 | str->getChar(); | ||
2477 | } else { | ||
2478 | error(getPos(), "Unknown DCT marker <%02x>", c); | ||
2479 | return gFalse; | ||
2480 | } | ||
2481 | break; | ||
2482 | } | ||
2483 | } | ||
2484 | |||
2485 | // compute MCU size | ||
2486 | mcuWidth = minHSample = compInfo[0].hSample; | ||
2487 | mcuHeight = minVSample = compInfo[0].vSample; | ||
2488 | for (i = 1; i < numComps; ++i) { | ||
2489 | if (compInfo[i].hSample < minHSample) | ||
2490 | minHSample = compInfo[i].hSample; | ||
2491 | if (compInfo[i].vSample < minVSample) | ||
2492 | minVSample = compInfo[i].vSample; | ||
2493 | if (compInfo[i].hSample > mcuWidth) | ||
2494 | mcuWidth = compInfo[i].hSample; | ||
2495 | if (compInfo[i].vSample > mcuHeight) | ||
2496 | mcuHeight = compInfo[i].vSample; | ||
2497 | } | ||
2498 | for (i = 0; i < numComps; ++i) { | ||
2499 | compInfo[i].hSample /= minHSample; | ||
2500 | compInfo[i].vSample /= minVSample; | ||
2501 | } | ||
2502 | mcuWidth = (mcuWidth / minHSample) * 8; | ||
2503 | mcuHeight = (mcuHeight / minVSample) * 8; | ||
2504 | |||
2505 | // allocate buffers | ||
2506 | bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; | ||
2507 | for (i = 0; i < numComps; ++i) | ||
2508 | for (j = 0; j < mcuHeight; ++j) | ||
2509 | rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); | ||
2510 | |||
2511 | // figure out color transform | ||
2512 | if (!gotAdobeMarker && numComps == 3) { | ||
2513 | if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) { | ||
2514 | colorXform = 1; | ||
2515 | } | ||
2516 | } | ||
2517 | |||
2518 | // initialize counters | ||
2519 | comp = 0; | ||
2520 | x = 0; | ||
2521 | y = 0; | ||
2522 | dy = mcuHeight; | ||
2523 | |||
2524 | return gTrue; | ||
2525 | } | ||
2526 | |||
2527 | GBool DCTStream::readFrameInfo() { | ||
2528 | int length; | ||
2529 | int prec; | ||
2530 | int i; | ||
2531 | int c; | ||
2532 | |||
2533 | length = read16() - 2; | ||
2534 | prec = str->getChar(); | ||
2535 | height = read16(); | ||
2536 | width = read16(); | ||
2537 | numComps = str->getChar(); | ||
2538 | length -= 6; | ||
2539 | if (prec != 8) { | ||
2540 | error(getPos(), "Bad DCT precision %d", prec); | ||
2541 | return gFalse; | ||
2542 | } | ||
2543 | for (i = 0; i < numComps; ++i) { | ||
2544 | compInfo[i].id = str->getChar(); | ||
2545 | compInfo[i].inScan = gFalse; | ||
2546 | c = str->getChar(); | ||
2547 | compInfo[i].hSample = (c >> 4) & 0x0f; | ||
2548 | compInfo[i].vSample = c & 0x0f; | ||
2549 | compInfo[i].quantTable = str->getChar(); | ||
2550 | compInfo[i].dcHuffTable = 0; | ||
2551 | compInfo[i].acHuffTable = 0; | ||
2552 | } | ||
2553 | return gTrue; | ||
2554 | } | ||
2555 | |||
2556 | GBool DCTStream::readScanInfo() { | ||
2557 | int length; | ||
2558 | int scanComps, id, c; | ||
2559 | int i, j; | ||
2560 | |||
2561 | length = read16() - 2; | ||
2562 | scanComps = str->getChar(); | ||
2563 | --length; | ||
2564 | if (length != 2 * scanComps + 3) { | ||
2565 | error(getPos(), "Bad DCT scan info block"); | ||
2566 | return gFalse; | ||
2567 | } | ||
2568 | for (i = 0; i < scanComps; ++i) { | ||
2569 | id = str->getChar(); | ||
2570 | for (j = 0; j < numComps; ++j) { | ||
2571 | if (id == compInfo[j].id) | ||
2572 | break; | ||
2573 | } | ||
2574 | if (j == numComps) { | ||
2575 | error(getPos(), "Bad DCT component ID in scan info block"); | ||
2576 | return gFalse; | ||
2577 | } | ||
2578 | compInfo[j].inScan = gTrue; | ||
2579 | c = str->getChar(); | ||
2580 | compInfo[j].dcHuffTable = (c >> 4) & 0x0f; | ||
2581 | compInfo[j].acHuffTable = c & 0x0f; | ||
2582 | } | ||
2583 | str->getChar(); | ||
2584 | str->getChar(); | ||
2585 | str->getChar(); | ||
2586 | return gTrue; | ||
2587 | } | ||
2588 | |||
2589 | GBool DCTStream::readQuantTables() { | ||
2590 | int length; | ||
2591 | int i; | ||
2592 | int index; | ||
2593 | |||
2594 | length = read16() - 2; | ||
2595 | while (length > 0) { | ||
2596 | index = str->getChar(); | ||
2597 | if ((index & 0xf0) || index >= 4) { | ||
2598 | error(getPos(), "Bad DCT quantization table"); | ||
2599 | return gFalse; | ||
2600 | } | ||
2601 | if (index == numQuantTables) | ||
2602 | numQuantTables = index + 1; | ||
2603 | for (i = 0; i < 64; ++i) | ||
2604 | quantTables[index][dctZigZag[i]] = str->getChar(); | ||
2605 | length -= 65; | ||
2606 | } | ||
2607 | return gTrue; | ||
2608 | } | ||
2609 | |||
2610 | GBool DCTStream::readHuffmanTables() { | ||
2611 | DCTHuffTable *tbl; | ||
2612 | int length; | ||
2613 | int index; | ||
2614 | Gushort code; | ||
2615 | Guchar sym; | ||
2616 | int i; | ||
2617 | int c; | ||
2618 | |||
2619 | length = read16() - 2; | ||
2620 | while (length > 0) { | ||
2621 | index = str->getChar(); | ||
2622 | --length; | ||
2623 | if ((index & 0x0f) >= 4) { | ||
2624 | error(getPos(), "Bad DCT Huffman table"); | ||
2625 | return gFalse; | ||
2626 | } | ||
2627 | if (index & 0x10) { | ||
2628 | index &= 0x0f; | ||
2629 | if (index >= numACHuffTables) | ||
2630 | numACHuffTables = index+1; | ||
2631 | tbl = &acHuffTables[index]; | ||
2632 | } else { | ||
2633 | if (index >= numDCHuffTables) | ||
2634 | numDCHuffTables = index+1; | ||
2635 | tbl = &dcHuffTables[index]; | ||
2636 | } | ||
2637 | sym = 0; | ||
2638 | code = 0; | ||
2639 | for (i = 1; i <= 16; ++i) { | ||
2640 | c = str->getChar(); | ||
2641 | tbl->firstSym[i] = sym; | ||
2642 | tbl->firstCode[i] = code; | ||
2643 | tbl->numCodes[i] = c; | ||
2644 | sym += c; | ||
2645 | code = (code + c) << 1; | ||
2646 | } | ||
2647 | length -= 16; | ||
2648 | for (i = 0; i < sym; ++i) | ||
2649 | tbl->sym[i] = str->getChar(); | ||
2650 | length -= sym; | ||
2651 | } | ||
2652 | return gTrue; | ||
2653 | } | ||
2654 | |||
2655 | GBool DCTStream::readRestartInterval() { | ||
2656 | int length; | ||
2657 | |||
2658 | length = read16(); | ||
2659 | if (length != 4) { | ||
2660 | error(getPos(), "Bad DCT restart interval"); | ||
2661 | return gFalse; | ||
2662 | } | ||
2663 | restartInterval = read16(); | ||
2664 | return gTrue; | ||
2665 | } | ||
2666 | |||
2667 | GBool DCTStream::readAdobeMarker() { | ||
2668 | int length, i; | ||
2669 | char buf[12]; | ||
2670 | int c; | ||
2671 | |||
2672 | length = read16(); | ||
2673 | if (length != 14) | ||
2674 | goto err; | ||
2675 | for (i = 0; i < 12; ++i) { | ||
2676 | if ((c = str->getChar()) == EOF) | ||
2677 | goto err; | ||
2678 | buf[i] = c; | ||
2679 | } | ||
2680 | if (strncmp(buf, "Adobe", 5)) | ||
2681 | goto err; | ||
2682 | colorXform = buf[11]; | ||
2683 | gotAdobeMarker = gTrue; | ||
2684 | return gTrue; | ||
2685 | |||
2686 | err: | ||
2687 | error(getPos(), "Bad DCT Adobe APP14 marker"); | ||
2688 | return gFalse; | ||
2689 | } | ||
2690 | |||
2691 | GBool DCTStream::readTrailer() { | ||
2692 | int c; | ||
2693 | |||
2694 | c = readMarker(); | ||
2695 | if (c != 0xd9) { // EOI | ||
2696 | error(getPos(), "Bad DCT trailer"); | ||
2697 | return gFalse; | ||
2698 | } | ||
2699 | return gTrue; | ||
2700 | } | ||
2701 | |||
2702 | int DCTStream::readMarker() { | ||
2703 | int c; | ||
2704 | |||
2705 | do { | ||
2706 | do { | ||
2707 | c = str->getChar(); | ||
2708 | } while (c != 0xff); | ||
2709 | do { | ||
2710 | c = str->getChar(); | ||
2711 | } while (c == 0xff); | ||
2712 | } while (c == 0x00); | ||
2713 | return c; | ||
2714 | } | ||
2715 | |||
2716 | int DCTStream::read16() { | ||
2717 | int c1, c2; | ||
2718 | |||
2719 | if ((c1 = str->getChar()) == EOF) | ||
2720 | return EOF; | ||
2721 | if ((c2 = str->getChar()) == EOF) | ||
2722 | return EOF; | ||
2723 | return (c1 << 8) + c2; | ||
2724 | } | ||
2725 | |||
2726 | GString *DCTStream::getPSFilter(char *indent) { | ||
2727 | GString *s; | ||
2728 | |||
2729 | if (!(s = str->getPSFilter(indent))) { | ||
2730 | return NULL; | ||
2731 | } | ||
2732 | s->append(indent)->append("<< >> /DCTDecode filter\n"); | ||
2733 | return s; | ||
2734 | } | ||
2735 | |||
2736 | GBool DCTStream::isBinary(GBool last) { | ||
2737 | return str->isBinary(gTrue); | ||
2738 | } | ||
2739 | |||
2740 | //------------------------------------------------------------------------ | ||
2741 | // FlateStream | ||
2742 | //------------------------------------------------------------------------ | ||
2743 | |||
2744 | int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = { | ||
2745 | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 | ||
2746 | }; | ||
2747 | |||
2748 | FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { | ||
2749 | {0, 3}, | ||
2750 | {0, 4}, | ||
2751 | {0, 5}, | ||
2752 | {0, 6}, | ||
2753 | {0, 7}, | ||
2754 | {0, 8}, | ||
2755 | {0, 9}, | ||
2756 | {0, 10}, | ||
2757 | {1, 11}, | ||
2758 | {1, 13}, | ||
2759 | {1, 15}, | ||
2760 | {1, 17}, | ||
2761 | {2, 19}, | ||
2762 | {2, 23}, | ||
2763 | {2, 27}, | ||
2764 | {2, 31}, | ||
2765 | {3, 35}, | ||
2766 | {3, 43}, | ||
2767 | {3, 51}, | ||
2768 | {3, 59}, | ||
2769 | {4, 67}, | ||
2770 | {4, 83}, | ||
2771 | {4, 99}, | ||
2772 | {4, 115}, | ||
2773 | {5, 131}, | ||
2774 | {5, 163}, | ||
2775 | {5, 195}, | ||
2776 | {5, 227}, | ||
2777 | {0, 258} | ||
2778 | }; | ||
2779 | |||
2780 | FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { | ||
2781 | { 0, 1}, | ||
2782 | { 0, 2}, | ||
2783 | { 0, 3}, | ||
2784 | { 0, 4}, | ||
2785 | { 1, 5}, | ||
2786 | { 1, 7}, | ||
2787 | { 2, 9}, | ||
2788 | { 2, 13}, | ||
2789 | { 3, 17}, | ||
2790 | { 3, 25}, | ||
2791 | { 4, 33}, | ||
2792 | { 4, 49}, | ||
2793 | { 5, 65}, | ||
2794 | { 5, 97}, | ||
2795 | { 6, 129}, | ||
2796 | { 6, 193}, | ||
2797 | { 7, 257}, | ||
2798 | { 7, 385}, | ||
2799 | { 8, 513}, | ||
2800 | { 8, 769}, | ||
2801 | { 9, 1025}, | ||
2802 | { 9, 1537}, | ||
2803 | {10, 2049}, | ||
2804 | {10, 3073}, | ||
2805 | {11, 4097}, | ||
2806 | {11, 6145}, | ||
2807 | {12, 8193}, | ||
2808 | {12, 12289}, | ||
2809 | {13, 16385}, | ||
2810 | {13, 24577} | ||
2811 | }; | ||
2812 | |||
2813 | FlateStream::FlateStream(Stream *strA, int predictor, int columns, | ||
2814 | int colors, int bits): | ||
2815 | FilterStream(strA) { | ||
2816 | if (predictor != 1) { | ||
2817 | pred = new StreamPredictor(this, predictor, columns, colors, bits); | ||
2818 | } else { | ||
2819 | pred = NULL; | ||
2820 | } | ||
2821 | } | ||
2822 | |||
2823 | FlateStream::~FlateStream() { | ||
2824 | if (pred) { | ||
2825 | delete pred; | ||
2826 | } | ||
2827 | delete str; | ||
2828 | } | ||
2829 | |||
2830 | void FlateStream::reset() { | ||
2831 | int cmf, flg; | ||
2832 | |||
2833 | index = 0; | ||
2834 | remain = 0; | ||
2835 | codeBuf = 0; | ||
2836 | codeSize = 0; | ||
2837 | compressedBlock = gFalse; | ||
2838 | endOfBlock = gTrue; | ||
2839 | eof = gTrue; | ||
2840 | |||
2841 | str->reset(); | ||
2842 | |||
2843 | // read header | ||
2844 | //~ need to look at window size? | ||
2845 | endOfBlock = eof = gTrue; | ||
2846 | cmf = str->getChar(); | ||
2847 | flg = str->getChar(); | ||
2848 | if (cmf == EOF || flg == EOF) | ||
2849 | return; | ||
2850 | if ((cmf & 0x0f) != 0x08) { | ||
2851 | error(getPos(), "Unknown compression method in flate stream"); | ||
2852 | return; | ||
2853 | } | ||
2854 | if ((((cmf << 8) + flg) % 31) != 0) { | ||
2855 | error(getPos(), "Bad FCHECK in flate stream"); | ||
2856 | return; | ||
2857 | } | ||
2858 | if (flg & 0x20) { | ||
2859 | error(getPos(), "FDICT bit set in flate stream"); | ||
2860 | return; | ||
2861 | } | ||
2862 | |||
2863 | eof = gFalse; | ||
2864 | } | ||
2865 | |||
2866 | int FlateStream::getChar() { | ||
2867 | int c; | ||
2868 | |||
2869 | if (pred) { | ||
2870 | return pred->getChar(); | ||
2871 | } | ||
2872 | while (remain == 0) { | ||
2873 | if (endOfBlock && eof) | ||
2874 | return EOF; | ||
2875 | readSome(); | ||
2876 | } | ||
2877 | c = buf[index]; | ||
2878 | index = (index + 1) & flateMask; | ||
2879 | --remain; | ||
2880 | return c; | ||
2881 | } | ||
2882 | |||
2883 | int FlateStream::lookChar() { | ||
2884 | int c; | ||
2885 | |||
2886 | if (pred) { | ||
2887 | return pred->lookChar(); | ||
2888 | } | ||
2889 | while (remain == 0) { | ||
2890 | if (endOfBlock && eof) | ||
2891 | return EOF; | ||
2892 | readSome(); | ||
2893 | } | ||
2894 | c = buf[index]; | ||
2895 | return c; | ||
2896 | } | ||
2897 | |||
2898 | int FlateStream::getRawChar() { | ||
2899 | int c; | ||
2900 | |||
2901 | while (remain == 0) { | ||
2902 | if (endOfBlock && eof) | ||
2903 | return EOF; | ||
2904 | readSome(); | ||
2905 | } | ||
2906 | c = buf[index]; | ||
2907 | index = (index + 1) & flateMask; | ||
2908 | --remain; | ||
2909 | return c; | ||
2910 | } | ||
2911 | |||
2912 | GString *FlateStream::getPSFilter(char *indent) { | ||
2913 | return NULL; | ||
2914 | } | ||
2915 | |||
2916 | GBool FlateStream::isBinary(GBool last) { | ||
2917 | return str->isBinary(gTrue); | ||
2918 | } | ||
2919 | |||
2920 | void FlateStream::readSome() { | ||
2921 | int code1, code2; | ||
2922 | int len, dist; | ||
2923 | int i, j, k; | ||
2924 | int c; | ||
2925 | |||
2926 | if (endOfBlock) { | ||
2927 | if (!startBlock()) | ||
2928 | return; | ||
2929 | } | ||
2930 | |||
2931 | if (compressedBlock) { | ||
2932 | if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF) | ||
2933 | goto err; | ||
2934 | if (code1 < 256) { | ||
2935 | buf[index] = code1; | ||
2936 | remain = 1; | ||
2937 | } else if (code1 == 256) { | ||
2938 | endOfBlock = gTrue; | ||
2939 | remain = 0; | ||
2940 | } else { | ||
2941 | code1 -= 257; | ||
2942 | code2 = lengthDecode[code1].bits; | ||
2943 | if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) | ||
2944 | goto err; | ||
2945 | len = lengthDecode[code1].first + code2; | ||
2946 | if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF) | ||
2947 | goto err; | ||
2948 | code2 = distDecode[code1].bits; | ||
2949 | if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) | ||
2950 | goto err; | ||
2951 | dist = distDecode[code1].first + code2; | ||
2952 | i = index; | ||
2953 | j = (index - dist) & flateMask; | ||
2954 | for (k = 0; k < len; ++k) { | ||
2955 | buf[i] = buf[j]; | ||
2956 | i = (i + 1) & flateMask; | ||
2957 | j = (j + 1) & flateMask; | ||
2958 | } | ||
2959 | remain = len; | ||
2960 | } | ||
2961 | |||
2962 | } else { | ||
2963 | len = (blockLen < flateWindow) ? blockLen : flateWindow; | ||
2964 | for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) { | ||
2965 | if ((c = str->getChar()) == EOF) { | ||
2966 | endOfBlock = eof = gTrue; | ||
2967 | break; | ||
2968 | } | ||
2969 | buf[j] = c & 0xff; | ||
2970 | } | ||
2971 | remain = i; | ||
2972 | blockLen -= len; | ||
2973 | if (blockLen == 0) | ||
2974 | endOfBlock = gTrue; | ||
2975 | } | ||
2976 | |||
2977 | return; | ||
2978 | |||
2979 | err: | ||
2980 | error(getPos(), "Unexpected end of file in flate stream"); | ||
2981 | endOfBlock = eof = gTrue; | ||
2982 | remain = 0; | ||
2983 | } | ||
2984 | |||
2985 | GBool FlateStream::startBlock() { | ||
2986 | int blockHdr; | ||
2987 | int c; | ||
2988 | int check; | ||
2989 | |||
2990 | // read block header | ||
2991 | blockHdr = getCodeWord(3); | ||
2992 | if (blockHdr & 1) | ||
2993 | eof = gTrue; | ||
2994 | blockHdr >>= 1; | ||
2995 | |||
2996 | // uncompressed block | ||
2997 | if (blockHdr == 0) { | ||
2998 | compressedBlock = gFalse; | ||
2999 | if ((c = str->getChar()) == EOF) | ||
3000 | goto err; | ||
3001 | blockLen = c & 0xff; | ||
3002 | if ((c = str->getChar()) == EOF) | ||
3003 | goto err; | ||
3004 | blockLen |= (c & 0xff) << 8; | ||
3005 | if ((c = str->getChar()) == EOF) | ||
3006 | goto err; | ||
3007 | check = c & 0xff; | ||
3008 | if ((c = str->getChar()) == EOF) | ||
3009 | goto err; | ||
3010 | check |= (c & 0xff) << 8; | ||
3011 | if (check != (~blockLen & 0xffff)) | ||
3012 | error(getPos(), "Bad uncompressed block length in flate stream"); | ||
3013 | codeBuf = 0; | ||
3014 | codeSize = 0; | ||
3015 | |||
3016 | // compressed block with fixed codes | ||
3017 | } else if (blockHdr == 1) { | ||
3018 | compressedBlock = gTrue; | ||
3019 | loadFixedCodes(); | ||
3020 | |||
3021 | // compressed block with dynamic codes | ||
3022 | } else if (blockHdr == 2) { | ||
3023 | compressedBlock = gTrue; | ||
3024 | if (!readDynamicCodes()) | ||
3025 | goto err; | ||
3026 | |||
3027 | // unknown block type | ||
3028 | } else { | ||
3029 | goto err; | ||
3030 | } | ||
3031 | |||
3032 | endOfBlock = gFalse; | ||
3033 | return gTrue; | ||
3034 | |||
3035 | err: | ||
3036 | error(getPos(), "Bad block header in flate stream"); | ||
3037 | endOfBlock = eof = gTrue; | ||
3038 | return gFalse; | ||
3039 | } | ||
3040 | |||
3041 | void FlateStream::loadFixedCodes() { | ||
3042 | int i; | ||
3043 | |||
3044 | // set up code arrays | ||
3045 | litCodeTab.codes = allCodes; | ||
3046 | distCodeTab.codes = allCodes + flateMaxLitCodes; | ||
3047 | |||
3048 | // initialize literal code table | ||
3049 | for (i = 0; i <= 143; ++i) | ||
3050 | litCodeTab.codes[i].len = 8; | ||
3051 | for (i = 144; i <= 255; ++i) | ||
3052 | litCodeTab.codes[i].len = 9; | ||
3053 | for (i = 256; i <= 279; ++i) | ||
3054 | litCodeTab.codes[i].len = 7; | ||
3055 | for (i = 280; i <= 287; ++i) | ||
3056 | litCodeTab.codes[i].len = 8; | ||
3057 | compHuffmanCodes(&litCodeTab, flateMaxLitCodes); | ||
3058 | |||
3059 | // initialize distance code table | ||
3060 | for (i = 0; i <= 5; ++i) { | ||
3061 | distCodeTab.start[i] = 0; | ||
3062 | } | ||
3063 | for (i = 6; i <= flateMaxHuffman+1; ++i) { | ||
3064 | distCodeTab.start[i] = flateMaxDistCodes; | ||
3065 | } | ||
3066 | for (i = 0; i < flateMaxDistCodes; ++i) { | ||
3067 | distCodeTab.codes[i].len = 5; | ||
3068 | distCodeTab.codes[i].code = i; | ||
3069 | distCodeTab.codes[i].val = i; | ||
3070 | } | ||
3071 | } | ||
3072 | |||
3073 | GBool FlateStream::readDynamicCodes() { | ||
3074 | int numCodeLenCodes; | ||
3075 | int numLitCodes; | ||
3076 | int numDistCodes; | ||
3077 | FlateCode codeLenCodes[flateMaxCodeLenCodes]; | ||
3078 | FlateHuffmanTab codeLenCodeTab; | ||
3079 | int len, repeat, code; | ||
3080 | int i; | ||
3081 | |||
3082 | // read lengths | ||
3083 | if ((numLitCodes = getCodeWord(5)) == EOF) | ||
3084 | goto err; | ||
3085 | numLitCodes += 257; | ||
3086 | if ((numDistCodes = getCodeWord(5)) == EOF) | ||
3087 | goto err; | ||
3088 | numDistCodes += 1; | ||
3089 | if ((numCodeLenCodes = getCodeWord(4)) == EOF) | ||
3090 | goto err; | ||
3091 | numCodeLenCodes += 4; | ||
3092 | if (numLitCodes > flateMaxLitCodes || | ||
3093 | numDistCodes > flateMaxDistCodes || | ||
3094 | numCodeLenCodes > flateMaxCodeLenCodes) | ||
3095 | goto err; | ||
3096 | |||
3097 | // read code length code table | ||
3098 | codeLenCodeTab.codes = codeLenCodes; | ||
3099 | for (i = 0; i < flateMaxCodeLenCodes; ++i) | ||
3100 | codeLenCodes[i].len = 0; | ||
3101 | for (i = 0; i < numCodeLenCodes; ++i) { | ||
3102 | if ((codeLenCodes[codeLenCodeMap[i]].len = getCodeWord(3)) == -1) | ||
3103 | goto err; | ||
3104 | } | ||
3105 | compHuffmanCodes(&codeLenCodeTab, flateMaxCodeLenCodes); | ||
3106 | |||
3107 | // set up code arrays | ||
3108 | litCodeTab.codes = allCodes; | ||
3109 | distCodeTab.codes = allCodes + numLitCodes; | ||
3110 | |||
3111 | // read literal and distance code tables | ||
3112 | len = 0; | ||
3113 | repeat = 0; | ||
3114 | i = 0; | ||
3115 | while (i < numLitCodes + numDistCodes) { | ||
3116 | if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) | ||
3117 | goto err; | ||
3118 | if (code == 16) { | ||
3119 | if ((repeat = getCodeWord(2)) == EOF) | ||
3120 | goto err; | ||
3121 | for (repeat += 3; repeat > 0; --repeat) | ||
3122 | allCodes[i++].len = len; | ||
3123 | } else if (code == 17) { | ||
3124 | if ((repeat = getCodeWord(3)) == EOF) | ||
3125 | goto err; | ||
3126 | len = 0; | ||
3127 | for (repeat += 3; repeat > 0; --repeat) | ||
3128 | allCodes[i++].len = 0; | ||
3129 | } else if (code == 18) { | ||
3130 | if ((repeat = getCodeWord(7)) == EOF) | ||
3131 | goto err; | ||
3132 | len = 0; | ||
3133 | for (repeat += 11; repeat > 0; --repeat) | ||
3134 | allCodes[i++].len = 0; | ||
3135 | } else { | ||
3136 | allCodes[i++].len = len = code; | ||
3137 | } | ||
3138 | } | ||
3139 | compHuffmanCodes(&litCodeTab, numLitCodes); | ||
3140 | compHuffmanCodes(&distCodeTab, numDistCodes); | ||
3141 | |||
3142 | return gTrue; | ||
3143 | |||
3144 | err: | ||
3145 | error(getPos(), "Bad dynamic code table in flate stream"); | ||
3146 | return gFalse; | ||
3147 | } | ||
3148 | |||
3149 | // On entry, the <tab->codes> array contains the lengths of each code, | ||
3150 | // stored in code value order. This function computes the code words. | ||
3151 | // The result is sorted in order of (1) code length and (2) code word. | ||
3152 | // The length values are no longer valid. The <tab->start> array is | ||
3153 | // filled with the indexes of the first code of each length. | ||
3154 | void FlateStream::compHuffmanCodes(FlateHuffmanTab *tab, int n) { | ||
3155 | int numLengths[flateMaxHuffman+1]; | ||
3156 | int nextCode[flateMaxHuffman+1]; | ||
3157 | int nextIndex[flateMaxHuffman+2]; | ||
3158 | int code; | ||
3159 | int i, j; | ||
3160 | |||
3161 | // count number of codes for each code length | ||
3162 | for (i = 0; i <= flateMaxHuffman; ++i) | ||
3163 | numLengths[i] = 0; | ||
3164 | for (i = 0; i < n; ++i) | ||
3165 | ++numLengths[tab->codes[i].len]; | ||
3166 | |||
3167 | // compute first index for each length | ||
3168 | tab->start[0] = nextIndex[0] = 0; | ||
3169 | for (i = 1; i <= flateMaxHuffman + 1; ++i) | ||
3170 | tab->start[i] = nextIndex[i] = tab->start[i-1] + numLengths[i-1]; | ||
3171 | |||
3172 | // compute first code for each length | ||
3173 | code = 0; | ||
3174 | numLengths[0] = 0; | ||
3175 | for (i = 1; i <= flateMaxHuffman; ++i) { | ||
3176 | code = (code + numLengths[i-1]) << 1; | ||
3177 | nextCode[i] = code; | ||
3178 | } | ||
3179 | |||
3180 | // compute the codes -- this permutes the codes array from value | ||
3181 | // order to length/code order | ||
3182 | for (i = 0; i < n; ++i) { | ||
3183 | j = nextIndex[tab->codes[i].len]++; | ||
3184 | if (tab->codes[i].len == 0) | ||
3185 | tab->codes[j].code = 0; | ||
3186 | else | ||
3187 | tab->codes[j].code = nextCode[tab->codes[i].len]++; | ||
3188 | tab->codes[j].val = i; | ||
3189 | } | ||
3190 | } | ||
3191 | |||
3192 | int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { | ||
3193 | int len; | ||
3194 | int code; | ||
3195 | int c; | ||
3196 | int i, j; | ||
3197 | |||
3198 | code = 0; | ||
3199 | for (len = 1; len <= flateMaxHuffman; ++len) { | ||
3200 | |||
3201 | // add a bit to the code | ||
3202 | if (codeSize == 0) { | ||
3203 | if ((c = str->getChar()) == EOF) | ||
3204 | return EOF; | ||
3205 | codeBuf = c & 0xff; | ||
3206 | codeSize = 8; | ||
3207 | } | ||
3208 | code = (code << 1) | (codeBuf & 1); | ||
3209 | codeBuf >>= 1; | ||
3210 | --codeSize; | ||
3211 | |||
3212 | // look for code | ||
3213 | i = tab->start[len]; | ||
3214 | j = tab->start[len + 1]; | ||
3215 | if (i < j && code >= tab->codes[i].code && code <= tab->codes[j-1].code) { | ||
3216 | i += code - tab->codes[i].code; | ||
3217 | return tab->codes[i].val; | ||
3218 | } | ||
3219 | } | ||
3220 | |||
3221 | // not found | ||
3222 | error(getPos(), "Bad code (%04x) in flate stream", code); | ||
3223 | return EOF; | ||
3224 | } | ||
3225 | |||
3226 | int FlateStream::getCodeWord(int bits) { | ||
3227 | int c; | ||
3228 | |||
3229 | while (codeSize < bits) { | ||
3230 | if ((c = str->getChar()) == EOF) | ||
3231 | return EOF; | ||
3232 | codeBuf |= (c & 0xff) << codeSize; | ||
3233 | codeSize += 8; | ||
3234 | } | ||
3235 | c = codeBuf & ((1 << bits) - 1); | ||
3236 | codeBuf >>= bits; | ||
3237 | codeSize -= bits; | ||
3238 | return c; | ||
3239 | } | ||
3240 | |||
3241 | //------------------------------------------------------------------------ | ||
3242 | // EOFStream | ||
3243 | //------------------------------------------------------------------------ | ||
3244 | |||
3245 | EOFStream::EOFStream(Stream *strA): | ||
3246 | FilterStream(strA) { | ||
3247 | } | ||
3248 | |||
3249 | EOFStream::~EOFStream() { | ||
3250 | delete str; | ||
3251 | } | ||
3252 | |||
3253 | //------------------------------------------------------------------------ | ||
3254 | // FixedLengthEncoder | ||
3255 | //------------------------------------------------------------------------ | ||
3256 | |||
3257 | FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): | ||
3258 | FilterStream(strA) { | ||
3259 | length = lengthA; | ||
3260 | count = 0; | ||
3261 | } | ||
3262 | |||
3263 | FixedLengthEncoder::~FixedLengthEncoder() { | ||
3264 | if (str->isEncoder()) | ||
3265 | delete str; | ||
3266 | } | ||
3267 | |||
3268 | void FixedLengthEncoder::reset() { | ||
3269 | str->reset(); | ||
3270 | count = 0; | ||
3271 | } | ||
3272 | |||
3273 | void FixedLengthEncoder::close() { | ||
3274 | } | ||
3275 | |||
3276 | int FixedLengthEncoder::getChar() { | ||
3277 | if (length >= 0 && count >= length) | ||
3278 | return EOF; | ||
3279 | ++count; | ||
3280 | return str->getChar(); | ||
3281 | } | ||
3282 | |||
3283 | int FixedLengthEncoder::lookChar() { | ||
3284 | if (length >= 0 && count >= length) | ||
3285 | return EOF; | ||
3286 | return str->getChar(); | ||
3287 | } | ||
3288 | |||
3289 | //------------------------------------------------------------------------ | ||
3290 | // ASCII85Encoder | ||
3291 | //------------------------------------------------------------------------ | ||
3292 | |||
3293 | ASCII85Encoder::ASCII85Encoder(Stream *strA): | ||
3294 | FilterStream(strA) { | ||
3295 | bufPtr = bufEnd = buf; | ||
3296 | lineLen = 0; | ||
3297 | eof = gFalse; | ||
3298 | } | ||
3299 | |||
3300 | ASCII85Encoder::~ASCII85Encoder() { | ||
3301 | if (str->isEncoder()) | ||
3302 | delete str; | ||
3303 | } | ||
3304 | |||
3305 | void ASCII85Encoder::reset() { | ||
3306 | str->reset(); | ||
3307 | bufPtr = bufEnd = buf; | ||
3308 | lineLen = 0; | ||
3309 | eof = gFalse; | ||
3310 | } | ||
3311 | |||
3312 | void ASCII85Encoder::close() { | ||
3313 | } | ||
3314 | |||
3315 | GBool ASCII85Encoder::fillBuf() { | ||
3316 | Gulong t; | ||
3317 | char buf1[5]; | ||
3318 | int c; | ||
3319 | int n, i; | ||
3320 | |||
3321 | if (eof) | ||
3322 | return gFalse; | ||
3323 | t = 0; | ||
3324 | for (n = 0; n < 4; ++n) { | ||
3325 | if ((c = str->getChar()) == EOF) | ||
3326 | break; | ||
3327 | t = (t << 8) + c; | ||
3328 | } | ||
3329 | bufPtr = bufEnd = buf; | ||
3330 | if (n > 0) { | ||
3331 | if (n == 4 && t == 0) { | ||
3332 | *bufEnd++ = 'z'; | ||
3333 | if (++lineLen == 65) { | ||
3334 | *bufEnd++ = '\n'; | ||
3335 | lineLen = 0; | ||
3336 | } | ||
3337 | } else { | ||
3338 | if (n < 4) | ||
3339 | t <<= 8 * (4 - n); | ||
3340 | for (i = 4; i >= 0; --i) { | ||
3341 | buf1[i] = (char)(t % 85 + 0x21); | ||
3342 | t /= 85; | ||
3343 | } | ||
3344 | for (i = 0; i <= n; ++i) { | ||
3345 | *bufEnd++ = buf1[i]; | ||
3346 | if (++lineLen == 65) { | ||
3347 | *bufEnd++ = '\n'; | ||
3348 | lineLen = 0; | ||
3349 | } | ||
3350 | } | ||
3351 | } | ||
3352 | } | ||
3353 | if (n < 4) { | ||
3354 | *bufEnd++ = '~'; | ||
3355 | *bufEnd++ = '>'; | ||
3356 | eof = gTrue; | ||
3357 | } | ||
3358 | return bufPtr < bufEnd; | ||
3359 | } | ||
3360 | |||
3361 | //------------------------------------------------------------------------ | ||
3362 | // RunLengthEncoder | ||
3363 | //------------------------------------------------------------------------ | ||
3364 | |||
3365 | RunLengthEncoder::RunLengthEncoder(Stream *strA): | ||
3366 | FilterStream(strA) { | ||
3367 | bufPtr = bufEnd = nextEnd = buf; | ||
3368 | eof = gFalse; | ||
3369 | } | ||
3370 | |||
3371 | RunLengthEncoder::~RunLengthEncoder() { | ||
3372 | if (str->isEncoder()) | ||
3373 | delete str; | ||
3374 | } | ||
3375 | |||
3376 | void RunLengthEncoder::reset() { | ||
3377 | str->reset(); | ||
3378 | bufPtr = bufEnd = nextEnd = buf; | ||
3379 | eof = gFalse; | ||
3380 | } | ||
3381 | |||
3382 | void RunLengthEncoder::close() { | ||
3383 | } | ||
3384 | |||
3385 | // | ||
3386 | // When fillBuf finishes, buf[] looks like this: | ||
3387 | // +-----+--------------+-----------------+-- | ||
3388 | // + tag | ... data ... | next 0, 1, or 2 | | ||
3389 | // +-----+--------------+-----------------+-- | ||
3390 | // ^ ^ ^ | ||
3391 | // bufPtr bufEnd nextEnd | ||
3392 | // | ||
3393 | GBool RunLengthEncoder::fillBuf() { | ||
3394 | int c, c1, c2; | ||
3395 | int n; | ||
3396 | |||
3397 | // already hit EOF? | ||
3398 | if (eof) | ||
3399 | return gFalse; | ||
3400 | |||
3401 | // grab two bytes | ||
3402 | if (nextEnd < bufEnd + 1) { | ||
3403 | if ((c1 = str->getChar()) == EOF) { | ||
3404 | eof = gTrue; | ||
3405 | return gFalse; | ||
3406 | } | ||
3407 | } else { | ||
3408 | c1 = bufEnd[0] & 0xff; | ||
3409 | } | ||
3410 | if (nextEnd < bufEnd + 2) { | ||
3411 | if ((c2 = str->getChar()) == EOF) { | ||
3412 | eof = gTrue; | ||
3413 | buf[0] = 0; | ||
3414 | buf[1] = c1; | ||
3415 | bufPtr = buf; | ||
3416 | bufEnd = &buf[2]; | ||
3417 | return gTrue; | ||
3418 | } | ||
3419 | } else { | ||
3420 | c2 = bufEnd[1] & 0xff; | ||
3421 | } | ||
3422 | |||
3423 | // check for repeat | ||
3424 | c = 0; // make gcc happy | ||
3425 | if (c1 == c2) { | ||
3426 | n = 2; | ||
3427 | while (n < 128 && (c = str->getChar()) == c1) | ||
3428 | ++n; | ||
3429 | buf[0] = (char)(257 - n); | ||
3430 | buf[1] = c1; | ||
3431 | bufEnd = &buf[2]; | ||
3432 | if (c == EOF) { | ||
3433 | eof = gTrue; | ||
3434 | } else if (n < 128) { | ||
3435 | buf[2] = c; | ||
3436 | nextEnd = &buf[3]; | ||
3437 | } else { | ||
3438 | nextEnd = bufEnd; | ||
3439 | } | ||
3440 | |||
3441 | // get up to 128 chars | ||
3442 | } else { | ||
3443 | buf[1] = c1; | ||
3444 | buf[2] = c2; | ||
3445 | n = 2; | ||
3446 | while (n < 128) { | ||
3447 | if ((c = str->getChar()) == EOF) { | ||
3448 | eof = gTrue; | ||
3449 | break; | ||
3450 | } | ||
3451 | ++n; | ||
3452 | buf[n] = c; | ||
3453 | if (buf[n] == buf[n-1]) | ||
3454 | break; | ||
3455 | } | ||
3456 | if (buf[n] == buf[n-1]) { | ||
3457 | buf[0] = (char)(n-2-1); | ||
3458 | bufEnd = &buf[n-1]; | ||
3459 | nextEnd = &buf[n+1]; | ||
3460 | } else { | ||
3461 | buf[0] = (char)(n-1); | ||
3462 | bufEnd = nextEnd = &buf[n+1]; | ||
3463 | } | ||
3464 | } | ||
3465 | bufPtr = buf; | ||
3466 | return gTrue; | ||
3467 | } | ||