Commit 6eebbb9c authored by Adrian Johnson's avatar Adrian Johnson

Add Int64 object type

Bug 44085
parent be495d73
......@@ -62,6 +62,7 @@ static const char specialChars[256] = {
};
static const int IntegerSafeLimit = (INT_MAX - 9) / 10;
static const long long LongLongSafeLimit = (LLONG_MAX - 9) / 10;
//------------------------------------------------------------------------
// Lexer
......@@ -155,10 +156,10 @@ int Lexer::lookChar() {
Object *Lexer::getObj(Object *obj, int objNum) {
char *p;
int c, c2;
GBool comment, neg, done, overflownInteger, overflownUnsignedInteger;
GBool comment, neg, done, overflownInteger, overflownLongLong;
int numParen;
int xi;
unsigned int xui = 0;
long long xll = 0;
double xf = 0, scale;
GooString *s;
int n, m;
......@@ -187,7 +188,7 @@ Object *Lexer::getObj(Object *obj, int objNum) {
case '5': case '6': case '7': case '8': case '9':
case '+': case '-': case '.':
overflownInteger = gFalse;
overflownUnsignedInteger = gFalse;
overflownLongLong = gFalse;
neg = gFalse;
xi = 0;
if (c == '-') {
......@@ -201,23 +202,21 @@ Object *Lexer::getObj(Object *obj, int objNum) {
c = lookChar();
if (isdigit(c)) {
getChar();
if (unlikely(overflownInteger)) {
if (overflownUnsignedInteger) {
xf = xf * 10.0 + (c - '0');
if (unlikely(overflownLongLong)) {
xf = xf * 10.0 + (c - '0');
} else if (unlikely (overflownInteger)) {
if (unlikely(xll > LongLongSafeLimit) &&
(xll > (LLONG_MAX - (c - '0')) / 10.0)) {
overflownLongLong = gTrue;
xf = xll * 10.0 + (c - '0');
} else {
overflownUnsignedInteger = gTrue;
xf = xui * 10.0 + (c - '0');
xll = xll * 10 + (c - '0');
}
} else {
if (unlikely(xi > IntegerSafeLimit) &&
(xi > (INT_MAX - (c - '0')) / 10.0)) {
overflownInteger = gTrue;
if (xi > (UINT_MAX - (c - '0')) / 10.0) {
overflownUnsignedInteger = gTrue;
xf = xi * 10.0 + (c - '0');
} else {
xui = xi * 10.0 + (c - '0');
}
xll = xi * 10LL + (c - '0');
} else {
xi = xi * 10 + (c - '0');
}
......@@ -231,22 +230,17 @@ Object *Lexer::getObj(Object *obj, int objNum) {
}
if (neg) {
xi = -xi;
xll = -xll;
xf = -xf;
}
if (unlikely(overflownInteger)) {
if (overflownUnsignedInteger) {
if (overflownLongLong) {
obj->initReal(xf);
} else {
if (neg) {
if (xui-1 == INT_MAX) {
obj->initInt(INT_MIN);
} else {
xf = xui;
xf = -xf;
obj->initReal(xf);
}
if (unlikely(xll == INT_MIN)) {
obj->initInt(INT_MIN);
} else {
obj->initUint(xui);
obj->initInt64(xll);
}
}
} else {
......@@ -256,8 +250,8 @@ Object *Lexer::getObj(Object *obj, int objNum) {
doReal:
if (likely(!overflownInteger)) {
xf = xi;
} else if (!overflownUnsignedInteger) {
xf = xui;
} else if (!overflownLongLong) {
xf = xll;
}
scale = 0.1;
while (1) {
......
......@@ -53,7 +53,7 @@ static const char *objTypeNames[numObjTypes] = {
"error",
"eof",
"none",
"unsigned integer"
"integer64"
};
#ifdef DEBUG_MEM
......@@ -224,8 +224,8 @@ void Object::print(FILE *f) {
case objNone:
fprintf(f, "<none>");
break;
case objUint:
fprintf(f, "%u", uintg);
case objInt64:
fprintf(f, "%lld", int64g);
break;
}
}
......
......@@ -48,10 +48,10 @@
abort(); \
}
#define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2) \
if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \
#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \
if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \
error(errInternal, 0, (char *) "Call to Object where the object was type {0:d}, " \
"not the expected type {1:d} or {2:d}", type, wanted_type1, wanted_type2); \
"not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \
abort(); \
}
......@@ -95,7 +95,7 @@ enum ObjType {
objNone, // uninitialized object
// poppler-only objects
objUint // overflown integer that still fits in a unsigned integer
objInt64 // integer with at least 64-bits
};
#define numObjTypes 15 // total number of object types
......@@ -144,8 +144,8 @@ public:
{ initObj(objError); return this; }
Object *initEOF()
{ initObj(objEOF); return this; }
Object *initUint(unsigned int uintgA)
{ initObj(objUint); uintg = uintgA; return this; }
Object *initInt64(long long int64gA)
{ initObj(objInt64); int64g = int64gA; return this; }
// Copy an object.
Object *copy(Object *obj);
......@@ -166,7 +166,7 @@ public:
GBool isBool() { return type == objBool; }
GBool isInt() { return type == objInt; }
GBool isReal() { return type == objReal; }
GBool isNum() { return type == objInt || type == objReal; }
GBool isNum() { return type == objInt || type == objReal || type == objInt64; }
GBool isString() { return type == objString; }
GBool isName() { return type == objName; }
GBool isNull() { return type == objNull; }
......@@ -178,7 +178,7 @@ public:
GBool isError() { return type == objError; }
GBool isEOF() { return type == objEOF; }
GBool isNone() { return type == objNone; }
GBool isUint() { return type == objUint; }
GBool isInt64() { return type == objInt64; }
// Special type checking.
GBool isName(const char *nameA)
......@@ -192,7 +192,11 @@ public:
GBool getBool() { OBJECT_TYPE_CHECK(objBool); return booln; }
int getInt() { OBJECT_TYPE_CHECK(objInt); return intg; }
double getReal() { OBJECT_TYPE_CHECK(objReal); return real; }
double getNum() { OBJECT_2TYPES_CHECK(objInt, objReal); return type == objInt ? (double)intg : real; }
// Note: integers larger than 2^53 can not be exactly represented by a double.
// Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64().
double getNum() { OBJECT_3TYPES_CHECK(objInt, objInt64, objReal);
return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; }
GooString *getString() { OBJECT_TYPE_CHECK(objString); return string; }
char *getName() { OBJECT_TYPE_CHECK(objName); return name; }
Array *getArray() { OBJECT_TYPE_CHECK(objArray); return array; }
......@@ -202,7 +206,7 @@ public:
int getRefNum() { OBJECT_TYPE_CHECK(objRef); return ref.num; }
int getRefGen() { OBJECT_TYPE_CHECK(objRef); return ref.gen; }
char *getCmd() { OBJECT_TYPE_CHECK(objCmd); return cmd; }
unsigned int getUint() { OBJECT_TYPE_CHECK(objUint); return uintg; }
long long getInt64() { OBJECT_TYPE_CHECK(objInt64); return int64g; }
// Array accessors.
int arrayGetLength();
......@@ -247,7 +251,7 @@ private:
union { // value for each type:
GBool booln; // boolean
int intg; // integer
unsigned int uintg; // unsigned integer
long long int64g; // 64-bit integer
double real; // real
GooString *string; // string
char *name; // name
......
......@@ -1122,8 +1122,8 @@ void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numO
case objInt:
outStr->printf("%i ", obj->getInt());
break;
case objUint:
outStr->printf("%u ", obj->getUint());
case objInt64:
outStr->printf("%lli ", obj->getInt64());
break;
case objReal:
{
......
......@@ -167,8 +167,8 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
encryptDictA->dictLookup("OE", &ownerEncObj);
encryptDictA->dictLookup("UE", &userEncObj);
encryptDictA->dictLookup("P", &permObj);
if (permObj.isUint()) {
unsigned int permUint = permObj.getUint();
if (permObj.isInt64()) {
unsigned int permUint = permObj.getInt64();
int perms = permUint - UINT_MAX - 1;
permObj.free();
permObj.initInt(perms);
......
......@@ -12,7 +12,7 @@ private slots:
void TestLexer::testNumbers()
{
char *data = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1";
char *data = "0 1 -1 2147483647 -2147483647 2147483648 -2147483648 4294967297 -2147483649 0.1 1.1 -1.1 2147483647.1 -2147483647.1 2147483648.1 -2147483648.1 4294967297.1 -2147483649.1 9223372036854775807 18446744073709551615";
Object dummy;
MemStream *stream = new MemStream(data, 0, strlen(data), &dummy);
Lexer *lexer = new Lexer(NULL, stream);
......@@ -46,8 +46,8 @@ void TestLexer::testNumbers()
obj.free();
lexer->getObj(&obj);
QCOMPARE(obj.getType(), objUint);
QCOMPARE(obj.getUint(), 2147483648u);
QCOMPARE(obj.getType(), objInt64);
QCOMPARE(obj.getInt64(), 2147483648ll);
obj.free();
lexer->getObj(&obj);
......@@ -56,13 +56,13 @@ void TestLexer::testNumbers()
obj.free();
lexer->getObj(&obj);
QCOMPARE(obj.getType(), objReal);
QCOMPARE(obj.getReal(), 4294967297.);
QCOMPARE(obj.getType(), objInt64);
QCOMPARE(obj.getInt64(), 4294967297ll);
obj.free();
lexer->getObj(&obj);
QCOMPARE(obj.getType(), objReal);
QCOMPARE(obj.getReal(), -2147483649.);
QCOMPARE(obj.getType(), objInt64);
QCOMPARE(obj.getInt64(), -2147483649ll);
obj.free();
lexer->getObj(&obj);
......@@ -110,6 +110,16 @@ void TestLexer::testNumbers()
QCOMPARE(obj.getReal(), -2147483649.1);
obj.free();
lexer->getObj(&obj);
QCOMPARE(obj.getType(), objInt64);
QCOMPARE(obj.getInt64(), 9223372036854775807ll);
obj.free();
lexer->getObj(&obj);
QCOMPARE(obj.getType(), objReal);
QCOMPARE(obj.getReal(), 18446744073709551616.);
obj.free();
delete lexer;
}
......
......@@ -149,6 +149,7 @@ static GBool compareObjects(Object *objA, Object *objB)
}
}
case objInt:
case objInt64:
case objReal:
{
if (!objB->isNum()) {
......@@ -159,14 +160,6 @@ static GBool compareObjects(Object *objA, Object *objB)
return (-0.01 < diff) && (diff < 0.01);
}
}
case objUint:
{
if (objB->getType() != objUint) {
return gFalse;
} else {
return (objA->getUint() == objB->getUint());
}
}
case objString:
{
if (objB->getType() != objString) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment