#include <ctype.h>
#include "gmem.h"
#include "gfile.h"
-#include "config.h"
+#include "xpdfconfig.h"
#include "Error.h"
#include "Object.h"
#ifndef NO_DECRYPTION
#endif
#include "Stream.h"
#include "JBIG2Stream.h"
+#include "JPXStream.h"
#include "Stream-CCITT.h"
#ifdef __DJGPP__
return buf;
}
-GString *Stream::getPSFilter(char *indent) {
+GString *Stream::getPSFilter(int psLevel, char *indent) {
return new GString();
}
}
str = new JBIG2Stream(str, &globals);
globals.free();
+ } else if (!strcmp(name, "JPXDecode")) {
+ str = new JPXStream(str);
} else {
error(getPos(), "Unknown filter '%s'", name);
str = new EOFStream(str);
int i, j, k;
// get PNG optimum predictor number
- if (predictor == 15) {
+ if (predictor >= 10) {
if ((curPred = str->getRawChar()) == EOF) {
return gFalse;
}
// MemStream
//------------------------------------------------------------------------
-MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA):
+MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA):
BaseStream(dictA) {
buf = bufA;
- needFree = gFalse;
+ start = startA;
length = lengthA;
- bufEnd = buf + length;
- bufPtr = buf;
+ bufEnd = buf + start + length;
+ bufPtr = buf + start;
+ needFree = gFalse;
}
MemStream::~MemStream() {
}
}
-Stream *MemStream::makeSubStream(Guint start, GBool limited,
+Stream *MemStream::makeSubStream(Guint startA, GBool limited,
Guint lengthA, Object *dictA) {
+ MemStream *subStr;
Guint newLength;
- if (!limited || start + lengthA > length) {
- newLength = length - start;
+ if (!limited || startA + lengthA > start + length) {
+ newLength = start + length - startA;
} else {
newLength = lengthA;
}
- return new MemStream(buf + start, newLength, dictA);
+ subStr = new MemStream(buf, startA, newLength, dictA);
+ return subStr;
}
void MemStream::reset() {
- bufPtr = buf;
+ bufPtr = buf + start;
#ifndef NO_DECRYPTION
if (decrypt) {
decrypt->reset();
}
void MemStream::setPos(Guint pos, int dir) {
+ Guint i;
+
if (dir >= 0) {
- if (pos > length) {
- bufPtr = bufEnd;
- } else {
- bufPtr = buf + pos;
- }
+ i = pos;
} else {
- if (pos > length) {
- bufPtr = buf;
- } else {
- bufPtr = bufEnd - pos;
- }
+ i = start + length - pos;
+ }
+ if (i < start) {
+ i = start;
+ } else if (i > start + length) {
+ i = start + length;
}
+ bufPtr = buf + i;
}
void MemStream::moveStart(int delta) {
- buf += delta;
- bufPtr = buf;
+ start += delta;
+ bufPtr = buf + start;
}
#ifndef NO_DECRYPTION
this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen);
if (decrypt) {
- newBuf = (char *)gmalloc(bufEnd - buf);
- for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) {
+ newBuf = (char *)gmalloc(length);
+ for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) {
*q = (char)decrypt->decryptByte((Guchar)*p);
}
- bufEnd = newBuf + (bufEnd - buf);
- bufPtr = newBuf + (bufPtr - buf);
+ bufEnd = newBuf + length;
+ bufPtr = newBuf + (bufPtr - (buf + start));
+ start = 0;
buf = newBuf;
needFree = gTrue;
}
// EmbedStream
//------------------------------------------------------------------------
-EmbedStream::EmbedStream(Stream *strA, Object *dictA):
+EmbedStream::EmbedStream(Stream *strA, Object *dictA,
+ GBool limitedA, Guint lengthA):
BaseStream(dictA) {
str = strA;
+ limited = limitedA;
+ length = lengthA;
}
EmbedStream::~EmbedStream() {
}
-Stream *EmbedStream::makeSubStream(Guint start, GBool limited,
- Guint length, Object *dictA) {
+Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA,
+ Guint lengthA, Object *dictA) {
error(-1, "Internal: called makeSubStream() on EmbedStream");
return NULL;
}
+int EmbedStream::getChar() {
+ if (limited && !length) {
+ return EOF;
+ }
+ --length;
+ return str->getChar();
+}
+
+int EmbedStream::lookChar() {
+ if (limited && !length) {
+ return EOF;
+ }
+ return str->lookChar();
+}
+
void EmbedStream::setPos(Guint pos, int dir) {
error(-1, "Internal: called setPos() on EmbedStream");
}
return buf;
}
-GString *ASCIIHexStream::getPSFilter(char *indent) {
+GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/ASCIIHexDecode filter\n");
return b[index];
}
-GString *ASCII85Stream::getPSFilter(char *indent) {
+GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/ASCII85Decode filter\n");
return code;
}
-GString *LZWStream::getPSFilter(char *indent) {
+GString *LZWStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (pred) {
+ if (psLevel < 2 || pred) {
return NULL;
}
- if (!(s = str->getPSFilter(indent))) {
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/LZWDecode filter\n");
eof = gFalse;
}
-GString *RunLengthStream::getPSFilter(char *indent) {
+GString *RunLengthStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/RunLengthDecode filter\n");
}
void CCITTFaxStream::reset() {
- int n;
+ short code1;
str->reset();
eof = gFalse;
a0 = 1;
buf = EOF;
- // get initial end-of-line marker and 2D encoding tag
- if (endOfBlock) {
- if (lookBits(12) == 0x001) {
- eatBits(12);
- }
- } else {
- for (n = 0; n < 11 && lookBits(n) == 0; ++n) ;
- if (n == 11 && lookBits(12) == 0x001) {
- eatBits(12);
- }
+ // skip any initial zero bits and end-of-line marker, and get the 2D
+ // encoding tag
+ while ((code1 = lookBits(12)) == 0) {
+ eatBits(1);
+ }
+ if (code1 == 0x001) {
+ eatBits(12);
}
if (encoding > 0) {
nextLine2D = !lookBits(1);
int CCITTFaxStream::lookChar() {
short code1, code2, code3;
int a0New;
-#if 0
- GBool err;
-#endif
- GBool gotEOL;
+ GBool err, gotEOL;
int ret;
int bits, i;
}
// read the next row
-#if 0
err = gFalse;
-#endif
if (codingLine[a0] >= columns) {
// 2-D encoding
code2 += code3 = getWhiteCode();
} while (code3 >= 64);
}
- codingLine[a0 + 1] = a0New + code1;
- ++a0;
- a0New = codingLine[a0 + 1] = codingLine[a0] + code2;
- ++a0;
- while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
- b1 += 2;
+ if (code1 > 0 || code2 > 0) {
+ codingLine[a0 + 1] = a0New + code1;
+ ++a0;
+ a0New = codingLine[a0 + 1] = codingLine[a0] + code2;
+ ++a0;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ }
break;
case twoDimVert0:
a0New = codingLine[++a0] = refLine[b1];
return EOF;
default:
error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1);
-#if 0
err = gTrue;
break;
-#else
- eof = gTrue;
- return EOF;
-#endif
}
} while (codingLine[a0] < columns);
if (codingLine[a0] != columns) {
error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]);
-#if 0
+ // force the row to be the correct length
+ while (codingLine[a0] > columns) {
+ --a0;
+ }
+ codingLine[++a0] = columns;
err = gTrue;
-#endif
}
// byte-align the row
}
eof = gTrue;
}
- }
-#if 0
- // This looks for an end-of-line marker after an error, however
- // some (most?) CCITT streams in PDF files don't use end-of-line
- // markers, and the just-plow-on technique works better in those
- // cases.
- else if (err) {
+ // look for an end-of-line marker after an error -- we only do
+ // this if we know the stream contains end-of-line markers because
+ // the "just plow on" technique tends to work better otherwise
+ } else if (err && endOfLine) {
do {
if (code1 == EOF) {
eof = gTrue;
return EOF;
}
eatBits(1);
- code1 = look13Bits();
+ code1 = lookBits(13);
} while ((code1 >> 1) != 0x001);
eatBits(12);
- codingLine[++a0] = columns;
if (encoding > 0) {
eatBits(1);
nextLine2D = !(code1 & 1);
}
}
-#endif
a0 = 0;
outputBits = codingLine[1] - codingLine[0];
return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n));
}
-GString *CCITTFaxStream::getPSFilter(char *indent) {
+GString *CCITTFaxStream::getPSFilter(int psLevel, char *indent) {
GString *s;
char s1[50];
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("<< ");
numDCHuffTables = 0;
numACHuffTables = 0;
colorXform = 0;
+ gotJFIFMarker = gFalse;
gotAdobeMarker = gFalse;
restartInterval = 0;
// figure out color transform
if (!gotAdobeMarker && numComps == 3) {
- if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) {
+ if (gotJFIFMarker) {
+ colorXform = 1;
+ } else if (compInfo[0].id == 82 && compInfo[1].id == 71 &&
+ compInfo[2].id == 66) { // ASCII "RGB"
+ colorXform = 0;
+ } else {
colorXform = 1;
}
}
void DCTStream::readScan() {
int data[64];
int x1, y1, dx1, dy1, x2, y2, y3, cc, i;
- int h, v, horiz, vert, hSub, vSub;
+ int h, v, horiz, vert, vSub;
int *p1;
int c;
v = compInfo[cc].vSample;
horiz = mcuWidth / h;
vert = mcuHeight / v;
- hSub = horiz / 8;
vSub = vert / 8;
for (y2 = 0; y2 < dy1; y2 += vert) {
for (x2 = 0; x2 < dx1; x2 += horiz) {
break;
case 0xd9: // EOI
return gFalse;
- break;
case 0xda: // SOS
if (!readScanInfo()) {
return gFalse;
return gFalse;
}
break;
+ case 0xe0: // APP0
+ if (!readJFIFMarker()) {
+ return gFalse;
+ }
+ break;
case 0xee: // APP14
if (!readAdobeMarker()) {
return gFalse;
}
for (i = 0; i < scanInfo.numComps; ++i) {
id = str->getChar();
- for (j = 0; j < numComps; ++j) {
- if (id == compInfo[j].id) {
- break;
+ // some (broken) DCT streams reuse ID numbers, but at least they
+ // keep the components in order, so we check compInfo[i] first to
+ // work around the problem
+ if (id == compInfo[i].id) {
+ j = i;
+ } else {
+ for (j = 0; j < numComps; ++j) {
+ if (id == compInfo[j].id) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ error(getPos(), "Bad DCT component ID in scan info block");
+ return gFalse;
}
- }
- if (j == numComps) {
- error(getPos(), "Bad DCT component ID in scan info block");
- return gFalse;
}
scanInfo.comp[j] = gTrue;
c = str->getChar();
return gTrue;
}
+GBool DCTStream::readJFIFMarker() {
+ int length, i;
+ char buf[5];
+ int c;
+
+ length = read16();
+ length -= 2;
+ if (length >= 5) {
+ for (i = 0; i < 5; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ error(getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ buf[i] = c;
+ }
+ length -= 5;
+ if (!memcmp(buf, "JFIF\0", 5)) {
+ gotJFIFMarker = gTrue;
+ }
+ }
+ while (length > 0) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ --length;
+ }
+ return gTrue;
+}
+
GBool DCTStream::readAdobeMarker() {
int length, i;
char buf[12];
return (c1 << 8) + c2;
}
-GString *DCTStream::getPSFilter(char *indent) {
+GString *DCTStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("<< >> /DCTDecode filter\n");
return c;
}
-GString *FlateStream::getPSFilter(char *indent) {
- return NULL;
+GString *FlateStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 3 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /FlateDecode filter\n");
+ return s;
}
GBool FlateStream::isBinary(GBool last) {
count = 0;
}
-void FixedLengthEncoder::close() {
-}
-
int FixedLengthEncoder::getChar() {
if (length >= 0 && count >= length)
return EOF;
return str->getChar();
}
+GBool FixedLengthEncoder::isBinary(GBool last) {
+ return str->isBinary(gTrue);
+}
+
//------------------------------------------------------------------------
// ASCIIHexEncoder
//------------------------------------------------------------------------
eof = gFalse;
}
-void ASCIIHexEncoder::close() {
-}
-
GBool ASCIIHexEncoder::fillBuf() {
static char *hex = "0123456789abcdef";
int c;
eof = gFalse;
}
-void ASCII85Encoder::close() {
-}
-
GBool ASCII85Encoder::fillBuf() {
Gulong t;
char buf1[5];
eof = gFalse;
}
-void RunLengthEncoder::close() {
-}
-
//
// When fillBuf finishes, buf[] looks like this:
// +-----+--------------+-----------------+--