summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2012-01-05 16:23:26 +0100
committerJamey Hicks <jamey.hicks@nokia.com>2012-01-05 22:57:09 +0100
commitaf7c2aafdc283c76f64ff254021855944e44b1a8 (patch)
treea4baff02e07f3c18dea8cad68df464e7d188c669 /src
parent51039d6bfbbde485a8d87840bbbbe7fdf014dd95 (diff)
Make the data structure endian-safe
The binary data structure is always little-endian. Use some special types to ensure that we store things correctly even on a big endian machine. Change-Id: Ief814d14f163344eae4860b6324b69b005ce8ae7 Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Jamey Hicks <jamey.hicks@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qjson.cpp4
-rw-r--r--src/qjson_p.h193
-rw-r--r--src/qjsonarray.cpp10
-rw-r--r--src/qjsonobject.cpp12
-rw-r--r--src/qjsonparser.cpp3
-rw-r--r--src/qjsonvalue.cpp6
-rw-r--r--src/qjsonwriter.cpp2
7 files changed, 177 insertions, 53 deletions
diff --git a/src/qjson.cpp b/src/qjson.cpp
index b99640d..b77dcf2 100644
--- a/src/qjson.cpp
+++ b/src/qjson.cpp
@@ -188,7 +188,7 @@ bool Object::isValid() const
if (tableOffset + length*sizeof(offset) > size)
return false;
- for (int i = 0; i < length; ++i) {
+ for (uint i = 0; i < length; ++i) {
offset entryOffset = table()[i];
if (entryOffset + sizeof(Entry) >= tableOffset)
return false;
@@ -209,7 +209,7 @@ bool Array::isValid() const
if (tableOffset + length*sizeof(offset) > size)
return false;
- for (int i = 0; i < length; ++i) {
+ for (uint i = 0; i < length; ++i) {
if (!at(i).isValid(this))
return false;
}
diff --git a/src/qjson_p.h b/src/qjson_p.h
index 9175366..5ddee90 100644
--- a/src/qjson_p.h
+++ b/src/qjson_p.h
@@ -112,12 +112,121 @@
namespace QtJson
{
-typedef uint offset;
struct Array;
struct Object;
struct Value;
struct Entry;
+template<typename T>
+struct q_littleendian
+{
+ T val;
+
+ q_littleendian &operator =(T i) { val = qToLittleEndian(i); return *this; }
+ operator T() const { return qFromLittleEndian(val); }
+
+ bool operator ==(T i) { return qFromLittleEndian(val) == i; }
+ bool operator !=(T i) { return qFromLittleEndian(val) != i; }
+ bool operator <(T i) { return qFromLittleEndian(val) < i; }
+ bool operator >(T i) { return qFromLittleEndian(val) > i; }
+ bool operator <=(T i) { return qFromLittleEndian(val) <= i; }
+ bool operator >=(T i) { return qFromLittleEndian(val) >= i; }
+ q_littleendian &operator +=(T i) {
+ val = qToLittleEndian(qFromLittleEndian(val) + i);
+ return *this;
+ }
+};
+
+typedef q_littleendian<short> qle_short;
+typedef q_littleendian<unsigned short> qle_ushort;
+typedef q_littleendian<int> qle_int;
+typedef q_littleendian<unsigned int> qle_uint;
+
+template<int pos, int width>
+struct qle_bitfield
+{
+ uint val;
+
+ enum {
+ mask = ((1u << width) - 1) << pos
+ };
+
+ void operator =(uint t) {
+ uint i = qFromLittleEndian(val);
+ i &= ~mask;
+ i |= t << pos;
+ val = qToLittleEndian(i);
+ }
+ operator uint() const {
+ uint t = qFromLittleEndian(val);
+ t &= mask;
+ t >>= pos;
+ return t;
+ }
+ bool operator !() const {
+ return !operator uint();
+ }
+
+ bool operator ==(uint t) { return uint(*this) == t; }
+ bool operator !=(uint t) { return uint(*this) != t; }
+ bool operator <(uint t) { return uint(*this) < t; }
+ bool operator >(uint t) { return uint(*this) > t; }
+ bool operator <=(uint t) { return uint(*this) <= t; }
+ bool operator >=(uint t) { return uint(*this) >= t; }
+ qle_bitfield &operator +=(uint i) {
+ *this = (uint(*this) + i);
+ return *this;
+ }
+ qle_bitfield &operator -=(uint i) {
+ *this = (uint(*this) - i);
+ return *this;
+ }
+};
+
+template<int pos, int width>
+struct qle_signedbitfield
+{
+ uint val;
+
+ enum {
+ mask = ((1u << width) - 1) << pos
+ };
+
+ void operator =(int t) {
+ uint i = qFromLittleEndian(val);
+ i &= ~mask;
+ i |= t << pos;
+ val = qToLittleEndian(i);
+ }
+ operator int() const {
+ uint i = qFromLittleEndian(val);
+ i <<= 32 - width - pos;
+ int t = (int) i;
+ t >>= pos;
+ return t;
+ }
+ bool operator !() const {
+ return !operator int();
+ }
+
+ bool operator ==(int t) { return int(*this) == t; }
+ bool operator !=(int t) { return int(*this) != t; }
+ bool operator <(int t) { return int(*this) < t; }
+ bool operator >(int t) { return int(*this) > t; }
+ bool operator <=(int t) { return int(*this) <= t; }
+ bool operator >=(int t) { return int(*this) >= t; }
+ qle_signedbitfield &operator +=(int i) {
+ *this = (int(*this) + i);
+ return *this;
+ }
+ qle_signedbitfield &operator -=(int i) {
+ *this = (int(*this) - i);
+ return *this;
+ }
+};
+
+typedef qle_uint offset;
+
static inline int alignedSize(int size) { return (size + 3) & ~3; }
static inline bool useCompressed(const QString &s)
@@ -178,8 +287,8 @@ struct String
String(const char *data) { d = (Data *)data; }
struct Data {
- int length;
- ushort utf16[1];
+ qle_int length;
+ qle_ushort utf16[1];
};
Data *d;
@@ -187,19 +296,24 @@ struct String
inline String &operator=(const QString &str)
{
d->length = str.length();
- memcpy(d->utf16, str.unicode(), d->length*sizeof(ushort));
- if (d->length & 1)
- d->utf16[d->length] = 0;
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ for (int i = 0; i < str.length(); ++i)
+ d->utf16[i] = uc[i];
+#else
+ memcpy(d->utf16, str.unicode(), str.length()*sizeof(ushort));
+#endif
+ if (str.length() & 1)
+ d->utf16[str.length()] = 0;
return *this;
}
bool operator ==(const QString &str) {
int slen = str.length();
const ushort *s = (const ushort *)str.constData();
- if (slen != d->length)
- return false;
int l = d->length;
- const ushort *a = d->utf16;
+ if (slen != l)
+ return false;
+ const qle_ushort *a = d->utf16;
const ushort *b = s;
while (l-- && *a == *b)
a++,b++;
@@ -208,6 +322,19 @@ struct String
bool operator !=(const QString &str) {
return !operator ==(str);
}
+ QString toString() const {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ return QString((QChar *)d->utf16, d->length);
+#else
+ int l = d->length;
+ QString str(l, QChar());
+ QChar *ch = str.data();
+ for (int i = 0; i < l; ++i)
+ ch[i] = d->utf16[i];
+ return str;
+#endif
+ }
+
};
struct Latin1String
@@ -215,15 +342,15 @@ struct Latin1String
Latin1String(const char *data) { d = (Data *)data; }
struct Data {
- short length;
- uchar latin1[1];
+ qle_short length;
+ char latin1[1];
};
Data *d;
inline Latin1String &operator=(const QString &str)
{
d->length = str.length();
- uchar *l = d->latin1;
+ uchar *l = (uchar *)d->latin1;
const ushort *uc = (const ushort *)str.unicode();
for (int i = 0; i < str.length(); ++i)
*l++ = uc[i];
@@ -238,7 +365,7 @@ struct Latin1String
if (slen != d->length)
return false;
int l = d->length;
- const uchar *a = d->latin1;
+ const uchar *a = (uchar *)d->latin1;
const ushort *b = s;
while (l-- && *a == *b)
a++,b++;
@@ -247,6 +374,10 @@ struct Latin1String
bool operator !=(const QString &str) {
return !operator ==(str);
}
+
+ QString toString() const {
+ return QString::fromLatin1(d->latin1, d->length);
+ }
};
@@ -265,14 +396,17 @@ static inline void copyString(char *dest, const QString &str, bool compress)
struct Base
{
- uint size;
- uint length : 31;
- uint is_object : 1; // object or Array
+ qle_uint size;
+ union {
+ uint _dummy;
+ qle_bitfield<0, 1> is_object;
+ qle_bitfield<1, 31> length;
+ };
offset tableOffset;
// content follows here
inline bool isObject() const { return is_object; }
- inline bool isArray() const { return !is_object; }
+ inline bool isArray() const { return !isObject(); }
inline offset *table() const { return (offset *) (((char *) this) + tableOffset); }
@@ -307,19 +441,14 @@ struct Value
// unfortunately some compilers can't handle mixed types in bitfields.
// this works around the problem
union {
- struct {
- int unused : 5;
- int int_val : 27;
- };
- struct {
- uint type : 3;
- uint latinOrIntValue : 1;
- uint latinKey : 1;
- uint val : 27;
- };
+ uint _dummy;
+ qle_bitfield<0, 3> type;
+ qle_bitfield<3, 1> latinOrIntValue;
+ qle_bitfield<4, 1> latinKey;
+ qle_bitfield<5, 27> val;
+ qle_signedbitfield<5, 27> int_val;
};
-
inline char *data(const Base *b) const { return ((char *)b) + val; }
int usedStorage(const Base *b) const;
@@ -348,8 +477,6 @@ inline Value &Array::operator [](int i)
struct Entry {
Value value;
- ushort *keyData() const { return (ushort *)((const char *)this + sizeof(Entry) + sizeof(int)); }
- uchar *latin1KeyData() const { return (uchar *)((const char *)this + sizeof(Entry) + sizeof(ushort)); }
// key
// value data follows key
@@ -379,11 +506,9 @@ struct Entry {
QString key() const
{
if (value.latinKey) {
- int length = *(ushort *) ((const char *)this + sizeof(Entry));
- return QString::fromLatin1((const char *)latin1KeyData(), length);
+ return shallowLatin1Key().toString();
}
- int length = *(int *) ((const char *)this + sizeof(Entry));
- return QString((const QChar *)keyData(), length);
+ return shallowKey().toString();
}
bool matchesKey(const QString &key);
diff --git a/src/qjsonarray.cpp b/src/qjsonarray.cpp
index 6a5ed4a..4d3a969 100644
--- a/src/qjsonarray.cpp
+++ b/src/qjsonarray.cpp
@@ -130,7 +130,7 @@ bool JsonArray::isEmpty() const
if (!d)
return true;
- return a->length == 0;
+ return !a->length;
}
JsonValue JsonArray::at(int i) const
@@ -164,7 +164,7 @@ void JsonArray::removeAt(int i)
detach();
a->removeItems(i, 1);
++d->compactionCounter;
- if (d->compactionCounter > 32 && d->compactionCounter >= a->length/2)
+ if (d->compactionCounter > 32 && d->compactionCounter >= (int)a->length/2)
compact();
}
@@ -190,7 +190,7 @@ void JsonArray::insert(int i, const JsonValue &value)
bool compressed;
int valueSize = value.requiredStorage(&compressed);
- detach(valueSize + sizeof(offset) + sizeof(Value)); // offset for the new index entry
+ detach(valueSize + sizeof(Value));
if (!a->length)
a->tableOffset = sizeof(Array);
@@ -232,9 +232,9 @@ bool JsonArray::operator==(const JsonArray &other) const
return true;
if (!a)
- return other.a->length == 0;
+ return !other.a->length;
if (!other.a)
- return a->length == 0;
+ return !a->length;
if (a->length != other.a->length)
return false;
diff --git a/src/qjsonobject.cpp b/src/qjsonobject.cpp
index e75dccc..5905e03 100644
--- a/src/qjsonobject.cpp
+++ b/src/qjsonobject.cpp
@@ -147,7 +147,7 @@ bool JsonObject::isEmpty() const
if (!d)
return true;
- return o->length == 0;
+ return !o->length;
}
JsonValue JsonObject::value(const QString &key) const
@@ -189,7 +189,7 @@ void JsonObject::insert(const QString &key, const JsonValue &value)
int pos = o->insertKey(key);
- if (pos < o->length)
+ if (pos < (int)o->length)
++d->compactionCounter;
o->reserveSpace(requiredSize, pos, 1);
@@ -215,7 +215,7 @@ void JsonObject::remove(const QString &key)
detach();
o->removeItems(index, 1);
++d->compactionCounter;
- if (d->compactionCounter > 32 && d->compactionCounter >= o->length/2)
+ if (d->compactionCounter > 32 && d->compactionCounter >= (int)o->length/2)
compact();
}
@@ -231,7 +231,7 @@ JsonValue JsonObject::take(const QString &key)
Entry *e = o->entryAt(index);
o->removeItems(index, 1);
++d->compactionCounter;
- if (d->compactionCounter > 32 && d->compactionCounter >= o->length/2)
+ if (d->compactionCounter > 32 && d->compactionCounter >= (int)o->length/2)
compact();
return JsonValue(d, o, e->value);
@@ -251,9 +251,9 @@ bool JsonObject::operator==(const JsonObject &other) const
return true;
if (!o)
- return other.o->length == 0;
+ return !other.o->length;
if (!other.o)
- return o->length == 0;
+ return !o->length;
if (o->length != other.o->length)
return false;
diff --git a/src/qjsonparser.cpp b/src/qjsonparser.cpp
index b72cdaa..bd60386 100644
--- a/src/qjsonparser.cpp
+++ b/src/qjsonparser.cpp
@@ -325,8 +325,7 @@ value = false / null / true / object / array / number / string
bool QJsonParser::parseValue(Value *val, int baseOffset)
{
BEGIN << "parse Value" << json;
- val->int_val = 0;
- val->unused = 0;
+ val->_dummy = 0;
switch (*json++) {
case 'n':
diff --git a/src/qjsonvalue.cpp b/src/qjsonvalue.cpp
index d92b567..dcf7a5f 100644
--- a/src/qjsonvalue.cpp
+++ b/src/qjsonvalue.cpp
@@ -51,8 +51,8 @@
using namespace QtJson;
-static const Base emptyArray = { sizeof(Base), 0, false, 0 };
-static const Base emptyObject = { sizeof(Base), 0, true, 0 };
+static const Base emptyArray = { { qToLittleEndian(sizeof(Base)) }, { 0 }, { 0 } };
+static const Base emptyObject = { { qToLittleEndian(sizeof(Base)) }, { 0 }, { 0 } };
JsonValue::JsonValue(ValueType type)
: t(type), d(0), dbl(0.)
@@ -62,7 +62,7 @@ JsonValue::JsonValue(ValueType type)
JsonValue::JsonValue(Data *data, Base *base, const Value &v)
: d(0)
{
- t = (ValueType)v.type;
+ t = (ValueType)(uint)v.type;
switch (t) {
case UndefinedValue:
case NullValue:
diff --git a/src/qjsonwriter.cpp b/src/qjsonwriter.cpp
index 3959021..b151490 100644
--- a/src/qjsonwriter.cpp
+++ b/src/qjsonwriter.cpp
@@ -177,7 +177,7 @@ static QByteArray escapedString(const QString &s)
static void valueToJson(const Base *b, const Value &v, QByteArray &json, int indent)
{
- ValueType type = (ValueType)v.type;
+ ValueType type = (ValueType)(uint)v.type;
switch (type) {
case BooleanValue:
json += v.toBoolean() ? "true" : "false";