pdf-parser.cpp revision 7661da76b07fa9330cf0b898a620a521c9d0b890
/** \file
* PDF parsing using libpoppler
*
* Derived from poppler's Gfx.cc
*
* Copyright 1996-2003 Glyph & Cog, LLC
*
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_POPPLER
#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
extern "C" {
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
}
#include "svg-builder.h"
#include "Gfx.h"
#include "pdf-parser.h"
#include "unit-constants.h"
#include "goo/GooTimer.h"
#include "GlobalParams.h"
#include "CharTypes.h"
#include "Object.h"
#include "Array.h"
#include "Dict.h"
#include "Stream.h"
#include "Lexer.h"
#include "Parser.h"
#include "GfxFont.h"
#include "GfxState.h"
#include "OutputDev.h"
#include "Page.h"
#include "Annot.h"
#include "Error.h"
// the MSVC math.h doesn't define this
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
//------------------------------------------------------------------------
// constants
//------------------------------------------------------------------------
// Default max delta allowed in any color component for a shading fill.
// Default max recursive depth for a shading fill.
#define defaultShadingMaxDepth 6
// Max number of operators kept in the history list.
#define maxOperatorHistoryDepth 16
//------------------------------------------------------------------------
// Operator table
//------------------------------------------------------------------------
#ifdef WIN32 // this works around a bug in the VC7 compiler
#endif
{"B", 0, {tchkNone},
{"B*", 0, {tchkNone},
{"BI", 0, {tchkNone},
{"BT", 0, {tchkNone},
&PdfParser::opBeginText},
{"BX", 0, {tchkNone},
&PdfParser::opMarkPoint},
{"EI", 0, {tchkNone},
&PdfParser::opEndImage},
{"EMC", 0, {tchkNone},
{"ET", 0, {tchkNone},
{"EX", 0, {tchkNone},
{"F", 0, {tchkNone},
{"ID", 0, {tchkNone},
&PdfParser::opImageData},
&PdfParser::opMarkPoint},
{"Q", 0, {tchkNone},
{"S", 0, {tchkNone},
tchkSCN},
{"T*", 0, {tchkNone},
&PdfParser::opTextMove},
&PdfParser::opShowText},
{"W", 0, {tchkNone},
{"W*", 0, {tchkNone},
{"b", 0, {tchkNone},
{"b*", 0, {tchkNone},
{"f", 0, {tchkNone},
{"f*", 0, {tchkNone},
{"h", 0, {tchkNone},
&PdfParser::opClosePath},
{"n", 0, {tchkNone},
{"q", 0, {tchkNone},
&PdfParser::opRectangle},
{"s", 0, {tchkNone},
tchkSCN},
&PdfParser::opCurveTo1},
};
#ifdef WIN32 // this works around a bug in the VC7 compiler
#endif
//------------------------------------------------------------------------
// PdfParser
//------------------------------------------------------------------------
int i;
printCommands = false;
// start the resource stack
// initialize
clipHistory = new ClipHistoryEntry();
ignoreUndef = 0;
double scaledCTM[6];
for (i = 0; i < 6; ++i) {
baseMatrix[i] = ctm[i];
}
saveState();
formDepth = 0;
// set crop box
if (cropBox) {
if (printCommands)
// do not clip if it's not needed
}
}
pushOperator("startPage");
}
int i;
printCommands = false;
// start the resource stack
// initialize
clipHistory = new ClipHistoryEntry();
ignoreUndef = 0;
for (i = 0; i < 6; ++i) {
}
formDepth = 0;
}
restoreState();
}
if (!subPage) {
//out->endPage();
}
while (res) {
popResources();
}
if (state) {
delete state;
}
if (clipHistory) {
delete clipHistory;
}
}
int i;
for (i = 0; i < obj->arrayGetLength(); ++i) {
return;
}
}
return;
}
delete parser;
}
int numArgs, i;
int lastAbortCheck;
// scan a sequence of objects
numArgs = 0;
// got a command - execute it
if (printCommands) {
for (i = 0; i < numArgs; ++i) {
printf(" ");
}
printf("\n");
}
// Run the operation
for (i = 0; i < numArgs; ++i)
numArgs = 0;
// got an argument - save it
// too many arguments - something is wrong
} else {
if (printCommands) {
printf("throwing away arg: ");
printf("\n");
}
}
// grab the next object
}
// args at end with no command
if (numArgs > 0) {
if (printCommands) {
for (i = 0; i < numArgs; ++i) {
printf(" ");
}
printf("\n");
}
for (i = 0; i < numArgs; ++i)
}
}
// Truncate list if needed
}
if (prev) {
delete curr;
}
}
}
}
}
} else {
return "";
}
}
char *name;
int i;
// find operator
if (ignoreUndef == 0)
return;
}
// type check args
return;
}
#if 0
#endif
}
} else {
return;
}
}
for (i = 0; i < numArgs; ++i) {
return;
}
}
// add to history
// do it
}
int a, b, m, cmp;
a = -1;
b = numOps;
// invariant: opTab[a] < name < opTab[b]
while (b - a > 1) {
m = (a + b) / 2;
if (cmp < 0)
a = m;
else if (cmp > 0)
b = m;
else
a = b = m;
}
if (cmp != 0)
return NULL;
return &opTab[a];
}
switch (type) {
}
return gFalse;
}
}
//------------------------------------------------------------------------
// graphics state operators
//------------------------------------------------------------------------
saveState();
}
restoreState();
}
const char *prevOp = getPreviousOperator();
// multiply it with the previous transform
double otherMatrix[6];
// construct identity matrix
}
} else {
}
fontChanged = gTrue;
}
Array *a;
int length;
double *dash;
int i;
if (length == 0) {
} else {
for (i = 0; i < length; ++i) {
}
}
}
}
}
}
}
}
int i;
return;
}
return;
}
if (printCommands) {
printf(" gfx state dict: ");
printf("\n");
}
} else {
}
}
}
}
}
if (!haveFillOP) {
}
}
// stroke adjust
}
// transfer function
}
for (i = 0; i < 4; ++i) {
if (!funcs[i]) {
break;
}
}
if (i == 4) {
}
}
}
// soft mask
} else { // "Luminosity"
}
"Invalid transfer function in soft mask in ExtGState");
delete funcs[0];
}
}
for (i = 0; i < gfxColorMaxComps; ++i) {
backdropColor.c[i] = 0;
}
}
}
}
}
}
}
if (!haveBackdropColor) {
if (blendingColorSpace) {
} else {
//~ need to get the parent or default color space (?)
for (i = 0; i < gfxColorMaxComps; ++i) {
backdropColor.c[i] = 0;
}
}
}
if (funcs[0]) {
delete funcs[0];
}
} else {
}
} else {
}
}
}
}
int i;
// check for excessive recursion
if (formDepth > 20) {
return;
}
// get stream dict
// check form type
}
// get bounding box
return;
}
for (i = 0; i < 4; ++i) {
}
// get matrix
for (i = 0; i < 6; ++i) {
}
} else {
m[0] = 1; m[1] = 0;
m[2] = 0; m[3] = 1;
m[4] = 0; m[5] = 0;
}
// get resources
// draw it
++formDepth;
--formDepth;
if (blendingColorSpace) {
delete blendingColorSpace;
}
}
}
//------------------------------------------------------------------------
// color operators
//------------------------------------------------------------------------
}
}
int i;
for (i = 0; i < 4; ++i) {
}
}
int i;
for (i = 0; i < 4; ++i) {
}
}
int i;
for (i = 0; i < 3; ++i) {
}
}
int i;
for (i = 0; i < 3; ++i) {
}
}
} else {
}
if (colorSpace) {
} else {
}
}
} else {
}
if (colorSpace) {
} else {
}
}
int i;
return;
}
for (i = 0; i < numArgs; ++i) {
}
}
int i;
return;
}
for (i = 0; i < numArgs; ++i) {
}
}
int i;
if (numArgs > 1) {
return;
}
}
}
}
}
} else {
return;
}
for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
}
}
}
}
int i;
if (numArgs > 1) {
->getUnder() ||
return;
}
}
}
}
}
} else {
return;
}
for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
}
}
}
}
//------------------------------------------------------------------------
// path segment operators
//------------------------------------------------------------------------
}
return;
}
}
return;
}
}
return;
}
}
return;
}
}
double x, y, w, h;
}
return;
}
}
//------------------------------------------------------------------------
// path painting operators
//------------------------------------------------------------------------
doEndPath();
}
//error(getPos(), "No path in stroke");
return;
}
} else {
}
}
doEndPath();
}
return;
}
} else {
}
}
doEndPath();
}
//error(getPos(), "No path in fill");
return;
}
} else {
}
}
doEndPath();
}
//error(getPos(), "No path in eofill");
return;
}
} else {
}
}
doEndPath();
}
return;
}
} else {
}
doEndPath();
}
return;
}
}
doEndPath();
}
return;
}
}
doEndPath();
}
return;
}
}
doEndPath();
}
}
}
} else {
}
}
return;
}
case 1:
break;
case 2:
break;
default:
break;
}
}
void PdfParser::doPatternStrokeFallback() {
return;
}
case 1:
break;
case 2:
break;
default:
break;
}
}
double det;
// save current graphics state
saveState();
// clip to bbox
if (0 ){//shading->getHasBBox()) {
//builder->clip(state);
}
// clip to current path
if (stroke) {
//out->clipToStrokePath(state);
} else {
if (eoFill) {
} else {
}
}
// set the color space
// background color fill
if (shading->getHasBackground()) {
}
// construct a (pattern space) -> (current space) transform matrix
btm = baseMatrix;
// iCTM = invert CTM
// m1 = PTM * BTM = PTM * base transform matrix
// m = m1 * iCTM = (PTM * BTM) * (iCTM)
// set the new matrix
// do shading type-specific operations
case 1:
break;
case 2:
case 3:
// no need to implement these
break;
case 4:
case 5:
break;
case 6:
case 7:
break;
}
// restore graphics state
restoreState();
}
double gradientTransform[6];
return;
}
// save current graphics state
saveState();
savedState = gTrue;
} else { // get gradient transform if possible
// check proper operator sequence
// first there should be one W(*) and then one 'cm' somewhere before 'sh'
seenConcat = gFalse;
int i = 1;
while (i <= maxOperatorHistoryDepth) {
const char *opName = getPreviousOperator(i);
if (seenConcat) { // more than one 'cm'
break;
} else {
seenConcat = gTrue;
}
}
i++;
}
if (seenConcat && seenClip) {
matrix = (double*)&gradientTransform;
}
}
}
// clip to bbox
if (shading->getHasBBox()) {
if (savedState)
else
}
// set the color space
if (savedState)
// do shading type-specific operations
case 1:
break;
case 2:
case 3:
if (clipHistory->getClipPath()) {
}
break;
case 4:
case 5:
break;
case 6:
case 7:
break;
}
// restore graphics state
if (savedState) {
restoreState();
}
delete shading;
}
}
double *matrix;
int nComps, i, j;
// compare the four corner colors
for (i = 0; i < 4; ++i) {
for (j = 0; j < nComps; ++j) {
break;
}
}
if (j < nComps) {
break;
}
}
// center of the rectangle
// the four corner colors are close (or we hit the recursive limit)
// -- fill the rectangle; but require at least one subdivision
// (depth==0) to avoid problems when the four outer corners of the
// shaded region are the same color
// use the center color
// fill the rectangle
// the four corner colors are not close enough -- subdivide the
// rectangle
} else {
// colors[0] colorM0 colors[2]
// (x0,y0) (xM,y0) (x1,y0)
// +----------+----------+
// | | |
// | UL | UR |
// color0M | colorMM | color1M
// (x0,yM) +----------+----------+ (x1,yM)
// | (xM,yM) |
// | LL | LR |
// | | |
// +----------+----------+
// colors[1] colorM1 colors[3]
// (x0,y1) (xM,y1) (x1,y1)
// upper-left sub-rectangle
// lower-left sub-rectangle
// upper-right sub-rectangle
// lower-right sub-rectangle
}
}
int i;
for (i = 0; i < shading->getNTriangles(); ++i) {
}
}
int i;
for (i = 0; i < nComps; ++i) {
break;
}
}
} else {
//~ if the shading has a Function, this should interpolate on the
//~ function parameter, not on the color components
for (i = 0; i < nComps; ++i) {
}
}
}
int start, i;
start = 3;
start = 2;
start = 1;
} else {
start = 0;
}
for (i = 0; i < shading->getNPatches(); ++i) {
start);
}
}
int i;
for (i = 0; i < nComps; ++i) {
> patchColorDelta ||
> patchColorDelta ||
> patchColorDelta ||
> patchColorDelta) {
break;
}
}
} else {
for (i = 0; i < 4; ++i) {
}
for (i = 0; i < 4; ++i) {
}
for (i = 4; i < 8; ++i) {
}
//~ if the shading has a Function, this should interpolate on the
//~ function parameter, not on the color components
for (i = 0; i < nComps; ++i) {
}
}
}
if (clip == clipNormal) {
} else {
}
}
}
//------------------------------------------------------------------------
// path clipping operators
//------------------------------------------------------------------------
clip = clipNormal;
}
}
//------------------------------------------------------------------------
// text object operators
//------------------------------------------------------------------------
state->textMoveTo(0, 0);
fontChanged = gTrue;
}
}
//------------------------------------------------------------------------
// text state operators
//------------------------------------------------------------------------
}
// unsetting the font (drawing no text) is better than using the
// previous one and drawing random glyphs from it
fontChanged = gTrue;
return;
}
if (printCommands) {
printf(" font: tag=%s name='%s' %g\n",
}
fontChanged = gTrue;
}
}
}
}
}
fontChanged = gTrue;
}
//------------------------------------------------------------------------
// text positioning operators
//------------------------------------------------------------------------
}
}
state->textMoveTo(0, 0);
fontChanged = gTrue;
}
}
//------------------------------------------------------------------------
// text string operators
//------------------------------------------------------------------------
return;
}
if (fontChanged) {
}
}
return;
}
if (fontChanged) {
}
}
return;
}
if (fontChanged) {
}
}
Array *a;
int wMode;
int i;
return;
}
if (fontChanged) {
}
for (i = 0; i < a->getLength(); ++i) {
// this uses the absolute value of the font size to match
// Acrobat's behavior
if (wMode) {
} else {
}
} else {
}
}
}
/*
* The `POPPLER_NEW_GFXFONT' stuff is for the change to GfxFont's getNextChar() call.
* Thanks to tsdgeos for the fix.
* Miklos, does this look ok?
*/
int wMode;
#ifdef POPPLER_NEW_GFXFONT
#else
Unicode u[8];
#endif
double *mat;
char *p;
// handle a Type 3 char
for (i = 0; i < 6; ++i) {
}
p = s->getCString();
while (len > 0) {
#ifdef POPPLER_NEW_GFXFONT
&u, &uLen, /* TODO: This looks like a memory leak for u. */
#else
#endif
if (n == 1 && *p == ' ') {
}
saveState();
//~ the CTM concat values here are wrong (but never used)
//out->updateCTM(state, 1, 0, 0, 1, 0, 0);
if (0){ /*!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
code, u, uLen)) {*/
}
//parse(&charProc, gFalse); // TODO: parse into SVG font
} else {
}
//out->endType3Char(state);
if (resDict) {
popResources();
}
}
restoreState();
// GfxState::restore() does *not* restore the current position,
// so we deal with it here using (curX, curY) and (lineX, lineY)
p += n;
len -= n;
}
} else {
p = s->getCString();
while (len > 0) {
#ifdef POPPLER_NEW_GFXFONT
&u, &uLen, /* TODO: This looks like a memory leak for u. */
#else
#endif
if (wMode) {
if (n == 1 && *p == ' ') {
}
} else {
if (n == 1 && *p == ' ') {
}
}
p += n;
len -= n;
}
}
}
//------------------------------------------------------------------------
// XObject operators
//------------------------------------------------------------------------
char *name;
return;
}
return;
}
/* out->psXObject(obj1.getStream(),
obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
} else {
}
}
int maskWidth, maskHeight;
int i;
// get info from the stream
bits = 0;
// get stream dict
// get size
}
else
goto err2;
}
else
goto err2;
// image or mask?
}
goto err2;
// bit depth
if (bits == 0) {
}
} else if (mask) {
bits = 1;
} else {
goto err2;
}
}
// display a mask
if (mask) {
// check for inverted mask
if (bits != 1)
goto err1;
}
goto err2;
}
// draw it
} else {
// get color space and color map
}
} else {
}
}
} else if (csMode == streamCSDeviceGray) {
colorSpace = new GfxDeviceGrayColorSpace();
} else if (csMode == streamCSDeviceRGB) {
colorSpace = new GfxDeviceRGBColorSpace();
} else if (csMode == streamCSDeviceCMYK) {
colorSpace = new GfxDeviceCMYKColorSpace();
} else {
colorSpace = NULL;
}
if (!colorSpace) {
goto err1;
}
}
delete colorMap;
goto err1;
}
// get the mask
// soft mask
if (inlineImg) {
goto err1;
}
}
goto err2;
}
}
goto err2;
}
}
goto err2;
}
}
} else {
}
}
goto err1;
}
}
if (!maskColorMap->isOk()) {
delete maskColorMap;
goto err1;
}
//~ handle the Matte entry
// color key mask
for (i = 0;
++i) {
}
// explicit mask
if (inlineImg) {
goto err1;
}
}
goto err2;
}
}
goto err2;
}
}
goto err2;
}
maskInvert = gFalse;
}
maskInvert = gTrue;
}
goto err2;
}
}
// draw it
if (haveSoftMask) {
delete maskColorMap;
} else if (haveExplicitMask) {
} else {
}
delete colorMap;
}
return;
err2:
err1:
}
int i;
// check for excessive recursion
if (formDepth > 20) {
return;
}
// get stream dict
// check form type
}
// get bounding box
return;
}
for (i = 0; i < 4; ++i) {
}
// get matrix
for (i = 0; i < 6; ++i) {
}
} else {
m[0] = 1; m[1] = 0;
m[2] = 0; m[3] = 1;
m[4] = 0; m[5] = 0;
}
// get resources
// check for a transparency group
transpGroup = gTrue;
}
}
}
}
}
// draw it
++formDepth;
--formDepth;
if (blendingColorSpace) {
delete blendingColorSpace;
}
}
double oldBaseMatrix[6];
int i;
// push new resources on stack
// save current graphics state
saveState();
// kill any pre-existing path
if (softMask || transpGroup) {
}
// save current parser
// set form transformation matrix
// set form bounding box
if (softMask || transpGroup) {
}
}
}
}
// set new base matrix
for (i = 0; i < 6; ++i) {
oldBaseMatrix[i] = baseMatrix[i];
}
// draw the form
// restore base matrix
for (i = 0; i < 6; ++i) {
baseMatrix[i] = oldBaseMatrix[i];
}
// restore parser
if (softMask || transpGroup) {
}
// restore graphics state
restoreState();
// pop resource stack
popResources();
if (softMask) {
} else if (transpGroup) {
}
return;
}
//------------------------------------------------------------------------
// in-line image operators
//------------------------------------------------------------------------
str = buildImageStream();
// display the image
if (str) {
// skip 'EI' tag
}
delete str;
}
}
char *key;
// build dictionary
} else {
break;
}
}
}
return NULL;
}
// make stream
return str;
}
}
}
//------------------------------------------------------------------------
// type 3 font operators
//------------------------------------------------------------------------
}
}
//------------------------------------------------------------------------
// compatibility operators
//------------------------------------------------------------------------
++ignoreUndef;
}
if (ignoreUndef > 0)
--ignoreUndef;
}
//------------------------------------------------------------------------
// marked content operators
//------------------------------------------------------------------------
if (printCommands) {
if (numArgs == 2)
printf("\n");
}
if(numArgs == 2) {
//out->beginMarkedContent(args[0].getName(),args[1].getDict());
} else {
//out->beginMarkedContent(args[0].getName());
}
}
//out->endMarkedContent();
}
if (printCommands) {
if (numArgs == 2)
printf("\n");
}
if(numArgs == 2) {
//out->markPoint(args[0].getName(),args[1].getDict());
} else {
//out->markPoint(args[0].getName());
}
}
//------------------------------------------------------------------------
// misc
//------------------------------------------------------------------------
}
void PdfParser::restoreState() {
builder->restoreState();
}
}
void PdfParser::popResources() {
delete res;
}
void PdfParser::setDefaultApproximationPrecision() {
int i;
for (i = 1; i <= pdfNumShadingTypes; ++i) {
}
}
int maxDepth) {
return;
}
}
//------------------------------------------------------------------------
// ClipHistoryEntry
//------------------------------------------------------------------------
if (clipPathA) {
} else {
}
}
if (clipPath) {
delete clipPath;
}
}
// Free previous clip path
if (clipPath) {
delete clipPath;
}
if (clipPathA) {
} else {
}
}
return newEntry;
}
if (saved) {
delete this;
} else {
oldEntry = this;
}
return oldEntry;
}
} else {
}
}
#endif /* HAVE_POPPLER */