Commit 7da5885e authored by Albert Astals Cid's avatar Albert Astals Cid

* goo/GooString.cc

* goo/GooString.h
* goo/gmem.c
* goo/gmem.h
* poppler/Lexer.cc
* poppler/Lexer.h
* poppler/PageLabelInfo.cc
* poppler/Parser.cc
* poppler/UGooString.cc
* poppler/UGooString.h: Patch by Krzysztof Kowalczyk <kkowalczyk@gmail.com> to improve performance. See bug 7808 for details.
parent fbc05a67
2006-12-28 Albert Astals Cid <aacid@kde.org>
* goo/GooString.cc
* goo/GooString.h
* goo/gmem.c
* goo/gmem.h
* poppler/Lexer.cc
* poppler/Lexer.h
* poppler/PageLabelInfo.cc
* poppler/Parser.cc
* poppler/UGooString.cc
* poppler/UGooString.h: Patch by Krzysztof Kowalczyk
<kkowalczyk@gmail.com> to improve performance.
See bug 7808 for details.
2006-12-28 Albert Astals Cid <aacid@kde.org> 2006-12-28 Albert Astals Cid <aacid@kde.org>
* poppler/Annot.cc: * poppler/Annot.cc:
......
...@@ -18,76 +18,119 @@ ...@@ -18,76 +18,119 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h>
#include "gtypes.h" #include "gtypes.h"
#include "GooString.h" #include "GooString.h"
static inline int size(int len) { int inline GooString::roundedSize(int len) {
int delta; int delta;
if (len <= STR_STATIC_SIZE-1)
return STR_STATIC_SIZE;
delta = len < 256 ? 7 : 255; delta = len < 256 ? 7 : 255;
return ((len + 1) + delta) & ~delta; return ((len + 1) + delta) & ~delta;
} }
inline void GooString::resize(int length1) { // Make sure that the buffer is big enough to contain <newLength> characters
char *s1; // plus terminating 0.
// We assume that if this is being called from the constructor, <s> was set
if (!s) { // to NULL and <length> was set to 0 to indicate unused string before calling us.
s = new char[size(length1)]; void inline GooString::resize(int newLength) {
} else if (size(length1) != size(length)) { char *s1 = s;
s1 = new char[size(length1)];
if (length1 < length) { if (!s || (roundedSize(length) != roundedSize(newLength))) {
memcpy(s1, s, length1); // requires re-allocating data for string
s1[length1] = '\0'; if (newLength < STR_STATIC_SIZE)
} else { s1 = sStatic;
memcpy(s1, s, length + 1); else
s1 = new char[roundedSize(newLength)];
// 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);
}
} }
delete[] s; if (s != sStatic)
s = s1; delete[] s;
} }
s = s1;
length = newLength;
s[length] = '\0';
}
GooString* GooString::Set(const char *s1, int s1Len, const char *s2, int s2Len)
{
int newLen = 0;
char *p;
if (s1) {
if (CALC_STRING_LEN == s1Len) {
s1Len = strlen(s1);
} else
assert(s1Len >= 0);
newLen += s1Len;
}
if (s2) {
if (CALC_STRING_LEN == s2Len) {
s2Len = strlen(s2);
} else
assert(s2Len >= 0);
newLen += s2Len;
}
resize(newLen);
p = s;
if (s1) {
memcpy(p, s1, s1Len);
p += s1Len;
}
if (s2) {
memcpy(p, s2, s2Len);
p += s2Len;
}
return this;
} }
GooString::GooString() { GooString::GooString() {
s = NULL; s = NULL;
resize(length = 0); length = 0;
s[0] = '\0'; Set(NULL);
} }
GooString::GooString(const char *sA) { GooString::GooString(const char *sA) {
int n = strlen(sA);
s = NULL; s = NULL;
resize(length = n); length = 0;
memcpy(s, sA, n + 1); Set(sA, CALC_STRING_LEN);
} }
GooString::GooString(const char *sA, int lengthA) { GooString::GooString(const char *sA, int lengthA) {
s = NULL; s = NULL;
resize(length = lengthA); length = 0;
memcpy(s, sA, length * sizeof(char)); Set(sA, lengthA);
s[length] = '\0';
} }
GooString::GooString(GooString *str, int idx, int lengthA) { GooString::GooString(GooString *str, int idx, int lengthA) {
s = NULL; s = NULL;
resize(length = lengthA); length = 0;
memcpy(s, str->getCString() + idx, length); assert(idx + lengthA < str->length);
s[length] = '\0'; Set(str->getCString() + idx, lengthA);
} }
GooString::GooString(GooString *str) { GooString::GooString(GooString *str) {
s = NULL; s = NULL;
resize(length = str->getLength()); length = 0;
memcpy(s, str->getCString(), length + 1); Set(str->getCString(), str->length);
} }
GooString::GooString(GooString *str1, GooString *str2) { GooString::GooString(GooString *str1, GooString *str2) {
int n1 = str1->getLength();
int n2 = str2->getLength();
s = NULL; s = NULL;
resize(length = n1 + n2); length = 0;
memcpy(s, str1->getCString(), n1); Set(str1->getCString(), str1->length, str2->getCString(), str2->length);
memcpy(s + n1, str2->getCString(), n2 + 1);
} }
GooString *GooString::fromInt(int x) { GooString *GooString::fromInt(int x) {
...@@ -117,91 +160,50 @@ GooString *GooString::fromInt(int x) { ...@@ -117,91 +160,50 @@ GooString *GooString::fromInt(int x) {
} }
GooString::~GooString() { GooString::~GooString() {
delete[] s; if (s != sStatic)
delete[] s;
} }
GooString *GooString::clear() { GooString *GooString::clear() {
s[length = 0] = '\0';
resize(0); resize(0);
return this; return this;
} }
GooString *GooString::append(char c) { GooString *GooString::append(char c) {
resize(length + 1); return append((const char*)&c, 1);
s[length++] = c;
s[length] = '\0';
return this;
} }
GooString *GooString::append(GooString *str) { GooString *GooString::append(GooString *str) {
int n = str->getLength(); return append(str->getCString(), str->getLength());
resize(length + n);
memcpy(s + length, str->getCString(), n + 1);
length += n;
return this;
}
GooString *GooString::append(const char *str) {
int n = strlen(str);
resize(length + n);
memcpy(s + length, str, n + 1);
length += n;
return this;
} }
GooString *GooString::append(const char *str, int lengthA) { GooString *GooString::append(const char *str, int lengthA) {
int prevLen = length;
if (CALC_STRING_LEN == lengthA)
lengthA = strlen(str);
resize(length + lengthA); resize(length + lengthA);
memcpy(s + length, str, lengthA); memcpy(s + prevLen, str, lengthA);
length += lengthA;
s[length] = '\0';
return this; return this;
} }
GooString *GooString::insert(int i, char c) { GooString *GooString::insert(int i, char c) {
int j; return insert(i, (const char*)&c, 1);
resize(length + 1);
for (j = length + 1; j > i; --j)
s[j] = s[j-1];
s[i] = c;
++length;
return this;
} }
GooString *GooString::insert(int i, GooString *str) { GooString *GooString::insert(int i, GooString *str) {
int n = str->getLength(); return insert(i, str->getCString(), str->getLength());
int j;
resize(length + n);
for (j = length; j >= i; --j)
s[j+n] = s[j];
memcpy(s+i, str->getCString(), n);
length += n;
return this;
}
GooString *GooString::insert(int i, const char *str) {
int n = strlen(str);
int j;
resize(length + n);
for (j = length; j >= i; --j)
s[j+n] = s[j];
memcpy(s+i, str, n);
length += n;
return this;
} }
GooString *GooString::insert(int i, const char *str, int lengthA) { GooString *GooString::insert(int i, const char *str, int lengthA) {
int j; int j;
int prevLen = length;
if (CALC_STRING_LEN == lengthA)
lengthA = strlen(str);
resize(length + lengthA); resize(length + lengthA);
for (j = length; j >= i; --j) for (j = prevLen; j >= i; --j)
s[j+lengthA] = s[j]; s[j+lengthA] = s[j];
memcpy(s+i, str, lengthA); memcpy(s+i, str, lengthA);
length += lengthA;
return this; return this;
} }
...@@ -215,7 +217,7 @@ GooString *GooString::del(int i, int n) { ...@@ -215,7 +217,7 @@ GooString *GooString::del(int i, int n) {
for (j = i; j <= length - n; ++j) { for (j = i; j <= length - n; ++j) {
s[j] = s[j + n]; s[j] = s[j + n];
} }
resize(length -= n); resize(length - n);
} }
return this; return this;
} }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#pragma interface #pragma interface
#endif #endif
#include <stdlib.h> // for NULL
#include "gtypes.h" #include "gtypes.h"
class GooString { class GooString {
...@@ -33,6 +34,12 @@ public: ...@@ -33,6 +34,12 @@ public:
// Create a string from <lengthA> chars at <idx> in <str>. // Create a string from <lengthA> chars at <idx> in <str>.
GooString(GooString *str, int idx, int lengthA); GooString(GooString *str, int idx, int lengthA);
// Set content of a string to concatination of <s1> and <s2>. They can both
// be NULL. if <s1Len> or <s2Len> is CALC_STRING_LEN, then length of the string
// will be calculated with strlen(). Otherwise we assume they are a valid
// 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. // Copy a string.
GooString(GooString *str); GooString(GooString *str);
GooString *copy() { return new GooString(this); } GooString *copy() { return new GooString(this); }
...@@ -64,14 +71,12 @@ public: ...@@ -64,14 +71,12 @@ public:
// Append a character or string. // Append a character or string.
GooString *append(char c); GooString *append(char c);
GooString *append(GooString *str); GooString *append(GooString *str);
GooString *append(const char *str); GooString *append(const char *str, int lengthA=CALC_STRING_LEN);
GooString *append(const char *str, int lengthA);
// Insert a character or string. // Insert a character or string.
GooString *insert(int i, char c); GooString *insert(int i, char c);
GooString *insert(int i, GooString *str); GooString *insert(int i, GooString *str);
GooString *insert(int i, const char *str); GooString *insert(int i, const char *str, int lengthA=CALC_STRING_LEN);
GooString *insert(int i, const char *str, int lengthA);
// Delete a character or range of characters. // Delete a character or range of characters.
GooString *del(int i, int n = 1); GooString *del(int i, int n = 1);
...@@ -89,11 +94,22 @@ public: ...@@ -89,11 +94,22 @@ public:
GBool hasUnicodeMarker(void); GBool hasUnicodeMarker(void);
private: 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);
char sStatic[STR_STATIC_SIZE];
int length; int length;
char *s; char *s;
void resize(int length1); void resize(int newLength);
}; };
#endif #endif
...@@ -196,8 +196,7 @@ void gfree(void *p) { ...@@ -196,8 +196,7 @@ void gfree(void *p) {
} }
} }
#else #else
if (p) free(p);
free(p);
#endif #endif
} }
......
...@@ -37,7 +37,7 @@ extern void *gmallocn(int nObjs, int objSize); ...@@ -37,7 +37,7 @@ extern void *gmallocn(int nObjs, int objSize);
extern void *greallocn(void *p, int nObjs, int objSize); extern void *greallocn(void *p, int nObjs, int objSize);
/* /*
* Same as free, but checks for and ignores NULL pointers. * #ifdef DEBUG_MEM, adds debuging info. If not, same as free.
*/ */
extern void gfree(void *p); extern void gfree(void *p);
......
...@@ -50,6 +50,7 @@ static char specialChars[256] = { ...@@ -50,6 +50,7 @@ static char specialChars[256] = {
Lexer::Lexer(XRef *xrefA, Stream *str) { Lexer::Lexer(XRef *xrefA, Stream *str) {
Object obj; Object obj;
lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
xref = xrefA; xref = xrefA;
curStr.initStream(str); curStr.initStream(str);
...@@ -63,6 +64,7 @@ Lexer::Lexer(XRef *xrefA, Stream *str) { ...@@ -63,6 +64,7 @@ Lexer::Lexer(XRef *xrefA, Stream *str) {
Lexer::Lexer(XRef *xrefA, Object *obj) { Lexer::Lexer(XRef *xrefA, Object *obj) {
Object obj2; Object obj2;
lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
xref = xrefA; xref = xrefA;
if (obj->isStream()) { if (obj->isStream()) {
...@@ -90,9 +92,15 @@ Lexer::~Lexer() { ...@@ -90,9 +92,15 @@ Lexer::~Lexer() {
} }
} }
int Lexer::getChar() { int inline Lexer::getChar() {
int c; int c;
if (LOOK_VALUE_NOT_CACHED != lookCharLastValueCached) {
c = lookCharLastValueCached;
lookCharLastValueCached = LOOK_VALUE_NOT_CACHED;
return c;
}
c = EOF; c = EOF;
while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
curStr.streamClose(); curStr.streamClose();
...@@ -106,11 +114,12 @@ int Lexer::getChar() { ...@@ -106,11 +114,12 @@ int Lexer::getChar() {
return c; return c;
} }
int Lexer::lookChar() { int inline Lexer::lookChar() {
if (curStr.isNone()) { if (LOOK_VALUE_NOT_CACHED != lookCharLastValueCached) {
return EOF; return lookCharLastValueCached;
} }
return curStr.streamLookChar(); lookCharLastValueCached = getChar();
return lookCharLastValueCached;
} }
Object *Lexer::getObj(Object *obj, int objNum) { Object *Lexer::getObj(Object *obj, int objNum) {
......
...@@ -63,6 +63,16 @@ public: ...@@ -63,6 +63,16 @@ public:
// Returns true if <c> is a whitespace character. // Returns true if <c> is a whitespace character.
static GBool isSpace(int c); static GBool isSpace(int c);
// often (e.g. ~30% on PDF Refernce 1.6 pdf file from Adobe site) getChar
// is called right after lookChar. In order to avoid expensive re-doing
// getChar() of underlying stream, we cache the last value found by
// lookChar() in lookCharLastValueCached. A special value
// LOOK_VALUE_NOT_CACHED that should never be part of stream indicates
// that no value was cached
static const int LOOK_VALUE_NOT_CACHED = -3;
int lookCharLastValueCached;
private: private:
int getChar(); int getChar();
......
#include <config.h>
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
......
...@@ -39,6 +39,7 @@ Parser::~Parser() { ...@@ -39,6 +39,7 @@ Parser::~Parser() {
Object *Parser::getObj(Object *obj, Object *Parser::getObj(Object *obj,
Guchar *fileKey, int keyLength, Guchar *fileKey, int keyLength,
int objNum, int objGen) { int objNum, int objGen) {
UGooString key;
Stream *str; Stream *str;
Object obj2; Object obj2;
int num; int num;
...@@ -75,14 +76,13 @@ Object *Parser::getObj(Object *obj, ...@@ -75,14 +76,13 @@ Object *Parser::getObj(Object *obj,
error(getPos(), "Dictionary key must be a name object"); error(getPos(), "Dictionary key must be a name object");
shift(); shift();
} else { } else {
// buf1 might go away in shift(), so construct the key // buf1 might go away in shift(), so construct the key
UGooString *key = new UGooString(buf1.getName()); key.Set(buf1.getName());
shift(); shift();
if (buf1.isEOF() || buf1.isError()) { if (buf1.isEOF() || buf1.isError()) {
gfree(key);
break; break;
} }
obj->dictAddOwnKeyVal(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen));
} }
} }
if (buf1.isEOF()) if (buf1.isEOF())
...@@ -120,8 +120,8 @@ Object *Parser::getObj(Object *obj, ...@@ -120,8 +120,8 @@ Object *Parser::getObj(Object *obj,
s = obj->getString(); s = obj->getString();
decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); decrypt = new Decrypt(fileKey, keyLength, objNum, objGen);
for (i = 0, p = obj->getString()->getCString(); for (i = 0, p = obj->getString()->getCString();
i < s->getLength(); i < s->getLength();
++i, ++p) { ++i, ++p) {
*p = decrypt->decryptByte(*p); *p = decrypt->decryptByte(*p);
} }
delete decrypt; delete decrypt;
...@@ -174,6 +174,11 @@ Stream *Parser::makeStream(Object *dict) { ...@@ -174,6 +174,11 @@ Stream *Parser::makeStream(Object *dict) {
baseStr = lexer->getStream()->getBaseStream(); baseStr = lexer->getStream()->getBaseStream();