? glib/poppler-features.h Index: poppler/Dict.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Dict.cc,v retrieving revision 1.4 diff -u -8 -p -r1.4 Dict.cc --- poppler/Dict.cc 18 Jan 2006 22:32:13 -0000 1.4 +++ poppler/Dict.cc 15 Aug 2006 14:08:45 -0000 @@ -50,16 +50,47 @@ void Dict::add(const UGooString &key, Ob } entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); } entries[length].key = new UGooString(key); entries[length].val = *val; ++length; } +void Dict::remove(const UGooString &key) { + int i; + bool found = false; + DictEntry tmp; + if(length == 0) return; + + for(i=0; ival.free(); + e->val = *val; + } else { + add (key, val); + } +} + inline DictEntry *Dict::find(const UGooString &key) { int i; for (i = 0; i < length; ++i) { if (!key.cmp(entries[i].key)) return &entries[i]; } return NULL; Index: poppler/Dict.h =================================================================== RCS file: /cvs/poppler/poppler/poppler/Dict.h,v retrieving revision 1.3 diff -u -8 -p -r1.3 Dict.h --- poppler/Dict.h 18 Jan 2006 22:32:13 -0000 1.3 +++ poppler/Dict.h 15 Aug 2006 14:08:45 -0000 @@ -38,16 +38,20 @@ public: int incRef() { return ++ref; } int decRef() { return --ref; } // Get number of entries. int getLength() { return length; } // Add an entry void add(const UGooString &key, Object *val); + // Update the value of an existing entry, otherwise create it + void set(const UGooString &key, Object *val); + // Remove an entry. This invalidate indexes + void remove(const UGooString &key); // Check if dictionary is of specified type. GBool is(char *type); // Look up an entry and return the value. Returns a null object // if is not in the dictionary. Object *lookup(const UGooString &key, Object *obj); Object *lookupNF(const UGooString &key, Object *obj); Index: poppler/Object.h =================================================================== RCS file: /cvs/poppler/poppler/poppler/Object.h,v retrieving revision 1.2 diff -u -8 -p -r1.2 Object.h --- poppler/Object.h 18 Jan 2006 22:32:13 -0000 1.2 +++ poppler/Object.h 15 Aug 2006 14:08:45 -0000 @@ -160,16 +160,17 @@ public: int arrayGetLength(); void arrayAdd(Object *elem); Object *arrayGet(int i, Object *obj); Object *arrayGetNF(int i, Object *obj); // Dict accessors. int dictGetLength(); void dictAdd(const UGooString &key, Object *val); + void dictSet(const UGooString &key, Object *val); GBool dictIs(char *dictType); Object *dictLookup(const UGooString &key, Object *obj); Object *dictLookupNF(const UGooString &key, Object *obj); UGooString *dictGetKey(int i); Object *dictGetVal(int i, Object *obj); Object *dictGetValNF(int i, Object *obj); // Stream accessors. @@ -237,16 +238,19 @@ inline Object *Object::arrayGetNF(int i, #include "Dict.h" inline int Object::dictGetLength() { return dict->getLength(); } inline void Object::dictAdd(const UGooString &key, Object *val) { dict->add(key, val); } +inline void Object::dictSet(const UGooString &key, Object *val) + { dict->set(key, val); } + inline GBool Object::dictIs(char *dictType) { return dict->is(dictType); } inline GBool Object::isDict(char *dictType) { return type == objDict && dictIs(dictType); } inline Object *Object::dictLookup(const UGooString &key, Object *obj) { return dict->lookup(key, obj); } Index: poppler/PDFDoc.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/PDFDoc.cc,v retrieving revision 1.10 diff -u -8 -p -r1.10 PDFDoc.cc --- poppler/PDFDoc.cc 18 Jan 2006 22:32:13 -0000 1.10 +++ poppler/PDFDoc.cc 15 Aug 2006 14:08:46 -0000 @@ -464,23 +464,193 @@ GBool PDFDoc::isLinearized() { GBool PDFDoc::saveAs(GooString *name) { FILE *f; int c; if (!(f = fopen(name->getCString(), "wb"))) { error(-1, "Couldn't open file '%s'", name->getCString()); return gFalse; } - str->reset(); - while ((c = str->getChar()) != EOF) { - fputc(c, f); + + + + + fprintf(f, "%%PDF-%.1f\r\n",pdfVersion); + XRef *uxref = new XRef(); + uxref->add(0, 65535, 0, gFalse); + for(int i=0; igetNumObjects(); i++) { + Object obj1; + Ref ref; + if (xref->getEntry(i)->type == xrefEntryFree) { + ref.num = i; + ref.gen = xref->getEntry(i)->gen; + /* the XRef class add a lot of unrelevant free entries, we only want the significant one + and we don't want the one with num=0 because it has already been added (gen = 65535)*/ + if (ref.gen > 0 && ref.num > 0) + uxref->add(ref.num, ref.gen, 0, gFalse); + } else { + ref.num = i; + ref.gen = xref->getEntry(i)->gen; + xref->fetch(ref.num, ref.gen, &obj1); + Guint offset = writeObject(&obj1, &ref, f); + uxref->add(ref.num, ref.gen, offset, gTrue); + obj1.free(); + } } - str->close(); + Guint uxrefOffset = ftell(f); + uxref->writeToFile(f); + + Ref catRef; + catRef.gen = xref->getRootGen(); + catRef.num = xref->getRootNum(); + writeTrailer(uxrefOffset, uxref->getSize(), f, &catRef); + fclose(f); + delete uxref; return gTrue; } +void PDFDoc::writeDictionnary (Dict* dict, FILE *file) +{ + Object obj1; + fprintf(file,"<< "); + for (int i=0; igetLength(); i++) { + fprintf(file,"/%s ", dict->getKey(i)->getCString()); + writeObject(dict->getValNF(i, &obj1), NULL, file); + fprintf(file,"\r\n"); + + obj1.free(); + } + fprintf(file,">>\r\n"); +} + +void PDFDoc::writeStream (Stream* str, FILE *file) +{ + int c; + fprintf(file,"stream\r\n"); + str->reset(); + for (int c=str->getChar(); c!= EOF; c=str->getChar()) { + fprintf(file,"%c", c); + } + fprintf(file,"\r\nendstream\r\n"); +} + +void PDFDoc::writeString (GooString* s, FILE* file) +{ + //write hexa string + const char* c = s->getCString(); + fprintf(file, "<"); + while(*c!='\0') { + fprintf(file, "%02x", *c); + c++; + } + fprintf(file, "> "); +} + +Guint PDFDoc::writeObject (Object* obj, Ref* ref, FILE *file) +{ + Array *array; + Object obj1; + Guint offset = ftell(file); + int tmp; + + if(ref) + fprintf(file,"%i %i obj\r\n", ref->num, ref->gen); + + switch (obj->getType()) { + case objBool: + fprintf(file,"%s ", obj->getBool()?"true":"false"); + break; + case objInt: + fprintf(file,"%i ", obj->getInt()); + break; + case objReal: + fprintf(file,"%f ", obj->getReal()); + break; + case objString: + writeString(obj->getString(), file); + break; + case objName: + fprintf(file,"/%s ", obj->getName()); + break; + case objNull: + fprintf(file, "null\r\n"); + break; + case objArray: + array = obj->getArray(); + fprintf(file,"["); + for (int i=0; igetLength(); i++) { + writeObject(array->getNF(i, &obj1), NULL,file); + obj1.free(); + } + fprintf(file,"]"); + break; + case objDict: + writeDictionnary (obj->getDict(),file); + break; + case objStream: + //we write the stream unencoded => TODO: write stream encoder + obj->getStream()->reset(); + //recalculate stream length + tmp = 0; + for (int c=obj->getStream()->getChar(); c!=EOF; c=obj->getStream()->getChar()) { + tmp++; + } + obj1.initInt(tmp); + obj->getStream()->getDict()->set("Length", &obj1); + + //Remove Stream encoding + obj->getStream()->getDict()->remove("Filter"); + obj->getStream()->getDict()->remove("DecodeParms"); + + writeDictionnary (obj->getStream()->getDict(),file); + writeStream (obj->getStream(),file); + obj1.free(); + break; + case objRef: + fprintf(file,"%i %i R ", obj->getRef().num, obj->getRef().gen); + break; + case objCmd: + fprintf(file,"null\r\n"); + break; + case objError: + fprintf(file,"null\r\n"); + break; + case objEOF: + fprintf(file,"null\r\n"); + break; + case objNone: + fprintf(file,"null\r\n"); + break; + default: + error(-1,"Unhandled objType : %i, please report a bug with a testcase\r\n", obj->getType()); + break; + } + if (ref) + fprintf(file,"endobj\r\n\r\n"); + return offset; +} + +void PDFDoc::writeTrailer (Guint uxrefOffset, int uxrefSize, FILE* f, Ref* rootRef) +{ + Dict* trailerDict = xref->getTrailerDict()->getDict(); + Object obj1; + obj1.initInt(uxrefSize); + trailerDict->set("Size", &obj1); + obj1.free(); + if(rootRef) { + obj1.initRef(rootRef->num, rootRef->gen); + trailerDict->set("Root", &obj1); + obj1.free(); + } + fprintf(f, "trailer\r\n"); + writeDictionnary(trailerDict, f); + fprintf(f, "startxref\r\n"); + fprintf(f, "%i\r\n", uxrefOffset); + fprintf(f, "%%%%EOF\r\n"); +} + void PDFDoc::getLinks(Page *page) { Object obj; links = new Links(page->getAnnots(&obj), catalog->getBaseURI()); obj.free(); } Index: poppler/PDFDoc.h =================================================================== RCS file: /cvs/poppler/poppler/poppler/PDFDoc.h,v retrieving revision 1.7 diff -u -8 -p -r1.7 PDFDoc.h --- poppler/PDFDoc.h 18 Jan 2006 22:32:13 -0000 1.7 +++ poppler/PDFDoc.h 15 Aug 2006 14:08:46 -0000 @@ -165,16 +165,22 @@ public: // Save this file with another name. GBool saveAs(GooString *name); // Return a pointer to the GUI (XPDFCore or WinPDFCore object). void *getGUIData() { return guiData; } private: + // Add object to current file stream and return the offset of the beginning of the object + Guint writeObject (Object *obj, Ref *ref, FILE* f); + void writeDictionnary (Dict* dict, FILE* f); + void writeStream (Stream* str, FILE* f); + void writeTrailer (Guint uxrefOffset, int uxrefSize, FILE* f, Ref* rootRef); + void writeString (GooString* s, FILE* f); GBool setup(GooString *ownerPassword, GooString *userPassword); GBool checkFooter(); void checkHeader(); GBool checkEncryption(GooString *ownerPassword, GooString *userPassword); void getLinks(Page *page); GooString *fileName; Index: poppler/XRef.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/XRef.cc,v retrieving revision 1.13 diff -u -8 -p -r1.13 XRef.cc --- poppler/XRef.cc 1 Apr 2006 11:25:57 -0000 1.13 +++ poppler/XRef.cc 15 Aug 2006 14:08:47 -0000 @@ -196,16 +196,28 @@ Object *ObjectStream::getObject(int objI } return objs[objIdx].copy(obj); } //------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ +XRef::XRef() { + ok = gTrue; + errCode = errNone; + entries = NULL; + size = 0; + streamEnds = NULL; + streamEndsLen = 0; + objStr = NULL; + for (int i=0; isetXRef(this); } XRef::~XRef() { + for (int i=0; i= size) { goto err; } + + //check for updated object + if(objectsPool[num] != NULL) { + objectsPool[num]->copy(obj); + return obj; + + } e = &entries[num]; switch (e->type) { case xrefEntryUncompressed: if (e->gen != gen) { goto err; } @@ -962,8 +985,54 @@ Guint XRef::strToUnsigned(char *s) { int i; x = 0; for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { x = 10 * x + (*p - '0'); } return x; } + +void XRef::add(int num, int gen, Guint offs, GBool used) { + size += 1; + entries = (XRefEntry *)greallocn(entries, size, sizeof(XRefEntry)); + entries[size-1].offset = offs; + entries[size-1].gen = gen; + entries[size-1].num = num; + if (used) + entries[size-1].type = xrefEntryUncompressed; + else + entries[size-1].type = xrefEntryFree; +} + +void XRef::setModifiedObject (Object* o, Ref r) { + if (r.num < 0 || r.num >= size) { + error(-1,"XRef::setModifiedObject on unknown ref: %i, %i\n", r.num, r.gen); + return; + } + + objectsPool[r.num] = new Object(); + o->copy(objectsPool[r.num]); +} + +//used to sort the entries +int compare (const void* a, const void* b) +{ + return (((XRefEntry*)a)->num - ((XRefEntry*)b)->num); +} + +void XRef::writeToFile(FILE* file) { + qsort(entries, size, sizeof(XRefEntry), compare); + int j; + fprintf(file,"xref\r\n"); + for (int i=0; i array int rootNum, rootGen; // catalog dict @@ -120,16 +130,17 @@ private: ObjectStream *objStr; // cached object stream GBool encrypted; // true if file is encrypted int encRevision; int encVersion; // encryption algorithm int keyLength; // length of key, in bytes int permFlags; // permission bits Guchar fileKey[16]; // file decryption key GBool ownerPasswordOk; // true if owner password is correct + Object* objectsPool[XREF_SIZE]; //list of updated objects, indexed by number Guint getStartXref(); GBool readXRef(Guint *pos); GBool readXRefTable(Parser *parser, Guint *pos); GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); GBool readXRefStream(Stream *xrefStr, Guint *pos); GBool constructXRef(); Guint strToUnsigned(char *s);