summaryrefslogtreecommitdiffstats
path: root/examples/corelib/serialization
diff options
context:
space:
mode:
Diffstat (limited to 'examples/corelib/serialization')
-rw-r--r--examples/corelib/serialization/CMakeLists.txt14
-rw-r--r--examples/corelib/serialization/cbordump/CMakeLists.txt30
-rwxr-xr-xexamples/corelib/serialization/cbordump/cbortag.py188
-rw-r--r--examples/corelib/serialization/cbordump/doc/images/cbordump.pngbin0 -> 9556 bytes
-rw-r--r--examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc55
-rw-r--r--examples/corelib/serialization/cbordump/main.cpp289
-rw-r--r--examples/corelib/serialization/cbordump/tag-transform.xslt25
-rw-r--r--examples/corelib/serialization/convert/CMakeLists.txt34
-rw-r--r--examples/corelib/serialization/convert/cborconverter.cpp148
-rw-r--r--examples/corelib/serialization/convert/cborconverter.h79
-rw-r--r--examples/corelib/serialization/convert/convert.pro16
-rw-r--r--examples/corelib/serialization/convert/converter.cpp44
-rw-r--r--examples/corelib/serialization/convert/converter.h100
-rw-r--r--examples/corelib/serialization/convert/datastreamconverter.cpp188
-rw-r--r--examples/corelib/serialization/convert/datastreamconverter.h79
-rw-r--r--examples/corelib/serialization/convert/debugtextdumper.cpp74
-rw-r--r--examples/corelib/serialization/convert/debugtextdumper.h20
-rw-r--r--examples/corelib/serialization/convert/doc/images/convert.pngbin0 -> 7707 bytes
-rw-r--r--examples/corelib/serialization/convert/doc/src/convert.qdoc156
-rw-r--r--examples/corelib/serialization/convert/jsonconverter.cpp107
-rw-r--r--examples/corelib/serialization/convert/jsonconverter.h68
-rw-r--r--examples/corelib/serialization/convert/main.cpp257
-rw-r--r--examples/corelib/serialization/convert/nullconverter.cpp92
-rw-r--r--examples/corelib/serialization/convert/nullconverter.h63
-rw-r--r--examples/corelib/serialization/convert/textconverter.cpp103
-rw-r--r--examples/corelib/serialization/convert/textconverter.h65
-rw-r--r--examples/corelib/serialization/convert/variantorderedmap.h24
-rw-r--r--examples/corelib/serialization/convert/xmlconverter.cpp214
-rw-r--r--examples/corelib/serialization/convert/xmlconverter.h66
-rw-r--r--examples/corelib/serialization/savegame/CMakeLists.txt30
-rw-r--r--examples/corelib/serialization/savegame/character.cpp104
-rw-r--r--examples/corelib/serialization/savegame/character.h70
-rw-r--r--examples/corelib/serialization/savegame/doc/src/savegame.qdoc182
-rw-r--r--examples/corelib/serialization/savegame/game.cpp181
-rw-r--r--examples/corelib/serialization/savegame/game.h66
-rw-r--r--examples/corelib/serialization/savegame/level.cpp106
-rw-r--r--examples/corelib/serialization/savegame/level.h64
-rw-r--r--examples/corelib/serialization/savegame/main.cpp78
-rw-r--r--examples/corelib/serialization/serialization.pro4
-rw-r--r--examples/corelib/serialization/streambookmarks/CMakeLists.txt40
-rw-r--r--examples/corelib/serialization/streambookmarks/doc/images/filemenu.pngbin0 -> 3728 bytes
-rw-r--r--examples/corelib/serialization/streambookmarks/doc/images/helpmenu.pngbin0 -> 2099 bytes
-rw-r--r--examples/corelib/serialization/streambookmarks/doc/images/screenshot.pngbin0 -> 66567 bytes
-rw-r--r--examples/corelib/serialization/streambookmarks/doc/src/qxmlstreambookmarks.qdoc223
-rw-r--r--examples/corelib/serialization/streambookmarks/jennifer.xbel69
-rw-r--r--examples/corelib/serialization/streambookmarks/main.cpp17
-rw-r--r--examples/corelib/serialization/streambookmarks/mainwindow.cpp151
-rw-r--r--examples/corelib/serialization/streambookmarks/mainwindow.h35
-rw-r--r--examples/corelib/serialization/streambookmarks/streambookmarks.pro15
-rw-r--r--examples/corelib/serialization/streambookmarks/xbelreader.cpp140
-rw-r--r--examples/corelib/serialization/streambookmarks/xbelreader.h45
-rw-r--r--examples/corelib/serialization/streambookmarks/xbelwriter.cpp56
-rw-r--r--examples/corelib/serialization/streambookmarks/xbelwriter.h28
53 files changed, 2269 insertions, 2033 deletions
diff --git a/examples/corelib/serialization/CMakeLists.txt b/examples/corelib/serialization/CMakeLists.txt
index 7f3701ad99..e32e4df441 100644
--- a/examples/corelib/serialization/CMakeLists.txt
+++ b/examples/corelib/serialization/CMakeLists.txt
@@ -1,3 +1,11 @@
-qt_internal_add_example(cbordump)
-qt_internal_add_example(convert)
-qt_internal_add_example(savegame)
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+if(NOT ANDROID)
+ qt_internal_add_example(cbordump)
+ qt_internal_add_example(convert)
+ qt_internal_add_example(savegame)
+endif()
+if(TARGET Qt6::Widgets)
+ qt_internal_add_example(streambookmarks)
+endif()
diff --git a/examples/corelib/serialization/cbordump/CMakeLists.txt b/examples/corelib/serialization/cbordump/CMakeLists.txt
index b64ec2524c..b2c3a536e3 100644
--- a/examples/corelib/serialization/cbordump/CMakeLists.txt
+++ b/examples/corelib/serialization/cbordump/CMakeLists.txt
@@ -1,26 +1,34 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(cbordump LANGUAGES CXX)
-set(CMAKE_AUTOMOC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
+if (ANDROID)
+ message(FATAL_ERROR "This project cannot be built on Android.")
endif()
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/serialization/cbordump")
-
find_package(Qt6 REQUIRED COMPONENTS Core)
+qt_standard_project_setup()
+
qt_add_executable(cbordump
main.cpp
)
-target_link_libraries(cbordump PUBLIC
- Qt::Core
+target_link_libraries(cbordump PRIVATE
+ Qt6::Core
)
install(TARGETS cbordump
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET cbordump
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/corelib/serialization/cbordump/cbortag.py b/examples/corelib/serialization/cbordump/cbortag.py
new file mode 100755
index 0000000000..26a0f969e4
--- /dev/null
+++ b/examples/corelib/serialization/cbordump/cbortag.py
@@ -0,0 +1,188 @@
+#!/bin/env python3
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+"""Digest cbor-tags.xml file into code for insertion into main.cpp
+
+See main.cpp's comment on how to regenerate its GENERATED CODE.
+See ./cbortag.py --help for further details on how to invoke.
+You can import this is a module without invoking the script.
+"""
+
+def firstChild(parent, tag):
+ """Return parent's first child element with the given tag."""
+ return next(node for node in parent.childNodes
+ if node.nodeType == parent.ELEMENT_NODE and node.nodeName == tag)
+
+def nodeAttrIs(node, attr, seek):
+ """Checks whether the node has a given value for an attribute
+
+ Takes the node to check, the name of the attribute and the value
+ to check against. Returns true if the node does have that value
+ for the named attribute."""
+ if node.nodeType != node.ELEMENT_NODE:
+ return False
+ if node.attributes is None or attr not in node.attributes:
+ return False
+ return node.attributes[attr].value == seek
+
+def getRfcValue(node):
+ """Extract RFC reference from an <xref type="rfc" ...> element
+
+ Some of these have a reference including section details as the
+ body of the element, otherwise the data attribute should identify
+ the RFC. If neither is found, an empty string is returned."""
+ if node.childNodes:
+ return node.childNodes[0].nodeValue # Maybe accumulate several children ?
+ if node.attributes is None or 'data' not in node.attributes:
+ return ''
+ return node.attributes['data'].value
+
+def readRegistry(filename):
+ """Handles the XML parsing and returns the relevant parts.
+
+ Single argument is the path to the cbor-tags.xml file; returns a
+ twople of the title element's text and an interator over the
+ record nodes. Checks some things are as expected while doing so."""
+ from xml.dom.minidom import parse
+ doc = parse(filename).documentElement
+ assert nodeAttrIs(doc, 'id', 'cbor-tags')
+ title = firstChild(doc, 'title').childNodes[0].nodeValue
+ registry = firstChild(doc, 'registry')
+ assert nodeAttrIs(registry, 'id', 'tags')
+ records = (node for node in registry.childNodes if node.nodeName == 'record')
+ return title, records
+
+def digest(record):
+ """Digest a single record from cbor-tags.xml
+
+ If the record is not of interest, returns the twople (None, None).
+ For records of interest, returns (n, t) where n is the numeric tag
+ code of the record and t is a text describing it. If the record,
+ or its semantics field, has an xref child with type="rfc", the RFC
+ mentioned there is included with the text of the semantics; such a
+ record is of interest, provided it has a semantics field and no
+ dash in its value. Records with a value field containing a dash
+ (indicating a range) are not of interest. Records with a value of
+ 256 or above are only of interest if they include an RFC."""
+ data = {}
+ for kid in record.childNodes:
+ if kid.nodeName == 'xref':
+ if not nodeAttrIs(kid, 'type', 'rfc'):
+ continue
+ rfc = getRfcValue(kid)
+ if rfc:
+ # Potentially stomping one taken from semantics
+ data['rfc'] = rfc
+ elif kid.nodeName == 'semantics':
+ text = rfc = ''
+ for part in kid.childNodes:
+ if part.nodeType == kid.TEXT_NODE:
+ text += part.nodeValue
+ elif part.nodeType == kid.ELEMENT_NODE:
+ if part.nodeName != 'xref' or not nodeAttrIs(part, 'type', 'rfc'):
+ continue # potentially append content to text
+ assert not rfc, ('Duplicate RFC ?', rfc, part)
+ rfc = getRfcValue(part)
+ if rfc:
+ if text.endswith('()'):
+ text = text[:-2].rstrip()
+ if 'rfc' not in data:
+ data['rfc'] = rfc
+ data['semantics'] = ' '.join(text.split())
+ elif kid.nodeName == 'value':
+ data['value'] = kid.childNodes[0].nodeValue
+ text = data.get('semantics')
+ if not text or 'value' not in data or '-' in data['value']:
+ return None, None
+ value = int(data['value'])
+ if 'rfc' in data:
+ rfc = data["rfc"].replace('rfc', 'RFC')
+ text = f'{text} [{rfc}]'
+ elif value >= 256:
+ return None, None
+ return value, text
+
+def entries(records):
+ """Digest each record of interest into a value and text.
+
+ The value and text form the raw material of the tagDescriptions
+ array in main.cpp; see digest for which records are retained."""
+ for record in records:
+ value, text = digest(record)
+ if value is not None:
+ yield value, text
+
+def marginBound(text, prior, left, right):
+ """Split up a string literal for tidy display.
+
+ The first parameter, text, is the content of the string literal;
+ quotes shall be added. It may be split into several fragments,
+ each quoted, so as to abide by line length constraints.
+
+ The remaining parameters are integers: prior is the text already
+ present on the line before text is to be added; left is the width
+ of the left margin for all subsequent lines; and right is the
+ right margin to stay within, where possible. The returned string
+ is either a space with the whole quoted text following, to fit on
+ the line already started to length prior, or a sequence of quoted
+ strings, each preceded by a newline and indent of width left."""
+ if prior + 3 + len(text) < right: # 1 for space, 2 for quotes
+ return f' "{text}"'
+ width = right - left - 2 # 2 for the quotes
+ words = iter(text.split(' '))
+ lines, current = [''], [next(words)]
+ for word in words:
+ if len(word) + sum(len(w) + 1 for w in current) > width:
+ line = ' '.join(current)
+ lines.append(f'"{line}"')
+ current = ['', word]
+ else:
+ current.append(word)
+ line = ' '.join(current)
+ lines.append(f'"{line}"')
+ return ('\n' + ' ' * left).join(lines)
+
+def main(argv, speak):
+ """Takes care of driving the process.
+
+ Takes the command-line argument list (whose first entry is the
+ name of this script) and standard output (or compatible stream of
+ your choosing) to which to write data. If the --out option is
+ specified in the arguments, the file it names is used in place of
+ this output stream."""
+ from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+ parser = ArgumentParser(
+ description='Digest cbor-tags.xml into code to insert in main.cpp',
+ formatter_class=ArgumentDefaultsHelpFormatter)
+ parser.add_argument('path', help='path of the cbor-tags.xml file',
+ default='cbor-tags.xml')
+ parser.add_argument('--out', help='file to write instead of standard output')
+ args = parser.parse_args(argv[1:])
+ emit = (open(args.out) if args.out else speak).write
+
+ title, records = readRegistry(args.path)
+ emit(f"""\
+struct CborTagDescription
+{{
+ QCborTag tag;
+ const char *description; // with space and parentheses
+}};
+
+// {title}
+static const CborTagDescription tagDescriptions[] = {{
+ // from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
+""")
+
+ for value, text in sorted(entries(records)):
+ prior = f' {{ QCborTag({value}),'
+ body = marginBound(f' ({text})', len(prior), 6, 96)
+ emit(f"{prior}{body} }},\n")
+
+ emit("""\
+ { QCborTag(-1), nullptr }
+};
+""")
+
+if __name__ == '__main__':
+ import sys
+ sys.exit(main(sys.argv, sys.stdout))
diff --git a/examples/corelib/serialization/cbordump/doc/images/cbordump.png b/examples/corelib/serialization/cbordump/doc/images/cbordump.png
new file mode 100644
index 0000000000..d5ff1da0bf
--- /dev/null
+++ b/examples/corelib/serialization/cbordump/doc/images/cbordump.png
Binary files differ
diff --git a/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc b/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc
new file mode 100644
index 0000000000..a4dc01116f
--- /dev/null
+++ b/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc
@@ -0,0 +1,55 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example serialization/cbordump
+ \examplecategory {Data Processing & I/O}
+ \meta tag {network}
+ \title Parsing and displaying CBOR data
+
+ \brief A demonstration of how to parse files in CBOR format.
+
+ This example shows how to use the QCborStreamReader class directly to parse
+ CBOR content. The \c cbordump program reads content in CBOR format from
+ files or standard input and dumps the decoded content to stdout in a
+ human-readable format. It can output in CBOR diagnostic notation (which is
+ similar to JSON), or it can produce a verbose output where each byte input
+ is displayed with its encoding beside it.
+
+ \sa QCborStreamReader
+
+ \image cbordump.png
+
+ \section1 The CborDumper Class
+
+ The CborDumper class contains a QCborStreamReader object that is initialized
+ using the QFile object argument passed to the CborDumper constructor. Based
+ on the arguments the dump function calls either dumpOne() or
+ dumpOneDetailed() to dump the contents to standard output,
+
+ \snippet serialization/cbordump/main.cpp 0
+
+ \section2 The dumpOne() Function
+
+ Switching on QCborStreamReader::type() enables printing appropriate to the
+ type of the current value in the stream. If the type is an array or map, the
+ value's content is iterated over, and for each entry the dumpOne() function
+ is called recursively with a higher indentation argument. If the type is a
+ tag, it is printed out and dumpOne() is called once without increasing the
+ indentation argument.
+
+ \section2 The dumpOneDetailed() Function
+
+ This function dumps out both the incoming bytes and the decoded contents
+ on the same line. It uses lambda functions to print out the bytes and
+ decoded content, but otherwise has a similar structure as dumpOne().
+
+ \section1 CborTagDescription
+
+ The \c tagDescriptions table, describing the CBOR tags available, is
+ automatically generated from an XML file available from the iana.org
+ website. When \c dumpOneDetailed() reports a tag, it uses its description
+ from this table.
+
+ \sa {CBOR Support in Qt}
+*/
diff --git a/examples/corelib/serialization/cbordump/main.cpp b/examples/corelib/serialization/cbordump/main.cpp
index 928bc024c5..03c940452e 100644
--- a/examples/corelib/serialization/cbordump/main.cpp
+++ b/examples/corelib/serialization/cbordump/main.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <QCborStreamReader>
#include <QCommandLineParser>
@@ -61,86 +14,137 @@
#include <stdarg.h>
#include <stdio.h>
+using namespace Qt::StringLiterals;
+
/*
* To regenerate:
* curl -O https://www.iana.org/assignments/cbor-tags/cbor-tags.xml
- * xsltproc tag-transform.xslt cbor-tags.xml
+ * ./cbortag.py cbor-tags.xml
+ *
+ * The XHTML URL mentioned in the comment below is a human-readable version of
+ * the same resource.
*/
// GENERATED CODE
struct CborTagDescription
{
QCborTag tag;
- const char *description; // with space and parentheses
+ const char *description; // with space and parentheses
};
-// CBOR Tags
+// Concise Binary Object Representation (CBOR) Tags
static const CborTagDescription tagDescriptions[] = {
// from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
- { QCborTag(0), " (Standard date/time string; see Section 2.4.1 [RFC7049])" },
- { QCborTag(1), " (Epoch-based date/time; see Section 2.4.1 [RFC7049])" },
- { QCborTag(2), " (Positive bignum; see Section 2.4.2 [RFC7049])" },
- { QCborTag(3), " (Negative bignum; see Section 2.4.2 [RFC7049])" },
- { QCborTag(4), " (Decimal fraction; see Section 2.4.3 [RFC7049])" },
- { QCborTag(5), " (Bigfloat; see Section 2.4.3 [RFC7049])" },
- { QCborTag(16), " (COSE Single Recipient Encrypted Data Object [RFC8152])" },
- { QCborTag(17), " (COSE Mac w/o Recipients Object [RFC8152])" },
- { QCborTag(18), " (COSE Single Signer Data Object [RFC8152])" },
- { QCborTag(21), " (Expected conversion to base64url encoding; see Section 2.4.4.2 [RFC7049])" },
- { QCborTag(22), " (Expected conversion to base64 encoding; see Section 2.4.4.2 [RFC7049])" },
- { QCborTag(23), " (Expected conversion to base16 encoding; see Section 2.4.4.2 [RFC7049])" },
- { QCborTag(24), " (Encoded CBOR data item; see Section 2.4.4.1 [RFC7049])" },
+ { QCborTag(0), " (Standard date/time string; see Section 3.4.1 [RFC8949])" },
+ { QCborTag(1), " (Epoch-based date/time; see Section 3.4.2 [RFC8949])" },
+ { QCborTag(2), " (Positive bignum; see Section 3.4.3 [RFC8949])" },
+ { QCborTag(3), " (Negative bignum; see Section 3.4.3 [RFC8949])" },
+ { QCborTag(4), " (Decimal fraction; see Section 3.4.4 [RFC8949])" },
+ { QCborTag(5), " (Bigfloat; see Section 3.4.4 [RFC8949])" },
+ { QCborTag(16), " (COSE Single Recipient Encrypted Data Object [RFC9052])" },
+ { QCborTag(17), " (COSE Mac w/o Recipients Object [RFC9052])" },
+ { QCborTag(18), " (COSE Single Signer Data Object [RFC9052])" },
+ { QCborTag(19), " (COSE standalone V2 countersignature [RFC9338])" },
+ { QCborTag(21),
+ " (Expected conversion to base64url encoding; see Section 3.4.5.2 [RFC8949])" },
+ { QCborTag(22), " (Expected conversion to base64 encoding; see Section 3.4.5.2 [RFC8949])" },
+ { QCborTag(23), " (Expected conversion to base16 encoding; see Section 3.4.5.2 [RFC8949])" },
+ { QCborTag(24), " (Encoded CBOR data item; see Section 3.4.5.1 [RFC8949])" },
{ QCborTag(25), " (reference the nth previously seen string)" },
{ QCborTag(26), " (Serialised Perl object with classname and constructor arguments)" },
- { QCborTag(27), " (Serialised language-independent object with type name and constructor arguments)" },
+ { QCborTag(27),
+ " (Serialised language-independent object with type name and constructor arguments)" },
{ QCborTag(28), " (mark value as (potentially) shared)" },
{ QCborTag(29), " (reference nth marked value)" },
{ QCborTag(30), " (Rational number)" },
- { QCborTag(32), " (URI; see Section 2.4.4.3 [RFC7049])" },
- { QCborTag(33), " (base64url; see Section 2.4.4.3 [RFC7049])" },
- { QCborTag(34), " (base64; see Section 2.4.4.3 [RFC7049])" },
+ { QCborTag(31), " (Absent value in a CBOR Array)" },
+ { QCborTag(32), " (URI; see Section 3.4.5.3 [RFC8949])" },
+ { QCborTag(33), " (base64url; see Section 3.4.5.3 [RFC8949])" },
+ { QCborTag(34), " (base64; see Section 3.4.5.3 [RFC8949])" },
{ QCborTag(35), " (Regular expression; see Section 2.4.4.3 [RFC7049])" },
- { QCborTag(36), " (MIME message; see Section 2.4.4.3 [RFC7049])" },
- { QCborTag(37), " (Binary UUID ( section 4.1.2))" },
- { QCborTag(38), " (Language-tagged string)" },
+ { QCborTag(36), " (MIME message; see Section 3.4.5.3 [RFC8949])" },
+ { QCborTag(37), " (Binary UUID [RFC4122, Section 4.1.2])" },
+ { QCborTag(38), " (Language-tagged string [RFC9290, Appendix A])" },
{ QCborTag(39), " (Identifier)" },
- { QCborTag(61), " (CBOR Web Token (CWT))" },
- { QCborTag(96), " (COSE Encrypted Data Object [RFC8152])" },
- { QCborTag(97), " (COSE MACed Data Object [RFC8152])" },
- { QCborTag(98), " (COSE Signed Data Object [RFC8152])" },
- { QCborTag(256), " (mark value as having string references)" },
- { QCborTag(257), " (Binary MIME message)" },
- { QCborTag(258), " (Mathematical finite set)" },
- { QCborTag(260), " (Network Address (IPv4 or IPv6 or MAC Address))" },
- { QCborTag(264), " (Decimal fraction with arbitrary exponent)" },
- { QCborTag(265), " (Bigfloat with arbitrary exponent)" },
- { QCborTag(1001), " (extended time)" },
- { QCborTag(1002), " (duration)" },
- { QCborTag(1003), " (period)" },
- { QCborTag(22098), " (hint that indicates an additional level of indirection)" },
- { QCborTag(55799), " (Self-describe CBOR; see Section 2.4.5 [RFC7049])" },
- { QCborTag(15309736), " (RAINS Message)" },
+ { QCborTag(40), " (Multi-dimensional Array, row-major order [RFC8746])" },
+ { QCborTag(41), " (Homogeneous Array [RFC8746])" },
+ { QCborTag(42), " (IPLD content identifier)" },
+ { QCborTag(43), " (YANG bits datatype; see Section 6.7. [RFC9254])" },
+ { QCborTag(44), " (YANG enumeration datatype; see Section 6.6. [RFC9254])" },
+ { QCborTag(45), " (YANG identityref datatype; see Section 6.10. [RFC9254])" },
+ { QCborTag(46), " (YANG instance-identifier datatype; see Section 6.13. [RFC9254])" },
+ { QCborTag(47), " (YANG Schema Item iDentifier (sid); see Section 3.2. [RFC9254])" },
+ { QCborTag(52), " (IPv4, [prefixlen,IPv4], [IPv4,prefixpart] [RFC9164])" },
+ { QCborTag(54), " (IPv6, [prefixlen,IPv6], [IPv6,prefixpart] [RFC9164])" },
+ { QCborTag(61), " (CBOR Web Token (CWT) [RFC8392])" },
+ { QCborTag(63), " (Encoded CBOR Sequence [RFC8742])" },
+ { QCborTag(64), " (uint8 Typed Array [RFC8746])" },
+ { QCborTag(65), " (uint16, big endian, Typed Array [RFC8746])" },
+ { QCborTag(66), " (uint32, big endian, Typed Array [RFC8746])" },
+ { QCborTag(67), " (uint64, big endian, Typed Array [RFC8746])" },
+ { QCborTag(68), " (uint8 Typed Array, clamped arithmetic [RFC8746])" },
+ { QCborTag(69), " (uint16, little endian, Typed Array [RFC8746])" },
+ { QCborTag(70), " (uint32, little endian, Typed Array [RFC8746])" },
+ { QCborTag(71), " (uint64, little endian, Typed Array [RFC8746])" },
+ { QCborTag(72), " (sint8 Typed Array [RFC8746])" },
+ { QCborTag(73), " (sint16, big endian, Typed Array [RFC8746])" },
+ { QCborTag(74), " (sint32, big endian, Typed Array [RFC8746])" },
+ { QCborTag(75), " (sint64, big endian, Typed Array [RFC8746])" },
+ { QCborTag(76), " ((reserved) [RFC8746])" },
+ { QCborTag(77), " (sint16, little endian, Typed Array [RFC8746])" },
+ { QCborTag(78), " (sint32, little endian, Typed Array [RFC8746])" },
+ { QCborTag(79), " (sint64, little endian, Typed Array [RFC8746])" },
+ { QCborTag(80), " (IEEE 754 binary16, big endian, Typed Array [RFC8746])" },
+ { QCborTag(81), " (IEEE 754 binary32, big endian, Typed Array [RFC8746])" },
+ { QCborTag(82), " (IEEE 754 binary64, big endian, Typed Array [RFC8746])" },
+ { QCborTag(83), " (IEEE 754 binary128, big endian, Typed Array [RFC8746])" },
+ { QCborTag(84), " (IEEE 754 binary16, little endian, Typed Array [RFC8746])" },
+ { QCborTag(85), " (IEEE 754 binary32, little endian, Typed Array [RFC8746])" },
+ { QCborTag(86), " (IEEE 754 binary64, little endian, Typed Array [RFC8746])" },
+ { QCborTag(87), " (IEEE 754 binary128, little endian, Typed Array [RFC8746])" },
+ { QCborTag(96), " (COSE Encrypted Data Object [RFC9052])" },
+ { QCborTag(97), " (COSE MACed Data Object [RFC9052])" },
+ { QCborTag(98), " (COSE Signed Data Object [RFC9052])" },
+ { QCborTag(100), " (Number of days since the epoch date 1970-01-01 [RFC8943])" },
+ { QCborTag(101), " (alternatives as given by the uint + 128; see Section 9.1)" },
+ { QCborTag(103), " (Geographic Coordinates)" },
+ { QCborTag(104), " (Geographic Coordinate Reference System WKT or EPSG number)" },
+ { QCborTag(110), " (relative object identifier (BER encoding); SDNV sequence [RFC9090])" },
+ { QCborTag(111), " (object identifier (BER encoding) [RFC9090])" },
+ { QCborTag(112), " (object identifier (BER encoding), relative to 1.3.6.1.4.1 [RFC9090])" },
+ { QCborTag(120), " (Internet of Things Data Point)" },
+ { QCborTag(260),
+ " (Network Address (IPv4 or IPv6 or MAC Address) (DEPRECATED in favor of 52 and 54 for IP"
+ " addresses) [RFC9164])" },
+ { QCborTag(261),
+ " (Network Address Prefix (IPv4 or IPv6 Address + Mask Length) (DEPRECATED in favor of 52"
+ " and 54 for IP addresses) [RFC9164])" },
+ { QCborTag(271),
+ " (DDoS Open Threat Signaling (DOTS) signal channel object, as defined in [RFC9132])" },
+ { QCborTag(1004), " (full-date string [RFC8943])" },
+ { QCborTag(1040), " (Multi-dimensional Array, column-major order [RFC8746])" },
+ { QCborTag(55799), " (Self-described CBOR; see Section 3.4.6 [RFC8949])" },
+ { QCborTag(55800), " (indicates that the file contains CBOR Sequences [RFC9277])" },
+ { QCborTag(55801),
+ " (indicates that the file starts with a CBOR-Labeled Non-CBOR Data label. [RFC9277])" },
{ QCborTag(-1), nullptr }
};
// END GENERATED CODE
enum {
// See RFC 7049 section 2.
- SmallValueBitLength = 5,
- SmallValueMask = (1 << SmallValueBitLength) - 1, /* 0x1f */
- Value8Bit = 24,
- Value16Bit = 25,
- Value32Bit = 26,
- Value64Bit = 27
+ SmallValueBitLength = 5,
+ SmallValueMask = (1 << SmallValueBitLength) - 1, /* 0x1f */
+ Value8Bit = 24,
+ Value16Bit = 25,
+ Value32Bit = 26,
+ Value64Bit = 27
};
+//! [0]
struct CborDumper
{
- enum DumpOption {
- ShowCompact = 0x01,
- ShowWidthIndicators = 0x02,
- ShowAnnotated = 0x04
- };
+ enum DumpOption { ShowCompact = 0x01, ShowWidthIndicators = 0x02, ShowAnnotated = 0x04 };
Q_DECLARE_FLAGS(DumpOptions, DumpOption)
CborDumper(QFile *f, DumpOptions opts_);
@@ -160,6 +164,7 @@ private:
qint64 offset = 0;
DumpOptions opts;
};
+//! [0]
Q_DECLARE_OPERATORS_FOR_FLAGS(CborDumper::DumpOptions)
static int cborNumberSize(quint64 value)
@@ -176,8 +181,7 @@ static int cborNumberSize(quint64 value)
return normalSize;
}
-CborDumper::CborDumper(QFile *f, DumpOptions opts_)
- : opts(opts_)
+CborDumper::CborDumper(QFile *f, DumpOptions opts_) : opts(opts_)
{
// try to mmap the file, this is faster
char *ptr = reinterpret_cast<char *>(f->map(0, f->size(), QFile::MapPrivateOption));
@@ -224,51 +228,54 @@ QCborError CborDumper::dump()
return err;
}
-template <typename T> static inline bool canConvertTo(double v)
+template<typename T>
+static inline bool canConvertTo(double v)
{
+ using TypeInfo = std::numeric_limits<T>;
// The [conv.fpint] (7.10 Floating-integral conversions) section of the
// standard says only exact conversions are guaranteed. Converting
// integrals to floating-point with loss of precision has implementation-
// defined behavior whether the next higher or next lower is returned;
// converting FP to integral is UB if it can't be represented.;
- static_assert(std::numeric_limits<T>::is_integer);
+ static_assert(TypeInfo::is_integer);
- double supremum = ldexp(1, std::numeric_limits<T>::digits);
+ double supremum = ldexp(1, TypeInfo::digits);
if (v >= supremum)
return false;
- if (v < std::numeric_limits<T>::min()) // either zero or a power of two, so it's exact
+ if (v < TypeInfo::min()) // either zero or a power of two, so it's exact
return false;
// we're in range
return v == floor(v);
}
-static QString fpToString(double v, const char *suffix)
+static QString fpToString(double v, QLatin1StringView suffix = ""_L1)
{
if (qIsInf(v))
- return v < 0 ? QStringLiteral("-inf") : QStringLiteral("inf");
+ return v < 0 ? "-inf"_L1 : "inf"_L1;
if (qIsNaN(v))
- return QStringLiteral("nan");
+ return "nan"_L1;
if (canConvertTo<qint64>(v))
- return QString::number(qint64(v)) + ".0" + suffix;
+ return QString::number(qint64(v)) + ".0"_L1 + suffix;
if (canConvertTo<quint64>(v))
- return QString::number(quint64(v)) + ".0" + suffix;
+ return QString::number(quint64(v)) + ".0"_L1 + suffix;
QString s = QString::number(v, 'g', QLocale::FloatingPointShortest);
- if (!s.contains('.') && !s.contains('e'))
- s += '.';
- s += suffix;
+ if (!s.contains(u'.') && !s.contains(u'e'))
+ s += u'.';
+ if (suffix.size())
+ s += suffix;
return s;
};
void CborDumper::dumpOne(int nestingLevel)
{
- QString indent(1, QLatin1Char(' '));
+ QString indent(1, u' ');
QString indented = indent;
if (!opts.testFlag(ShowCompact)) {
- indent = QLatin1Char('\n') + QString(4 * nestingLevel, QLatin1Char(' '));
- indented = QLatin1Char('\n') + QString(4 + 4 * nestingLevel, QLatin1Char(' '));
+ indent = u'\n' + QString(4 * nestingLevel, u' ');
+ indented = u'\n' + QString(4 + 4 * nestingLevel, u' ');
}
switch (reader.type()) {
@@ -308,7 +315,7 @@ void CborDumper::dumpOne(int nestingLevel)
printStringWidthIndicator(r.data.size());
r = reader.readByteArray();
- comma = QLatin1Char(',') + indented;
+ comma = u',' + indented;
}
} else {
auto r = reader.readString();
@@ -317,7 +324,7 @@ void CborDumper::dumpOne(int nestingLevel)
printStringWidthIndicator(r.data.toUtf8().size());
r = reader.readString();
- comma = QLatin1Char(',') + indented;
+ comma = u',' + indented;
}
}
@@ -373,7 +380,7 @@ void CborDumper::dumpOne(int nestingLevel)
if (reader.next()) {
printWidthIndicator(quint64(tag));
printf("(");
- dumpOne(nestingLevel); // same level!
+ dumpOne(nestingLevel); // same level!
printf(")");
}
@@ -405,15 +412,15 @@ void CborDumper::dumpOne(int nestingLevel)
break;
case QCborStreamReader::Float16:
- printf("%s", qPrintable(fpToString(reader.toFloat16(), "f16")));
+ printf("%s", qPrintable(fpToString(reader.toFloat16(), "f16"_L1)));
reader.next();
break;
case QCborStreamReader::Float:
- printf("%s", qPrintable(fpToString(reader.toFloat(), "f")));
+ printf("%s", qPrintable(fpToString(reader.toFloat(), "f"_L1)));
reader.next();
break;
case QCborStreamReader::Double:
- printf("%s", qPrintable(fpToString(reader.toDouble(), "")));
+ printf("%s", qPrintable(fpToString(reader.toDouble())));
reader.next();
break;
case QCborStreamReader::Invalid:
@@ -438,7 +445,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
if (cborNumberSize(value) != actualSize)
printf(" (overlong)");
};
- auto print = [=](const char *descr, const char *fmt, ...) {
+ auto print = [&](const char *descr, const char *fmt, ...) {
qint64 prevOffset = offset;
offset = reader.currentOffset();
if (prevOffset == offset)
@@ -466,13 +473,14 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
};
auto printFp = [=](const char *descr, double d) {
- QString s = fpToString(d, "");
+ QString s = fpToString(d);
if (s.size() <= 6)
return print(descr, "%s", qPrintable(s));
return print(descr, "%a", d);
};
- auto printString = [=](const char *descr) {
+ auto printString = [&](const char *descr) {
+ constexpr qsizetype ChunkSizeLimit = std::numeric_limits<int>::max();
QByteArray indent(nestingLevel * 2, ' ');
const char *chunkStr = (reader.isLengthKnown() ? "" : "chunk ");
int width = 48 - indent.size();
@@ -480,8 +488,8 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
qsizetype size = reader.currentStringChunkSize();
if (size < 0)
- return; // error
- if (size >= std::numeric_limits<int>::max()) {
+ return; // error
+ if (size >= ChunkSizeLimit) {
fprintf(stderr, "String length too big, %lli\n", qint64(size));
exit(EXIT_FAILURE);
}
@@ -525,7 +533,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
printf(" %s%s", indent.constData(), section.toHex(' ').constData());
// print the decode
- QByteArray spaces(width > 0 ? width - section.size() * 3 + 1: 0, ' ');
+ QByteArray spaces(width > 0 ? width - section.size() * 3 + 1 : 0, ' ');
printf("%s # \"", spaces.constData());
auto ptr = reinterpret_cast<const uchar *>(section.constData());
for (int j = 0; j < section.size(); ++j)
@@ -537,8 +545,8 @@ void CborDumper::dumpOneDetailed(int nestingLevel)
// get the next chunk
size = reader.currentStringChunkSize();
if (size < 0)
- return; // error
- if (size >= std::numeric_limits<int>::max()) {
+ return; // error
+ if (size >= ChunkSizeLimit) {
fprintf(stderr, "String length too big, %lli\n", qint64(size));
exit(EXIT_FAILURE);
}
@@ -676,7 +684,9 @@ void CborDumper::printByteArray(const QByteArray &ba)
break;
case quint8(QCborKnownTags::ExpectedBase64url):
- printf("b64'%s'", ba.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals).constData());
+ printf("b64'%s'",
+ ba.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals)
+ .constData());
break;
}
}
@@ -717,23 +727,20 @@ int main(int argc, char *argv[])
setlocale(LC_ALL, "C");
QCommandLineParser parser;
- parser.setApplicationDescription(QStringLiteral("CBOR Dumper tool"));
+ parser.setApplicationDescription("CBOR Dumper tool"_L1);
parser.addHelpOption();
- QCommandLineOption compact({QStringLiteral("c"), QStringLiteral("compact")},
- QStringLiteral("Use compact form (no line breaks)"));
+ QCommandLineOption compact({"c"_L1, "compact"_L1}, "Use compact form (no line breaks)"_L1);
parser.addOption(compact);
- QCommandLineOption showIndicators({QStringLiteral("i"), QStringLiteral("indicators")},
- QStringLiteral("Show indicators for width of lengths and integrals"));
+ QCommandLineOption showIndicators({ "i"_L1, "indicators"_L1 },
+ "Show indicators for width of lengths and integrals"_L1);
parser.addOption(showIndicators);
- QCommandLineOption verbose({QStringLiteral("a"), QStringLiteral("annotated")},
- QStringLiteral("Show bytes and annotated decoding"));
+ QCommandLineOption verbose({"a"_L1, "annotated"_L1}, "Show bytes and annotated decoding"_L1);
parser.addOption(verbose);
- parser.addPositionalArgument(QStringLiteral("[source]"),
- QStringLiteral("CBOR file to read from"));
+ parser.addPositionalArgument("[source]"_L1, "CBOR file to read from"_L1);
parser.process(app);
@@ -748,7 +755,7 @@ int main(int argc, char *argv[])
QStringList files = parser.positionalArguments();
if (files.isEmpty())
files << "-";
- for (const QString &file : qAsConst(files)) {
+ for (const QString &file : std::as_const(files)) {
QFile f(file);
if (file == "-" ? f.open(stdin, QIODevice::ReadOnly) : f.open(QIODevice::ReadOnly)) {
if (files.size() > 1)
diff --git a/examples/corelib/serialization/cbordump/tag-transform.xslt b/examples/corelib/serialization/cbordump/tag-transform.xslt
deleted file mode 100644
index 3cc1b9b293..0000000000
--- a/examples/corelib/serialization/cbordump/tag-transform.xslt
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0"?>
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://www.iana.org/assignments" xmlns="http://www.iana.org/assignments" xmlns:_="http://www.iana.org/assignments" xmlns:DEFAULT="http://www.iana.org/assignments" version="1.0">
-<xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
-<xsl:template match="/a:registry[@id='cbor-tags']">struct CborTagDescription
-{
- QCborTag tag;
- const char *description; // with space and parentheses
-};
-
-// <xsl:value-of select="a:registry/a:title"/>
-static const CborTagDescription tagDescriptions[] = {
- // from https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
-<xsl:for-each select="a:registry/a:record">
- <xsl:sort select="a:value" data-type="number"/>
- <xsl:if test="a:semantics != ''">
- <xsl:call-template name="row"/>
- </xsl:if>
- </xsl:for-each> { QCborTag(-1), nullptr }
-};
-</xsl:template>
-<xsl:template name="row"> { QCborTag(<xsl:value-of select="a:value"/>), " (<xsl:value-of select="a:semantics"/> <xsl:call-template name="xref"/>)" },
-</xsl:template>
-<xsl:template name="xref"><xsl:if test="a:xref/@type = 'rfc'"> [<xsl:value-of select="translate(a:xref/@data,'rfc','RFC')"/>]</xsl:if>
-</xsl:template>
-</xsl:stylesheet>
diff --git a/examples/corelib/serialization/convert/CMakeLists.txt b/examples/corelib/serialization/convert/CMakeLists.txt
index b8476253e6..24ad5bbb6a 100644
--- a/examples/corelib/serialization/convert/CMakeLists.txt
+++ b/examples/corelib/serialization/convert/CMakeLists.txt
@@ -1,33 +1,43 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(convert LANGUAGES CXX)
-set(CMAKE_AUTOMOC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
+if (ANDROID)
+ message(FATAL_ERROR "This project cannot be built on Android.")
endif()
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/serialization/convert")
-
find_package(Qt6 REQUIRED COMPONENTS Core)
+qt_standard_project_setup()
+
qt_add_executable(convert
cborconverter.cpp cborconverter.h
- converter.h
+ converter.cpp converter.h
datastreamconverter.cpp datastreamconverter.h
+ debugtextdumper.cpp debugtextdumper.h
jsonconverter.cpp jsonconverter.h
main.cpp
nullconverter.cpp nullconverter.h
textconverter.cpp textconverter.h
+ variantorderedmap.h
xmlconverter.cpp xmlconverter.h
)
-target_link_libraries(convert PUBLIC
- Qt::Core
+target_link_libraries(convert PRIVATE
+ Qt6::Core
)
install(TARGETS convert
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET convert
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/corelib/serialization/convert/cborconverter.cpp b/examples/corelib/serialization/convert/cborconverter.cpp
index 4fc8408983..969f2741e0 100644
--- a/examples/corelib/serialization/convert/cborconverter.cpp
+++ b/examples/corelib/serialization/convert/cborconverter.cpp
@@ -1,72 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "cborconverter.h"
+#include "variantorderedmap.h"
+#include <QCborArray>
+#include <QCborMap>
#include <QCborStreamReader>
#include <QCborStreamWriter>
-#include <QCborMap>
-#include <QCborArray>
#include <QCborValue>
#include <QDataStream>
-#include <QFloat16>
+#include <QDebug>
#include <QFile>
+#include <QFloat16>
#include <QMetaType>
#include <QTextStream>
#include <stdio.h>
+using namespace Qt::StringLiterals;
+
static CborConverter cborConverter;
static CborDiagnosticDumper cborDiagnosticDumper;
-static const char optionHelp[] =
+static const char cborOptionHelp[] =
"convert-float-to-int=yes|no Write integers instead of floating point, if no\n"
" loss of precision occurs on conversion.\n"
"float16=yes|always|no Write using half-precision floating point.\n"
@@ -102,6 +59,7 @@ QT_END_NAMESPACE
// non-string keys in CBOR maps (QVariantMap can't handle those). Instead, we
// have our own set of converter functions so we can keep the keys properly.
+//! [0]
static QVariant convertCborValue(const QCborValue &value);
static QVariant convertCborMap(const QCborMap &map)
@@ -130,7 +88,9 @@ static QVariant convertCborValue(const QCborValue &value)
return convertCborMap(value.toMap());
return value.toVariant();
}
+//! [0]
+//! [1]
enum TrimFloatingPoint { Double, Float, Float16 };
static QCborValue convertFromVariant(const QVariant &v, TrimFloatingPoint fpTrimming)
{
@@ -161,42 +121,30 @@ static QCborValue convertFromVariant(const QVariant &v, TrimFloatingPoint fpTrim
return QCborValue::fromVariant(v);
}
+//! [1]
-QString CborDiagnosticDumper::name()
+QString CborDiagnosticDumper::name() const
{
- return QStringLiteral("cbor-dump");
+ return "cbor-dump"_L1;
}
-Converter::Direction CborDiagnosticDumper::directions()
+Converter::Directions CborDiagnosticDumper::directions() const
{
- return Out;
+ return Direction::Out;
}
-Converter::Options CborDiagnosticDumper::outputOptions()
+Converter::Options CborDiagnosticDumper::outputOptions() const
{
return SupportsArbitraryMapKeys;
}
-const char *CborDiagnosticDumper::optionsHelp()
+const char *CborDiagnosticDumper::optionsHelp() const
{
return diagnosticHelp;
}
-bool CborDiagnosticDumper::probeFile(QIODevice *f)
-{
- Q_UNUSED(f);
- return false;
-}
-
-QVariant CborDiagnosticDumper::loadFile(QIODevice *f, Converter *&outputConverter)
-{
- Q_UNREACHABLE();
- Q_UNUSED(f);
- Q_UNUSED(outputConverter);
- return QVariant();
-}
-
-void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
{
QCborValue::DiagnosticNotationOptions opts = QCborValue::LineWrapped;
for (const QString &s : options) {
@@ -219,14 +167,12 @@ void CborDiagnosticDumper::saveFile(QIODevice *f, const QVariant &contents, cons
}
}
- fprintf(stderr, "Unknown CBOR diagnostic option '%s'. Available options are:\n%s",
- qPrintable(s), diagnosticHelp);
- exit(EXIT_FAILURE);
+ qFatal("Unknown CBOR diagnostic option '%s'. Available options are:\n%s",
+ qPrintable(s), diagnosticHelp);
}
QTextStream out(f);
- out << convertFromVariant(contents, Double).toDiagnosticNotation(opts)
- << Qt::endl;
+ out << convertFromVariant(contents, Double).toDiagnosticNotation(opts) << Qt::endl;
}
CborConverter::CborConverter()
@@ -234,36 +180,36 @@ CborConverter::CborConverter()
qRegisterMetaType<QCborTag>();
}
-QString CborConverter::name()
+QString CborConverter::name() const
{
return "cbor";
}
-Converter::Direction CborConverter::directions()
+Converter::Directions CborConverter::directions() const
{
- return InOut;
+ return Direction::InOut;
}
-Converter::Options CborConverter::outputOptions()
+Converter::Options CborConverter::outputOptions() const
{
return SupportsArbitraryMapKeys;
}
-const char *CborConverter::optionsHelp()
+const char *CborConverter::optionsHelp() const
{
- return optionHelp;
+ return cborOptionHelp;
}
-bool CborConverter::probeFile(QIODevice *f)
+bool CborConverter::probeFile(QIODevice *f) const
{
if (QFile *file = qobject_cast<QFile *>(f)) {
- if (file->fileName().endsWith(QLatin1String(".cbor")))
+ if (file->fileName().endsWith(".cbor"_L1))
return true;
}
return f->isReadable() && f->peek(3) == QByteArray("\xd9\xd9\xf7", 3);
}
-QVariant CborConverter::loadFile(QIODevice *f, Converter *&outputConverter)
+QVariant CborConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
const char *ptr = nullptr;
if (auto file = qobject_cast<QFile *>(f))
@@ -280,25 +226,24 @@ QVariant CborConverter::loadFile(QIODevice *f, Converter *&outputConverter)
QCborValue contents = QCborValue::fromCbor(reader);
qint64 offset = reader.currentOffset();
if (reader.lastError()) {
- fprintf(stderr, "Error loading CBOR contents (byte %lld): %s\n", offset,
- qPrintable(reader.lastError().toString()));
- fprintf(stderr, " bytes: %s\n",
- (ptr ? mapped.mid(offset, 9) : f->read(9)).toHex(' ').constData());
- exit(EXIT_FAILURE);
+ qFatal().nospace()
+ << "Error loading CBOR contents (byte " << offset
+ << "): " << reader.lastError().toString()
+ << "\n bytes: " << (ptr ? mapped.mid(offset, 9) : f->read(9));
} else if (offset < mapped.size() || (!ptr && f->bytesAvailable())) {
- fprintf(stderr, "Warning: bytes remaining at the end of the CBOR stream\n");
+ qWarning("Warning: bytes remaining at the end of the CBOR stream");
}
if (outputConverter == nullptr)
outputConverter = &cborDiagnosticDumper;
- else if (outputConverter == null)
+ else if (isNull(outputConverter))
return QVariant();
else if (!outputConverter->outputOptions().testFlag(SupportsArbitraryMapKeys))
return contents.toVariant();
return convertCborValue(contents);
}
-void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) const
{
bool useSignature = true;
bool useIntegers = true;
@@ -354,13 +299,13 @@ void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStri
}
}
- fprintf(stderr, "Unknown CBOR format option '%s'. Valid options are:\n%s",
- qPrintable(s), optionHelp);
- exit(EXIT_FAILURE);
+ qFatal("Unknown CBOR format option '%s'. Valid options are:\n%s",
+ qPrintable(s), cborOptionHelp);
}
- QCborValue v = convertFromVariant(contents,
- useFloat16 == Always ? Float16 : useFloat == Always ? Float : Double);
+ QCborValue v =
+ convertFromVariant(contents,
+ useFloat16 == Always ? Float16 : useFloat == Always ? Float : Double);
QCborStreamWriter writer(f);
if (useSignature)
writer.append(QCborKnownTags::Signature);
@@ -374,4 +319,3 @@ void CborConverter::saveFile(QIODevice *f, const QVariant &contents, const QStri
opts |= QCborValue::UseFloat16;
v.toCbor(writer, opts);
}
-
diff --git a/examples/corelib/serialization/convert/cborconverter.h b/examples/corelib/serialization/convert/cborconverter.h
index f0a89cb141..db68f99fda 100644
--- a/examples/corelib/serialization/convert/cborconverter.h
+++ b/examples/corelib/serialization/convert/cborconverter.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CBORCONVERTER_H
#define CBORCONVERTER_H
@@ -57,13 +10,12 @@ class CborDiagnosticDumper : public Converter
{
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ Options outputOptions() const override;
+ const char *optionsHelp() const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
class CborConverter : public Converter
@@ -73,13 +25,14 @@ public:
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ Options outputOptions() const override;
+ const char *optionsHelp() const override;
+ bool probeFile(QIODevice *f) const override;
+ QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
#endif // CBORCONVERTER_H
diff --git a/examples/corelib/serialization/convert/convert.pro b/examples/corelib/serialization/convert/convert.pro
index 4c6b0b557a..7592de7a22 100644
--- a/examples/corelib/serialization/convert/convert.pro
+++ b/examples/corelib/serialization/convert/convert.pro
@@ -11,18 +11,22 @@ target.path = $$[QT_INSTALL_EXAMPLES]/corelib/serialization/convert
INSTALLS += target
SOURCES += main.cpp \
+ converter.cpp \
cborconverter.cpp \
- jsonconverter.cpp \
datastreamconverter.cpp \
+ debugtextdumper.cpp \
+ jsonconverter.cpp \
+ nullconverter.cpp \
textconverter.cpp \
- xmlconverter.cpp \
- nullconverter.cpp
+ xmlconverter.cpp
HEADERS += \
converter.h \
cborconverter.h \
- jsonconverter.h \
datastreamconverter.h \
+ debugtextdumper.h \
+ jsonconverter.h \
+ nullconverter.h \
textconverter.h \
- xmlconverter.h \
- nullconverter.h
+ variantorderedmap.h \
+ xmlconverter.h
diff --git a/examples/corelib/serialization/convert/converter.cpp b/examples/corelib/serialization/convert/converter.cpp
new file mode 100644
index 0000000000..a57f305971
--- /dev/null
+++ b/examples/corelib/serialization/convert/converter.cpp
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "converter.h"
+
+//! [0]
+Converter::Converter()
+{
+ converters().append(this);
+}
+
+Converter::~Converter()
+{
+ converters().removeAll(this);
+}
+
+QList<const Converter *> &Converter::converters()
+{
+ Q_CONSTINIT static QList<const Converter *> store;
+ return store;
+}
+
+const QList<const Converter *> &Converter::allConverters()
+{
+ return converters();
+}
+//! [0]
+
+// Some virtual methods that Converter classes needn't override, when not relevant:
+Converter::Options Converter::outputOptions() const { return {}; }
+const char *Converter::optionsHelp() const { return nullptr; }
+bool Converter::probeFile(QIODevice *) const { return false; }
+
+// The virtual method they should override if they claim to support In:
+QVariant Converter::loadFile(QIODevice *, const Converter *&outputConverter) const
+{
+ Q_ASSERT(!directions().testFlag(Converter::Direction::In));
+ // For those that don't, this should never be called.
+ Q_UNIMPLEMENTED();
+ // But every implementation should at least do this:
+ if (!outputConverter)
+ outputConverter = this;
+ return QVariant();
+}
diff --git a/examples/corelib/serialization/convert/converter.h b/examples/corelib/serialization/convert/converter.h
index 56b501a076..40b7575a1e 100644
--- a/examples/corelib/serialization/convert/converter.h
+++ b/examples/corelib/serialization/convert/converter.h
@@ -1,103 +1,45 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CONVERTER_H
#define CONVERTER_H
#include <QIODevice>
-#include <QPair>
-#include <QVariant>
#include <QList>
+#include <QStringList>
+#include <QVariant>
-class VariantOrderedMap : public QList<QPair<QVariant, QVariant>>
-{
-public:
- VariantOrderedMap() = default;
- VariantOrderedMap(const QVariantMap &map)
- {
- reserve(map.size());
- for (auto it = map.begin(); it != map.end(); ++it)
- append({it.key(), it.value()});
- }
-};
-using Map = VariantOrderedMap;
-Q_DECLARE_METATYPE(Map)
-
+//! [0]
class Converter
{
+ static QList<const Converter *> &converters();
protected:
Converter();
+ static bool isNull(const Converter *converter); // in nullconverter.cpp
public:
- static Converter *null;
+ static const QList<const Converter *> &allConverters();
- enum Direction {
- In = 1, Out = 2, InOut = 3
- };
+ enum class Direction { In = 1, Out = 2, InOut = In | Out };
+ Q_DECLARE_FLAGS(Directions, Direction)
- enum Option {
- SupportsArbitraryMapKeys = 0x01
- };
+ enum Option { SupportsArbitraryMapKeys = 0x01 };
Q_DECLARE_FLAGS(Options, Option)
virtual ~Converter() = 0;
- virtual QString name() = 0;
- virtual Direction directions() = 0;
- virtual Options outputOptions() = 0;
- virtual const char *optionsHelp() = 0;
- virtual bool probeFile(QIODevice *f) = 0;
- virtual QVariant loadFile(QIODevice *f, Converter *&outputConverter) = 0;
- virtual void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) = 0;
+ virtual QString name() const = 0;
+ virtual Directions directions() const = 0;
+ virtual Options outputOptions() const;
+ virtual const char *optionsHelp() const;
+ virtual bool probeFile(QIODevice *f) const;
+ virtual QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const;
+ virtual void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const = 0;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Directions)
Q_DECLARE_OPERATORS_FOR_FLAGS(Converter::Options)
+//! [0]
#endif // CONVERTER_H
diff --git a/examples/corelib/serialization/convert/datastreamconverter.cpp b/examples/corelib/serialization/convert/datastreamconverter.cpp
index c459696b26..ce28fcb98e 100644
--- a/examples/corelib/serialization/convert/datastreamconverter.cpp
+++ b/examples/corelib/serialization/convert/datastreamconverter.cpp
@@ -1,68 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "datastreamconverter.h"
+#include "debugtextdumper.h"
+#include "variantorderedmap.h"
#include <QDataStream>
-#include <QDebug>
-#include <QTextStream>
-static const char optionHelp[] =
+using namespace Qt::StringLiterals;
+
+static const char dataStreamOptionHelp[] =
"byteorder=host|big|little Byte order to use.\n"
- "version=<n> QDataStream version (default: Qt 5.0).\n"
+ "version=<n> QDataStream version (default: Qt 6.0).\n"
;
static const char signature[] = "qds";
-static DataStreamDumper dataStreamDumper;
-static DataStreamConverter DataStreamConverter;
+static DataStreamConverter dataStreamConverter;
+static DebugTextDumper debugTextDumper;
QDataStream &operator<<(QDataStream &ds, const VariantOrderedMap &map)
{
@@ -89,126 +44,44 @@ QDataStream &operator>>(QDataStream &ds, VariantOrderedMap &map)
return ds;
}
-
-static QString dumpVariant(const QVariant &v, const QString &indent = QLatin1String("\n"))
-{
- QString result;
- QString indented = indent + QLatin1String(" ");
-
- int type = v.userType();
- if (type == qMetaTypeId<VariantOrderedMap>() || type == QMetaType::QVariantMap) {
- const auto map = (type == QMetaType::QVariantMap) ?
- VariantOrderedMap(v.toMap()) : qvariant_cast<VariantOrderedMap>(v);
-
- result = QLatin1String("Map {");
- for (const auto &pair : map) {
- result += indented + dumpVariant(pair.first, indented);
- result.chop(1); // remove comma
- result += QLatin1String(" => ") + dumpVariant(pair.second, indented);
-
- }
- result.chop(1); // remove comma
- result += indent + QLatin1String("},");
- } else if (type == QMetaType::QVariantList) {
- const QVariantList list = v.toList();
-
- result = QLatin1String("List [");
- for (const auto &item : list)
- result += indented + dumpVariant(item, indented);
- result.chop(1); // remove comma
- result += indent + QLatin1String("],");
- } else {
- QDebug debug(&result);
- debug.nospace() << v << ',';
- }
- return result;
-}
-
-QString DataStreamDumper::name()
-{
- return QStringLiteral("datastream-dump");
-}
-
-Converter::Direction DataStreamDumper::directions()
-{
- return Out;
-}
-
-Converter::Options DataStreamDumper::outputOptions()
-{
- return SupportsArbitraryMapKeys;
-}
-
-const char *DataStreamDumper::optionsHelp()
-{
- return nullptr;
-}
-
-bool DataStreamDumper::probeFile(QIODevice *f)
-{
- Q_UNUSED(f);
- return false;
-}
-
-QVariant DataStreamDumper::loadFile(QIODevice *f, Converter *&outputConverter)
-{
- Q_UNREACHABLE();
- Q_UNUSED(f);
- Q_UNUSED(outputConverter);
- return QVariant();
-}
-
-void DataStreamDumper::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
-{
- Q_UNUSED(options);
- QString s = dumpVariant(contents);
- s[s.size() - 1] = QLatin1Char('\n'); // replace the comma with newline
-
- QTextStream out(f);
- out << s;
-}
-
DataStreamConverter::DataStreamConverter()
{
qRegisterMetaType<VariantOrderedMap>();
}
-QString DataStreamConverter::name()
+QString DataStreamConverter::name() const
{
- return QStringLiteral("datastream");
+ return "datastream"_L1;
}
-Converter::Direction DataStreamConverter::directions()
+Converter::Directions DataStreamConverter::directions() const
{
- return InOut;
+ return Direction::InOut;
}
-Converter::Options DataStreamConverter::outputOptions()
+Converter::Options DataStreamConverter::outputOptions() const
{
return SupportsArbitraryMapKeys;
}
-const char *DataStreamConverter::optionsHelp()
+const char *DataStreamConverter::optionsHelp() const
{
- return optionHelp;
+ return dataStreamOptionHelp;
}
-bool DataStreamConverter::probeFile(QIODevice *f)
+bool DataStreamConverter::probeFile(QIODevice *f) const
{
return f->isReadable() && f->peek(sizeof(signature) - 1) == signature;
}
-QVariant DataStreamConverter::loadFile(QIODevice *f, Converter *&outputConverter)
+QVariant DataStreamConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
if (!outputConverter)
- outputConverter = &dataStreamDumper;
+ outputConverter = &debugTextDumper;
char c;
- if (f->read(sizeof(signature) -1) != signature ||
- !f->getChar(&c) || (c != 'l' && c != 'B')) {
- fprintf(stderr, "Could not load QDataStream file: invalid signature.\n");
- exit(EXIT_FAILURE);
- }
+ if (f->read(sizeof(signature) - 1) != signature || !f->getChar(&c) || (c != 'l' && c != 'B'))
+ qFatal("Could not load QDataStream file: invalid signature.");
QDataStream ds(f);
ds.setByteOrder(c == 'l' ? QDataStream::LittleEndian : QDataStream::BigEndian);
@@ -222,9 +95,10 @@ QVariant DataStreamConverter::loadFile(QIODevice *f, Converter *&outputConverter
return result;
}
-void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
{
- QDataStream::Version version = QDataStream::Qt_5_0;
+ QDataStream::Version version = QDataStream::Qt_6_0;
auto order = QDataStream::ByteOrder(QSysInfo::ByteOrder);
for (const QString &option : options) {
const QStringList pair = option.split('=');
@@ -249,18 +123,16 @@ void DataStreamConverter::saveFile(QIODevice *f, const QVariant &contents, const
continue;
}
- fprintf(stderr, "Invalid version number '%s': must be a number from 1 to %d.\n",
- qPrintable(pair.last()), QDataStream::Qt_DefaultCompiledVersion);
- exit(EXIT_FAILURE);
+ qFatal("Invalid version number '%s': must be a number from 1 to %d.",
+ qPrintable(pair.last()), QDataStream::Qt_DefaultCompiledVersion);
}
}
- fprintf(stderr, "Unknown QDataStream formatting option '%s'. Available options are:\n%s",
- qPrintable(option), optionHelp);
- exit(EXIT_FAILURE);
+ qFatal("Unknown QDataStream formatting option '%s'. Available options are:\n%s",
+ qPrintable(option), dataStreamOptionHelp);
}
- char c = order == QDataStream::LittleEndian ? 'l' : 'B';
+ char c = order == QDataStream::LittleEndian ? 'l' : 'B';
f->write(signature);
f->write(&c, 1);
diff --git a/examples/corelib/serialization/convert/datastreamconverter.h b/examples/corelib/serialization/convert/datastreamconverter.h
index 1b74abc54f..201f3c4754 100644
--- a/examples/corelib/serialization/convert/datastreamconverter.h
+++ b/examples/corelib/serialization/convert/datastreamconverter.h
@@ -1,71 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef DATASTREAMCONVERTER_H
#define DATASTREAMCONVERTER_H
#include "converter.h"
-class DataStreamDumper : public Converter
-{
- // Converter interface
-public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
-};
-
class DataStreamConverter : public Converter
{
public:
@@ -73,13 +13,14 @@ public:
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ Options outputOptions() const override;
+ const char *optionsHelp() const override;
+ bool probeFile(QIODevice *f) const override;
+ QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
#endif // DATASTREAMCONVERTER_H
diff --git a/examples/corelib/serialization/convert/debugtextdumper.cpp b/examples/corelib/serialization/convert/debugtextdumper.cpp
new file mode 100644
index 0000000000..f010bd8e2a
--- /dev/null
+++ b/examples/corelib/serialization/convert/debugtextdumper.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "debugtextdumper.h"
+#include "variantorderedmap.h"
+
+#include <QDebug>
+#include <QTextStream>
+
+using namespace Qt::StringLiterals;
+
+// Static instance is declared in datastreamconverter.cpp, since it uses it.
+
+static QString dumpVariant(const QVariant &v, const QString &indent = "\n"_L1)
+{
+ QString result;
+ QString indented = indent + " "_L1;
+
+ int type = v.userType();
+ if (type == qMetaTypeId<VariantOrderedMap>() || type == QMetaType::QVariantMap) {
+ const auto map = (type == QMetaType::QVariantMap) ? VariantOrderedMap(v.toMap())
+ : qvariant_cast<VariantOrderedMap>(v);
+
+ result = "Map {"_L1;
+ for (const auto &pair : map) {
+ result += indented + dumpVariant(pair.first, indented);
+ result.chop(1); // remove comma
+ result += " => "_L1 + dumpVariant(pair.second, indented);
+ }
+ result.chop(1); // remove comma
+ result += indent + "},"_L1;
+ } else if (type == QMetaType::QVariantList) {
+ const QVariantList list = v.toList();
+
+ result = "List ["_L1;
+ for (const auto &item : list)
+ result += indented + dumpVariant(item, indented);
+ result.chop(1); // remove comma
+ result += indent + "],"_L1;
+ } else {
+ QDebug debug(&result);
+ debug.nospace() << v << ',';
+ }
+ return result;
+}
+
+QString DebugTextDumper::name() const
+{
+ return "debugtext-dump"_L1;
+}
+
+Converter::Directions DebugTextDumper::directions() const
+{
+ return Direction::Out;
+}
+
+Converter::Options DebugTextDumper::outputOptions() const
+{
+ return SupportsArbitraryMapKeys;
+}
+
+void DebugTextDumper::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
+{
+ if (!options.isEmpty()) {
+ qFatal("Unknown option '%s' to debug text output. This format has no options.",
+ qPrintable(options.first()));
+ }
+ QString s = dumpVariant(contents);
+ s[s.size() - 1] = u'\n'; // replace the comma with newline
+
+ QTextStream out(f);
+ out << s;
+}
diff --git a/examples/corelib/serialization/convert/debugtextdumper.h b/examples/corelib/serialization/convert/debugtextdumper.h
new file mode 100644
index 0000000000..7d3d762104
--- /dev/null
+++ b/examples/corelib/serialization/convert/debugtextdumper.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef DEBUGTEXTDUMPER_H
+#define DEBUGTEXTDUMPER_H
+
+#include "converter.h"
+
+class DebugTextDumper : public Converter
+{
+ // Converter interface
+public:
+ QString name() const override;
+ Directions directions() const override;
+ Options outputOptions() const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
+};
+
+#endif // DEBUGTEXTDUMPER_H
diff --git a/examples/corelib/serialization/convert/doc/images/convert.png b/examples/corelib/serialization/convert/doc/images/convert.png
new file mode 100644
index 0000000000..53e05b4333
--- /dev/null
+++ b/examples/corelib/serialization/convert/doc/images/convert.png
Binary files differ
diff --git a/examples/corelib/serialization/convert/doc/src/convert.qdoc b/examples/corelib/serialization/convert/doc/src/convert.qdoc
new file mode 100644
index 0000000000..187e81a85e
--- /dev/null
+++ b/examples/corelib/serialization/convert/doc/src/convert.qdoc
@@ -0,0 +1,156 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example serialization/convert
+ \examplecategory {Data Processing & I/O}
+ \meta tag {network}
+ \title Serialization Converter
+
+ \brief How to convert between different serialization formats.
+
+ This example converts between JSON, CBOR, XML, QDataStream and some simple
+ text formats. It can auto-detect the format being used, or be told which
+ format to use. Not all formats support both input and output, and they have
+ different sets of which content datatypes they support. QDataStream and XML
+ are the richest, followed by CBOR, then JSON, and then the plain text
+ formats. Conversion via the less capable formats is apt to lose structure
+ from the data.
+
+ \image convert.png
+
+ \sa {Parsing and displaying CBOR data}, {Saving and Loading a Game}
+
+ \section1 The Converter Class
+
+ The Converter class is the abstract superclass for all the converters to and
+ from all the formats. They all convert from or to the QVariant class, which
+ is used to represent all the datastructures internally.
+
+ \snippet serialization/convert/converter.h 0
+
+ The Converter constructor and destructor manage a list of available
+ converters used by the main program so that it knows what converters are
+ available. Each converter type defines a static instance that ensures it is
+ constructed and thus available to the main program via this list. The \c
+ allConverters() method provides \c main()'s code with access to the list.
+
+ \snippet serialization/convert/converter.cpp 0
+
+ The name() function returns the name of the converter. The directions()
+ function is used to determine if a converter can be used for input, output,
+ or both. These enable the main program to report what converters are
+ available in its help text for the command-line options to select input and
+ output formats.
+
+ \snippet serialization/convert/main.cpp 0
+
+ The optionsHelp() function is used to report the various command-line
+ options supported by the available formats, when queried using its \c
+ {--format-options <format>} command-line option.
+
+ \snippet serialization/convert/main.cpp 1
+
+ The outputOptions() function reports the output capabilities of a converter.
+ At present the only optional feature is support for arbitrary keys in
+ mappings from keys to values. An input converter's loadFile() can use this
+ information to tailor the form in which it presents the data it has read, to
+ be as faithfully represented by the output converter as its capabilities
+ permit.
+
+ The probeFile() function is used to determine if a file matches the format
+ of the converter. The main program uses this to determine what format to use
+ when reading or writing a file, based on its name and potentially content,
+ when the user has not specified the format to use on the command-line.
+
+ The loadFile() function deserializes data. The caller tells loadFile() which
+ serializer it intends to use, so that loadFile() can query its
+ outputOptions() to determine the form in which to represent the loaded data.
+ If the caller hasn't settled on a choice of output converter, loadFile()
+ supplies it with a default output converter suitable to the data it is
+ returning.
+
+ The saveFile() function serializes data. It is passed options from the
+ command-line, as described by loadHelp(), that can tune the details of how
+ it represents the data when saving to file.
+
+ Both loadFile() and saveFile() can be used with an arbitrary \l QIODevice.
+ This means that a Converter could also be used with a network socket or
+ other source of data, to read from or write to. In the present program, the
+ main program always passes a \l QFile, accessing either a file on disk or
+ one of the standard streams of the process.
+
+ \section2 The Available Converters
+
+ Several converters are supported, illustrating how the converter program
+ could be adapted to other formats, should the need arise. See the source
+ code for each for its details. The CBOR converters serve as a relatively
+ full-featured illustration of the ways converters can work, that we'll look
+ into in more detail below. This table summarizes the available converters:
+
+ \table
+ \header \li Class \li mode \li format
+ \row \li CborConverter \li In/Out \li CBOR
+ \row \li CborDiagnosticDumper \li Out \li CBOR diagnostic
+ \row \li DataStreamConverter \li In/Out \li QDataStream
+ \row \li DebugTextDumper \li Out \li Lossless, non-standard, human-readable
+ \row \li JsonConverter \li In/Out \li JSON
+ \row \li NullConverter \li Out \li No output
+ \row \li TextConverter \li In/Out \li Structured plain text
+ \row \li XmlConverter \li In/Out \li XML
+ \endtable
+
+ Those that support input use themselves as loadFile()'s fallback converter,
+ except for the CBOR and QDataStream converters, which use their respective
+ output-only dumper companion classes. The null converter can be used as
+ output converter when running the program for the sake of any validation or
+ verification that an input converter may perform.
+
+ \section2 The CborConverter and CborDiagnosticDumper Classes
+
+ The CborConverter class supports serializing to and from the CBOR format.
+ It supports various options to configure the output of floating point values
+ and a \c{signature} option to determine whether to start its output with a
+ CBOR tag that serves as a file header, identifying the file as containing
+ CBOR data.
+
+ There is also a CborDiagnosticDumper class to output in CBOR diagnostic
+ notation. It does not support loading data. The form of its output can be
+ configured using two options. One selects whether to use the (more verbose)
+ extended CBOR diagnostic format. The other control whether each CBOR value
+ appears on a separate line.
+
+ The plain diagnostic notation is similar to JSON, but not exactly, because
+ it supports displaying the contents of a CBOR stream losslessly, while a
+ conversion to JSON can be lossy. CborConverter's loadFile() uses
+ CborDiagnosticDumper for the fallback output converter, if its caller hasn't
+ determined the output format for itself.
+
+ The convertCborValue(), convertCborMap() and convertCborArray() helper
+ functions are used to convert a QCborValue to a QVariant, for the benefit of
+ CborConverter::loadFile().
+
+ \snippet serialization/convert/cborconverter.cpp 0
+
+ The convertFromVariant() function is used to convert a QVariant to a
+ QCborValue for output by the \c saveFile() of either class.
+
+ \snippet serialization/convert/cborconverter.cpp 1
+
+ \sa {CBOR Support in Qt}
+
+ \section1 The convert program
+
+ The \c main() function sets up a \l QApplication and a \l QCommandLineParser
+ to make sense of the options the user has specified and provide help if the
+ user asks for it. It uses the values obtained for the various \l
+ QCommandLineOption instances describing the user's choices, plus the
+ positional arguments for file names, to prepare the converters it will use.
+
+ It then uses its input converter to load data (and possibly resolve its
+ choice of output converter, if it hasn't selected one yet) and its output
+ converter to serialize that data, taking account of any output options the
+ user has supplied on the command-line.
+
+ \snippet serialization/convert/main.cpp 2
+*/
diff --git a/examples/corelib/serialization/convert/jsonconverter.cpp b/examples/corelib/serialization/convert/jsonconverter.cpp
index ec24af703d..1b59ed5c1f 100644
--- a/examples/corelib/serialization/convert/jsonconverter.cpp
+++ b/examples/corelib/serialization/convert/jsonconverter.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "jsonconverter.h"
@@ -56,49 +9,39 @@
#include <QJsonObject>
#include <QJsonValue>
+using namespace Qt::StringLiterals;
+
static JsonConverter jsonConverter;
-static const char optionHelp[] =
- "compact=no|yes Use compact JSON form.\n";
+static const char jsonOptionHelp[] = "compact=no|yes Use compact JSON form.\n";
static QJsonDocument convertFromVariant(const QVariant &v)
{
QJsonDocument doc = QJsonDocument::fromVariant(v);
- if (!doc.isObject() && !doc.isArray()) {
- fprintf(stderr, "Could not convert contents to JSON.\n");
- exit(EXIT_FAILURE);
- }
+ if (!doc.isObject() && !doc.isArray())
+ qFatal("Could not convert contents to JSON.");
return doc;
}
-JsonConverter::JsonConverter()
-{
-}
-
-QString JsonConverter::name()
-{
- return "json";
-}
-
-Converter::Direction JsonConverter::directions()
+QString JsonConverter::name() const
{
- return InOut;
+ return "json"_L1;
}
-Converter::Options JsonConverter::outputOptions()
+Converter::Directions JsonConverter::directions() const
{
- return {};
+ return Direction::InOut;
}
-const char *JsonConverter::optionsHelp()
+const char *JsonConverter::optionsHelp() const
{
- return optionHelp;
+ return jsonOptionHelp;
}
-bool JsonConverter::probeFile(QIODevice *f)
+bool JsonConverter::probeFile(QIODevice *f) const
{
if (QFile *file = qobject_cast<QFile *>(f)) {
- if (file->fileName().endsWith(QLatin1String(".json")))
+ if (file->fileName().endsWith(".json"_L1))
return true;
}
@@ -109,7 +52,7 @@ bool JsonConverter::probeFile(QIODevice *f)
return false;
}
-QVariant JsonConverter::loadFile(QIODevice *f, Converter *&outputConverter)
+QVariant JsonConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
if (!outputConverter)
outputConverter = this;
@@ -125,26 +68,26 @@ QVariant JsonConverter::loadFile(QIODevice *f, Converter *&outputConverter)
if (doc.isNull())
doc = QJsonDocument::fromJson(f->readAll(), &error);
if (error.error) {
- fprintf(stderr, "Could not parse JSON content: offset %d: %s",
- error.offset, qPrintable(error.errorString()));
- exit(EXIT_FAILURE);
+ qFatal("Could not parse JSON content: offset %d: %s",
+ error.offset, qPrintable(error.errorString()));
}
- if (outputConverter == null)
+ if (isNull(outputConverter))
return QVariant();
return doc.toVariant();
}
-void JsonConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void JsonConverter::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
{
QJsonDocument::JsonFormat format = QJsonDocument::Indented;
for (const QString &s : options) {
- if (s == QLatin1String("compact=no")) {
+ if (s == "compact=no"_L1) {
format = QJsonDocument::Indented;
- } else if (s == QLatin1String("compact=yes")) {
+ } else if (s == "compact=yes"_L1) {
format = QJsonDocument::Compact;
} else {
- fprintf(stderr, "Unknown option '%s' to JSON output. Valid options are:\n%s", qPrintable(s), optionHelp);
- exit(EXIT_FAILURE);
+ qFatal("Unknown option '%s' to JSON output. Valid options are:\n%s",
+ qPrintable(s), jsonOptionHelp);
}
}
diff --git a/examples/corelib/serialization/convert/jsonconverter.h b/examples/corelib/serialization/convert/jsonconverter.h
index 445a0e6695..e1dd1ecdb4 100644
--- a/examples/corelib/serialization/convert/jsonconverter.h
+++ b/examples/corelib/serialization/convert/jsonconverter.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef JSONCONVERTER_H
#define JSONCONVERTER_H
@@ -55,18 +8,15 @@
class JsonConverter : public Converter
{
-public:
- JsonConverter();
-
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ const char *optionsHelp() const override;
+ bool probeFile(QIODevice *f) const override;
+ QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
#endif // JSONCONVERTER_H
diff --git a/examples/corelib/serialization/convert/main.cpp b/examples/corelib/serialization/convert/main.cpp
index 161fec6bcd..d3021fadca 100644
--- a/examples/corelib/serialization/convert/main.cpp
+++ b/examples/corelib/serialization/convert/main.cpp
@@ -1,52 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "converter.h"
@@ -58,177 +12,144 @@
#include <stdio.h>
-static QList<Converter *> *availableConverters;
+using namespace Qt::StringLiterals;
-Converter::Converter()
+static const Converter *prepareConverter(QString format, Converter::Direction direction,
+ QFile *stream)
{
- if (!availableConverters)
- availableConverters = new QList<Converter *>;
- availableConverters->append(this);
-}
+ const bool out = direction == Converter::Direction::Out;
+ const QIODevice::OpenMode mode = out
+ ? QIODevice::WriteOnly | QIODevice::Truncate
+ : QIODevice::ReadOnly;
+ const char *dirn = out ? "output" : "input";
+
+ if (stream->fileName().isEmpty())
+ stream->open(out ? stdout : stdin, mode);
+ else
+ stream->open(mode);
+
+ if (!stream->isOpen()) {
+ qFatal("Could not open \"%s\" for %s: %s",
+ qPrintable(stream->fileName()), dirn, qPrintable(stream->errorString()));
+ } else if (format == "auto"_L1) {
+ for (const Converter *conv : Converter::allConverters()) {
+ if (conv->directions().testFlag(direction) && conv->probeFile(stream))
+ return conv;
+ }
+ if (out) // Failure to identify output format can be remedied by loadFile().
+ return nullptr;
-Converter::~Converter()
-{
- availableConverters->removeAll(this);
+ // Input format, however, we must know before we can call that:
+ qFatal("Could not determine input format. Specify it with the -I option.");
+ } else {
+ for (const Converter *conv : Converter::allConverters()) {
+ if (conv->name() == format) {
+ if (!conv->directions().testFlag(direction)) {
+ qWarning("File format \"%s\" cannot be used for %s",
+ qPrintable(format), dirn);
+ continue; // on the off chance there's another with the same name
+ }
+ return conv;
+ }
+ }
+ qFatal("Unknown %s file format \"%s\"", dirn, qPrintable(format));
+ }
+ Q_UNREACHABLE_RETURN(nullptr);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
+//! [0]
QStringList inputFormats;
QStringList outputFormats;
- for (Converter *conv : qAsConst(*availableConverters)) {
+ for (const Converter *conv : Converter::allConverters()) {
auto direction = conv->directions();
QString name = conv->name();
- if (direction & Converter::In)
+ if (direction.testFlag(Converter::Direction::In))
inputFormats << name;
- if (direction & Converter::Out)
+ if (direction.testFlag(Converter::Direction::Out))
outputFormats << name;
}
+//! [0]
inputFormats.sort();
outputFormats.sort();
- inputFormats.prepend("auto");
- outputFormats.prepend("auto");
+ inputFormats.prepend("auto"_L1);
+ outputFormats.prepend("auto"_L1);
QCommandLineParser parser;
- parser.setApplicationDescription(QStringLiteral("Qt file format conversion tool"));
+ parser.setApplicationDescription("Qt serialization format conversion tool"_L1);
parser.addHelpOption();
- QCommandLineOption inputFormatOption(QStringList{"I", "input-format"});
- inputFormatOption.setDescription(QLatin1String("Select the input format for the input file. Available formats: ") +
- inputFormats.join(", "));
- inputFormatOption.setValueName("format");
+ QCommandLineOption inputFormatOption(QStringList{ "I"_L1, "input-format"_L1 });
+ inputFormatOption.setDescription(
+ "Select the input format for the input file. Available formats: "_L1
+ + inputFormats.join(", "_L1));
+ inputFormatOption.setValueName("format"_L1);
inputFormatOption.setDefaultValue(inputFormats.constFirst());
parser.addOption(inputFormatOption);
- QCommandLineOption outputFormatOption(QStringList{"O", "output-format"});
- outputFormatOption.setDescription(QLatin1String("Select the output format for the output file. Available formats: ") +
- outputFormats.join(", "));
- outputFormatOption.setValueName("format");
+ QCommandLineOption outputFormatOption(QStringList{ "O"_L1, "output-format"_L1 });
+ outputFormatOption.setDescription(
+ "Select the output format for the output file. Available formats: "_L1
+ + outputFormats.join(", "_L1));
+ outputFormatOption.setValueName("format"_L1);
outputFormatOption.setDefaultValue(outputFormats.constFirst());
parser.addOption(outputFormatOption);
- QCommandLineOption optionOption(QStringList{"o", "option"});
- optionOption.setDescription(QStringLiteral("Format-specific options. Use --format-options to find out what options are available."));
- optionOption.setValueName("options...");
+ QCommandLineOption optionOption(QStringList{ "o"_L1, "option"_L1 });
+ optionOption.setDescription(
+ "Format-specific options. Use --format-options to find out what options are available."_L1);
+ optionOption.setValueName("options..."_L1);
optionOption.setDefaultValues({});
parser.addOption(optionOption);
- QCommandLineOption formatOptionsOption("format-options");
- formatOptionsOption.setDescription(QStringLiteral("Prints the list of valid options for --option for the converter format <format>."));
- formatOptionsOption.setValueName("format");
+ QCommandLineOption formatOptionsOption("format-options"_L1);
+ formatOptionsOption.setDescription(
+ "Prints the list of valid options for --option for the converter format <format>."_L1);
+ formatOptionsOption.setValueName("format"_L1);
parser.addOption(formatOptionsOption);
- parser.addPositionalArgument(QStringLiteral("[source]"),
- QStringLiteral("File to read from (stdin if none)"));
- parser.addPositionalArgument(QStringLiteral("[destination]"),
- QStringLiteral("File to write to (stdout if none)"));
+ parser.addPositionalArgument("[source]"_L1, "File to read from (stdin if none)"_L1);
+ parser.addPositionalArgument("[destination]"_L1, "File to write to (stdout if none)"_L1);
parser.process(app);
if (parser.isSet(formatOptionsOption)) {
QString format = parser.value(formatOptionsOption);
- for (Converter *conv : qAsConst(*availableConverters)) {
+//! [1]
+ for (const Converter *conv : Converter::allConverters()) {
if (conv->name() == format) {
const char *help = conv->optionsHelp();
- if (help)
- printf("The following options are available for format '%s':\n\n%s", qPrintable(format), help);
- else
- printf("Format '%s' supports no options.\n", qPrintable(format));
+ if (help) {
+ qInfo("The following options are available for format '%s':\n\n%s",
+ qPrintable(format), help);
+ } else {
+ qInfo("Format '%s' supports no options.", qPrintable(format));
+ }
return EXIT_SUCCESS;
}
}
+//! [1]
- fprintf(stderr, "Unknown file format '%s'\n", qPrintable(format));
- return EXIT_FAILURE;
- }
-
- Converter *inconv = nullptr;
- QString format = parser.value(inputFormatOption);
- if (format != "auto") {
- for (Converter *conv : qAsConst(*availableConverters)) {
- if (conv->name() == format) {
- inconv = conv;
- break;
- }
- }
-
- if (!inconv) {
- fprintf(stderr, "Unknown file format \"%s\"\n", qPrintable(format));
- return EXIT_FAILURE;
- }
- }
-
- Converter *outconv = nullptr;
- format = parser.value(outputFormatOption);
- if (format != "auto") {
- for (Converter *conv : qAsConst(*availableConverters)) {
- if (conv->name() == format) {
- outconv = conv;
- break;
- }
- }
-
- if (!outconv) {
- fprintf(stderr, "Unknown file format \"%s\"\n", qPrintable(format));
- return EXIT_FAILURE;
- }
+ qFatal("Unknown file format '%s'", qPrintable(format));
}
+//! [2]
QStringList files = parser.positionalArguments();
QFile input(files.value(0));
QFile output(files.value(1));
+ const Converter *inconv = prepareConverter(parser.value(inputFormatOption),
+ Converter::Direction::In, &input);
+ const Converter *outconv = prepareConverter(parser.value(outputFormatOption),
+ Converter::Direction::Out, &output);
- if (input.fileName().isEmpty())
- input.open(stdin, QIODevice::ReadOnly);
- else
- input.open(QIODevice::ReadOnly);
- if (!input.isOpen()) {
- fprintf(stderr, "Could not open \"%s\" for reading: %s\n",
- qPrintable(input.fileName()), qPrintable(input.errorString()));
- return EXIT_FAILURE;
- }
-
- if (output.fileName().isEmpty())
- output.open(stdout, QIODevice::WriteOnly | QIODevice::Truncate);
- else
- output.open(QIODevice::WriteOnly | QIODevice::Truncate);
- if (!output.isOpen()) {
- fprintf(stderr, "Could not open \"%s\" for writing: %s\n",
- qPrintable(output.fileName()), qPrintable(output.errorString()));
- return EXIT_FAILURE;
- }
-
- if (!inconv) {
- // probe the input to find a file format
- for (Converter *conv : qAsConst(*availableConverters)) {
- if (conv->directions() & Converter::In && conv->probeFile(&input)) {
- inconv = conv;
- break;
- }
- }
-
- if (!inconv) {
- fprintf(stderr, "Could not determine input format. pass -I option.\n");
- return EXIT_FAILURE;
- }
- }
-
- if (!outconv) {
- // probe the output to find a file format
- for (Converter *conv : qAsConst(*availableConverters)) {
- if (conv->directions() & Converter::Out && conv->probeFile(&output)) {
- outconv = conv;
- break;
- }
- }
- }
-
- // now finally perform the conversion
+ // Now finally perform the conversion:
QVariant data = inconv->loadFile(&input, outconv);
- Q_ASSERT_X(outconv, "Converter Tool",
+ Q_ASSERT_X(outconv, "Serialization Converter",
"Internal error: converter format did not provide default");
outconv->saveFile(&output, data, parser.values(optionOption));
return EXIT_SUCCESS;
+//! [2]
}
diff --git a/examples/corelib/serialization/convert/nullconverter.cpp b/examples/corelib/serialization/convert/nullconverter.cpp
index 2de492e64e..fb8be5c944 100644
--- a/examples/corelib/serialization/convert/nullconverter.cpp
+++ b/examples/corelib/serialization/convert/nullconverter.cpp
@@ -1,97 +1,37 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "nullconverter.h"
-static NullConverter nullConverter;
-Converter* Converter::null = &nullConverter;
-
-QString NullConverter::name()
-{
- return QLatin1String("null");
-}
-
-Converter::Direction NullConverter::directions()
-{
- return Out;
-}
+using namespace Qt::StringLiterals;
-Converter::Options NullConverter::outputOptions()
+static NullConverter nullConverter;
+bool Converter::isNull(const Converter *converter)
{
- return SupportsArbitraryMapKeys;
+ return converter == &nullConverter;
}
-const char *NullConverter::optionsHelp()
+QString NullConverter::name() const
{
- return nullptr;
+ return "null"_L1;
}
-bool NullConverter::probeFile(QIODevice *f)
+Converter::Directions NullConverter::directions() const
{
- Q_UNUSED(f);
- return false;
+ return Direction::Out;
}
-QVariant NullConverter::loadFile(QIODevice *f, Converter *&outputConverter)
+Converter::Options NullConverter::outputOptions() const
{
- Q_UNUSED(f);
- Q_UNUSED(outputConverter);
- outputConverter = this;
- return QVariant();
+ return SupportsArbitraryMapKeys;
}
-void NullConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void NullConverter::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
{
if (!options.isEmpty()) {
- fprintf(stderr, "Unknown option '%s' to null output. This format has no options.\n", qPrintable(options.first()));
- exit(EXIT_FAILURE);
+ qFatal("Unknown option '%s' to null output. This format has no options.",
+ qPrintable(options.first()));
}
Q_UNUSED(f);
diff --git a/examples/corelib/serialization/convert/nullconverter.h b/examples/corelib/serialization/convert/nullconverter.h
index af7339f092..1bdf9f22f7 100644
--- a/examples/corelib/serialization/convert/nullconverter.h
+++ b/examples/corelib/serialization/convert/nullconverter.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef NULLCONVERTER_H
#define NULLCONVERTER_H
@@ -57,13 +10,11 @@ class NullConverter : public Converter
{
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ Options outputOptions() const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
#endif // NULLCONVERTER_H
diff --git a/examples/corelib/serialization/convert/textconverter.cpp b/examples/corelib/serialization/convert/textconverter.cpp
index ae03b9a334..1f8b4f9c19 100644
--- a/examples/corelib/serialization/convert/textconverter.cpp
+++ b/examples/corelib/serialization/convert/textconverter.cpp
@@ -1,58 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "textconverter.h"
#include <QFile>
#include <QTextStream>
+using namespace Qt::StringLiterals;
+
static void dumpVariant(QTextStream &out, const QVariant &v)
{
switch (v.userType()) {
@@ -89,68 +44,52 @@ static void dumpVariant(QTextStream &out, const QVariant &v)
}
}
-QString TextConverter::name()
-{
- return QStringLiteral("text");
-}
-
-Converter::Direction TextConverter::directions()
-{
- return InOut;
-}
-
-Converter::Options TextConverter::outputOptions()
+QString TextConverter::name() const
{
- return {};
+ return "text"_L1;
}
-const char *TextConverter::optionsHelp()
+Converter::Directions TextConverter::directions() const
{
- return nullptr;
+ return Direction::InOut;
}
-bool TextConverter::probeFile(QIODevice *f)
+bool TextConverter::probeFile(QIODevice *f) const
{
if (QFile *file = qobject_cast<QFile *>(f))
- return file->fileName().endsWith(QLatin1String(".txt"));
+ return file->fileName().endsWith(".txt"_L1);
return false;
}
-QVariant TextConverter::loadFile(QIODevice *f, Converter *&outputConverter)
+QVariant TextConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
if (!outputConverter)
outputConverter = this;
QVariantList list;
QTextStream in(f);
- QString line ;
+ QString line;
while (!in.atEnd()) {
in.readLineInto(&line);
-
bool ok;
- qint64 v = line.toLongLong(&ok);
- if (ok) {
- list.append(v);
- continue;
- }
- double d = line.toDouble(&ok);
- if (ok) {
+ if (qint64 v = line.toLongLong(&ok); ok)
+ list.append(v);
+ else if (double d = line.toDouble(&ok); ok)
list.append(d);
- continue;
- }
-
- list.append(line);
+ else
+ list.append(line);
}
return list;
}
-void TextConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void TextConverter::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
{
if (!options.isEmpty()) {
- fprintf(stderr, "Unknown option '%s' to text output. This format has no options.\n", qPrintable(options.first()));
- exit(EXIT_FAILURE);
+ qFatal("Unknown option '%s' to text output. This format has no options.",
+ qPrintable(options.first()));
}
QTextStream out(f);
diff --git a/examples/corelib/serialization/convert/textconverter.h b/examples/corelib/serialization/convert/textconverter.h
index 66f5136c02..526f295517 100644
--- a/examples/corelib/serialization/convert/textconverter.h
+++ b/examples/corelib/serialization/convert/textconverter.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef TEXTCONVERTER_H
#define TEXTCONVERTER_H
@@ -55,16 +8,14 @@
class TextConverter : public Converter
{
-
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ bool probeFile(QIODevice *f) const override;
+ QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
#endif // TEXTCONVERTER_H
diff --git a/examples/corelib/serialization/convert/variantorderedmap.h b/examples/corelib/serialization/convert/variantorderedmap.h
new file mode 100644
index 0000000000..c65316b182
--- /dev/null
+++ b/examples/corelib/serialization/convert/variantorderedmap.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef VARIANTORDEREDMAP_H
+#define VARIANTORDEREDMAP_H
+
+#include <QList>
+#include <QPair>
+#include <QVariant>
+#include <QVariantMap>
+
+class VariantOrderedMap : public QList<QPair<QVariant, QVariant>>
+{
+public:
+ VariantOrderedMap() = default;
+ VariantOrderedMap(const QVariantMap &map)
+ {
+ reserve(map.size());
+ for (auto it = map.begin(); it != map.end(); ++it)
+ append({it.key(), it.value()});
+ }
+};
+
+#endif // VARIANTORDEREDMAP_H
diff --git a/examples/corelib/serialization/convert/xmlconverter.cpp b/examples/corelib/serialization/convert/xmlconverter.cpp
index c2811c5745..ef71fecb9f 100644
--- a/examples/corelib/serialization/convert/xmlconverter.cpp
+++ b/examples/corelib/serialization/convert/xmlconverter.cpp
@@ -1,54 +1,8 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "xmlconverter.h"
+#include "variantorderedmap.h"
#include <QBitArray>
#include <QtCborCommon>
@@ -60,8 +14,9 @@
#include <QXmlStreamReader>
#include <QXmlStreamWriter>
-static const char optionHelp[] =
- "compact=no|yes Use compact XML form.\n";
+using namespace Qt::StringLiterals;
+
+static const char xmlOptionHelp[] = "compact=no|yes Use compact XML form.\n";
static XmlConverter xmlConverter;
@@ -70,7 +25,7 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options options)
{
QVariantList list;
- while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == QLatin1String("list"))) {
+ while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == "list"_L1)) {
xml.readNext();
switch (xml.tokenType()) {
case QXmlStreamReader::StartElement:
@@ -94,20 +49,19 @@ static QVariantList listFromXml(QXmlStreamReader &xml, Converter::Options option
break;
}
- fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n",
- xml.lineNumber(), xml.columnNumber(),
- qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
+ qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
}
xml.readNext();
return list;
}
-static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml, Converter::Options options)
+static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml,
+ Converter::Options options)
{
QVariant key, value;
- while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == QLatin1String("entry"))) {
+ while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == "entry"_L1)) {
xml.readNext();
switch (xml.tokenType()) {
case QXmlStreamReader::StartElement:
@@ -136,10 +90,8 @@ static VariantOrderedMap::value_type mapEntryFromXml(QXmlStreamReader &xml, Conv
break;
}
- fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n",
- xml.lineNumber(), xml.columnNumber(),
- qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
+ qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
}
return { key, value };
@@ -150,11 +102,11 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
QVariantMap map1;
VariantOrderedMap map2;
- while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == QLatin1String("map"))) {
+ while (!xml.atEnd() && !(xml.isEndElement() && xml.name() == "map"_L1)) {
xml.readNext();
switch (xml.tokenType()) {
case QXmlStreamReader::StartElement:
- if (xml.name() == QLatin1String("entry")) {
+ if (xml.name() == "entry"_L1) {
auto pair = mapEntryFromXml(xml, options);
if (options & Converter::SupportsArbitraryMapKeys)
map2.append(pair);
@@ -181,10 +133,8 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
break;
}
- fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n",
- xml.lineNumber(), xml.columnNumber(),
- qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
+ qPrintable(xml.tokenString()), qPrintable(xml.name().toString()));
}
xml.readNext();
@@ -196,18 +146,17 @@ static QVariant mapFromXml(QXmlStreamReader &xml, Converter::Options options)
static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options)
{
QStringView name = xml.name();
- if (name == QLatin1String("list"))
+ if (name == "list"_L1)
return listFromXml(xml, options);
- if (name == QLatin1String("map"))
+ if (name == "map"_L1)
return mapFromXml(xml, options);
- if (name != QLatin1String("value")) {
- fprintf(stderr, "%lld:%lld: Invalid XML key '%s'.\n",
- xml.lineNumber(), xml.columnNumber(), qPrintable(name.toString()));
- exit(EXIT_FAILURE);
+ if (name != "value"_L1) {
+ qFatal("%lld:%lld: Invalid XML key '%s'.",
+ xml.lineNumber(), xml.columnNumber(), qPrintable(name.toString()));
}
QXmlStreamAttributes attrs = xml.attributes();
- QStringView type = attrs.value(QLatin1String("type"));
+ QStringView type = attrs.value("type"_L1);
forever {
xml.readNext();
@@ -216,10 +165,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
if (xml.isCDATA() || xml.isCharacters() || xml.isEndElement())
break;
- fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n",
- xml.lineNumber(), xml.columnNumber(),
- qPrintable(xml.tokenString()), qPrintable(name.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
+ qPrintable(xml.tokenString()), qPrintable(name.toString()));
}
QStringView text = xml.text();
@@ -227,45 +174,43 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
text = text.trimmed();
QVariant result;
- bool ok;
if (type.isEmpty()) {
// ok
- } else if (type == QLatin1String("number")) {
+ } else if (type == "number"_L1) {
// try integer first
+ bool ok;
qint64 v = text.toLongLong(&ok);
if (ok) {
result = v;
} else {
// let's see floating point
double d = text.toDouble(&ok);
- result = d;
if (!ok) {
- fprintf(stderr, "%lld:%lld: Invalid XML: could not interpret '%s' as a number.\n",
- xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML: could not interpret '%s' as a number.",
+ xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
}
+ result = d;
}
- } else if (type == QLatin1String("bytes")) {
+ } else if (type == "bytes"_L1) {
QByteArray data = text.toLatin1();
QStringView encoding = attrs.value("encoding");
- if (encoding == QLatin1String("base64url")) {
+ if (encoding == "base64url"_L1) {
result = QByteArray::fromBase64(data, QByteArray::Base64UrlEncoding);
- } else if (encoding == QLatin1String("hex")) {
+ } else if (encoding == "hex"_L1) {
result = QByteArray::fromHex(data);
- } else if (encoding.isEmpty() || encoding == QLatin1String("base64")) {
+ } else if (encoding.isEmpty() || encoding == "base64"_L1) {
result = QByteArray::fromBase64(data);
} else {
- fprintf(stderr, "%lld:%lld: Invalid XML: unknown encoding '%s' for bytes.\n",
- xml.lineNumber(), xml.columnNumber(), qPrintable(encoding.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML: unknown encoding '%s' for bytes.",
+ xml.lineNumber(), xml.columnNumber(), qPrintable(encoding.toString()));
}
- } else if (type == QLatin1String("string")) {
+ } else if (type == "string"_L1) {
result = text.toString();
- } else if (type == QLatin1String("null")) {
+ } else if (type == "null"_L1) {
result = QVariant::fromValue(nullptr);
- } else if (type == QLatin1String("CBOR simple type")) {
+ } else if (type == "CBOR simple type"_L1) {
result = QVariant::fromValue(QCborSimpleType(text.toShort()));
- } else if (type == QLatin1String("bits")) {
+ } else if (type == "bits"_L1) {
QBitArray ba;
ba.resize(text.size());
qsizetype n = 0;
@@ -276,36 +221,33 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
} else if (c == '0') {
++n;
} else if (!c.isSpace()) {
- fprintf(stderr, "%lld:%lld: Invalid XML: invalid bit string '%s'.\n",
- xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML: invalid bit string '%s'.",
+ xml.lineNumber(), xml.columnNumber(), qPrintable(text.toString()));
}
}
ba.resize(n);
result = ba;
} else {
int id = QMetaType::UnknownType;
- if (type == QLatin1String("datetime"))
+ if (type == "datetime"_L1)
id = QMetaType::QDateTime;
- else if (type == QLatin1String("url"))
+ else if (type == "url"_L1)
id = QMetaType::QUrl;
- else if (type == QLatin1String("uuid"))
+ else if (type == "uuid"_L1)
id = QMetaType::QUuid;
- else if (type == QLatin1String("regex"))
+ else if (type == "regex"_L1)
id = QMetaType::QRegularExpression;
else
id = QMetaType::fromName(type.toLatin1()).id();
if (id == QMetaType::UnknownType) {
- fprintf(stderr, "%lld:%lld: Invalid XML: unknown type '%s'.\n",
- xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML: unknown type '%s'.",
+ xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
}
result = text.toString();
if (!result.convert(QMetaType(id))) {
- fprintf(stderr, "%lld:%lld: Invalid XML: could not parse content as type '%s'.\n",
- xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML: could not parse content as type '%s'.",
+ xml.lineNumber(), xml.columnNumber(), qPrintable(type.toString()));
}
}
@@ -314,10 +256,8 @@ static QVariant variantFromXml(QXmlStreamReader &xml, Converter::Options options
} while (xml.isComment() || xml.isWhitespace());
if (!xml.isEndElement()) {
- fprintf(stderr, "%lld:%lld: Invalid XML %s '%s'.\n",
- xml.lineNumber(), xml.columnNumber(),
- qPrintable(xml.tokenString()), qPrintable(name.toString()));
- exit(EXIT_FAILURE);
+ qFatal("%lld:%lld: Invalid XML %s '%s'.", xml.lineNumber(), xml.columnNumber(),
+ qPrintable(xml.tokenString()), qPrintable(name.toString()));
}
xml.readNext();
@@ -334,9 +274,9 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
variantToXml(xml, v);
xml.writeEndElement();
} else if (type == QMetaType::QVariantMap || type == qMetaTypeId<VariantOrderedMap>()) {
- const VariantOrderedMap map = (type == QMetaType::QVariantMap) ?
- VariantOrderedMap(v.toMap()) :
- qvariant_cast<VariantOrderedMap>(v);
+ const VariantOrderedMap map = (type == QMetaType::QVariantMap)
+ ? VariantOrderedMap(v.toMap())
+ : qvariant_cast<VariantOrderedMap>(v);
xml.writeStartElement("map");
for (const auto &pair : map) {
@@ -348,7 +288,7 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
xml.writeEndElement();
} else {
xml.writeStartElement("value");
- QString typeString = QStringLiteral("type");
+ QString typeString = "type"_L1;
switch (type) {
case QMetaType::Short:
case QMetaType::UShort:
@@ -437,8 +377,7 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
xml.writeAttribute(typeString, QString::fromLatin1(typeName));
xml.writeCharacters(copy.toString());
} else {
- fprintf(stderr, "XML: don't know how to serialize type '%s'.\n", typeName);
- exit(EXIT_FAILURE);
+ qFatal("XML: don't know how to serialize type '%s'.", typeName);
}
}
}
@@ -446,37 +385,37 @@ static void variantToXml(QXmlStreamWriter &xml, const QVariant &v)
}
}
-QString XmlConverter::name()
+QString XmlConverter::name() const
{
- return QStringLiteral("xml");
+ return "xml"_L1;
}
-Converter::Direction XmlConverter::directions()
+Converter::Directions XmlConverter::directions() const
{
- return InOut;
+ return Direction::InOut;
}
-Converter::Options XmlConverter::outputOptions()
+Converter::Options XmlConverter::outputOptions() const
{
return SupportsArbitraryMapKeys;
}
-const char *XmlConverter::optionsHelp()
+const char *XmlConverter::optionsHelp() const
{
- return optionHelp;
+ return xmlOptionHelp;
}
-bool XmlConverter::probeFile(QIODevice *f)
+bool XmlConverter::probeFile(QIODevice *f) const
{
if (QFile *file = qobject_cast<QFile *>(f)) {
- if (file->fileName().endsWith(QLatin1String(".xml")))
+ if (file->fileName().endsWith(".xml"_L1))
return true;
}
return f->isReadable() && f->peek(5) == "<?xml";
}
-QVariant XmlConverter::loadFile(QIODevice *f, Converter *&outputConverter)
+QVariant XmlConverter::loadFile(QIODevice *f, const Converter *&outputConverter) const
{
if (!outputConverter)
outputConverter = this;
@@ -484,25 +423,24 @@ QVariant XmlConverter::loadFile(QIODevice *f, Converter *&outputConverter)
QXmlStreamReader xml(f);
xml.readNextStartElement();
QVariant v = variantFromXml(xml, outputConverter->outputOptions());
- if (xml.hasError()) {
- fprintf(stderr, "XML error: %s", qPrintable(xml.errorString()));
- exit(EXIT_FAILURE);
- }
+ if (xml.hasError())
+ qFatal("XML error: %s", qPrintable(xml.errorString()));
return v;
}
-void XmlConverter::saveFile(QIODevice *f, const QVariant &contents, const QStringList &options)
+void XmlConverter::saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const
{
bool compact = false;
for (const QString &s : options) {
- if (s == QLatin1String("compact=no")) {
+ if (s == "compact=no"_L1) {
compact = false;
- } else if (s == QLatin1String("compact=yes")) {
+ } else if (s == "compact=yes"_L1) {
compact = true;
} else {
- fprintf(stderr, "Unknown option '%s' to XML output. Valid options are:\n%s", qPrintable(s), optionHelp);
- exit(EXIT_FAILURE);
+ qFatal("Unknown option '%s' to XML output. Valid options are:\n%s",
+ qPrintable(s), xmlOptionHelp);
}
}
diff --git a/examples/corelib/serialization/convert/xmlconverter.h b/examples/corelib/serialization/convert/xmlconverter.h
index 8fc0fea592..4888b0616f 100644
--- a/examples/corelib/serialization/convert/xmlconverter.h
+++ b/examples/corelib/serialization/convert/xmlconverter.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 Intel Corporation.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef XMLCONVERTER_H
#define XMLCONVERTER_H
@@ -57,13 +10,14 @@ class XmlConverter : public Converter
{
// Converter interface
public:
- QString name() override;
- Direction directions() override;
- Options outputOptions() override;
- const char *optionsHelp() override;
- bool probeFile(QIODevice *f) override;
- QVariant loadFile(QIODevice *f, Converter *&outputConverter) override;
- void saveFile(QIODevice *f, const QVariant &contents, const QStringList &options) override;
+ QString name() const override;
+ Directions directions() const override;
+ Options outputOptions() const override;
+ const char *optionsHelp() const override;
+ bool probeFile(QIODevice *f) const override;
+ QVariant loadFile(QIODevice *f, const Converter *&outputConverter) const override;
+ void saveFile(QIODevice *f, const QVariant &contents,
+ const QStringList &options) const override;
};
#endif // XMLCONVERTER_H
diff --git a/examples/corelib/serialization/savegame/CMakeLists.txt b/examples/corelib/serialization/savegame/CMakeLists.txt
index f757d1359b..14621ccc23 100644
--- a/examples/corelib/serialization/savegame/CMakeLists.txt
+++ b/examples/corelib/serialization/savegame/CMakeLists.txt
@@ -1,16 +1,17 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
cmake_minimum_required(VERSION 3.16)
project(savegame LANGUAGES CXX)
-set(CMAKE_AUTOMOC ON)
-
-if(NOT DEFINED INSTALL_EXAMPLESDIR)
- set(INSTALL_EXAMPLESDIR "examples")
+if (ANDROID)
+ message(FATAL_ERROR "This project cannot be built on Android.")
endif()
-set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/serialization/savegame")
-
find_package(Qt6 REQUIRED COMPONENTS Core)
+qt_standard_project_setup()
+
qt_add_executable(savegame
character.cpp character.h
game.cpp game.h
@@ -18,12 +19,19 @@ qt_add_executable(savegame
main.cpp
)
-target_link_libraries(savegame PUBLIC
- Qt::Core
+target_link_libraries(savegame PRIVATE
+ Qt6::Core
)
install(TARGETS savegame
- RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
- BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
- LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET savegame
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
)
+install(SCRIPT ${deploy_script})
diff --git a/examples/corelib/serialization/savegame/character.cpp b/examples/corelib/serialization/savegame/character.cpp
index 046cde3091..863fcb9153 100644
--- a/examples/corelib/serialization/savegame/character.cpp
+++ b/examples/corelib/serialization/savegame/character.cpp
@@ -1,69 +1,15 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "character.h"
#include <QMetaEnum>
#include <QTextStream>
-Character::Character() :
- mLevel(0),
- mClassType(Warrior) {
-}
+Character::Character() = default;
-Character::Character(const QString &name,
- int level,
- Character::ClassType classType) :
- mName(name),
- mLevel(level),
- mClassType(classType)
+Character::Character(const QString &name, int level, Character::ClassType classType)
+ : mName(name), mLevel(level), mClassType(classType)
{
}
@@ -97,35 +43,41 @@ void Character::setClassType(Character::ClassType classType)
mClassType = classType;
}
-//! [0]
-void Character::read(const QJsonObject &json)
+//! [fromJson]
+Character Character::fromJson(const QJsonObject &json)
{
- if (json.contains("name") && json["name"].isString())
- mName = json["name"].toString();
+ Character result;
+
+ if (const QJsonValue v = json["name"]; v.isString())
+ result.mName = v.toString();
+
+ if (const QJsonValue v = json["level"]; v.isDouble())
+ result.mLevel = v.toInt();
- if (json.contains("level") && json["level"].isDouble())
- mLevel = json["level"].toInt();
+ if (const QJsonValue v = json["classType"]; v.isDouble())
+ result.mClassType = ClassType(v.toInt());
- if (json.contains("classType") && json["classType"].isDouble())
- mClassType = ClassType(json["classType"].toInt());
+ return result;
}
-//! [0]
+//! [fromJson]
-//! [1]
-void Character::write(QJsonObject &json) const
+//! [toJson]
+QJsonObject Character::toJson() const
{
+ QJsonObject json;
json["name"] = mName;
json["level"] = mLevel;
json["classType"] = mClassType;
+ return json;
}
-//! [1]
+//! [toJson]
-void Character::print(int indentation) const
+void Character::print(QTextStream &s, int indentation) const
{
const QString indent(indentation * 2, ' ');
- QTextStream(stdout) << indent << "Name:\t" << mName << "\n";
- QTextStream(stdout) << indent << "Level:\t" << mLevel << "\n";
+ const QString className = QMetaEnum::fromType<ClassType>().valueToKey(mClassType);
- QString className = QMetaEnum::fromType<ClassType>().valueToKey(mClassType);
- QTextStream(stdout) << indent << "Class:\t" << className << "\n";
+ s << indent << "Name:\t" << mName << "\n"
+ << indent << "Level:\t" << mLevel << "\n"
+ << indent << "Class:\t" << className << "\n";
}
diff --git a/examples/corelib/serialization/savegame/character.h b/examples/corelib/serialization/savegame/character.h
index cbf06d7fd6..0504750320 100644
--- a/examples/corelib/serialization/savegame/character.h
+++ b/examples/corelib/serialization/savegame/character.h
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CHARACTER_H
#define CHARACTER_H
@@ -55,15 +8,15 @@
#include <QObject>
#include <QString>
+QT_FORWARD_DECLARE_CLASS(QTextStream)
+
//! [0]
class Character
{
- Q_GADGET;
+ Q_GADGET
public:
- enum ClassType {
- Warrior, Mage, Archer
- };
+ enum ClassType { Warrior, Mage, Archer };
Q_ENUM(ClassType)
Character();
@@ -78,14 +31,15 @@ public:
ClassType classType() const;
void setClassType(ClassType classType);
- void read(const QJsonObject &json);
- void write(QJsonObject &json) const;
+ static Character fromJson(const QJsonObject &json);
+ QJsonObject toJson() const;
+
+ void print(QTextStream &s, int indentation = 0) const;
- void print(int indentation = 0) const;
private:
QString mName;
- int mLevel;
- ClassType mClassType;
+ int mLevel = 0;
+ ClassType mClassType = Warrior;
};
//! [0]
diff --git a/examples/corelib/serialization/savegame/doc/src/savegame.qdoc b/examples/corelib/serialization/savegame/doc/src/savegame.qdoc
index 72dd393cb0..46fca15b62 100644
--- a/examples/corelib/serialization/savegame/doc/src/savegame.qdoc
+++ b/examples/corelib/serialization/savegame/doc/src/savegame.qdoc
@@ -1,44 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\example serialization/savegame
- \title JSON Save Game Example
+ \examplecategory {Data Processing & I/O}
+ \title Saving and Loading a Game
- \brief The JSON Save Game example demonstrates how to save and load a
- small game using QJsonDocument, QJsonObject and QJsonArray.
+ \brief How to save and load a game using Qt's JSON or CBOR classes.
Many games provide save functionality, so that the player's progress through
the game can be saved and loaded at a later time. The process of saving a
- game generally involves serializing each game object's member variables
- to a file. Many formats can be used for this purpose, one of which is JSON.
- With QJsonDocument, you also have the ability to serialize a document in a
- \l {RFC 7049} {CBOR} format, which is great if you
- don't want the save file to be readable, or if you need to keep the file size down.
+ game generally involves serializing each game object's member variables to a
+ file. Many formats can be used for this purpose, one of which is JSON. With
+ QJsonDocument, you also have the ability to serialize a document in a \l
+ {RFC 7049} {CBOR} format, which is great if you don't want the save file to
+ be easy to read (but see \l {Parsing and displaying CBOR data} for how it \e
+ can be read), or if you need to keep the file size down.
In this example, we'll demonstrate how to save and load a simple game to
and from JSON and binary formats.
@@ -48,45 +25,83 @@
The Character class represents a non-player character (NPC) in our game, and
stores the player's name, level, and class type.
- It provides read() and write() functions to serialise its member variables.
+ It provides static fromJson() and non-static toJson() functions to
+ serialise itself.
+
+ \note This pattern (fromJson()/toJson()) works because QJsonObjects can be
+ constructed independent of an owning QJsonDocument, and because the data
+ types being (de)serialized here are value types, so can be copied. When
+ serializing to another format — for example XML or QDataStream, which require passing
+ a document-like object — or when the object identity is important (QObject
+ subclasses, for example), other patterns may be more suitable. See the
+ \l{dombookmarks} example for XML, and the implementation of
+ \l QListWidgetItem::read() and \l QListWidgetItem::write()
+ for idiomatic QDataStream serialization. The \c{print()} functions in this example
+ are good examples of QTextStream serialization, even though they, of course, lack
+ the deserialization side.
\snippet serialization/savegame/character.h 0
- Of particular interest to us are the read and write function
+ Of particular interest to us are the fromJson() and toJson() function
implementations:
- \snippet serialization/savegame/character.cpp 0
+ \snippet serialization/savegame/character.cpp fromJson
- In the read() function, we assign Character's members values from the
- QJsonObject argument. You can use either \l QJsonObject::operator[]() or
- QJsonObject::value() to access values within the JSON object; both are
- const functions and return QJsonValue::Undefined if the key is invalid. We
- check if the keys are valid before attempting to read them with
- QJsonObject::contains().
+ In the fromJson() function, we construct a local \c result Character object
+ and assign \c{result}'s members values from the QJsonObject argument. You
+ can use either \l QJsonObject::operator[]() or QJsonObject::value() to
+ access values within the JSON object; both are const functions and return
+ QJsonValue::Undefined if the key is invalid. In particular, the \c{is...}
+ functions (for example \l QJsonValue::isString(), \l
+ QJsonValue::isDouble()) return \c false for QJsonValue::Undefined, so we
+ can check for existence as well as the correct type in a single lookup.
- \snippet serialization/savegame/character.cpp 1
+ If a value does not exist in the JSON object, or has the wrong type, we
+ don't write to the corresponding \c result member, either, thereby
+ preserving any values the default constructor may have set. This means
+ default values are centrally defined in one location (the default
+ constructor) and need not be repeated in serialisation code
+ (\l{https://en.wikipedia.org/wiki/Don%27t_repeat_yourself}{DRY}).
- In the write() function, we do the reverse of the read() function; assign
- values from the Character object to the JSON object. As with accessing
- values, there are two ways to set values on a QJsonObject:
- \l QJsonObject::operator[]() and QJsonObject::insert(). Both will override
- any existing value at the given key.
+ Observe the use of
+ \l{https://en.cppreference.com/w/cpp/language/if#If_statements_with_initializer}
+ {C++17 if-with-initializer} to separate scoping and checking of the variable \c v.
+ This means we can keep the variable name short, because its scope is limited.
- Next up is the Level class:
+ Compare that to the naïve approach using \c QJsonObject::contains():
+
+ \badcode
+ if (json.contains("name") && json["name"].isString())
+ result.mName = json["name"].toString();
+ \endcode
+
+ which, beside being less readable, requires a total of three lookups (no,
+ the compiler will \e not optimize these into one), so is three times
+ slower and repeats \c{"name"} three times (violating the DRY principle).
+
+ \snippet serialization/savegame/character.cpp toJson
+
+ In the toJson() function, we do the reverse of the fromJson() function;
+ assign values from the Character object to a new JSON object we then
+ return. As with accessing values, there are two ways to set values on a
+ QJsonObject: \l QJsonObject::operator[]() and \l QJsonObject::insert().
+ Both will override any existing value at the given key.
+
+ \section1 The Level Class
\snippet serialization/savegame/level.h 0
- We want to have several levels in our game, each with several NPCs, so we
- keep a QList of Character objects. We also provide the familiar read() and
- write() functions.
+ We want the levels in our game to each each have several NPCs, so we keep a QList
+ of Character objects. We also provide the familiar fromJson() and toJson()
+ functions.
- \snippet serialization/savegame/level.cpp 0
+ \snippet serialization/savegame/level.cpp fromJson
- Containers can be written and read to and from JSON using QJsonArray. In our
+ Containers can be written to and read from JSON using QJsonArray. In our
case, we construct a QJsonArray from the value associated with the key
\c "npcs". Then, for each QJsonValue element in the array, we call
- toObject() to get the Character's JSON object. The Character object can then
- read their JSON and be appended to our NPC array.
+ toObject() to get the Character's JSON object. Character::fromJson() can
+ then turn that QJSonObject into a Character object to append to our NPC array.
\note \l{Container Classes}{Associate containers} can be written by storing
the key in each value object (if it's not already). With this approach, the
@@ -94,11 +109,13 @@
element is used as the key to construct the container when reading it back
in.
- \snippet serialization/savegame/level.cpp 1
+ \snippet serialization/savegame/level.cpp toJson
- Again, the write() function is similar to the read() function, except
+ Again, the toJson() function is similar to the fromJson() function, except
reversed.
+ \section1 The Game Class
+
Having established the Character and Level classes, we can move on to
the Game class:
@@ -110,26 +127,43 @@
Next, we provide accessors for the player and levels. We then expose three
functions: newGame(), saveGame() and loadGame().
- The read() and write() functions are used by saveGame() and loadGame().
+ The read() and toJson() functions are used by saveGame() and loadGame().
+
+ \div{class="admonition note"}\b{Note:}
+ Despite \c Game being a value class, we assume that the author wants a game to have
+ identity, much like your main window would have. We therefore don't use a
+ static fromJson() function, which would create a new object, but a read()
+ function we can call on existing objects. There's a 1:1 correspondence
+ between read() and fromJson(), in that one can be implemented in terms of
+ the other:
+
+ \code
+ void read(const QJsonObject &json) { *this = fromJson(json); }
+ static Game fromObject(const QJsonObject &json) { Game g; g.read(json); return g; }
+ \endcode
- \snippet serialization/savegame/game.cpp 0
+ We just use what's more convenient for callers of the functions.
+ \enddiv
+
+ \snippet serialization/savegame/game.cpp newGame
To setup a new game, we create the player and populate the levels and their
NPCs.
- \snippet serialization/savegame/game.cpp 1
+ \snippet serialization/savegame/game.cpp read
- The first thing we do in the read() function is tell the player to read
- itself. We then clear the level array so that calling loadGame() on the
- same Game object twice doesn't result in old levels hanging around.
+ The read() function starts by replacing the player with the
+ one read from JSON. We then clear() the level array so that calling
+ loadGame() on the same Game object twice doesn't result in old levels
+ hanging around.
We then populate the level array by reading each Level from a QJsonArray.
- \snippet serialization/savegame/game.cpp 2
+ \snippet serialization/savegame/game.cpp toJson
- We write the game to JSON similarly to how we write Level.
+ Writing the game to JSON is similar to writing a level.
- \snippet serialization/savegame/game.cpp 3
+ \snippet serialization/savegame/game.cpp loadGame
When loading a saved game in loadGame(), the first thing we do is open the
save file based on which format it was saved to; \c "save.json" for JSON,
@@ -143,14 +177,16 @@
After constructing the QJsonDocument, we instruct the Game object to read
itself and then return \c true to indicate success.
- \snippet serialization/savegame/game.cpp 4
+ \snippet serialization/savegame/game.cpp saveGame
Not surprisingly, saveGame() looks very much like loadGame(). We determine
the file extension based on the format, print a warning and return \c false
if the opening of the file fails. We then write the Game object to a
- QJsonDocument, and call either QJsonDocument::toJson() or to
- QJsonDocument::toBinaryData() to save the game, depending on which format
- was specified.
+ QJsonObject. To save the game in the format that was specified, we
+ convert the JSON object into either a QJsonDocument for a subsequent
+ QJsonDocument::toJson() call, or a QCborValue for QCborValue::toCbor().
+
+ \section1 Tying It All Together
We are now ready to enter main():
@@ -182,5 +218,5 @@
human-readable JSON files, but you also have the option to use a binary
format if it's required, \e without rewriting any code.
- \sa {JSON Support in Qt}, {Data Storage}
+ \sa {JSON Support in Qt}, {CBOR Support in Qt}, {Data Input Output}
*/
diff --git a/examples/corelib/serialization/savegame/game.cpp b/examples/corelib/serialization/savegame/game.cpp
index bb7c2013f2..f99ecb8b51 100644
--- a/examples/corelib/serialization/savegame/game.cpp
+++ b/examples/corelib/serialization/savegame/game.cpp
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "game.h"
@@ -58,6 +11,8 @@
#include <QRandomGenerator>
#include <QTextStream>
+using namespace Qt::StringLiterals;
+
Character Game::player() const
{
return mPlayer;
@@ -68,52 +23,45 @@ QList<Level> Game::levels() const
return mLevels;
}
-//! [0]
+//! [newGame]
void Game::newGame()
{
mPlayer = Character();
- mPlayer.setName(QStringLiteral("Hero"));
+ mPlayer.setName("Hero"_L1);
mPlayer.setClassType(Character::Archer);
mPlayer.setLevel(QRandomGenerator::global()->bounded(15, 21));
mLevels.clear();
mLevels.reserve(2);
- Level village(QStringLiteral("Village"));
+ Level village("Village"_L1);
QList<Character> villageNpcs;
villageNpcs.reserve(2);
- villageNpcs.append(Character(QStringLiteral("Barry the Blacksmith"),
- QRandomGenerator::global()->bounded(8, 11),
- Character::Warrior));
- villageNpcs.append(Character(QStringLiteral("Terry the Trader"),
- QRandomGenerator::global()->bounded(6, 8),
- Character::Warrior));
+ villageNpcs.append(Character("Barry the Blacksmith"_L1,
+ QRandomGenerator::global()->bounded(8, 11), Character::Warrior));
+ villageNpcs.append(Character("Terry the Trader"_L1,
+ QRandomGenerator::global()->bounded(6, 8), Character::Warrior));
village.setNpcs(villageNpcs);
mLevels.append(village);
- Level dungeon(QStringLiteral("Dungeon"));
+ Level dungeon("Dungeon"_L1);
QList<Character> dungeonNpcs;
dungeonNpcs.reserve(3);
- dungeonNpcs.append(Character(QStringLiteral("Eric the Evil"),
- QRandomGenerator::global()->bounded(18, 26),
- Character::Mage));
- dungeonNpcs.append(Character(QStringLiteral("Eric's Left Minion"),
- QRandomGenerator::global()->bounded(5, 7),
- Character::Warrior));
- dungeonNpcs.append(Character(QStringLiteral("Eric's Right Minion"),
- QRandomGenerator::global()->bounded(4, 9),
- Character::Warrior));
+ dungeonNpcs.append(Character("Eric the Evil"_L1,
+ QRandomGenerator::global()->bounded(18, 26), Character::Mage));
+ dungeonNpcs.append(Character("Eric's Left Minion"_L1,
+ QRandomGenerator::global()->bounded(5, 7), Character::Warrior));
+ dungeonNpcs.append(Character("Eric's Right Minion"_L1,
+ QRandomGenerator::global()->bounded(4, 9), Character::Warrior));
dungeon.setNpcs(dungeonNpcs);
mLevels.append(dungeon);
}
-//! [0]
+//! [newGame]
-//! [3]
+//! [loadGame]
bool Game::loadGame(Game::SaveFormat saveFormat)
{
- QFile loadFile(saveFormat == Json
- ? QStringLiteral("save.json")
- : QStringLiteral("save.dat"));
+ QFile loadFile(saveFormat == Json ? "save.json"_L1 : "save.dat"_L1);
if (!loadFile.open(QIODevice::ReadOnly)) {
qWarning("Couldn't open save file.");
@@ -123,85 +71,72 @@ bool Game::loadGame(Game::SaveFormat saveFormat)
QByteArray saveData = loadFile.readAll();
QJsonDocument loadDoc(saveFormat == Json
- ? QJsonDocument::fromJson(saveData)
- : QJsonDocument(QCborValue::fromCbor(saveData).toMap().toJsonObject()));
+ ? QJsonDocument::fromJson(saveData)
+ : QJsonDocument(QCborValue::fromCbor(saveData).toMap().toJsonObject()));
read(loadDoc.object());
- QTextStream(stdout) << "Loaded save for "
- << loadDoc["player"]["name"].toString()
- << " using "
- << (saveFormat != Json ? "CBOR" : "JSON") << "...\n";
+ QTextStream(stdout) << "Loaded save for " << loadDoc["player"]["name"].toString()
+ << " using " << (saveFormat != Json ? "CBOR" : "JSON") << "...\n";
return true;
}
-//! [3]
+//! [loadGame]
-//! [4]
+//! [saveGame]
bool Game::saveGame(Game::SaveFormat saveFormat) const
{
- QFile saveFile(saveFormat == Json
- ? QStringLiteral("save.json")
- : QStringLiteral("save.dat"));
+ QFile saveFile(saveFormat == Json ? "save.json"_L1 : "save.dat"_L1);
if (!saveFile.open(QIODevice::WriteOnly)) {
qWarning("Couldn't open save file.");
return false;
}
- QJsonObject gameObject;
- write(gameObject);
- saveFile.write(saveFormat == Json
- ? QJsonDocument(gameObject).toJson()
- : QCborValue::fromJsonValue(gameObject).toCbor());
+ QJsonObject gameObject = toJson();
+ saveFile.write(saveFormat == Json ? QJsonDocument(gameObject).toJson()
+ : QCborValue::fromJsonValue(gameObject).toCbor());
return true;
}
-//! [4]
+//! [saveGame]
-//! [1]
+//! [read]
void Game::read(const QJsonObject &json)
{
- if (json.contains("player") && json["player"].isObject())
- mPlayer.read(json["player"].toObject());
+ if (const QJsonValue v = json["player"]; v.isObject())
+ mPlayer = Character::fromJson(v.toObject());
- if (json.contains("levels") && json["levels"].isArray()) {
- QJsonArray levelArray = json["levels"].toArray();
+ if (const QJsonValue v = json["levels"]; v.isArray()) {
+ const QJsonArray levels = v.toArray();
mLevels.clear();
- mLevels.reserve(levelArray.size());
- for (int levelIndex = 0; levelIndex < levelArray.size(); ++levelIndex) {
- QJsonObject levelObject = levelArray[levelIndex].toObject();
- Level level;
- level.read(levelObject);
- mLevels.append(level);
- }
+ mLevels.reserve(levels.size());
+ for (const QJsonValue &level : levels)
+ mLevels.append(Level::fromJson(level.toObject()));
}
}
-//! [1]
+//! [read]
-//! [2]
-void Game::write(QJsonObject &json) const
+//! [toJson]
+QJsonObject Game::toJson() const
{
- QJsonObject playerObject;
- mPlayer.write(playerObject);
- json["player"] = playerObject;
-
- QJsonArray levelArray;
- for (const Level &level : mLevels) {
- QJsonObject levelObject;
- level.write(levelObject);
- levelArray.append(levelObject);
- }
- json["levels"] = levelArray;
+ QJsonObject json;
+ json["player"] = mPlayer.toJson();
+
+ QJsonArray levels;
+ for (const Level &level : mLevels)
+ levels.append(level.toJson());
+ json["levels"] = levels;
+ return json;
}
-//! [2]
+//! [toJson]
-void Game::print(int indentation) const
+void Game::print(QTextStream &s, int indentation) const
{
const QString indent(indentation * 2, ' ');
- QTextStream(stdout) << indent << "Player\n";
- mPlayer.print(indentation + 1);
+ s << indent << "Player\n";
+ mPlayer.print(s, indentation + 1);
- QTextStream(stdout) << indent << "Levels\n";
- for (Level level : mLevels)
- level.print(indentation + 1);
+ s << indent << "Levels\n";
+ for (const Level &level : mLevels)
+ level.print(s, indentation + 1);
}
diff --git a/examples/corelib/serialization/savegame/game.h b/examples/corelib/serialization/savegame/game.h
index dfcb27eb1c..5ba5952923 100644
--- a/examples/corelib/serialization/savegame/game.h
+++ b/examples/corelib/serialization/savegame/game.h
@@ -1,69 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef GAME_H
#define GAME_H
+#include "character.h"
+#include "level.h"
+
#include <QJsonObject>
#include <QList>
-#include "character.h"
-#include "level.h"
+QT_FORWARD_DECLARE_CLASS(QTextStream)
//! [0]
class Game
{
public:
- enum SaveFormat {
- Json, Binary
- };
+ enum SaveFormat { Json, Binary };
Character player() const;
QList<Level> levels() const;
@@ -73,9 +26,10 @@ public:
bool saveGame(SaveFormat saveFormat) const;
void read(const QJsonObject &json);
- void write(QJsonObject &json) const;
+ QJsonObject toJson() const;
+
+ void print(QTextStream &s, int indentation = 0) const;
- void print(int indentation = 0) const;
private:
Character mPlayer;
QList<Level> mLevels;
diff --git a/examples/corelib/serialization/savegame/level.cpp b/examples/corelib/serialization/savegame/level.cpp
index ea6ef147b9..f30d35e57f 100644
--- a/examples/corelib/serialization/savegame/level.cpp
+++ b/examples/corelib/serialization/savegame/level.cpp
@@ -1,61 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "level.h"
#include <QJsonArray>
#include <QTextStream>
-Level::Level(const QString &name) : mName(name)
-{
-}
+Level::Level(const QString &name) : mName(name) { }
QString Level::name() const
{
@@ -72,46 +23,43 @@ void Level::setNpcs(const QList<Character> &npcs)
mNpcs = npcs;
}
-//! [0]
-void Level::read(const QJsonObject &json)
+//! [fromJson]
+Level Level::fromJson(const QJsonObject &json)
{
- if (json.contains("name") && json["name"].isString())
- mName = json["name"].toString();
+ Level result;
+
+ if (const QJsonValue v = json["name"]; v.isString())
+ result.mName = v.toString();
- if (json.contains("npcs") && json["npcs"].isArray()) {
- QJsonArray npcArray = json["npcs"].toArray();
- mNpcs.clear();
- mNpcs.reserve(npcArray.size());
- for (int npcIndex = 0; npcIndex < npcArray.size(); ++npcIndex) {
- QJsonObject npcObject = npcArray[npcIndex].toObject();
- Character npc;
- npc.read(npcObject);
- mNpcs.append(npc);
- }
+ if (const QJsonValue v = json["npcs"]; v.isArray()) {
+ const QJsonArray npcs = v.toArray();
+ result.mNpcs.reserve(npcs.size());
+ for (const QJsonValue &npc : npcs)
+ result.mNpcs.append(Character::fromJson(npc.toObject()));
}
+
+ return result;
}
-//! [0]
+//! [fromJson]
-//! [1]
-void Level::write(QJsonObject &json) const
+//! [toJson]
+QJsonObject Level::toJson() const
{
+ QJsonObject json;
json["name"] = mName;
QJsonArray npcArray;
- for (const Character &npc : mNpcs) {
- QJsonObject npcObject;
- npc.write(npcObject);
- npcArray.append(npcObject);
- }
+ for (const Character &npc : mNpcs)
+ npcArray.append(npc.toJson());
json["npcs"] = npcArray;
+ return json;
}
-//! [1]
+//! [toJson]
-void Level::print(int indentation) const
+void Level::print(QTextStream &s, int indentation) const
{
const QString indent(indentation * 2, ' ');
- QTextStream(stdout) << indent << "Name:\t" << mName << "\n";
- QTextStream(stdout) << indent << "NPCs:\n";
+ s << indent << "Name:\t" << mName << "\n" << indent << "NPCs:\n";
for (const Character &character : mNpcs)
- character.print(2);
+ character.print(s, indentation + 1);
}
diff --git a/examples/corelib/serialization/savegame/level.h b/examples/corelib/serialization/savegame/level.h
index ecffde8f22..e487e55ae3 100644
--- a/examples/corelib/serialization/savegame/level.h
+++ b/examples/corelib/serialization/savegame/level.h
@@ -1,77 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef LEVEL_H
#define LEVEL_H
+#include "character.h"
+
#include <QJsonObject>
#include <QList>
-#include "character.h"
+QT_FORWARD_DECLARE_CLASS(QTextStream)
//! [0]
class Level
{
public:
Level() = default;
- Level(const QString &name);
+ explicit Level(const QString &name);
QString name() const;
QList<Character> npcs() const;
void setNpcs(const QList<Character> &npcs);
- void read(const QJsonObject &json);
- void write(QJsonObject &json) const;
+ static Level fromJson(const QJsonObject &json);
+ QJsonObject toJson() const;
+
+ void print(QTextStream &s, int indentation = 0) const;
- void print(int indentation = 0) const;
private:
QString mName;
QList<Character> mNpcs;
diff --git a/examples/corelib/serialization/savegame/main.cpp b/examples/corelib/serialization/savegame/main.cpp
index d091684211..3fc0f3af10 100644
--- a/examples/corelib/serialization/savegame/main.cpp
+++ b/examples/corelib/serialization/savegame/main.cpp
@@ -1,79 +1,37 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "game.h"
#include <QCoreApplication>
+#include <QStringList>
+#include <QString>
#include <QTextStream>
-#include "game.h"
+using namespace Qt::StringLiterals; // for _L1
+
//! [0]
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
- QStringList args = QCoreApplication::arguments();
- bool newGame = true;
- if (args.length() > 1)
- newGame = (args[1].toLower() != QStringLiteral("load"));
- bool json = true;
- if (args.length() > 2)
- json = (args[2].toLower() != QStringLiteral("binary"));
+
+ const QStringList args = QCoreApplication::arguments();
+ const bool newGame
+ = args.size() <= 1 || QString::compare(args[1], "load"_L1, Qt::CaseInsensitive) != 0;
+ const bool json
+ = args.size() <= 2 || QString::compare(args[2], "binary"_L1, Qt::CaseInsensitive) != 0;
Game game;
if (newGame)
game.newGame();
else if (!game.loadGame(json ? Game::Json : Game::Binary))
- return 1;
+ return 1;
// Game is played; changes are made...
//! [0]
//! [1]
- QTextStream(stdout) << "Game ended in the following state:\n";
- game.print();
+ QTextStream s(stdout);
+ s << "Game ended in the following state:\n";
+ game.print(s);
if (!game.saveGame(json ? Game::Json : Game::Binary))
return 1;
diff --git a/examples/corelib/serialization/serialization.pro b/examples/corelib/serialization/serialization.pro
index 7651444f19..e20fcb57fd 100644
--- a/examples/corelib/serialization/serialization.pro
+++ b/examples/corelib/serialization/serialization.pro
@@ -3,3 +3,7 @@ SUBDIRS = \
cbordump \
convert \
savegame
+
+qtHaveModule(widgets) {
+ SUBDIRS += streambookmarks
+}
diff --git a/examples/corelib/serialization/streambookmarks/CMakeLists.txt b/examples/corelib/serialization/streambookmarks/CMakeLists.txt
new file mode 100644
index 0000000000..bad55fa661
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/CMakeLists.txt
@@ -0,0 +1,40 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(streambookmarks LANGUAGES CXX)
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
+
+qt_standard_project_setup()
+
+qt_add_executable(streambookmarks
+ main.cpp
+ mainwindow.cpp mainwindow.h
+ xbelreader.cpp xbelreader.h
+ xbelwriter.cpp xbelwriter.h
+)
+
+set_target_properties(streambookmarks PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(streambookmarks PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+)
+
+install(TARGETS streambookmarks
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET streambookmarks
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
+)
+install(SCRIPT ${deploy_script})
diff --git a/examples/corelib/serialization/streambookmarks/doc/images/filemenu.png b/examples/corelib/serialization/streambookmarks/doc/images/filemenu.png
new file mode 100644
index 0000000000..1a92895ccf
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/doc/images/filemenu.png
Binary files differ
diff --git a/examples/corelib/serialization/streambookmarks/doc/images/helpmenu.png b/examples/corelib/serialization/streambookmarks/doc/images/helpmenu.png
new file mode 100644
index 0000000000..baa98bee96
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/doc/images/helpmenu.png
Binary files differ
diff --git a/examples/corelib/serialization/streambookmarks/doc/images/screenshot.png b/examples/corelib/serialization/streambookmarks/doc/images/screenshot.png
new file mode 100644
index 0000000000..422873b6d0
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/doc/images/screenshot.png
Binary files differ
diff --git a/examples/corelib/serialization/streambookmarks/doc/src/qxmlstreambookmarks.qdoc b/examples/corelib/serialization/streambookmarks/doc/src/qxmlstreambookmarks.qdoc
new file mode 100644
index 0000000000..8e32dd8d0b
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/doc/src/qxmlstreambookmarks.qdoc
@@ -0,0 +1,223 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example serialization/streambookmarks
+ \examplecategory {Data Processing & I/O}
+ \meta tag {network}
+ \title QXmlStream Bookmarks Example
+ \brief Demonstrates how to read and write XBEL files.
+ \ingroup xml-examples
+
+ The QXmlStream Bookmarks example provides a viewer for XML Bookmark Exchange
+ Language (XBEL) files. It can read bookmarks using Qt's QXmlStreamReader and
+ write them back out again using QXmlStreamWriter. As this example aims to
+ show how to use these reader and writer types, it provides no means to open
+ a bookmark, add a new one, or merge two bookmark files, and only minimal
+ scope for editing bookmarks. None the less, it could surely be extended with
+ such features, if desired.
+
+ \image screenshot.png
+
+ \section1 XbelWriter Class Definition
+
+ The \c XbelWriter class takes a \l{QTreeWidget}{tree widget} describing a
+ hierarchy of folders containing bookmarks. Its \c writeFile() provides the
+ means to write out this hierarchy, in XBEL format, to a given output device.
+
+ Internally, it records the tree widget it was given and packages a private
+ instance of QXmlStreamWriter, which provides it with the means to stream
+ XML. It has an internal \c writeItem() to write each item in its tree.
+
+ \snippet serialization/streambookmarks/xbelwriter.h 0
+
+ \section1 XbelWriter Class Implementation
+
+ The \c XbelWriter constructor accepts the \a treeWidget it will describe. It
+ stores that and enables \l{QXmlStreamWriter}'s auto-formatting property.
+ This last splits the data into several lines, with indentation to indicate
+ the structure of the tree, which makes the XML output easier to read.
+
+ \snippet serialization/streambookmarks/xbelwriter.cpp 0
+
+ The \c writeFile() function accepts a QIODevice object and directs its
+ QXmlStreamWriter member to write to this device, using \c setDevice(). This
+ function then writes the document type definition(DTD), the start element,
+ the version, and delegates writing of each of the \c{treeWidget}'s top-level
+ items to \c writeItem(). Finally, it closes the document and returns.
+
+ \snippet serialization/streambookmarks/xbelwriter.cpp 1
+
+ The \c writeItem() function accepts a QTreeWidgetItem object and writes to
+ its XML stream a representation of the object, which depends on its \c
+ UserRole, which can be one of a \c{"folder"}, \c{"bookmark"},
+ or \c{"separator"}. Within each folder, it calls itself recursively on each
+ child item, to recursively include a representation of each child within the
+ folder's XML element.
+
+ \snippet serialization/streambookmarks/xbelwriter.cpp 2
+
+ \section1 XbelReader Class Definition
+
+ The \c XbelReader takes a \l{QTreeWidget}{tree widget} to populate with
+ items describing a bookmark hierarchy. It supports reading XBEL data from a
+ QIODevice as a source of these items. If parsing of the XBEL data fails, it
+ can report what went wrong.
+
+ Internally, it records the QTreeWidget that it will populate and packages an
+ instance of QXmlStreamReader, the companion class to QXmlStreamWriter, which
+ it will use to read XBEL data.
+
+ \snippet serialization/streambookmarks/xbelreader.h 0
+
+ \section1 XbelReader Class Implementation
+
+ Since the XBEL reader is only concerned with reading XML elements, it makes
+ extensive use of the \l{QXmlStreamReader::}{readNextStartElement()}
+ convenience function.
+
+ The \c XbelReader constructor requires a QTreeWidget that it will populate.
+ It populates the tree widget's style with suitable icons: a folder icon that
+ changes form to indicate whether each folder as open or closed; and a
+ standard file icon for the individual bookmarks within those folders.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 0
+
+ The \c read() function accepts a QIODevice. It directs its QXmlStreamReader
+ member to read content from that device. Note that the XML input must be
+ well-formed to be accepted by QXmlStreamReader. First it reads the outer
+ structure and verifies the content is an XBEL 1.0 file; if it is, \c read()
+ delegates the actual reading of content to the internal \c readXBEL().
+
+ Otherwise, the \l{QXmlStreamReader::}{raiseError()} function is used to
+ record an error message. The reader itself may also do the same if it
+ encounters errors in the input. When \c read() has finished, it returns
+ true if there were no errors.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 1
+
+ If \c read() returns false, its caller can obtain a description of the
+ error, complete with line and column number within the stream, by calling
+ the \c errorString() function.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 2
+
+ The \c readXBEL() function reads the name of a startElement and calls the
+ appropriate function to read it, depending on whether if its tag name
+ is \c{"folder"}, \c{"bookmark"} or \c{"separator"}. Any other elements
+ encountered are skipped. The function starts with a precondition, verifying
+ that the XML reader has just opened an \c{"xbel"} element.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 3
+
+ The \c readBookmark() function creates a new editable item representing a
+ single bookmark. It records the XML \c{"href"} attribute of the current
+ element as second column text of the item and provisionally sets its first
+ column text to \c{"Unknown title"} before scanning the rest of the element
+ for a title element to over-ride that, skipping any unrecognized child
+ elements.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 5
+
+ The \c readTitle() function reads a bookmark's title and records it as the
+ title (first column text) of the item for which it was called.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 6
+
+ The \c readSeparator() function creates a separator and sets its flags. The
+ separator item's text is set to 30 centered dots. The rest of the element is
+ then skipped using \l{QXmlStreamReader::}{skipCurrentElement()}.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 6
+
+ The \c readFolder() function creates an item and iterates the content of the
+ folder element, adding children to this item to represent the contents of
+ the folder element. The loop over folder content is similar in form to the
+ one in \c readXBEL(), save that it now accepts a title element to set the
+ title of the folder.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 7
+
+ The \c createChildItem() helper function creates a new tree widget item
+ that's either a child of the given item or, if no parent item is given, a
+ direct child of the tree widget. It sets the new item's \c UserRole to the
+ tag name of the current XML element, matching how XbelWriter::writeFile()
+ uses that \c UserRole.
+
+ \snippet serialization/streambookmarks/xbelreader.cpp 8
+
+ \section1 MainWindow Class Definition
+
+ The \c MainWindow class is a subclass of QMainWindow, with a \c File menu
+ and a \c Help menu.
+
+ \snippet serialization/streambookmarks/mainwindow.h 0
+
+ \section1 MainWindow Class Implementation
+
+ The \c MainWindow constructor sets up its QTreeWidget object, \c treeWidget,
+ as its own central widget, with column headings for the title and location
+ of each book-mark. It configures a custom menu that enables the user to
+ perform actions on individual bookmarks within the tree widget.
+
+ It invokes \c createMenus() to set up its own menus and their corresponding
+ actions. It sets its title, announces itself as ready and sets its size to a
+ reasonable proportion of the available screen space.
+
+ \snippet serialization/streambookmarks/mainwindow.cpp 0
+
+ A custom menu, triggered when the user right-clicks on a bookmark, provides
+ for copying the bookmark as a link or directing a desktop browser to open
+ the URL it references. This menu is implemented (when relevant features are
+ enabled) by \c onCustomContextMenuRequested().
+
+ \snippet serialization/streambookmarks/mainwindow.cpp 1
+
+ The \c createMenus() function creates the \c fileMenu and \c helpMenu and
+ adds QAction objects to them, bound variously to the \c open(), \c saveAs()
+ and \c about() functions, along with QWidget::close() and
+ QApplication::aboutQt(). The connections are as shown below:
+
+ \snippet serialization/streambookmarks/mainwindow.cpp 2
+
+ This creates the menu shown in the screenshots below:
+
+ \table
+ \row
+ \li \inlineimage filemenu.png
+ \li \inlineimage helpmenu.png
+ \endtable
+
+ The \c open() function, when triggered, offers the user a file dialog to use
+ to select a bookmarks file. If a file is selected, it is parsed using an \c
+ XBelReader to populate the \c treeWidget with bookmarks. If problems arise
+ with opening or parsing the file, a suitable warning message is displayed to
+ the user, including file name and error message. Otherwise, the bookmarks
+ read from the file are displayed and the window's status bar briefly reports
+ that the file has been loaded.
+
+ \snippet serialization/streambookmarks/mainwindow.cpp 3
+
+ The \c saveAs() function displays a QFileDialog, prompting the user for a \c
+ fileName, to which to save a copy of the bookmarks data. Similar to the \c
+ open() function, this function also displays a warning message if the file
+ cannot be written to.
+
+ \snippet serialization/streambookmarks/mainwindow.cpp 4
+
+ The \c about() function displays a QMessageBox with a brief description of
+ the example, or general information about Qt and the version of it in use.
+
+ \snippet serialization/streambookmarks/mainwindow.cpp 5
+
+ \section1 \c{main()} Function
+
+ The \c main() function instantiates \c MainWindow and invokes the \c show()
+ function to display it, then its \c open(), as this is most likely what the
+ user shall want to do first.
+
+ \snippet serialization/streambookmarks/main.cpp 0
+
+ See the \l{https://pyxml.sourceforge.net/topics/xbel/} {XML Bookmark
+ Exchange Language Resource Page} for more information about XBEL files.
+*/
diff --git a/examples/corelib/serialization/streambookmarks/jennifer.xbel b/examples/corelib/serialization/streambookmarks/jennifer.xbel
new file mode 100644
index 0000000000..d504236830
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/jennifer.xbel
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE xbel>
+<xbel version="1.0">
+ <folder folded="no">
+ <title>Qt Resources</title>
+ <bookmark href="https://www.qt.io/">
+ <title>Qt home page</title>
+ </bookmark>
+ <bookmark href="https://www.qt.io/contact-us/partners">
+ <title>Qt Partners</title>
+ </bookmark>
+ <bookmark href="https://www.qt.io/qt-professional-services">
+ <title>Professional Services</title>
+ </bookmark>
+ <bookmark href="https://doc.qt.io/">
+ <title>Qt Documentation</title>
+ </bookmark>
+ <folder folded="yes">
+ <title>Community Resources</title>
+ <bookmark href="https://contribute.qt-project.org">
+ <title>The Qt Project</title>
+ </bookmark>
+ <bookmark href="https://www.qtcentre.org/content/">
+ <title>Qt Centre</title>
+ </bookmark>
+ <bookmark href="https://forum.qt.io/">
+ <title>Forum.Qt.org</title>
+ </bookmark>
+ <bookmark href="https://digitalfanatics.org/projects/qt_tutorial/">
+ <title>The Independent Qt Tutorial</title>
+ </bookmark>
+ <bookmark href="https://www.qtforum.de/">
+ <title>German Qt Forum</title>
+ </bookmark>
+ <bookmark href="https://www.qt-dev.com/">
+ <title>Korean Qt Community Site</title>
+ </bookmark>
+ <bookmark href="http://www.prog.org.ru/">
+ <title>Russian Qt Forum</title>
+ </bookmark>
+ </folder>
+ </folder>
+ <folder folded="no">
+ <title>Online Dictionaries</title>
+ <bookmark href="https://www.dictionary.com/">
+ <title>Dictionary.com</title>
+ </bookmark>
+ <bookmark href="https://www.merriam-webster.com/">
+ <title>Merriam-Webster Online</title>
+ </bookmark>
+ <bookmark href="https://dictionary.cambridge.org/">
+ <title>Cambridge Dictionaries Online</title>
+ </bookmark>
+ <bookmark href="https://www.onelook.com/">
+ <title>OneLook Dictionary Search</title>
+ </bookmark>
+ <separator/>
+ <bookmark href="https://dict.tu-chemnitz.de/">
+ <title>BEOLINGUS, a service of TU Chemnitz</title>
+ </bookmark>
+ <separator/>
+ <bookmark href="http://atilf.atilf.fr/tlf.htm">
+ <title>Trésor de la Langue Française informatisé</title>
+ </bookmark>
+ <bookmark href="https://www.dictionnaire-academie.fr/">
+ <title>Dictionnaire de l'Académie Française</title>
+ </bookmark>
+ </folder>
+</xbel>
diff --git a/examples/corelib/serialization/streambookmarks/main.cpp b/examples/corelib/serialization/streambookmarks/main.cpp
new file mode 100644
index 0000000000..0fd317de43
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/main.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+
+#include <QApplication>
+
+//! [0]
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow mainWin;
+ mainWin.show();
+ mainWin.open();
+ return app.exec();
+}
+//! [0]
diff --git a/examples/corelib/serialization/streambookmarks/mainwindow.cpp b/examples/corelib/serialization/streambookmarks/mainwindow.cpp
new file mode 100644
index 0000000000..a863f77ab7
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/mainwindow.cpp
@@ -0,0 +1,151 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "mainwindow.h"
+#include "xbelreader.h"
+#include "xbelwriter.h"
+
+#include <QFileDialog>
+#include <QHeaderView>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QStatusBar>
+#include <QTreeWidget>
+
+#include <QAction>
+#if QT_CONFIG(clipboard)
+# include <QClipboard>
+#endif
+#include <QDesktopServices>
+#include <QApplication>
+#include <QScreen>
+
+using namespace Qt::StringLiterals;
+
+//! [0]
+MainWindow::MainWindow() : treeWidget(new QTreeWidget)
+{
+ treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
+ treeWidget->setHeaderLabels(QStringList{tr("Title"), tr("Location")});
+#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
+ treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(treeWidget, &QWidget::customContextMenuRequested,
+ this, &MainWindow::onCustomContextMenuRequested);
+#endif
+ setCentralWidget(treeWidget);
+
+ createMenus();
+
+ statusBar()->showMessage(tr("Ready"));
+
+ setWindowTitle(tr("QXmlStream Bookmarks"));
+ const QSize availableSize = screen()->availableGeometry().size();
+ resize(availableSize.width() / 2, availableSize.height() / 3);
+}
+//! [0]
+
+//! [1]
+#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
+void MainWindow::onCustomContextMenuRequested(const QPoint &pos)
+{
+ const QTreeWidgetItem *item = treeWidget->itemAt(pos);
+ if (!item)
+ return;
+ const QString url = item->text(1);
+ QMenu contextMenu;
+ QAction *copyAction = contextMenu.addAction(tr("Copy Link to Clipboard"));
+ QAction *openAction = contextMenu.addAction(tr("Open"));
+ QAction *action = contextMenu.exec(treeWidget->viewport()->mapToGlobal(pos));
+ if (action == copyAction)
+ QGuiApplication::clipboard()->setText(url);
+ else if (action == openAction)
+ QDesktopServices::openUrl(QUrl(url));
+}
+#endif // QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
+//! [1]
+
+//! [2]
+void MainWindow::createMenus()
+{
+ QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
+ QAction *openAct = fileMenu->addAction(tr("&Open..."), this, &MainWindow::open);
+ openAct->setShortcuts(QKeySequence::Open);
+
+ QAction *saveAsAct = fileMenu->addAction(tr("&Save As..."), this, &MainWindow::saveAs);
+ saveAsAct->setShortcuts(QKeySequence::SaveAs);
+
+ QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close);
+ exitAct->setShortcuts(QKeySequence::Quit);
+
+ menuBar()->addSeparator();
+
+ QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(tr("&About"), this, &MainWindow::about);
+ helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
+}
+//! [2]
+
+//! [3]
+void MainWindow::open()
+{
+ QFileDialog fileDialog(this, tr("Open Bookmark File"), QDir::currentPath());
+ fileDialog.setMimeTypeFilters({"application/x-xbel"_L1});
+ if (fileDialog.exec() != QDialog::Accepted)
+ return;
+
+ treeWidget->clear();
+
+ const QString fileName = fileDialog.selectedFiles().constFirst();
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly | QFile::Text)) {
+ QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
+ tr("Cannot read file %1:\n%2.")
+ .arg(QDir::toNativeSeparators(fileName), file.errorString()));
+ return;
+ }
+
+ XbelReader reader(treeWidget);
+ if (!reader.read(&file)) {
+ QMessageBox::warning(
+ this, tr("QXmlStream Bookmarks"),
+ tr("Parse error in file %1:\n\n%2")
+ .arg(QDir::toNativeSeparators(fileName), reader.errorString()));
+ } else {
+ statusBar()->showMessage(tr("File loaded"), 2000);
+ }
+}
+//! [3]
+
+//! [4]
+void MainWindow::saveAs()
+{
+ QFileDialog fileDialog(this, tr("Save Bookmark File"), QDir::currentPath());
+ fileDialog.setAcceptMode(QFileDialog::AcceptSave);
+ fileDialog.setDefaultSuffix("xbel"_L1);
+ fileDialog.setMimeTypeFilters({"application/x-xbel"_L1});
+ if (fileDialog.exec() != QDialog::Accepted)
+ return;
+
+ const QString fileName = fileDialog.selectedFiles().constFirst();
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Text)) {
+ QMessageBox::warning(this, tr("QXmlStream Bookmarks"),
+ tr("Cannot write file %1:\n%2.")
+ .arg(QDir::toNativeSeparators(fileName), file.errorString()));
+ return;
+ }
+
+ XbelWriter writer(treeWidget);
+ if (writer.writeFile(&file))
+ statusBar()->showMessage(tr("File saved"), 2000);
+}
+//! [4]
+
+//! [5]
+void MainWindow::about()
+{
+ QMessageBox::about(this, tr("About QXmlStream Bookmarks"),
+ tr("The <b>QXmlStream Bookmarks</b> example demonstrates how to use Qt's "
+ "QXmlStream classes to read and write XML documents."));
+}
+//! [5]
diff --git a/examples/corelib/serialization/streambookmarks/mainwindow.h b/examples/corelib/serialization/streambookmarks/mainwindow.h
new file mode 100644
index 0000000000..d9efe6b5a5
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/mainwindow.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidget;
+QT_END_NAMESPACE
+
+//! [0]
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+public slots:
+ void open();
+ void saveAs();
+ void about();
+#if QT_CONFIG(clipboard) && QT_CONFIG(contextmenu)
+ void onCustomContextMenuRequested(const QPoint &pos);
+#endif
+private:
+ void createMenus();
+
+ QTreeWidget *const treeWidget;
+};
+//! [0]
+
+#endif
diff --git a/examples/corelib/serialization/streambookmarks/streambookmarks.pro b/examples/corelib/serialization/streambookmarks/streambookmarks.pro
new file mode 100644
index 0000000000..34d2caae82
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/streambookmarks.pro
@@ -0,0 +1,15 @@
+HEADERS = mainwindow.h \
+ xbelreader.h \
+ xbelwriter.h
+SOURCES = main.cpp \
+ mainwindow.cpp \
+ xbelreader.cpp \
+ xbelwriter.cpp
+QT += widgets
+requires(qtConfig(filedialog))
+
+EXAMPLE_FILES = jennifer.xbel
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/corelib/serialization/streambookmarks
+INSTALLS += target
diff --git a/examples/corelib/serialization/streambookmarks/xbelreader.cpp b/examples/corelib/serialization/streambookmarks/xbelreader.cpp
new file mode 100644
index 0000000000..c622cf6642
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/xbelreader.cpp
@@ -0,0 +1,140 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "xbelreader.h"
+
+#include <QStyle>
+#include <QTreeWidget>
+
+using namespace Qt::StringLiterals;
+
+//! [0]
+XbelReader::XbelReader(QTreeWidget *treeWidget) : treeWidget(treeWidget)
+{
+ QStyle *style = treeWidget->style();
+
+ folderIcon.addPixmap(style->standardPixmap(QStyle::SP_DirClosedIcon), QIcon::Normal,
+ QIcon::Off);
+ folderIcon.addPixmap(style->standardPixmap(QStyle::SP_DirOpenIcon), QIcon::Normal, QIcon::On);
+ bookmarkIcon.addPixmap(style->standardPixmap(QStyle::SP_FileIcon));
+}
+//! [0]
+
+//! [1]
+bool XbelReader::read(QIODevice *device)
+{
+ xml.setDevice(device);
+
+ if (xml.readNextStartElement()) {
+ if (xml.name() == "xbel"_L1 && xml.attributes().value("version"_L1) == "1.0"_L1)
+ readXBEL();
+ else
+ xml.raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
+ }
+
+ return !xml.error();
+}
+//! [1]
+
+//! [2]
+QString XbelReader::errorString() const
+{
+ return QObject::tr("%1\nLine %2, column %3")
+ .arg(xml.errorString())
+ .arg(xml.lineNumber())
+ .arg(xml.columnNumber());
+}
+//! [2]
+
+//! [3]
+void XbelReader::readXBEL()
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "xbel"_L1);
+
+ while (xml.readNextStartElement()) {
+ if (xml.name() == "folder"_L1)
+ readFolder(nullptr);
+ else if (xml.name() == "bookmark"_L1)
+ readBookmark(nullptr);
+ else if (xml.name() == "separator"_L1)
+ readSeparator(nullptr);
+ else
+ xml.skipCurrentElement();
+ }
+}
+//! [3]
+
+//! [4]
+void XbelReader::readBookmark(QTreeWidgetItem *item)
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "bookmark"_L1);
+
+ QTreeWidgetItem *bookmark = createChildItem(item);
+ bookmark->setFlags(bookmark->flags() | Qt::ItemIsEditable);
+ bookmark->setIcon(0, bookmarkIcon);
+ bookmark->setText(0, QObject::tr("Unknown title"));
+ bookmark->setText(1, xml.attributes().value("href"_L1).toString());
+
+ while (xml.readNextStartElement()) {
+ if (xml.name() == "title"_L1)
+ readTitle(bookmark);
+ else
+ xml.skipCurrentElement();
+ }
+}
+//! [4]
+
+//! [5]
+void XbelReader::readTitle(QTreeWidgetItem *item)
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "title"_L1);
+ item->setText(0, xml.readElementText());
+}
+//! [5]
+
+//! [6]
+void XbelReader::readSeparator(QTreeWidgetItem *item)
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "separator"_L1);
+ constexpr char16_t midDot = u'\xB7';
+ static const QString dots(30, midDot);
+
+ QTreeWidgetItem *separator = createChildItem(item);
+ separator->setFlags(item ? item->flags() & ~Qt::ItemIsSelectable : Qt::ItemFlags{});
+ separator->setText(0, dots);
+ xml.skipCurrentElement();
+}
+//! [6]
+
+//! [7]
+void XbelReader::readFolder(QTreeWidgetItem *item)
+{
+ Q_ASSERT(xml.isStartElement() && xml.name() == "folder"_L1);
+
+ QTreeWidgetItem *folder = createChildItem(item);
+ bool folded = xml.attributes().value("folded"_L1) != "no"_L1;
+ folder->setExpanded(!folded);
+
+ while (xml.readNextStartElement()) {
+ if (xml.name() == "title"_L1)
+ readTitle(folder);
+ else if (xml.name() == "folder"_L1)
+ readFolder(folder);
+ else if (xml.name() == "bookmark"_L1)
+ readBookmark(folder);
+ else if (xml.name() == "separator"_L1)
+ readSeparator(folder);
+ else
+ xml.skipCurrentElement();
+ }
+}
+//! [7]
+
+//! [8]
+QTreeWidgetItem *XbelReader::createChildItem(QTreeWidgetItem *item)
+{
+ QTreeWidgetItem *childItem = item ? new QTreeWidgetItem(item) : new QTreeWidgetItem(treeWidget);
+ childItem->setData(0, Qt::UserRole, xml.name().toString());
+ return childItem;
+}
+//! [8]
diff --git a/examples/corelib/serialization/streambookmarks/xbelreader.h b/examples/corelib/serialization/streambookmarks/xbelreader.h
new file mode 100644
index 0000000000..a3fa59d813
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/xbelreader.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef XBELREADER_H
+#define XBELREADER_H
+
+#include <QIcon>
+#include <QXmlStreamReader>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidget;
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+//! [0]
+class XbelReader
+{
+public:
+//! [1]
+ XbelReader(QTreeWidget *treeWidget);
+//! [1]
+
+ bool read(QIODevice *device);
+ QString errorString() const;
+
+private:
+//! [2]
+ void readXBEL();
+ void readTitle(QTreeWidgetItem *item);
+ void readSeparator(QTreeWidgetItem *item);
+ void readFolder(QTreeWidgetItem *item);
+ void readBookmark(QTreeWidgetItem *item);
+
+ QTreeWidgetItem *createChildItem(QTreeWidgetItem *item);
+
+ QXmlStreamReader xml;
+ QTreeWidget *treeWidget;
+//! [2]
+
+ QIcon folderIcon;
+ QIcon bookmarkIcon;
+};
+//! [0]
+
+#endif
diff --git a/examples/corelib/serialization/streambookmarks/xbelwriter.cpp b/examples/corelib/serialization/streambookmarks/xbelwriter.cpp
new file mode 100644
index 0000000000..e50f47a5a5
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/xbelwriter.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include "xbelwriter.h"
+
+#include <QTreeWidget>
+
+using namespace Qt::StringLiterals;
+
+//! [0]
+XbelWriter::XbelWriter(const QTreeWidget *treeWidget) : treeWidget(treeWidget)
+{
+ xml.setAutoFormatting(true);
+}
+//! [0]
+
+//! [1]
+bool XbelWriter::writeFile(QIODevice *device)
+{
+ xml.setDevice(device);
+
+ xml.writeStartDocument();
+ xml.writeDTD("<!DOCTYPE xbel>"_L1);
+ xml.writeStartElement("xbel"_L1);
+ xml.writeAttribute("version"_L1, "1.0"_L1);
+ for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
+ writeItem(treeWidget->topLevelItem(i));
+
+ xml.writeEndDocument();
+ return true;
+}
+//! [1]
+
+//! [2]
+void XbelWriter::writeItem(const QTreeWidgetItem *item)
+{
+ QString tagName = item->data(0, Qt::UserRole).toString();
+ if (tagName == "folder"_L1) {
+ bool folded = !item->isExpanded();
+ xml.writeStartElement(tagName);
+ xml.writeAttribute("folded"_L1, folded ? "yes"_L1 : "no"_L1);
+ xml.writeTextElement("title"_L1, item->text(0));
+ for (int i = 0; i < item->childCount(); ++i)
+ writeItem(item->child(i));
+ xml.writeEndElement();
+ } else if (tagName == "bookmark"_L1) {
+ xml.writeStartElement(tagName);
+ if (!item->text(1).isEmpty())
+ xml.writeAttribute("href"_L1, item->text(1));
+ xml.writeTextElement("title"_L1, item->text(0));
+ xml.writeEndElement();
+ } else if (tagName == "separator"_L1) {
+ xml.writeEmptyElement(tagName);
+ }
+}
+//! [2]
diff --git a/examples/corelib/serialization/streambookmarks/xbelwriter.h b/examples/corelib/serialization/streambookmarks/xbelwriter.h
new file mode 100644
index 0000000000..ec95315c4b
--- /dev/null
+++ b/examples/corelib/serialization/streambookmarks/xbelwriter.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#ifndef XBELWRITER_H
+#define XBELWRITER_H
+
+#include <QXmlStreamWriter>
+
+QT_BEGIN_NAMESPACE
+class QTreeWidget;
+class QTreeWidgetItem;
+QT_END_NAMESPACE
+
+//! [0]
+class XbelWriter
+{
+public:
+ explicit XbelWriter(const QTreeWidget *treeWidget);
+ bool writeFile(QIODevice *device);
+
+private:
+ void writeItem(const QTreeWidgetItem *item);
+ QXmlStreamWriter xml;
+ const QTreeWidget *treeWidget;
+};
+//! [0]
+
+#endif