diff options
Diffstat (limited to 'src/corelib/serialization')
-rw-r--r-- | src/corelib/serialization/qbinaryjson.cpp | 81 | ||||
-rw-r--r-- | src/corelib/serialization/qbinaryjson_p.h | 102 | ||||
-rw-r--r-- | src/corelib/serialization/qbinaryjsonarray.cpp | 12 | ||||
-rw-r--r-- | src/corelib/serialization/qbinaryjsonobject.cpp | 14 | ||||
-rw-r--r-- | src/corelib/serialization/qbinaryjsonvalue.cpp | 2 | ||||
-rw-r--r-- | src/corelib/serialization/qxmlstream.cpp | 2 | ||||
-rw-r--r-- | src/corelib/serialization/qxmlstream.g | 2 | ||||
-rw-r--r-- | src/corelib/serialization/qxmlstream_p.h | 2 |
8 files changed, 126 insertions, 91 deletions
diff --git a/src/corelib/serialization/qbinaryjson.cpp b/src/corelib/serialization/qbinaryjson.cpp index 3d359f0998..8c16178c59 100644 --- a/src/corelib/serialization/qbinaryjson.cpp +++ b/src/corelib/serialization/qbinaryjson.cpp @@ -64,17 +64,17 @@ void MutableData::compact() Base *base = header->root(); int reserve = 0; - if (base->is_object) { + if (base->isObject()) { auto *o = static_cast<Object *>(base); - for (uint i = 0; i < o->length; ++i) + for (uint i = 0; i < o->length(); ++i) reserve += o->entryAt(i)->usedStorage(o); } else { auto *a = static_cast<Array *>(base); - for (uint i = 0; i < a->length; ++i) + for (uint i = 0; i < a->length(); ++i) reserve += a->at(i)->usedStorage(a); } - uint size = sizeof(Base) + reserve + base->length * sizeof(offset); + uint size = sizeof(Base) + reserve + base->length() * sizeof(offset); uint alloc = sizeof(Header) + size; auto *h = reinterpret_cast<Header *>(malloc(alloc)); Q_CHECK_PTR(h); @@ -82,16 +82,19 @@ void MutableData::compact() h->version = 1; Base *b = h->root(); b->size = size; - b->is_object = header->root()->is_object; - b->length = base->length; + if (header->root()->isObject()) + b->setIsObject(); + else + b->setIsArray(); + b->setLength(base->length()); b->tableOffset = reserve + sizeof(Array); uint offset = sizeof(Base); - if (b->is_object) { + if (b->isObject()) { const auto *o = static_cast<const Object *>(base); auto *no = static_cast<Object *>(b); - for (uint i = 0; i < o->length; ++i) { + for (uint i = 0; i < o->length(); ++i) { no->table()[i] = offset; const Entry *e = o->entryAt(i); @@ -102,7 +105,7 @@ void MutableData::compact() uint dataSize = e->value.usedStorage(o); if (dataSize) { memcpy(reinterpret_cast<char *>(no) + offset, e->value.data(o), dataSize); - ne->value.value = offset; + ne->value.setValue(offset); offset += dataSize; } } @@ -110,14 +113,14 @@ void MutableData::compact() const auto *a = static_cast<const Array *>(base); auto *na = static_cast<Array *>(b); - for (uint i = 0; i < a->length; ++i) { + for (uint i = 0; i < a->length(); ++i) { const Value *v = a->at(i); Value *nv = na->at(i); *nv = *v; uint dataSize = v->usedStorage(a); if (dataSize) { memcpy(reinterpret_cast<char *>(na) + offset, v->data(a), dataSize); - nv->value = offset; + nv->setValue(offset); offset += dataSize; } } @@ -137,7 +140,7 @@ bool ConstData::isValid() const const Base *root = header->root(); const uint maxSize = alloc - sizeof(Header); - return root->is_object + return root->isObject() ? static_cast<const Object *>(root)->isValid(maxSize) : static_cast<const Array *>(root)->isValid(maxSize); } @@ -145,14 +148,14 @@ bool ConstData::isValid() const QJsonDocument ConstData::toJsonDocument() const { const Base *root = header->root(); - return root->is_object + return root->isObject() ? QJsonDocument(static_cast<const Object *>(root)->toJsonObject()) : QJsonDocument(static_cast<const Array *>(root)->toJsonArray()); } uint Base::reserveSpace(uint dataSize, uint posInTable, uint numItems, bool replace) { - Q_ASSERT(posInTable <= length); + Q_ASSERT(posInTable <= length()); if (size + dataSize >= Value::MaxSize) { qWarning("QJson: Document too large to store in data structure %d %d %d", uint(size), dataSize, Value::MaxSize); @@ -162,10 +165,10 @@ uint Base::reserveSpace(uint dataSize, uint posInTable, uint numItems, bool repl offset off = tableOffset; // move table to new position if (replace) { - memmove(reinterpret_cast<char *>(table()) + dataSize, table(), length * sizeof(offset)); + memmove(reinterpret_cast<char *>(table()) + dataSize, table(), length() * sizeof(offset)); } else { memmove(reinterpret_cast<char *>(table() + posInTable + numItems) + dataSize, - table() + posInTable, (length - posInTable) * sizeof(offset)); + table() + posInTable, (length() - posInTable) * sizeof(offset)); memmove(reinterpret_cast<char *>(table()) + dataSize, table(), posInTable * sizeof(offset)); } tableOffset += dataSize; @@ -173,7 +176,7 @@ uint Base::reserveSpace(uint dataSize, uint posInTable, uint numItems, bool repl table()[posInTable + i] = off; size += dataSize; if (!replace) { - length += numItems; + setLength(length() + numItems); size += numItems * sizeof(offset); } return off; @@ -182,7 +185,7 @@ uint Base::reserveSpace(uint dataSize, uint posInTable, uint numItems, bool repl uint Object::indexOf(QStringView key, bool *exists) const { uint min = 0; - uint n = length; + uint n = length(); while (n > 0) { uint half = n >> 1; uint middle = min + half; @@ -193,7 +196,7 @@ uint Object::indexOf(QStringView key, bool *exists) const n -= half + 1; } } - if (min < length && *entryAt(min) == key) { + if (min < length() && *entryAt(min) == key) { *exists = true; return min; } @@ -204,7 +207,7 @@ uint Object::indexOf(QStringView key, bool *exists) const QJsonObject Object::toJsonObject() const { QJsonObject object; - for (uint i = 0; i < length; ++i) { + for (uint i = 0; i < length(); ++i) { const Entry *e = entryAt(i); object.insert(e->key(), e->value.toJsonValue(this)); } @@ -213,11 +216,11 @@ QJsonObject Object::toJsonObject() const bool Object::isValid(uint maxSize) const { - if (size > maxSize || tableOffset + length * sizeof(offset) > size) + if (size > maxSize || tableOffset + length() * sizeof(offset) > size) return false; QString lastKey; - for (uint i = 0; i < length; ++i) { + for (uint i = 0; i < length(); ++i) { if (table()[i] + sizeof(Entry) >= tableOffset) return false; const Entry *e = entryAt(i); @@ -237,18 +240,18 @@ QJsonArray Array::toJsonArray() const { QJsonArray array; const offset *values = table(); - for (uint i = 0; i < length; ++i) + for (uint i = 0; i < length(); ++i) array.append(reinterpret_cast<const Value *>(values + i)->toJsonValue(this)); return array; } bool Array::isValid(uint maxSize) const { - if (size > maxSize || tableOffset + length * sizeof(offset) > size) + if (size > maxSize || tableOffset + length() * sizeof(offset) > size) return false; const offset *values = table(); - for (uint i = 0; i < length; ++i) { + for (uint i = 0; i < length(); ++i) { if (!reinterpret_cast<const Value *>(values + i)->isValid(this)) return false; } @@ -258,14 +261,14 @@ bool Array::isValid(uint maxSize) const uint Value::usedStorage(const Base *b) const { uint s = 0; - switch (type) { + switch (type()) { case QJsonValue::Double: - if (!latinOrIntValue) + if (!isLatinOrIntValue()) s = sizeof(double); break; case QJsonValue::String: { const char *d = data(b); - s = latinOrIntValue + s = isLatinOrIntValue() ? (sizeof(ushort) + qFromLittleEndian(*reinterpret_cast<const ushort *>(d))) : (sizeof(int) @@ -286,7 +289,7 @@ uint Value::usedStorage(const Base *b) const QJsonValue Value::toJsonValue(const Base *b) const { - switch (type) { + switch (type()) { case QJsonValue::Null: return QJsonValue(QJsonValue::Null); case QJsonValue::Bool: @@ -314,24 +317,24 @@ inline bool isValidValueOffset(uint offset, uint tableOffset) bool Value::isValid(const Base *b) const { - switch (type) { + switch (type()) { case QJsonValue::Null: case QJsonValue::Bool: return true; case QJsonValue::Double: - return latinOrIntValue || isValidValueOffset(value, b->tableOffset); + return isLatinOrIntValue() || isValidValueOffset(value(), b->tableOffset); case QJsonValue::String: - if (!isValidValueOffset(value, b->tableOffset)) + if (!isValidValueOffset(value(), b->tableOffset)) return false; - if (latinOrIntValue) - return asLatin1String(b).isValid(b->tableOffset - value); - return asString(b).isValid(b->tableOffset - value); + if (isLatinOrIntValue()) + return asLatin1String(b).isValid(b->tableOffset - value()); + return asString(b).isValid(b->tableOffset - value()); case QJsonValue::Array: - return isValidValueOffset(value, b->tableOffset) - && static_cast<const Array *>(base(b))->isValid(b->tableOffset - value); + return isValidValueOffset(value(), b->tableOffset) + && static_cast<const Array *>(base(b))->isValid(b->tableOffset - value()); case QJsonValue::Object: - return isValidValueOffset(value, b->tableOffset) - && static_cast<const Object *>(base(b))->isValid(b->tableOffset - value); + return isValidValueOffset(value(), b->tableOffset) + && static_cast<const Object *>(base(b))->isValid(b->tableOffset - value()); default: return false; } diff --git a/src/corelib/serialization/qbinaryjson_p.h b/src/corelib/serialization/qbinaryjson_p.h index 132c36f227..6502f1fbd2 100644 --- a/src/corelib/serialization/qbinaryjson_p.h +++ b/src/corelib/serialization/qbinaryjson_p.h @@ -136,11 +136,15 @@ using qle_ushort = q_littleendian<unsigned short>; using qle_int = q_littleendian<int>; using qle_uint = q_littleendian<unsigned int>; -template<int pos, int width> -using qle_bitfield = QLEIntegerBitfield<uint, pos, width>; +template<typename... Accessors> +using qle_bitfield = QLEIntegerBitfieldUnion<uint, Accessors...>; template<int pos, int width> -using qle_signedbitfield = QLEIntegerBitfield<int, pos, width>; +using qle_bitfield_accessor + = QSpecialIntegerAccessor<QLittleEndianStorageType<uint>, pos, width>; +template<int pos, int width> +using qle_signedbitfield_accessor + = QSpecialIntegerAccessor<QLittleEndianStorageType<uint>, pos, width, int>; using offset = qle_uint; @@ -316,19 +320,24 @@ static inline void copyString(char *dest, QStringView str, bool compress) */ class Base { +private: + using IsObjectAccessor = qle_bitfield_accessor<0, 1>; + using LengthAccessor = qle_bitfield_accessor<1, 31>; public: qle_uint size; - union { - uint _dummy; - qle_bitfield<0, 1> is_object; - qle_bitfield<1, 31> length; - }; + qle_bitfield<IsObjectAccessor, LengthAccessor> isObjectAndLength; offset tableOffset; // content follows here - bool isObject() const { return !!is_object; } + void setIsObject() { isObjectAndLength.set<IsObjectAccessor>(1); } + bool isObject() const { return !!isObjectAndLength.get<IsObjectAccessor>(); } + + void setIsArray() { isObjectAndLength.set<IsObjectAccessor>(0); } bool isArray() const { return !isObject(); } + void setLength(uint length) { isObjectAndLength.set<LengthAccessor>(length); } + uint length() const { return isObjectAndLength.get<LengthAccessor>(); } + offset *table() { return reinterpret_cast<offset *>(reinterpret_cast<char *>(this) + tableOffset); @@ -372,39 +381,46 @@ public: class Value { +private: + using TypeAccessor = qle_bitfield_accessor<0, 3>; + using LatinOrIntValueAccessor = qle_bitfield_accessor<3, 1>; + using LatinKeyAccessor = qle_bitfield_accessor<4, 1>; + using ValueAccessor = qle_bitfield_accessor<5, 27>; + using IntValueAccessor = qle_signedbitfield_accessor<5, 27>; + qle_bitfield< + TypeAccessor, + LatinOrIntValueAccessor, + LatinKeyAccessor, + ValueAccessor, + IntValueAccessor + > m_data; + int intValue() const { return m_data.get<IntValueAccessor>(); } + public: enum { MaxSize = (1 << 27) - 1 }; - union { - uint _dummy; - qle_bitfield<0, 3> type; - qle_bitfield<3, 1> latinOrIntValue; - qle_bitfield<4, 1> latinKey; - qle_bitfield<5, 27> value; - qle_signedbitfield<5, 27> int_value; - }; inline const char *data(const Base *b) const { - return reinterpret_cast<const char *>(b) + value; + return reinterpret_cast<const char *>(b) + value(); } uint usedStorage(const Base *b) const; bool toBoolean() const { - Q_ASSERT(type == QJsonValue::Bool); - return value != 0; + Q_ASSERT(type() == QJsonValue::Bool); + return value() != 0; } double toDouble(const Base *b) const { - Q_ASSERT(type == QJsonValue::Double); - if (latinOrIntValue) - return int_value; + Q_ASSERT(type() == QJsonValue::Double); + if (isLatinOrIntValue()) + return intValue(); - auto i = qFromLittleEndian<quint64>(reinterpret_cast<const uchar *>(b) + value); + auto i = qFromLittleEndian<quint64>(reinterpret_cast<const uchar *>(b) + value()); double d; memcpy(&d, &i, sizeof(double)); return d; @@ -412,26 +428,26 @@ public: QString toString(const Base *b) const { - return latinOrIntValue + return isLatinOrIntValue() ? asLatin1String(b).toString() : asString(b).toString(); } String asString(const Base *b) const { - Q_ASSERT(type == QJsonValue::String && !latinOrIntValue); + Q_ASSERT(type() == QJsonValue::String && !isLatinOrIntValue()); return String(data(b)); } Latin1String asLatin1String(const Base *b) const { - Q_ASSERT(type == QJsonValue::String && latinOrIntValue); + Q_ASSERT(type() == QJsonValue::String && isLatinOrIntValue()); return Latin1String(data(b)); } const Base *base(const Base *b) const { - Q_ASSERT(type == QJsonValue::Array || type == QJsonValue::Object); + Q_ASSERT(type() == QJsonValue::Array || type() == QJsonValue::Object); return reinterpret_cast<const Base *>(data(b)); } @@ -441,6 +457,15 @@ public: static uint requiredStorage(const QBinaryJsonValue &v, bool *compressed); static uint valueToStore(const QBinaryJsonValue &v, uint offset); static void copyData(const QBinaryJsonValue &v, char *dest, bool compressed); + + void setIsLatinKey(bool isLatinKey) { m_data.set<LatinKeyAccessor>(isLatinKey); } + bool isLatinKey() const { return m_data.get<LatinKeyAccessor>(); } + void setIsLatinOrIntValue(bool v) { m_data.set<LatinOrIntValueAccessor>(v); } + bool isLatinOrIntValue() const { return m_data.get<LatinOrIntValueAccessor>(); } + void setType(uint type) { m_data.set<TypeAccessor>(type); } + uint type() const { return m_data.get<TypeAccessor>(); } + void setValue(uint value) { m_data.set<ValueAccessor>(value); } + uint value() const { return m_data.get<ValueAccessor>(); } }; class Entry { @@ -452,7 +477,7 @@ public: uint size() const { uint s = sizeof(Entry); - if (value.latinKey) + if (value.isLatinKey()) s += shallowLatin1Key().byteSize(); else s += shallowKey().byteSize(); @@ -466,19 +491,19 @@ public: String shallowKey() const { - Q_ASSERT(!value.latinKey); + Q_ASSERT(!value.isLatinKey()); return String(reinterpret_cast<const char *>(this) + sizeof(Entry)); } Latin1String shallowLatin1Key() const { - Q_ASSERT(value.latinKey); + Q_ASSERT(value.isLatinKey()); return Latin1String(reinterpret_cast<const char *>(this) + sizeof(Entry)); } QString key() const { - return value.latinKey + return value.isLatinKey() ? shallowLatin1Key().toString() : shallowKey().toString(); } @@ -488,21 +513,21 @@ public: if (maxSize < sizeof(Entry)) return false; maxSize -= sizeof(Entry); - return value.latinKey + return value.isLatinKey() ? shallowLatin1Key().isValid(maxSize) : shallowKey().isValid(maxSize); } bool operator ==(QStringView key) const { - return value.latinKey + return value.isLatinKey() ? (shallowLatin1Key().toQLatin1String() == key) : (shallowKey() == key); } bool operator >=(QStringView key) const { - return value.latinKey + return value.isLatinKey() ? (shallowLatin1Key().toQLatin1String() >= key) : (shallowKey().toString() >= key); } @@ -560,9 +585,12 @@ public: header->version = 1; Base *b = header->root(); b->size = sizeof(Base); - b->is_object = (valueType == QJsonValue::Object); + if (valueType == QJsonValue::Object) + b->setIsObject(); + else + b->setIsArray(); b->tableOffset = sizeof(Base); - b->length = 0; + b->setLength(0); } ~MutableData() diff --git a/src/corelib/serialization/qbinaryjsonarray.cpp b/src/corelib/serialization/qbinaryjsonarray.cpp index 68937fe17d..dfbe94db84 100644 --- a/src/corelib/serialization/qbinaryjsonarray.cpp +++ b/src/corelib/serialization/qbinaryjsonarray.cpp @@ -63,7 +63,7 @@ QBinaryJsonArray QBinaryJsonArray::fromJsonArray(const QJsonArray &array) void QBinaryJsonArray::append(const QBinaryJsonValue &value) { - const uint i = a ? a->length : 0; + const uint i = a ? a->length() : 0; bool compressed; uint valueSize = QBinaryJsonPrivate::Value::requiredStorage(value, &compressed); @@ -71,7 +71,7 @@ void QBinaryJsonArray::append(const QBinaryJsonValue &value) if (!detach(valueSize + sizeof(QBinaryJsonPrivate::Value))) return; - if (!a->length) + if (!a->length()) a->tableOffset = sizeof(QBinaryJsonPrivate::Array); uint valueOffset = a->reserveSpace(valueSize, i, 1, false); @@ -79,10 +79,10 @@ void QBinaryJsonArray::append(const QBinaryJsonValue &value) return; QBinaryJsonPrivate::Value *v = a->at(i); - v->type = (value.t == QJsonValue::Undefined ? QJsonValue::Null : value.t); - v->latinOrIntValue = compressed; - v->latinKey = false; - v->value = QBinaryJsonPrivate::Value::valueToStore(value, valueOffset); + v->setType(value.t == QJsonValue::Undefined ? QJsonValue::Null : value.t); + v->setIsLatinOrIntValue(compressed); + v->setIsLatinKey(false); + v->setValue(QBinaryJsonPrivate::Value::valueToStore(value, valueOffset)); if (valueSize) { QBinaryJsonPrivate::Value::copyData(value, reinterpret_cast<char *>(a) + valueOffset, compressed); diff --git a/src/corelib/serialization/qbinaryjsonobject.cpp b/src/corelib/serialization/qbinaryjsonobject.cpp index 3186ab6087..a9e830228e 100644 --- a/src/corelib/serialization/qbinaryjsonobject.cpp +++ b/src/corelib/serialization/qbinaryjsonobject.cpp @@ -74,7 +74,7 @@ void QBinaryJsonObject::insert(const QString &key, const QBinaryJsonValue &value if (!detach(requiredSize + sizeof(QBinaryJsonPrivate::offset))) // offset for the new index entry return; - if (!o->length) + if (!o->length()) o->tableOffset = sizeof(QBinaryJsonPrivate::Object); bool keyExists = false; @@ -87,18 +87,18 @@ void QBinaryJsonObject::insert(const QString &key, const QBinaryJsonValue &value return; QBinaryJsonPrivate::Entry *e = o->entryAt(pos); - e->value.type = value.t; - e->value.latinKey = latinKey; - e->value.latinOrIntValue = latinOrIntValue; - e->value.value = QBinaryJsonPrivate::Value::valueToStore( - value, reinterpret_cast<char *>(e) - reinterpret_cast<char *>(o) + valueOffset); + e->value.setType(value.t); + e->value.setIsLatinKey(latinKey); + e->value.setIsLatinOrIntValue(latinOrIntValue); + e->value.setValue(QBinaryJsonPrivate::Value::valueToStore( + value, reinterpret_cast<char *>(e) - reinterpret_cast<char *>(o) + valueOffset)); QBinaryJsonPrivate::copyString(reinterpret_cast<char *>(e + 1), key, latinKey); if (valueSize) { QBinaryJsonPrivate::Value::copyData(value, reinterpret_cast<char *>(e) + valueOffset, latinOrIntValue); } - if (d->compactionCounter > 32U && d->compactionCounter >= unsigned(o->length) / 2U) + if (d->compactionCounter > 32U && d->compactionCounter >= unsigned(o->length()) / 2U) compact(); } diff --git a/src/corelib/serialization/qbinaryjsonvalue.cpp b/src/corelib/serialization/qbinaryjsonvalue.cpp index 5e3a01ad38..b1636b331e 100644 --- a/src/corelib/serialization/qbinaryjsonvalue.cpp +++ b/src/corelib/serialization/qbinaryjsonvalue.cpp @@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE QBinaryJsonValue::QBinaryJsonValue(QBinaryJsonPrivate::MutableData *data, QBinaryJsonPrivate::Base *parent, const QBinaryJsonPrivate::Value &v) - : t(QJsonValue::Type(uint(v.type))) + : t(QJsonValue::Type(uint(v.type()))) { switch (t) { case QJsonValue::Undefined: diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index b2f846544d..7cd457ba3a 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -980,7 +980,7 @@ inline uint QXmlStreamReaderPrivate::peekChar() bool QXmlStreamReaderPrivate::scanUntil(const char *str, short tokenToInject) { int pos = textBuffer.size(); - int oldLineNumber = lineNumber; + const auto oldLineNumber = lineNumber; uint c; while ((c = getChar()) != StreamEOF) { diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g index b623de9505..4321fed68a 100644 --- a/src/corelib/serialization/qxmlstream.g +++ b/src/corelib/serialization/qxmlstream.g @@ -557,6 +557,7 @@ bool QXmlStreamReaderPrivate::parse() setType(QXmlStreamReader::EndElement); Tag &tag = tagStack_pop(); namespaceUri = tag.namespaceDeclaration.namespaceUri; + prefix = tag.namespaceDeclaration.prefix; name = tag.name; qualifiedName = tag.qualifiedName; isEmptyElement = false; @@ -1617,6 +1618,7 @@ etag ::= LANGLE SLASH qname space_opt RANGLE; Tag &tag = tagStack_pop(); namespaceUri = tag.namespaceDeclaration.namespaceUri; + prefix = tag.namespaceDeclaration.prefix; name = tag.name; qualifiedName = tag.qualifiedName; if (qualifiedName != symName(3)) diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h index 103b123b10..e5bde7b98e 100644 --- a/src/corelib/serialization/qxmlstream_p.h +++ b/src/corelib/serialization/qxmlstream_p.h @@ -1046,6 +1046,7 @@ bool QXmlStreamReaderPrivate::parse() setType(QXmlStreamReader::EndElement); Tag &tag = tagStack_pop(); namespaceUri = tag.namespaceDeclaration.namespaceUri; + prefix = tag.namespaceDeclaration.prefix; name = tag.name; qualifiedName = tag.qualifiedName; isEmptyElement = false; @@ -1798,6 +1799,7 @@ bool QXmlStreamReaderPrivate::parse() namespaceUri = tag.namespaceDeclaration.namespaceUri; name = tag.name; qualifiedName = tag.qualifiedName; + prefix = tag.namespaceDeclaration.prefix; if (qualifiedName != symName(3)) raiseWellFormedError(QXmlStream::tr("Opening and ending tag mismatch.")); } break; |