📄 xref.cc
字号:
//========================================================================//// XRef.cc//// Copyright 1996-2003 Glyph & Cog, LLC////========================================================================#include <aconf.h>#ifdef USE_GCC_PRAGMAS#pragma implementation#endif#include <stdlib.h>#include <stddef.h>#include <string.h>#include <ctype.h>#include "gmem.h"#include "Object.h"#include "Stream.h"#include "Lexer.h"#include "Parser.h"#include "Dict.h"#include "Error.h"#include "ErrorCodes.h"#include "XRef.h"//------------------------------------------------------------------------#define xrefSearchSize 1024 // read this many bytes at end of file // to look for 'startxref'//------------------------------------------------------------------------// Permission bits//------------------------------------------------------------------------#define permPrint (1<<2)#define permChange (1<<3)#define permCopy (1<<4)#define permNotes (1<<5)#define defPermFlags 0xfffc//------------------------------------------------------------------------// ObjectStream//------------------------------------------------------------------------class ObjectStream {public: // Create an object stream, using object number <objStrNum>, // generation 0. ObjectStream(XRef *xref, int objStrNumA); ~ObjectStream(); // Return the object number of this object stream. int getObjStrNum() { return objStrNum; } // Get the <objIdx>th object from this stream, which should be // object number <objNum>, generation 0. Object *getObject(int objIdx, int objNum, Object *obj);private: int objStrNum; // object number of the object stream int nObjects; // number of objects in the stream Object *objs; // the objects (length = nObjects) int *objNums; // the object numbers (length = nObjects)};ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { Stream *str; Parser *parser; int *offsets; Object objStr, obj1, obj2; int first, i; objStrNum = objStrNumA; nObjects = 0; objs = NULL; objNums = NULL; if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { goto err1; } if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { obj1.free(); goto err1; } nObjects = obj1.getInt(); obj1.free(); if (nObjects <= 0) { goto err1; } if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { obj1.free(); goto err1; } first = obj1.getInt(); obj1.free(); if (first < 0) { goto err1; } objs = new Object[nObjects]; objNums = (int *)gmallocn(nObjects, sizeof(int)); offsets = (int *)gmallocn(nObjects, sizeof(int)); // parse the header: object numbers and offsets objStr.streamReset(); obj1.initNull(); str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); parser = new Parser(xref, new Lexer(xref, str), gFalse); for (i = 0; i < nObjects; ++i) { parser->getObj(&obj1); parser->getObj(&obj2); if (!obj1.isInt() || !obj2.isInt()) { obj1.free(); obj2.free(); delete parser; gfree(offsets); goto err1; } objNums[i] = obj1.getInt(); offsets[i] = obj2.getInt(); obj1.free(); obj2.free(); if (objNums[i] < 0 || offsets[i] < 0 || (i > 0 && offsets[i] < offsets[i-1])) { delete parser; gfree(offsets); goto err1; } } while (str->getChar() != EOF) ; delete parser; // skip to the first object - this shouldn't be necessary because // the First key is supposed to be equal to offsets[0], but just in // case... for (i = first; i < offsets[0]; ++i) { objStr.getStream()->getChar(); } // parse the objects for (i = 0; i < nObjects; ++i) { obj1.initNull(); if (i == nObjects - 1) { str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); } else { str = new EmbedStream(objStr.getStream(), &obj1, gTrue, offsets[i+1] - offsets[i]); } parser = new Parser(xref, new Lexer(xref, str), gFalse); parser->getObj(&objs[i]); while (str->getChar() != EOF) ; delete parser; } gfree(offsets); err1: objStr.free(); return;}ObjectStream::~ObjectStream() { int i; if (objs) { for (i = 0; i < nObjects; ++i) { objs[i].free(); } delete[] objs; } gfree(objNums);}Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { return obj->initNull(); } return objs[objIdx].copy(obj);}//------------------------------------------------------------------------// XRef//------------------------------------------------------------------------XRef::XRef(BaseStream *strA) { Guint pos; Object obj; ok = gTrue; errCode = errNone; size = 0; entries = NULL; streamEnds = NULL; streamEndsLen = 0; objStr = NULL; encrypted = gFalse; permFlags = defPermFlags; ownerPasswordOk = gFalse; // read the trailer str = strA; start = str->getStart(); pos = getStartXref(); // if there was a problem with the 'startxref' position, try to // reconstruct the xref table if (pos == 0) { if (!(ok = constructXRef())) { errCode = errDamaged; return; } // read the xref table } else { while (readXRef(&pos)) ; // if there was a problem with the xref table, // try to reconstruct it if (!ok) { if (!(ok = constructXRef())) { errCode = errDamaged; return; } } } // get the root dictionary (catalog) object trailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); obj.free(); } else { obj.free(); if (!(ok = constructXRef())) { errCode = errDamaged; return; } } // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this);}XRef::~XRef() { gfree(entries); trailerDict.free(); if (streamEnds) { gfree(streamEnds); } if (objStr) { delete objStr; }}// Read the 'startxref' position.Guint XRef::getStartXref() { char buf[xrefSearchSize+1]; char *p; int c, n, i; // read last xrefSearchSize bytes str->setPos(xrefSearchSize, -1); for (n = 0; n < xrefSearchSize; ++n) { if ((c = str->getChar()) == EOF) { break; } buf[n] = c; } buf[n] = '\0'; // find startxref for (i = n - 9; i >= 0; --i) { if (!strncmp(&buf[i], "startxref", 9)) { break; } } if (i < 0) { return 0; } for (p = &buf[i+9]; isspace(*p); ++p) ; lastXRefPos = strToUnsigned(p); return lastXRefPos;}// Read one xref table section. Also reads the associated trailer// dictionary, and returns the prev pointer (if any).GBool XRef::readXRef(Guint *pos) { Parser *parser; Object obj; GBool more; // start up a parser, parse one token obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + *pos, gFalse, 0, &obj)), gTrue); parser->getObj(&obj); // parse an old-style xref table if (obj.isCmd("xref")) { obj.free(); more = readXRefTable(parser, pos); // parse an xref stream } else if (obj.isInt()) { obj.free(); if (!parser->getObj(&obj)->isInt()) { goto err1; } obj.free(); if (!parser->getObj(&obj)->isCmd("obj")) { goto err1; } obj.free(); if (!parser->getObj(&obj)->isStream()) { goto err1; } more = readXRefStream(obj.getStream(), pos); obj.free(); } else { goto err1; } delete parser; return more; err1: obj.free(); delete parser; ok = gFalse; return gFalse;}GBool XRef::readXRefTable(Parser *parser, Guint *pos) { XRefEntry entry; GBool more; Object obj, obj2; Guint pos2; int first, n, newSize, i; while (1) { parser->getObj(&obj); if (obj.isCmd("trailer")) { obj.free(); break; } if (!obj.isInt()) { goto err1; } first = obj.getInt(); obj.free(); if (!parser->getObj(&obj)->isInt()) { goto err1; } n = obj.getInt(); obj.free(); if (first < 0 || n < 0 || first + n < 0) { goto err1; } if (first + n > size) { for (newSize = size ? 2 * size : 1024; first + n > newSize && newSize > 0; newSize <<= 1) ; if (newSize < 0) { goto err1; } entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; } size = newSize; } for (i = first; i < first + n; ++i) { if (!parser->getObj(&obj)->isInt()) { goto err1; } entry.offset = (Guint)obj.getInt(); obj.free(); if (!parser->getObj(&obj)->isInt()) { goto err1; } entry.gen = obj.getInt(); obj.free(); parser->getObj(&obj); if (obj.isCmd("n")) { entry.type = xrefEntryUncompressed; } else if (obj.isCmd("f")) { entry.type = xrefEntryFree; } else { goto err1; } obj.free(); if (entries[i].offset == 0xffffffff) { entries[i] = entry; // PDF files of patents from the IBM Intellectual Property // Network have a bug: the xref table claims to start at 1 // instead of 0. if (i == 1 && first == 1 && entries[1].offset == 0 && entries[1].gen == 65535 && entries[1].type == xrefEntryFree) { i = first = 0; entries[0] = entries[1]; entries[1].offset = 0xffffffff; } } } } // read the trailer dictionary if (!parser->getObj(&obj)->isDict()) { goto err1; } // get the 'Prev' pointer obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { *pos = (Guint)obj2.getInt(); more = gTrue; } else if (obj2.isRef()) { // certain buggy PDF generators generate "/Prev NNN 0 R" instead // of "/Prev NNN" *pos = (Guint)obj2.getRefNum(); more = gTrue; } else { more = gFalse; } obj2.free(); // save the first trailer dictionary if (trailerDict.isNone()) { obj.copy(&trailerDict); } // check for an 'XRefStm' key
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -