/* * 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 /* * $RCSfile: cxref.cc,v $ * * $Log: cxref.cc,v $ * Revision 1.26 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.25 2006/07/12 18:27:14 hockm0bm * minor changes - code comments etc. * * Revision 1.24 2006/06/27 18:19:48 hockm0bm * code formating - no code changed * * Revision 1.23 2006/06/27 17:27:49 hockm0bm * cosmetic changes * - post-incrementation replaced by pre-incrementation (for performance) * - thx to Jozo * * Revision 1.22 2006/06/25 16:25:08 hockm0bm * doc update - doxygen warnings removed (if they are real problem) * * Revision 1.21 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.20 2006/05/11 21:04:33 hockm0bm * doc update * * Revision 1.19 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.18 2006/05/09 20:06:43 hockm0bm * * stored field removed from ChangedEntry * * doc update * * Revision 1.17 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.16 2006/05/06 08:39:28 hockm0bm * knowsRef delegates to XRef::knowsRef if reference not available in newStorage * * Revision 1.15 2006/05/05 11:55:55 petrm1am * * Commiting changes sent by Michal: * * cpdf.cc: * * consolidatePageList bug fixed * - difference += pageCount not -= * * debug messages improved * * cxref.cc: * * reserveRef bug fix * - totalCount replaced by xrefCount from XRef::getNumObjects * - num is initialized to -1 * - kernelPrintDbg message wrong position (cannot use new entry) * * Revision 1.14 2006/05/01 13:53:07 hockm0bm * new style printDbg * * Revision 1.13 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.12 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.11 2006/04/23 22:03:40 hockm0bm * reopen sets lastXRefPos to given offset * * Revision 1.10 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.9 2006/04/17 17:45:47 hockm0bm * bug in knowsRef corrected * - checking for object number added when accessing XRef::entries * * Revision 1.8 2006/04/15 08:04:43 hockm0bm * reserveRef and createObject are protected now * * Revision 1.7 2006/04/13 18:15:02 hockm0bm * * releaseStorage removed * * releaseObject method removed * * Revision 1.6 2006/03/31 16:09:56 hockm0bm * printDbg messages with ref changed * * Revision 1.5 2006/03/23 22:13:51 hockm0bm * printDbg added * exception handling * TODO removed * FIXME for revisions handling - throwing exeption * * */ #include "cxref.h" #include "utils/debug.h" #include "factories.h" using namespace pdfobjects; void CXref::cleanUp() { using namespace debug; kernelPrintDbg(DBG_DBG, ""); // deallocates changed storage // goes through all elemenents, erases all of them and deallocates value // returned from remove object (iterators are not invalidated by remove // method) kernelPrintDbg(DBG_DBG, "Deallocating changedStorage (size="<::Iterator i; int index=0; for(i=changedStorage.begin(); i!=changedStorage.end(); ++i) { ::Ref ref=i->first; ObjectEntry * entry=i->second; // check for entry if(!entry) { // this shouldn't happen kernelPrintDbg(DBG_ERR, ref<<" doesn't have entry. (index="<object) { // this shouldn't happen kernelPrintDbg(DBG_ERR, ref<<" entry doesn't have an object (index="<second=NULL; continue; } kernelPrintDbg(DBG_DBG, "Deallocating entry for "<object); delete entry; i->second=NULL; } changedStorage.clear(); kernelPrintDbg(DBG_DBG, "changedStorage cleaned up"); kernelPrintDbg(DBG_DBG, "Cleaning newStorage"); // newStorage doesn't need special entries deallocation newStorage.clear(); kernelPrintDbg(DBG_DBG, "newStorage cleaned up"); } CXref::~CXref() { using namespace debug; kernelPrintDbg(DBG_DBG, ""); /* FIXME: uncoment when cache is ready. if(cache) { kernelPrintDbg(DBG_INFO, "Deallocating cache"); delete cache; } */ kernelPrintDbg(DBG_INFO, "Deallocating internal structures"); cleanUp(); // XRef doesn't deallocate stream, so it has to be deallocated here delete str; } ::Object * CXref::changeObject(::Ref ref, ::Object * instance) { using namespace debug; kernelPrintDbg(DBG_DBG, ref); assert(ref.num!=0); // discards from cache /* FIXME uncoment if cache is available if(cache) cache->discard(ref); */ // clones given object Object * clonedObject=instance->clone(); if(!clonedObject) { // cloning has failed kernelPrintDbg(DBG_ERR, "Object can't be cloned."); throw NotImplementedException("clone failure."); } // searches in changedStorage // this is returned so it can be used for some // history information - value keeper is responsible for // deallocation ObjectEntry * changedEntry = changedStorage.get(ref); ::Object * changed=(changedEntry)?changedEntry->object:NULL; // if changedEntry is NULL - object is changed for the first time // we have to allocate entry, otherwise, just sets new object // value and reset stored to false if(!changedEntry) { changedEntry=new ObjectEntry(); kernelPrintDbg(DBG_DBG, "object is changed for the first time, creating changedEntry"); } changedEntry->object=clonedObject; assert(ref.num!=0); // return value - original one - can be safely ignored, because either new // entry is inserted or one from storage is changed directly changedStorage.put(ref, changedEntry); // object has been newly created, so we will set value in // the newStorage to true (so we know, that the value has // been set after initialization) if(newStorage.contains(ref)) { newStorage.put(ref, INITIALIZED_REF); kernelPrintDbg(DBG_DBG, "newStorage entry changed to INITIALIZED_REF for "<update(key, clonedObject); // update doesn't store key if key, value has been already in the // dictionary if(prev) free(key); return prev; } ::Ref CXref::reserveRef() { using namespace debug; int i=1; int num=-1, gen; kernelPrintDbg(DBG_DBG, ""); // goes through entries array in XRef class (xref entries) // and reuses first free entry with its gen number. // Considers just first XRef::getNumObjects because entries array // is allocated by blocks and so there are entries which are marked // as free but they are not realy removed objects. int objectCount=0, xrefCount=XRef::getNumObjects(); for(; i=MAXOBJGEN) { kernelPrintDbg(DBG_DBG, "Entry ["<UNUSED_REF) { kernelPrintDbg(DBG_DBG, "Reference is in newStorage. state="<getType(), type2=obj2->getType(); // checks indirect if(type1==objRef) { kernelPrintDbg(DBG_DBG, "obj1 is reference - need to dereference"); fetch(dObj1.getRef().num, dObj1.getRef().gen, &dObj1); type1=dObj1.getType(); kernelPrintDbg(DBG_DBG, "obj1 target type="<< type1); // has to free object dObj1.free(); } if(type2==objRef) { kernelPrintDbg(DBG_DBG, "obj2 is reference - need to dereference"); fetch(dObj2.getRef().num, dObj2.getRef().gen, &dObj2); type2=dObj2.getType(); kernelPrintDbg(DBG_DBG, "obj2 target type="<< type2); // has to free object dObj2.free(); } // now we have direct values' types bool ret=type1==type2; // if these types are not same, one additional situation may occure: // obj1 is objRef (it is indirect) and dereferenced object is objNull // (it is not present in pdf). In such situation, type2 // can be everything - other direction (obj1 is whatever and obj2 is objNull // is not allowed) if(!ret && (obj1->getType() == objRef && type1 == objNull)) ret=true; kernelPrintDbg(DBG_DBG, "typeSafe result="<object; if(!object) { // this shouldn't not happen // TODO handle - exception should be called kernelPrintDbg(DBG_CRIT, "Changed object is NULL!"); return obj; } ::Object * deepCopy=entry->object->clone(); // shallow copy of content // content is deep copy of found object, so // this doesn't affect our ::Object in changedStorage *obj=*deepCopy; // dellocate deepCopy - content is kept gfree(deepCopy); return obj; } // delegates to original implementation kernelPrintDbg(DBG_INFO, ref<<" is not changed - using Xref"); Object tmpObj; XRef::fetch(num, gen, &tmpObj); // clones fetched object // this has to be done because return value may be stream and we want to // prevent direct changing of the stream Object * cloneObj=tmpObj.clone(); // deallocates XRef returned object content tmpObj.free(); if(!cloneObj) { // cloning has failed kernelPrintDbg(DBG_ERR, "Object can't be cloned. Uses objNull instead"); throw NotImplementedException("clone failure."); } // shallow copy of cloned value and // deallocates coned value, but keeps content *obj=*cloneObj; gfree(cloneObj); // if object is not null, caches object's deep copy /* FIXME uncoment, when cache is ready if(cache && obj->getType()!=objNull) { kernelPrintDbg(DBG_DBG, "Caching object "[num="<put(ref, obj->clone()); } */ return obj; } int CXref::getNumObjects() { using namespace debug; kernelPrintDbg(DBG_DBG, ""); size_t newSize=0; ObjectStorage< ::Ref, RefState, RefComparator>::Iterator begin, i; for(i=newStorage.begin(); i!=newStorage.end(); ++i) if(i->second==INITIALIZED_REF) ++newSize; kernelPrintDbg(DBG_INFO, "original objects count="<