summaryrefslogtreecommitdiffstats
path: root/src/corelib/serialization/qjsonwriter.cpp
blob: b12b1435b2add644ecc7f69a5411783f4c156da8 (plain)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
// Copyright (C) 2016 The Qt Company Ltd.// Copyright (C) 2016 Intel Corporation.// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only#include <cmath>#include <qlocale.h>#include"qjsonwriter_p.h"#include"qjson_p.h"#include"private/qstringconverter_p.h"#include <private/qnumeric_p.h>#include <private/qcborvalue_p.h> QT_BEGIN_NAMESPACE using namespace QJsonPrivate;static voidobjectContentToJson(const QCborContainerPrivate *o, QByteArray &json,int indent,bool compact);static voidarrayContentToJson(const QCborContainerPrivate *a, QByteArray &json,int indent,bool compact);staticinline uchar hexdig(uint u){return(u <0xa?'0'+ u :'a'+ u -0xa);}static QByteArray escapedString(QStringView s){// give it a minimum size to ensure the resize() below always adds enough space QByteArray ba(qMax(s.size(),16),Qt::Uninitialized);auto ba_const_start = [&]() {return reinterpret_cast<const uchar *>(ba.constData()); }; uchar *cursor =reinterpret_cast<uchar *>(const_cast<char*>(ba.constData()));const uchar *ba_end = cursor + ba.size();const char16_t *src = s.utf16();const char16_t *const end = s.utf16() + s.size();while(src != end) {if(cursor >= ba_end -6) {// ensure we have enough space qptrdiff pos = cursor -ba_const_start(); ba.resize(ba.size()*2); cursor =reinterpret_cast<uchar *>(ba.data()) + pos; ba_end =ba_const_start() + ba.size();} char16_t u = *src++;if(u <0x80) {if(u <0x20|| u ==0x22|| u ==0x5c) {*cursor++ ='\\';switch(u) {case0x22:*cursor++ ='"';break;case0x5c:*cursor++ ='\\';break;case0x8:*cursor++ ='b';break;case0xc:*cursor++ ='f';break;case0xa:*cursor++ ='n';break;case0xd:*cursor++ ='r';break;case0x9:*cursor++ ='t';break;default:*cursor++ ='u';*cursor++ ='0';*cursor++ ='0';*cursor++ =hexdig(u>>4);*cursor++ =hexdig(u &0xf);}}else{*cursor++ = (uchar)u;}}else if(QUtf8Functions::toUtf8<QUtf8BaseTraits>(u, cursor, src, end) <0) {// failed to get valid utf8 use JSON escape sequence*cursor++ ='\\';*cursor++ ='u';*cursor++ =hexdig(u>>12&0x0f);*cursor++ =hexdig(u>>8&0x0f);*cursor++ =hexdig(u>>4&0x0f);*cursor++ =hexdig(u &0x0f);}} ba.resize(cursor -ba_const_start());return ba;}static voidvalueContentToJson(const QCborValue &v, QByteArray &json,int indent,bool compact){QCborValue::Type type = v.type();switch(type) {caseQCborValue::True: json +="true";break;caseQCborValue::False: json +="false";break;caseQCborValue::Integer: json +=QByteArray::number(v.toInteger());break;caseQCborValue::Double: {const double d = v.toDouble();if(qt_is_finite(d)) json +=QByteArray::number(d,'g',QLocale::FloatingPointShortest);else json +="null";// +INF || -INF || NaN (see RFC4627#section2.4)break;}caseQCborValue::String: json +='"'; json +=escapedString(v.toString()); json +='"';break;caseQCborValue::Array: json += compact ?"[":"[\n";arrayContentToJson(QJsonPrivate::Value::container(v), json, indent + (compact ?0:1), compact); json +=QByteArray(4*indent,' '); json +=']';break;caseQCborValue::Map: json += compact ?"{":"{\n";objectContentToJson(QJsonPrivate::Value::container(v), json, indent + (compact ?0:1), compact); json +=QByteArray(4*indent,' '); json +='}';break;caseQCborValue::Null:default: json +="null";}}static voidarrayContentToJson(const QCborContainerPrivate *a, QByteArray &json,int indent,bool compact){if(!a || a->elements.empty())return; QByteArray indentString(4*indent,' '); qsizetype i =0;while(true) { json += indentString;valueContentToJson(a->valueAt(i), json, indent, compact);if(++i == a->elements.size()) {if(!compact) json +='\n';break;} json += compact ?",":",\n";}}static voidobjectContentToJson(const QCborContainerPrivate *o, QByteArray &json,int indent,bool compact){if(!o || o->elements.empty())return; QByteArray indentString(4*indent,' '); qsizetype i =0;while(true) { QCborValue e = o->valueAt(i); json += indentString; json +='"'; json +=escapedString(o->valueAt(i).toString()); json += compact ?"\":":"\": ";valueContentToJson(o->valueAt(i +1), json, indent, compact);if((i +=2) == o->elements.size()) {if(!compact) json +='\n';break;} json += compact ?",":",\n";}}voidWriter::objectToJson(const QCborContainerPrivate *o, QByteArray &json,int indent,bool compact){ json.reserve(json.size() + (o ? (int)o->elements.size() :16)); json += compact ?"{":"{\n";objectContentToJson(o, json, indent + (compact ?0:1), compact); json +=QByteArray(4*indent,' '); json += compact ?"}":"}\n";}voidWriter::arrayToJson(const QCborContainerPrivate *a, QByteArray &json,int indent,bool compact){ json.reserve(json.size() + (a ? (int)a->elements.size() :16)); json += compact ?"[":"[\n";arrayContentToJson(a, json, indent + (compact ?0:1), compact); json +=QByteArray(4*indent,' '); json += compact ?"]":"]\n";}voidWriter::valueToJson(const QCborValue &v, QByteArray &json,int indent,bool compact){const QCborContainerPrivate *container =QJsonPrivate::Value::container(v); json.reserve(json.size() + (container ? container->elements.size() :16));valueContentToJson(v, json, indent, compact);if(!compact && (v.isMap() || v.isArray())) { json.append('\n');}} QT_END_NAMESPACE 
close