/* * PDFedit - free program for PDF document manipulation. * Copyright (C) 2006, 2007 PDFedit team: Michal Hocko, * Miroslav Jahoda, * Jozef Misutka, * Martin Petricek * * Project is hosted on http://sourceforge.net/projects/pdfedit */ // vim:tabstop=4:shiftwidth=4:noexpandtab:textwidth=80 #ifndef _CXREF_H_ #define _CXREF_H_ /* * $RCSfile: cxref.h,v $ * * $Log: cxref.h,v $ * Revision 1.28 2007/04/25 18:24:35 bilboq * * applied patch from Martin Michlmayr to fix compilation with gcc-4.3 * * fixed some typos in comments * * Revision 1.27 2007/02/04 20:17:02 mstsxfx * Common Licence comment for all cc and h files available in doc/licence_header * file and its content to all cc and h files in src/{gui,kernel,utils} * directories. * Xpdf code, QSA and QOutputDevice code are not touched * * Revision 1.26 2006/07/12 18:27:17 hockm0bm * minor changes - code comments etc. * * Revision 1.25 2006/06/01 14:46:24 hockm0bm * doc update - doxygen warnings removed (if possible) * * Revision 1.24 2006/05/13 21:41:02 hockm0bm * * log messages update * * cleanUp reimplemented * - doesn't use remove message on changedStorage * * reserveRef and newStorage * - uses RefState * * Revision 1.23 2006/05/10 16:59:05 hockm0bm * * changeObject throws if instance->clone fails * * changeTrailer throws if value->clone fails * - plus cloning is done * * getTrailerEntry throws if value can't be cloned * * getDocInfo throws if value can't be cloned * * getDocInfoNF throws if value can't be cloned * * fetch throws if value can't be cloned * * Revision 1.22 2006/05/09 20:06:43 hockm0bm * * stored field removed from ChangedEntry * * doc update * * Revision 1.21 2006/05/08 10:34:04 hockm0bm * * reserveRef throws exception if no indirect object is available * * fetch always returns cloned value (because of streams) * * Revision 1.20 2006/05/01 10:03:01 hockm0bm * MAXOBJNUM value corrected to MAX_INT * * Revision 1.19 2006/04/28 17:16:51 hockm0bm * * reserveRef bug fixes * - reusing didn't check whether reference is in newStorage * - also not realy free entries were considered (XRef marks * all entries as free by default and allocates entries array * by blocks, so all behind last real objects are free too but * they are not free in pdf) * - gen number is not increase if reusing entry * - gen number == MAXOBJGEN is never reused * * MAXOBJNUM constant added * * MAXOBJGEN constant added * * Revision 1.18 2006/04/27 18:09:34 hockm0bm * * cleanUp method added * * debug messages minor changes * * changeTrailer handles trailer->update used correctly (key parameter) * * correct Object instancing * * Revision 1.17 2006/04/20 22:35:44 hockm0bm * typeSafe is firtual now to enable XRefWriter transparent overloading * * Revision 1.16 2006/04/19 06:01:59 hockm0bm * reopen signature changed to enable jumping to start from specified offset * - synchronization with XRef::initInternals method * * Revision 1.15 2006/04/15 08:04:43 hockm0bm * reserveRef and createObject are protected now * * Revision 1.14 2006/04/13 18:15:02 hockm0bm * * releaseStorage removed * * releaseObject method removed * * Revision 1.13 2006/04/12 17:48:46 hockm0bm * reopen method added * - not implemented yet - throws an exception * * Revision 1.12 2006/03/23 22:13:51 hockm0bm * printDbg added * exception handling * TODO removed * FIXME for revisions handling - throwing exeption * * Revision 1.11 2006/03/10 18:07:14 hockm0bm * reserveRef method added * createObject uses reserveRef * one FIXME in createObject - commented * * Revision 1.10 2006/03/08 12:10:12 misuj1am * * * -- precompiled headers support * * Revision 1.9 2006/03/06 18:18:55 hockm0bm * compilable changes - each module is compilable now * each object in pdfobjects namespace * more comments * cpdf - most of methods are just comments how to implement * * Revision 1.8 2006/02/28 19:19:26 hockm0bm * changeStorage changed - Object is associated with stored flag * getNumObjects - reimplemented (only initialized objects) * * Revision 1.7 2006/02/13 21:11:54 hockm0bm * Implementation of the class moved to cc file * fetch method prepared for cache * * Revision 1.6 2006/02/12 17:19:07 hockm0bm * first implementation (compileable) - not for real use * * Revision 1.4 2006/01/29 21:18:15 hockm0bm * minor changes for compilation (TODOs and FIXME comments) * */ // xpdf #include "xpdf.h" #include"iproperty.h" #include namespace pdfobjects { /** Maximal object number. */ const int MAXOBJNUM = INT_MAX; /** Maximal object generation number. * * Cross reference entry with this generation number can't be reused. */ const int MAXOBJGEN = 65535; /** Adapter for xpdf XRef class. * * This class has responsibility to transparently (same way as XRef do) provide * objects synchronized with changes. *
* Class works in three layers: * * Each request to XRef inherited interface, which manipulates with object which * can change, asks Maintaining layer at first. If it is not able to to get * required object, xpdf layer is used (delegates to super type). *
* Methods which produces changes are protected to prevent changing in gui, if * kernel wants to make changes, it should use XrefWriter subclass which * delegates functionality to inherited protected methods and adds some * checking. *

