diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2012-01-05 16:23:26 +0100 |
---|---|---|
committer | Jamey Hicks <jamey.hicks@nokia.com> | 2012-01-05 22:57:09 +0100 |
commit | af7c2aafdc283c76f64ff254021855944e44b1a8 (patch) | |
tree | a4baff02e07f3c18dea8cad68df464e7d188c669 /src | |
parent | 51039d6bfbbde485a8d87840bbbbe7fdf014dd95 (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.cpp | 4 | ||||
-rw-r--r-- | src/qjson_p.h | 193 | ||||
-rw-r--r-- | src/qjsonarray.cpp | 10 | ||||
-rw-r--r-- | src/qjsonobject.cpp | 12 | ||||
-rw-r--r-- | src/qjsonparser.cpp | 3 | ||||
-rw-r--r-- | src/qjsonvalue.cpp | 6 | ||||
-rw-r--r-- | src/qjsonwriter.cpp | 2 |
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"; |