Index: glib/poppler-action.cc =================================================================== RCS file: /cvs/poppler/poppler/glib/poppler-action.cc,v retrieving revision 1.9 diff -u -r1.9 poppler-action.cc --- glib/poppler-action.cc 19 May 2006 22:26:03 -0000 1.9 +++ glib/poppler-action.cc 28 Dec 2006 16:53:55 -0000 @@ -267,7 +267,7 @@ } dest->type = POPPLER_DEST_NAMED; - name = named_dest->getCString (); + name = named_dest->getCStringCopy (); dest->named_dest = g_strdup (name); delete[] name; Index: goo/GooString.cc =================================================================== RCS file: /cvs/poppler/poppler/goo/GooString.cc,v retrieving revision 1.4 diff -u -r1.4 GooString.cc --- goo/GooString.cc 28 Dec 2006 15:51:44 -0000 1.4 +++ goo/GooString.cc 28 Dec 2006 16:53:55 -0000 @@ -35,29 +35,30 @@ // We assume that if this is being called from the constructor, was set // to NULL and was set to 0 to indicate unused string before calling us. void inline GooString::resize(int newLength) { - char *s1 = s; + int curSize = roundedSize(length); + int newSize = roundedSize(newLength); - if (!s || (roundedSize(length) != roundedSize(newLength))) { - // requires re-allocating data for string - if (newLength < STR_STATIC_SIZE) - s1 = sStatic; - else - s1 = new char[roundedSize(newLength)]; + assert(s); + + if (curSize != newSize) { + char *sNew = sStatic; + if (newSize != STR_STATIC_SIZE) + sNew = new char[newSize]; // we had to re-allocate the memory, so copy the content of previous // buffer into a new buffer - if (s) { - if (newLength < length) { - memcpy(s1, s, newLength); - } else { - memcpy(s1, s, length); - } + if (newLength < length) { + memcpy(sNew, s, newLength); + } else { + memcpy(sNew, s, length); } - if (s != sStatic) + if (s != sStatic) { + assert(curSize != STR_STATIC_SIZE); delete[] s; + } + s = sNew; } - s = s1; length = newLength; s[length] = '\0'; } @@ -97,38 +98,38 @@ } GooString::GooString() { - s = NULL; + s = sStatic; length = 0; Set(NULL); } GooString::GooString(const char *sA) { - s = NULL; + s = sStatic; length = 0; Set(sA, CALC_STRING_LEN); } GooString::GooString(const char *sA, int lengthA) { - s = NULL; + s = sStatic; length = 0; Set(sA, lengthA); } GooString::GooString(GooString *str, int idx, int lengthA) { - s = NULL; + s = sStatic; length = 0; assert(idx + lengthA < str->length); Set(str->getCString() + idx, lengthA); } GooString::GooString(GooString *str) { - s = NULL; + s = sStatic; length = 0; Set(str->getCString(), str->length); } GooString::GooString(GooString *str1, GooString *str2) { - s = NULL; + s = sStatic; length = 0; Set(str1->getCString(), str1->length, str2->getCString(), str2->length); } Index: goo/GooString.h =================================================================== RCS file: /cvs/poppler/poppler/goo/GooString.h,v retrieving revision 1.4 diff -u -r1.4 GooString.h --- goo/GooString.h 28 Dec 2006 15:51:44 -0000 1.4 +++ goo/GooString.h 28 Dec 2006 16:53:55 -0000 @@ -40,8 +40,9 @@ // length of string (or its substring) GooString* Set(const char *s1, int s1Len=CALC_STRING_LEN, const char *s2=NULL, int s2Len=CALC_STRING_LEN); - // Copy a string. GooString(GooString *str); + + // Return a newly allocated copy of the string GooString *copy() { return new GooString(this); } // Concatenate two strings. @@ -50,14 +51,13 @@ // Convert an integer to a string. static GooString *fromInt(int x); - // Destructor. ~GooString(); // Get length. - int getLength() { return length; } + int getLength() const { return length; } // Get C string. - char *getCString() { return s; } + char *getCString() const { return s; } // Get th character. char getChar(int i) { return s[i]; } @@ -93,15 +93,16 @@ GBool hasUnicodeMarker(void); + // a special value telling that the length of the string is not given + // so it must be calculated from the strings + static const int CALC_STRING_LEN = -1; + private: // you can tweak this number for a different speed/memory usage tradeoffs. // In libc malloc() rounding is 16 so it's best to choose a value that // results in sizeof(GooString) be a multiple of 16. // 24 makes sizeof(GooString) to be 32. static const int STR_STATIC_SIZE = 24; - // a special value telling that the length of the string is not given - // so it must be calculated from the strings - static const int CALC_STRING_LEN = -1; int roundedSize(int len); @@ -112,4 +113,87 @@ void resize(int newLength); }; +//Uncomment if you want to gather stats on hit rate of the cache +//#define CALC_OBJECT_STRING_CACHE_STATS 1 + +/* A cache for GooString. You can think of it as a custom allocator + for GooString(). Use alloc() to get a new GooString() and free() to free + existing GooString(). It keeps last GooStringCache::CACHE_SIZE free()ed + strings in a cache (which is a stack) and satisfies the alloc()s from + the cache first, thus saves free()/malloc() cycle. + It's used by Object::free()/Object::init*() and works great for them + because they recycle strings like crazy. +*/ +class GooStringCache +{ +public: + GooStringCache() { + inCache = 0; +#ifdef CALC_OBJECT_STRING_CACHE_STATS + totalAllocs = 0; + allocsFromCache = 0; +#endif + } + + ~GooStringCache() { + for (int i=0; igetCString(), str->getLength()); + } + + // alloc and free are called a lot, so make them inline + GooString *alloc(const char *txt, int strLen = GooString::CALC_STRING_LEN) { +#ifdef CALC_OBJECT_STRING_CACHE_STATS + ++totalAllocs; +#endif + if (inCache > 0) { + GooString *res; + // pop the value from the top of the stack + res = stringsCached[inCache-1]; + res->Set(txt, strLen); + --inCache; +#ifdef CALC_OBJECT_STRING_CACHE_STATS + ++allocsFromCache; +#endif + return res; + } else { + return new GooString(txt); + } + } + + void free(GooString *str) { + if (inCache < CACHE_SIZE) { + // put the value at the top of the stack + stringsCached[inCache] = str; + ++inCache; + } else { + // cache is full + delete str; + } + } +private: + // CACHE_SIZE size affects 2 things: + // - alloc() hit ratio i.e. how many alloc()s can be satisfied from cache + // as opposed to allocating new GooString() with generic malloc() + // This is a *very* effective cache. I get 99.98% alloc() hit ratio even + // with CACHE_SIZE of 8. 95% with CACHE_SIZE of 4 + // - how often we call delete on GooString(). When cache is full, we delete + // strings the usual way. When CACHE_SIZE grows, we hit delete less + // 64 is chosen by gut feeling, might use some tweaking + static const int CACHE_SIZE = 64; + +#ifdef CALC_OBJECT_STRING_CACHE_STATS + int totalAllocs; + int allocsFromCache; +#endif + int inCache; + // you can think of it as a stack, we only add something to the top + // or take it from the top + GooString *stringsCached[CACHE_SIZE]; +}; + #endif Index: poppler/Annot.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Annot.cc,v retrieving revision 1.6 diff -u -r1.6 Annot.cc --- poppler/Annot.cc 27 Dec 2006 23:15:06 -0000 1.6 +++ poppler/Annot.cc 28 Dec 2006 16:53:55 -0000 @@ -81,7 +81,7 @@ if (dict->lookup("AP", &apObj)->isDict()) { if (dict->lookup("AS", &asObj)->isName()) { if (apObj.dictLookup("N", &obj1)->isDict()) { - if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { + if (obj1.dictLookupNF(asObj.getNameC(), &obj2)->isRef()) { obj2.copy(&appearance); ok = gTrue; } else { Index: poppler/Catalog.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Catalog.cc,v retrieving revision 1.17 diff -u -r1.17 Catalog.cc --- poppler/Catalog.cc 11 Aug 2006 13:12:11 -0000 1.17 +++ poppler/Catalog.cc 28 Dec 2006 16:53:55 -0000 @@ -205,7 +205,7 @@ dict = metadata.streamGetDict(); if (!dict->lookup("Subtype", &obj)->isName("XML")) { error(-1, "Unknown Metadata type: '%s'", - obj.isName() ? obj.getName() : "???"); + obj.isName() ? obj.getNameC() : "???"); } obj.free(); s = new GooString(); @@ -351,7 +351,7 @@ Object obj, obj2; obj = embeddedFileNameTree.getValue(i); GooString *fileName = new GooString(); - char *descString = embeddedFileNameTree.getName(i)->getCString(); + char *descString = embeddedFileNameTree.getName(i)->getCStringCopy(); GooString *desc = new GooString(descString); delete[] descString; GooString *createDate = new GooString(); @@ -527,7 +527,7 @@ (*entry)->value.fetch(xref, obj); return gTrue; } else { - cname = name->getCString(); + cname = name->getCStringCopy(); printf("failed to look up %s\n", cname); delete[] cname; obj->initNull(); Index: poppler/Gfx.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Gfx.cc,v retrieving revision 1.13 diff -u -r1.13 Gfx.cc --- poppler/Gfx.cc 21 Sep 2006 22:37:00 -0000 1.13 +++ poppler/Gfx.cc 28 Dec 2006 16:53:56 -0000 @@ -672,7 +672,7 @@ int i; // find operator - name = cmd->getCmd(); + name = cmd->getCmd()->getCString(); if (!(op = findOp(name))) { if (ignoreUndef == 0) error(getPos(), "Unknown operator '%s'", name); @@ -826,11 +826,11 @@ GfxBlendMode mode; GBool haveFillOP; - if (!res->lookupGState(args[0].getName(), &obj1)) { + if (!res->lookupGState(args[0].getNameC(), &obj1)) { return; } if (!obj1.isDict()) { - error(getPos(), "ExtGState '%s' is wrong type", args[0].getName()); + error(getPos(), "ExtGState '%s' is wrong type", args[0].getNameC()); obj1.free(); return; } @@ -967,7 +967,7 @@ int i; state->setFillPattern(NULL); - res->lookupColorSpace(args[0].getName(), &obj); + res->lookupColorSpace(args[0].getNameC(), &obj); if (obj.isNull()) { colorSpace = GfxColorSpace::parse(&args[0]); } else { @@ -994,7 +994,7 @@ int i; state->setStrokePattern(NULL); - res->lookupColorSpace(args[0].getName(), &obj); + res->lookupColorSpace(args[0].getNameC(), &obj); if (obj.isNull()) { colorSpace = GfxColorSpace::parse(&args[0]); } else { @@ -1054,7 +1054,7 @@ out->updateFillColor(state); } if (args[numArgs-1].isName() && - (pattern = res->lookupPattern(args[numArgs-1].getName()))) { + (pattern = res->lookupPattern(args[numArgs-1].getNameC()))) { state->setFillPattern(pattern); } @@ -1086,7 +1086,7 @@ out->updateStrokeColor(state); } if (args[numArgs-1].isName() && - (pattern = res->lookupPattern(args[numArgs-1].getName()))) { + (pattern = res->lookupPattern(args[numArgs-1].getNameC()))) { state->setStrokePattern(pattern); } @@ -1621,7 +1621,7 @@ GfxPath *savedPath; double xMin, yMin, xMax, yMax; - if (!(shading = res->lookupShading(args[0].getName()))) { + if (!(shading = res->lookupShading(args[0].getNameC()))) { return; } @@ -2513,7 +2513,7 @@ void Gfx::opSetFont(Object args[], int numArgs) { GfxFont *font; - if (!(font = res->lookupFont(args[0].getName()))) { + if (!(font = res->lookupFont(args[0].getNameC()))) { return; } if (printCommands) { @@ -2881,11 +2881,11 @@ Object opiDict; #endif - if (!res->lookupXObject(args[0].getName(), &obj1)) { + if (!res->lookupXObject(args[0].getNameC(), &obj1)) { return; } if (!obj1.isStream()) { - error(getPos(), "XObject '%s' is wrong type", args[0].getName()); + error(getPos(), "XObject '%s' is wrong type", args[0].getNameC()); obj1.free(); return; } @@ -2898,7 +2898,7 @@ obj1.streamGetDict()->lookup("Subtype", &obj2); if (obj2.isName("Image")) { if (out->needNonText()) { - res->lookupXObjectNF(args[0].getName(), &refObj); + res->lookupXObjectNF(args[0].getNameC(), &refObj); doImage(&refObj, obj1.getStream(), gFalse); refObj.free(); } @@ -2909,7 +2909,7 @@ out->psXObject(obj1.getStream(), obj3.isStream() ? obj3.getStream() : (Stream *)NULL); } else if (obj2.isName()) { - error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); + error(getPos(), "Unknown XObject subtype '%s'", obj2.getNameC()); } else { error(getPos(), "XObject subtype is missing or wrong type"); } @@ -3033,7 +3033,7 @@ dict->lookup("CS", &obj1); } if (obj1.isName()) { - res->lookupColorSpace(obj1.getName(), &obj2); + res->lookupColorSpace(obj1.getNameC(), &obj2); if (!obj2.isNull()) { obj1.free(); obj1 = obj2; @@ -3119,7 +3119,7 @@ maskDict->lookup("CS", &obj1); } if (obj1.isName()) { - res->lookupColorSpace(obj1.getName(), &obj2); + res->lookupColorSpace(obj1.getNameC(), &obj2); if (!obj2.isNull()) { obj1.free(); obj1 = obj2; @@ -3520,7 +3520,7 @@ error(getPos(), "Inline image dictionary key must be a name object"); obj.free(); } else { - key = copyString(obj.getName()); + key = copyString(obj.getNameC()); obj.free(); parser->getObj(&obj); if (obj.isEOF() || obj.isError()) { @@ -3588,7 +3588,7 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) { if (printCommands) { - printf(" marked content: %s ", args[0].getName()); + printf(" marked content: %s ", args[0].getNameC()); if (numArgs == 2) args[2].print(stdout); printf("\n"); @@ -3596,9 +3596,9 @@ } if(numArgs == 2) { - out->beginMarkedContent(args[0].getName(),args[1].getDict()); + out->beginMarkedContent(args[0].getNameC(),args[1].getDict()); } else { - out->beginMarkedContent(args[0].getName()); + out->beginMarkedContent(args[0].getNameC()); } } @@ -3608,7 +3608,7 @@ void Gfx::opMarkPoint(Object args[], int numArgs) { if (printCommands) { - printf(" mark point: %s ", args[0].getName()); + printf(" mark point: %s ", args[0].getNameC()); if (numArgs == 2) args[2].print(stdout); printf("\n"); @@ -3616,9 +3616,9 @@ } if(numArgs == 2) { - out->markPoint(args[0].getName(),args[1].getDict()); + out->markPoint(args[0].getNameC(),args[1].getDict()); } else { - out->markPoint(args[0].getName()); + out->markPoint(args[0].getNameC()); } } Index: poppler/GfxFont.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/GfxFont.cc,v retrieving revision 1.9 diff -u -r1.9 GfxFont.cc --- poppler/GfxFont.cc 2 May 2006 04:38:39 -0000 1.9 +++ poppler/GfxFont.cc 28 Dec 2006 16:53:56 -0000 @@ -129,7 +129,7 @@ font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict); } else { error(-1, "Unknown font type: '%s'", - obj1.isName() ? obj1.getName() : "???"); + obj1.isName() ? obj1.getNameC() : "???"); font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict); } obj1.free(); @@ -212,15 +212,16 @@ // get stretch obj1.dictLookup("FontStretch", &obj2); if (obj2.isName()) { - if (strcmp(obj2.getName(), "UltraCondensed") == 0) stretch = UltraCondensed; - else if (strcmp(obj2.getName(), "ExtraCondensed") == 0) stretch = ExtraCondensed; - else if (strcmp(obj2.getName(), "Condensed") == 0) stretch = Condensed; - else if (strcmp(obj2.getName(), "SemiCondensed") == 0) stretch = SemiCondensed; - else if (strcmp(obj2.getName(), "Normal") == 0) stretch = Normal; - else if (strcmp(obj2.getName(), "SemiExpanded") == 0) stretch = SemiExpanded; - else if (strcmp(obj2.getName(), "Expanded") == 0) stretch = Expanded; - else if (strcmp(obj2.getName(), "ExtraExpanded") == 0) stretch = ExtraExpanded; - else if (strcmp(obj2.getName(), "UltraExpanded") == 0) stretch = UltraExpanded; + char *name = obj2.getNameC(); + if (strcmp(name, "UltraCondensed") == 0) stretch = UltraCondensed; + else if (strcmp(name, "ExtraCondensed") == 0) stretch = ExtraCondensed; + else if (strcmp(name, "Condensed") == 0) stretch = Condensed; + else if (strcmp(name, "SemiCondensed") == 0) stretch = SemiCondensed; + else if (strcmp(name, "Normal") == 0) stretch = Normal; + else if (strcmp(name, "SemiExpanded") == 0) stretch = SemiExpanded; + else if (strcmp(name, "Expanded") == 0) stretch = Expanded; + else if (strcmp(name, "ExtraExpanded") == 0) stretch = ExtraExpanded; + else if (strcmp(name, "UltraExpanded") == 0) stretch = UltraExpanded; else error(-1, "Invalid Font Stretch"); } obj2.free(); @@ -289,7 +290,7 @@ type = fontCIDType0C; } else { error(-1, "Unknown embedded font type '%s'", - obj4.isName() ? obj4.getName() : "???"); + obj4.isName() ? obj4.getNameC() : "???"); } obj4.free(); } @@ -719,7 +720,7 @@ if (encFree[code]) { gfree(enc[code]); } - enc[code] = copyString(obj3.getName()); + enc[code] = copyString(obj3.getNameC()); encFree[code] = gTrue; } ++code; @@ -1159,7 +1160,7 @@ type = fontCIDType2; } else { error(-1, "Unknown Type 0 descendant font type '%s'", - obj1.isName() ? obj1.getName() : "???"); + obj1.isName() ? obj1.getNameC() : "???"); goto err3; } obj1.free(); @@ -1610,7 +1611,7 @@ r.gen = 999999; } } - char *aux = fontDict->getKey(i)->getCString(); + char *aux = fontDict->getKey(i)->getCStringCopy(); fonts[i] = GfxFont::makeFont(xref, aux, r, obj2.getDict()); delete[] aux; Index: poppler/GfxState.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/GfxState.cc,v retrieving revision 1.14 diff -u -r1.14 GfxState.cc --- poppler/GfxState.cc 30 Jul 2006 20:31:31 -0000 1.14 +++ poppler/GfxState.cc 28 Dec 2006 16:53:57 -0000 @@ -135,7 +135,7 @@ } else if (csObj->isName("Pattern")) { cs = new GfxPatternColorSpace(NULL); } else { - error(-1, "Bad color space '%s'", csObj->getName()); + error(-1, "Bad color space '%s'", csObj->getNameC()); } } else if (csObj->isArray()) { csObj->arrayGet(0, &obj1); @@ -4165,7 +4165,7 @@ if (obj->isName()) { for (i = 0; i < nGfxBlendModeNames; ++i) { - if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { + if (!strcmp(obj->getNameC(), gfxBlendModeNames[i].name)) { *mode = gfxBlendModeNames[i].mode; return gTrue; } @@ -4179,7 +4179,7 @@ return gFalse; } for (j = 0; j < nGfxBlendModeNames; ++j) { - if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { + if (!strcmp(obj2.getNameC(), gfxBlendModeNames[j].name)) { obj2.free(); *mode = gfxBlendModeNames[j].mode; return gTrue; Index: poppler/Link.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Link.cc,v retrieving revision 1.5 diff -u -r1.5 Link.cc --- poppler/Link.cc 8 Oct 2006 20:38:47 -0000 1.5 +++ poppler/Link.cc 28 Dec 2006 16:53:57 -0000 @@ -95,7 +95,7 @@ // unknown action } else if (obj2.isName()) { - action = new LinkUnknown(obj2.getName()); + action = new LinkUnknown(obj2.getNameC()); // action is missing or wrong type } else { @@ -427,7 +427,7 @@ // named destination if (destObj->isName()) { - namedDest = new UGooString(destObj->getName()); + namedDest = new UGooString(destObj->getNameC()); } else if (destObj->isString()) { namedDest = new UGooString(*destObj->getString()); @@ -465,7 +465,7 @@ // named destination if (destObj->isName()) { - namedDest = new UGooString(destObj->getName()); + namedDest = new UGooString(destObj->getNameC()); } else if (destObj->isString()) { namedDest = new UGooString(*destObj->getString()); Index: poppler/Object.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Object.cc,v retrieving revision 1.3 diff -u -r1.3 Object.cc --- poppler/Object.cc 25 Feb 2006 12:30:30 -0000 1.3 +++ poppler/Object.cc 28 Dec 2006 16:53:57 -0000 @@ -21,6 +21,8 @@ #include "UGooString.h" #include "XRef.h" +GooStringCache g_objectStringCache; + //------------------------------------------------------------------------ // Object //------------------------------------------------------------------------ @@ -76,10 +78,10 @@ *obj = *this; switch (type) { case objString: - obj->string = string->copy(); + obj->string = g_objectStringCache.alloc(string); break; case objName: - obj->name = copyString(name); + obj->name = g_objectStringCache.alloc(name); break; case objArray: array->incRef(); @@ -91,7 +93,7 @@ stream->incRef(); break; case objCmd: - obj->cmd = copyString(cmd); + obj->cmd = g_objectStringCache.alloc(cmd); break; default: break; @@ -110,10 +112,10 @@ void Object::free() { switch (type) { case objString: - delete string; + g_objectStringCache.free(string); break; case objName: - gfree(name); + g_objectStringCache.free(name); break; case objArray: if (!array->decRef()) { @@ -131,7 +133,7 @@ } break; case objCmd: - gfree(cmd); + g_objectStringCache.free(cmd); break; default: break; @@ -166,7 +168,7 @@ fprintf(f, ")"); break; case objName: - fprintf(f, "/%s", name); + fprintf(f, "/%s", name->getCString()); break; case objNull: fprintf(f, "null"); @@ -185,7 +187,9 @@ case objDict: fprintf(f, "<<"); for (i = 0; i < dictGetLength(); ++i) { - fprintf(f, " /%s ", dictGetKey(i)->getCString()); + char *key = dictGetKey(i)->getCStringCopy(); + fprintf(f, " /%s ", key); + delete[] key; dictGetValNF(i, &obj); obj.print(f); obj.free(); @@ -199,7 +203,7 @@ fprintf(f, "%d %d R", ref.num, ref.gen); break; case objCmd: - fprintf(f, "%s", cmd); + fprintf(f, "%s", cmd->getCString()); break; case objError: fprintf(f, ""); Index: poppler/Object.h =================================================================== RCS file: /cvs/poppler/poppler/poppler/Object.h,v retrieving revision 1.3 diff -u -r1.3 Object.h --- poppler/Object.h 3 Sep 2006 09:27:21 -0000 1.3 +++ poppler/Object.h 28 Dec 2006 16:53:57 -0000 @@ -25,6 +25,8 @@ class Stream; class UGooString; +extern GooStringCache g_objectStringCache; + //------------------------------------------------------------------------ // Ref //------------------------------------------------------------------------ @@ -86,10 +88,16 @@ { initObj(objInt); intg = intgA; return this; } Object *initReal(double realA) { initObj(objReal); real = realA; return this; } - Object *initString(GooString *stringA) - { initObj(objString); string = stringA; return this; } - Object *initName(char *nameA) - { initObj(objName); name = copyString(nameA); return this; } + Object *initString(GooString *stringA) { + initObj(objString); + string = stringA; + return this; } + Object *initName(char *nameA) { + initObj(objName); + name = g_objectStringCache.alloc(nameA); + return this; + } + Object *initNull() { initObj(objNull); return this; } Object *initArray(XRef *xref); @@ -98,8 +106,11 @@ Object *initStream(Stream *streamA); Object *initRef(int numA, int genA) { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } - Object *initCmd(char *cmdA) - { initObj(objCmd); cmd = copyString(cmdA); return this; } + Object *initCmd(char *cmdA) { + initObj(objCmd); + cmd = g_objectStringCache.alloc(cmdA); + return this; + } Object *initError() { initObj(objError); return this; } Object *initEOF() @@ -139,11 +150,11 @@ // Special type checking. GBool isName(char *nameA) - { return type == objName && !strcmp(name, nameA); } + { return type == objName && (0 == name->cmp(nameA)); } GBool isDict(char *dictType); GBool isStream(char *dictType); GBool isCmd(char *cmdA) - { return type == objCmd && !strcmp(cmd, cmdA); } + { return type == objCmd && (0 == cmd->cmp(cmdA)); } // Accessors. NB: these assume object is of correct type. GBool getBool() { return booln; } @@ -151,14 +162,15 @@ double getReal() { return real; } double getNum() { return type == objInt ? (double)intg : real; } GooString *getString() { return string; } - char *getName() { return name; } + GooString *getName() { return name; } + char *getNameC() { return name->getCString(); } Array *getArray() { return array; } Dict *getDict() { return dict; } Stream *getStream() { return stream; } Ref getRef() { return ref; } int getRefNum() { return ref.num; } int getRefGen() { return ref.gen; } - char *getCmd() { return cmd; } + GooString *getCmd() { return cmd; } // Array accessors. int arrayGetLength(); @@ -198,23 +210,23 @@ private: - ObjType type; // object type - union { // value for each type: - GBool booln; // boolean - int intg; // integer - double real; // real - GooString *string; // string - char *name; // name - Array *array; // array - Dict *dict; // dictionary - Stream *stream; // stream - Ref ref; // indirect reference - char *cmd; // command + ObjType type; // object type + union { // value for each type: + GBool booln; // boolean + int intg; // integer + double real; // real + GooString *string; // string + GooString *name; // name + Array *array; // array + Dict *dict; // dictionary + Stream *stream; // stream + Ref ref; // indirect reference + GooString *cmd; // command }; #ifdef DEBUG_MEM - static int // number of each type of object - numAlloc[numObjTypes]; // currently allocated + static int // number of each type of object + numAlloc[numObjTypes]; // currently allocated #endif }; Index: poppler/PSOutputDev.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/PSOutputDev.cc,v retrieving revision 1.12 diff -u -r1.12 PSOutputDev.cc --- poppler/PSOutputDev.cc 11 Nov 2006 15:41:27 -0000 1.12 +++ poppler/PSOutputDev.cc 28 Dec 2006 16:53:58 -0000 @@ -2297,7 +2297,7 @@ t3Cacheable = gFalse; for (i = 0; i < charProcs->getLength(); ++i) { writePS("/"); - char *aux = charProcs->getKey(i)->getCString(); + char *aux = charProcs->getKey(i)->getCStringCopy(); writePSName(aux); delete[] aux; writePS(" {\n"); @@ -4319,12 +4319,12 @@ dict->lookup("Inks", &obj1); if (obj1.isName()) { - writePSFmt("%%%%ImageInks: %s\n", obj1.getName()); + writePSFmt("%%%%ImageInks: %s\n", obj1.getNameC()); } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { obj1.arrayGet(0, &obj2); if (obj2.isName()) { writePSFmt("%%%%ImageInks: %s %d", - obj2.getName(), (obj1.arrayGetLength() - 1) / 2); + obj2.getNameC(), (obj1.arrayGetLength() - 1) / 2); for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) { obj1.arrayGet(i, &obj3); obj1.arrayGet(i+1, &obj4); @@ -4432,7 +4432,7 @@ dict->lookup("ColorType", &obj1); if (obj1.isName()) { - writePSFmt("%%ALDImageColorType: %s\n", obj1.getName()); + writePSFmt("%%ALDImageColorType: %s\n", obj1.getNameC()); } obj1.free(); Index: poppler/Parser.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Parser.cc,v retrieving revision 1.7 diff -u -r1.7 Parser.cc --- poppler/Parser.cc 28 Dec 2006 15:51:44 -0000 1.7 +++ poppler/Parser.cc 28 Dec 2006 16:53:58 -0000 @@ -77,7 +77,7 @@ shift(); } else { // buf1 might go away in shift(), so construct the key - key.Set(buf1.getName()); + key.Set(buf1.getNameC()); shift(); if (buf1.isEOF() || buf1.isError()) { break; Index: poppler/SecurityHandler.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/SecurityHandler.cc,v retrieving revision 1.2 diff -u -r1.2 SecurityHandler.cc --- poppler/SecurityHandler.cc 18 Jan 2006 22:32:13 -0000 1.2 +++ poppler/SecurityHandler.cc 28 Dec 2006 16:53:58 -0000 @@ -47,7 +47,7 @@ } else { #endif error(-1, "Couldn't find the '%s' security handler", - filterObj.getName()); + filterObj.getNameC()); secHdlr = NULL; #ifdef ENABLE_PLUGINS } @@ -168,8 +168,8 @@ if (cryptFiltersObj.isDict() && streamFilterObj.isName() && stringFilterObj.isName() && - !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { - if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), + !strcmp(streamFilterObj.getNameC(), stringFilterObj.getNameC())) { + if (cryptFiltersObj.dictLookup(streamFilterObj.getNameC(), &cryptFilterObj)->isDict()) { if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) { encVersion = 2; Index: poppler/Stream.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/Stream.cc,v retrieving revision 1.13 diff -u -r1.13 Stream.cc --- poppler/Stream.cc 27 Jul 2006 18:17:50 -0000 1.13 +++ poppler/Stream.cc 28 Dec 2006 16:53:58 -0000 @@ -117,7 +117,7 @@ dict->dictLookup("DP", ¶ms); } if (obj.isName()) { - str = makeFilter(obj.getName(), str, ¶ms); + str = makeFilter(obj.getNameC(), str, ¶ms); } else if (obj.isArray()) { for (i = 0; i < obj.arrayGetLength(); ++i) { obj.arrayGet(i, &obj2); @@ -126,7 +126,7 @@ else params2.initNull(); if (obj2.isName()) { - str = makeFilter(obj2.getName(), str, ¶ms2); + str = makeFilter(obj2.getNameC(), str, ¶ms2); } else { error(getPos(), "Bad filter name"); str = new EOFStream(str); Index: poppler/UGooString.cc =================================================================== RCS file: /cvs/poppler/poppler/poppler/UGooString.cc,v retrieving revision 1.4 diff -u -r1.4 UGooString.cc --- poppler/UGooString.cc 28 Dec 2006 15:51:44 -0000 1.4 +++ poppler/UGooString.cc 28 Dec 2006 16:53:58 -0000 @@ -8,6 +8,7 @@ // //======================================================================== +#include #include #include "goo/gmem.h" @@ -28,43 +29,45 @@ // We assume that if this is being called from the constructor, was set // to NULL and was set to 0 to indicate unused string before calling us. void inline UGooString::resize(int newLength) { - Unicode *s1 = s; + int curSize = roundedSize(length); + int newSize = roundedSize(newLength); - if (!s || (roundedSize(length) != roundedSize(newLength))) { - // requires re-allocating data for string - if (newLength < STR_STATIC_SIZE) - s1 = sStatic; - else - s1 = new Unicode[roundedSize(newLength)]; + assert(s); + + if (curSize != newSize) { + Unicode *sNew = sStatic; + if (newSize != STR_STATIC_SIZE) + sNew = new Unicode[newSize]; // we had to re-allocate the memory, so copy the content of previous // buffer into a new buffer - if (s) { - if (newLength < length) { - memcpy(s1, s, newLength); - } else { - memcpy(s1, s, length); - } + if (newLength < length) { + memcpy(sNew, s, newLength * sizeof(Unicode)); + } else { + memcpy(sNew, s, length * sizeof(Unicode)); } - if (s != sStatic) + + if (s != sStatic) { + assert(curSize != STR_STATIC_SIZE); delete[] s; + } + s = sNew; } - s = s1; length = newLength; s[length] = '\0'; } UGooString::UGooString() { - s = NULL; + s = sStatic; length = 0; resize(0); } UGooString::UGooString(GooString &str) { - s = NULL; + s = sStatic; length = 0; if (str.hasUnicodeMarker()) { @@ -84,14 +87,14 @@ UGooString::UGooString(const UGooString &str) { - s = NULL; + s = sStatic; length = 0; Set(str); } UGooString::UGooString(const char *str, int strLen) { - s = NULL; + s = sStatic; length = 0; if (CALC_STRING_LEN == strLen) strLen = strlen(str); @@ -121,7 +124,7 @@ break; } } - if ( foundUnencoded ) + if (foundUnencoded) { for (j = 0; j < length; ++j) { s[j] = str[j]; @@ -163,15 +166,7 @@ return n1 - n2; } -// FIXME: -// a) this is confusing because GooString::getCSTring() returns a pointer -// but UGooString returns a newly allocated copy. Should give this -// a different name, like copyAsAscii() or copyAsGooString() -// b) this interface requires copying. It should be changed to take a -// GooString& as a param and put the data inside it so that it uses -// caching optimization of GooString. Callers should be changed to use -// this new interface -char *UGooString::getCString() const +char *UGooString::getCStringCopy() const { char *res = new char[length + 1]; for (int i = 0; i < length; i++) res[i] = s[i]; Index: poppler/UGooString.h =================================================================== RCS file: /cvs/poppler/poppler/poppler/UGooString.h,v retrieving revision 1.2 diff -u -r1.2 UGooString.h --- poppler/UGooString.h 28 Dec 2006 15:51:44 -0000 1.2 +++ poppler/UGooString.h 28 Dec 2006 16:53:58 -0000 @@ -56,7 +56,7 @@ // Return a newly allocated copy of the string converted to // ascii (non-Unicode) format. Caller has to delete [] the result - char *getCString() const; + char *getCStringCopy() const; private: // you can tweak this number for a different speed/memory usage tradeoffs. Index: qt/poppler-document.cc =================================================================== RCS file: /cvs/poppler/poppler/qt/poppler-document.cc,v retrieving revision 1.12 diff -u -r1.12 poppler-document.cc --- qt/poppler-document.cc 26 Jul 2006 18:16:01 -0000 1.12 +++ qt/poppler-document.cc 28 Dec 2006 16:53:59 -0000 @@ -215,7 +215,8 @@ if ( infoDict->lookup( (char*)type.latin1(), &obj )->isString() ) { - s = UGooString(*obj.getString()).getCString(); + s = UGooString(*obj.getString()).getCStringCopy(); + const char *aux = s; if ( s[0] == 'D' && s[1] == ':' ) s += 2; /* FIXME process time zone on systems that support it */ @@ -232,6 +233,7 @@ else { obj.free(); info.free(); + delete aux; return QDateTime(); } } @@ -241,9 +243,11 @@ if ( d.isValid() && t.isValid() ) { obj.free(); info.free(); + delete aux; return QDateTime( d, t ); } } + delete aux; } obj.free(); info.free(); Index: qt/poppler-page-transition.cc =================================================================== RCS file: /cvs/poppler/poppler/qt/poppler-page-transition.cc,v retrieving revision 1.3 diff -u -r1.3 poppler-page-transition.cc --- qt/poppler-page-transition.cc 18 Jan 2006 22:32:13 -0000 1.3 +++ qt/poppler-page-transition.cc 28 Dec 2006 16:53:59 -0000 @@ -62,7 +62,7 @@ Object obj; if (transDict->lookup("S", &obj)->isName()) { - const char *s = obj.getName(); + const char *s = obj.getNameC(); if (strcmp("R", s) == 0) data->type = Replace; else if (strcmp("Split", s) == 0) @@ -96,7 +96,7 @@ obj.free(); if (transDict->lookup("Dm", &obj)->isName()) { - const char *dm = obj.getName(); + const char *dm = obj.getNameC(); if ( strcmp( "H", dm ) == 0 ) data->alignment = Horizontal; else if ( strcmp( "V", dm ) == 0 ) @@ -105,7 +105,7 @@ obj.free(); if (transDict->lookup("M", &obj)->isName()) { - const char *m = obj.getName(); + const char *m = obj.getNameC(); if ( strcmp( "I", m ) == 0 ) data->direction = Inward; else if ( strcmp( "O", m ) == 0 ) @@ -119,7 +119,7 @@ obj.free(); if (transDict->lookup("Di", &obj)->isName()) { - if ( strcmp( "None", obj.getName() ) == 0 ) + if ( strcmp( "None", obj.getNameC() ) == 0 ) data->angle = 0; } obj.free(); Index: qt4/src/poppler-annotation-helper.h =================================================================== RCS file: /cvs/poppler/poppler/qt4/src/poppler-annotation-helper.h,v retrieving revision 1.1 diff -u -r1.1 poppler-annotation-helper.h --- qt4/src/poppler-annotation-helper.h 12 May 2006 20:40:05 -0000 1.1 +++ qt4/src/poppler-annotation-helper.h 28 Dec 2006 16:53:59 -0000 @@ -46,7 +46,7 @@ if ( nameObj.isNull() ) return; if ( nameObj.isName() ) - dest = nameObj.getName(); + dest = nameObj.getNameC(); else qDebug() << type << " is not Name." << endl; nameObj.free(); Index: qt4/src/poppler-document.cc =================================================================== RCS file: /cvs/poppler/poppler/qt4/src/poppler-document.cc,v retrieving revision 1.25 diff -u -r1.25 poppler-document.cc --- qt4/src/poppler-document.cc 18 Nov 2006 17:08:05 -0000 1.25 +++ qt4/src/poppler-document.cc 28 Dec 2006 16:53:59 -0000 @@ -248,7 +248,9 @@ Dict *infoDict = info.getDict(); // somehow iterate over keys in infoDict for( int i=0; i < infoDict->getLength(); ++i ) { - keys.append( QString::fromAscii(infoDict->getKey(i)->getCString()) ); + char *aux = infoDict->getKey(i)->getCStringCopy(); + keys.append( QString::fromAscii(aux) ); + delete[] aux; } info.free(); @@ -275,7 +277,7 @@ if ( infoDict->lookup( type.toLatin1().data(), &obj )->isString() ) { - char *aux = UGooString(*obj.getString()).getCString(); + char *aux = UGooString(*obj.getString()).getCStringCopy(); result = Poppler::convertDate(aux); delete[] aux; } Index: qt4/src/poppler-embeddedfile.cc =================================================================== RCS file: /cvs/poppler/poppler/qt4/src/poppler-embeddedfile.cc,v retrieving revision 1.2 diff -u -r1.2 poppler-embeddedfile.cc --- qt4/src/poppler-embeddedfile.cc 5 Aug 2006 17:10:07 -0000 1.2 +++ qt4/src/poppler-embeddedfile.cc 28 Dec 2006 16:53:59 -0000 @@ -46,7 +46,9 @@ { m_embeddedFile = new EmbeddedFileData(); m_embeddedFile->m_label = QString(embfile->name()->getCString()); - m_embeddedFile->m_description = QString(UGooString(*embfile->description()).getCString()); + const char *aux = UGooString(*embfile->description()).getCStringCopy(); + m_embeddedFile->m_description = QString(aux); + delete[] aux; m_embeddedFile->m_modDate = convertDate(embfile->modDate()->getCString()); m_embeddedFile->m_createDate = convertDate(embfile->createDate()->getCString()); embfile->streamObject().copy(&m_embeddedFile->m_streamObject); Index: qt4/src/poppler-page.cc =================================================================== RCS file: /cvs/poppler/poppler/qt4/src/poppler-page.cc,v retrieving revision 1.31 diff -u -r1.31 poppler-page.cc --- qt4/src/poppler-page.cc 26 Dec 2006 20:07:03 -0000 1.31 +++ qt4/src/poppler-page.cc 28 Dec 2006 16:53:59 -0000 @@ -636,7 +636,7 @@ leArray.arrayGet( 0, &styleObj ); if ( styleObj.isName() ) { - const char * name = styleObj.getName(); + const char * name = styleObj.getNameC(); if ( !strcmp( name, "Square" ) ) l->lineStartStyle = LineAnnotation::Square; else if ( !strcmp( name, "Circle" ) ) @@ -663,7 +663,7 @@ leArray.arrayGet( 1, &styleObj ); if ( styleObj.isName() ) { - const char * name = styleObj.getName(); + const char * name = styleObj.getNameC(); if ( !strcmp( name, "Square" ) ) l->lineEndStyle = LineAnnotation::Square; else if ( !strcmp( name, "Circle" ) ) @@ -1069,7 +1069,7 @@ annotDict->lookup( "RT", &revObj ); if ( revObj.isName() ) { - const char * name = revObj.getName(); + const char * name = revObj.getNameC(); if ( !strcmp( name, "R" ) ) request.nextScope = Annotation::Reply; else if ( !strcmp( name, "Group" ) ) Index: qt4/src/poppler-sound.cc =================================================================== RCS file: /cvs/poppler/poppler/qt4/src/poppler-sound.cc,v retrieving revision 1.1 diff -u -r1.1 poppler-sound.cc --- qt4/src/poppler-sound.cc 8 Oct 2006 20:38:47 -0000 1.1 +++ qt4/src/poppler-sound.cc 28 Dec 2006 16:53:59 -0000 @@ -105,7 +105,7 @@ dict->lookup( "E", &tmp ); if ( tmp.isName() ) { - const char *enc = tmp.getName(); + const char *enc = tmp.getNameC(); if ( !strcmp( "Raw", enc ) ) m_soundData->m_soundEncoding = SoundObject::Raw; else if ( !strcmp( "Signed", enc ) )