* We have prepared XRef implementation to be virtual, so there is no problem to * use CXref instance as XRef in rest of xpdf code. Initialization of xref from * file (respectively from basestream) is done only by xpdf layer (if no changes * are done to the file - Maintaining layer doesn't contain any additional * information than after CXref initialization). *
* Because, in fact, all object which can be changed (we are meaning change * value inside Object instance) has to be indirect Object, obj and gen number * are used as identificators, when objects are stored to the ObjectStorage. So * when someone wants to change object value using changeObject method, he has * to suply also obj and gen numbers. * Only one exception in pdf format is trailer, which is not indirect object and * this can be changed using changeTrailer method. This method can change * entries in trailer. If user whants to change indirect object values stored * in trailer, it can be done in standard way as any other objects. *

* Objects returned by this interface are always deep copies of original object * stored inside and changes made to them are not visible through this interface * until changeObject or changeTrailer is called. * */ class CXref: public XRef { private: //ObjectCache * cache=NULL; /**< Cache for objects. */ protected: /** Empty constructor. * * This constructor is protected to prevent uninitialized instances. * We need at least to specify stream with data. */ CXref(): XRef(NULL){} /** Entry for ObjectStorage. * * Each entry contains pointer to changed object. It may be extended in * future, so structure is used. */ typedef struct { ::Object * object; } ObjectEntry; /** Object storage for changed objects. * Mapping from object referencies to the ObjectEntry structure. * This structure contains new Object value for reference and * flag. */ ObjectStorage< ::Ref, ObjectEntry*, RefComparator> changedStorage; /** Object storage for newly created objects. * Value is the flag of newly created reference. When new entry is added, it * should have Reserved state and when changed for the first time * Initialized. Unused is default value for not found, so unknown * (ObjectStorage returns 0 if entry is not found). */ ObjectStorage< ::Ref, RefState, RefComparator> newStorage; /** Registers change in given object addressable through given * reference. * @param ref Object reference identificator. * @param instance Instance of object value (must be direct value, * not indirect reference). * * Discards object from cache and stores given to the changedStorage. * Method should be called each time when object has changed its value. * Object value is copied not use as it is (creates deep copy by clone * method). *
* If object with same reference already was in changedStorage, this * is returned to enable history handling (and also to deallocate it). * 0 return value means first change of object. *
* If given reference is in newStorage, value is set to true to * signalize that value has been changed after object has been created. *
* Note that this function doesn't perform any value ckecking. * * @throw NotImplementedException if object cloning fails. * * @return Old value of object from changedStorage or NULL if it's first * revision of object - caller is responsible for deallocation. */ ::Object * changeObject(::Ref ref, ::Object * instance); /** Changes entry in trailer dictionary. * @param name Name of the value. * @param value Value to be set. * * Makes changes to the trailer dictionary. If given value is indirect * reference, it must be known. *
* NOTE: doesn't perform any value checking. * * @throw NotImplementedException if object cloning fails. * @return Previous value of object or 0 if previous revision not * available (new name value pair in trailer). */ ::Object * changeTrailer(const char * name, ::Object * value); /** Reinitializes all internal structures. * @param xrefOff Offset of cross reference table from which to start. * * Clears all internal structures and forces XRef super type to throw away * all internal structures too and parse them again from stream starting * from given position. *
* This method should be called if new revision is appended to the stream. * Otherwise all information about changes are lost! */ void reopen(size_t xrefOff); /** Reserves reference for new indirect object. * * Searches for free object number and generation number and uses * it to register reference for new indirect object. Reference is stored * to the newStorage with Reserved flag. This is changed to Initialized if * real object is stored to the CXref (using change method). *
* Created object is accesible only if default value has been changed. * This means that returned object has to be changed and after change * method has to be called. This is mainly because we want to prevent * unintialized object inside. *
* TODO reuse strathegy - REUSE_FIRST, REUSE_AFTER, NOREUSE * * @throw IndirectObjectsExhausted if all object numbers has been used. * @return Reference which can be used to add new indirect object. */ virtual ::Ref reserveRef(); /** Creates new xpdf indirect object. * @param type Type of the object. * @param ref Structure where to put object num and gen (if null, * nothing is set). * * New reference is registered using reserveRef method. This is just * wrapper method to reserveRef with object initialization capability. * *
* Implementation will initialize Object with type and value depending * on type: *

* To change value of the object, use init{Type} method then call * change method to register change and makes object visible by * fetch method. *
* Returned object has to be deallocated by Object::free and gfree methods * (first one for value deallocation and second for Object instance itself) * or by pdfobjects::utils::freeXpdfObject method. * * @return Object instance with given type or 0 if not able to create. */ virtual ::Object * createObject(::ObjType type, ::Ref * ref); /** Deallocates all internal structures. * * Cleanes up chnagedStorage and deallocates all its entries. *
* This method is responsible for deallocation of all internal structures * specific for CXref. */ void cleanUp(); public: /** Initialize constructor. * @param stream Stream with file data. * * Delegates to XRef constructor with same parameter. * * @throw MalformedFormatExeption if XRef creation fails (instance is * unusable in such situation). */ CXref(BaseStream * stream):XRef(stream) { if(getErrorCode() !=errNone) { // xref is corrupted throw MalformedFormatExeption("XRef parsing problem errorCode="+getErrorCode()); } } /** Initialize constructor with cache. * @param stream Stream with file data. * @param c Cache instance. * * Delegates to XRef constructor with the stream parameter and * sets cache instance. * * @throw MalformedFormatExeption if XRef creation fails (instance is * unusable in such situation). */ /* FIXME uncoment when cache is available CXref(BaseStream * stream, ObjectCache * c):XRef(stream), cache(c) { if(getErrorCode() !=errNone) { // xref is corrupted throw MalformedFormatExeption("XRef parsing problem errorCode="+getErrorCode); } } */ /** Destructor. * * Calls cleanUp for all internals deallocation and deletes stream. */ virtual ~CXref(); /** Checks if given reference is known. * @param ref Reference to check. * * Checks if reference is present in newStorage. If found, returns status * stored in newStorage. If not found, searches XRef::entries array. * * @see UNUSED_REF * @see RESERVED_REF * @see INITIALIZED_REF * @return Current state of given reference. */ virtual RefState knowsRef(::Ref ref); /** Checks if given reference is known. * @param ref Reference to check. * * Calls knowsRef(::Ref) method. This is just for easy to use wrapper for * non xpdf code. * * @see knowsRef(::Ref) * * @return reference current state. */ virtual RefState knowsRef(IndiRef ref) { ::Ref xpdfRef={ref.num, ref.gen}; return knowsRef(xpdfRef); } /** Checks whether obj1 can replace obj2. * @param obj1 Original object. * @param obj2 Replace object. * * obj2 can replace obj1 only iff at least 1 condition is true: * * * This means that in indirect value can replace direct one only * if both have same value type. * * @return true if obj2 can replace obj1, false otherwise. */ virtual bool typeSafe(::Object * obj1, ::Object * obj2); /** Gets value associated with name in trailer. * @param name Name of the entry. * * If value is indirect reference (according specification almost all * compound entries), reference is returned, so normal xref interface * can be used to ask for value. * If no value with given name can be found, objNull type object is * returned. *
* Changes made to returned object doesn't affect trailer entry with * given name. * * @return Deep copy of the object value. */ virtual ::Object * getTrailerEntry(char * name); // Returns the document's Info dictionary (if any). // @throw NotImplementedException if object cloning fails. virtual ::Object *getDocInfo(::Object *obj); // Returns the document's Info dictionary (dereferenced // if indirect value // @throw NotImplementedException if object cloning fails. virtual ::Object *getDocInfoNF(::Object *obj); /** Returns number of indirect objects. * * Delegates to XRef::getNumObjects and adds also number of all * newly inserted (and initialized) objects. * * @return Total number of objects. */ virtual int getNumObjects(); /** Fetches object. * @param num Object number. * @param gen Object generation. * @param obj Object where to store content. * * Try to find object in changedStorage and if not found, delegates * to original implementation. *
* NOTE: * Returned value is deepCopy of object and changes made to object * don't affect internally maintained values (e.g. it can and should be * deallocated by caller). * To register a change use change method. *
* This method provide transparent access to changed objects throught * XRef (xpdf class) interface. * * @throw NotImplementedException if object cloning fails. * @return Pointer with initialized object given as parameter, if not * found obj is set to objNull. */ virtual ::Object * fetch(int num, int gen, ::Object *obj); }; } // end of pdfobjects namespace #endif // _CXREF_H_