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.txt39
-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.txt43
-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.txt39
-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.qdoc187
-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, 2276 insertions, 2058 deletions
diff --git a/examples/corelib/serialization/CMakeLists.txt b/examples/corelib/serialization/CMakeLists.txt
index a64b5130d2..e32e4df441 100644
--- a/examples/corelib/serialization/CMakeLists.txt
+++ b/examples/corelib/serialization/CMakeLists.txt
@@ -1,5 +1,11 @@
-# Generated from serialization.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-add_subdirectory(cbordump)
-add_subdirectory(convert)
-add_subdirectory(savegame)
+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 d5795e23d3..b2c3a536e3 100644
--- a/examples/corelib/serialization/cbordump/CMakeLists.txt
+++ b/examples/corelib/serialization/cbordump/CMakeLists.txt
@@ -1,31 +1,34 @@
-# Generated from cbordump.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-cmake_minimum_required(VERSION 3.14)
+cmake_minimum_required(VERSION 3.16)
project(cbordump LANGUAGES CXX)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC 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)
-find_package(Qt6 COMPONENTS Core)
+qt_standard_project_setup()
-add_executable(cbordump
+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 2156867ba0..24ad5bbb6a 100644
--- a/examples/corelib/serialization/convert/CMakeLists.txt
+++ b/examples/corelib/serialization/convert/CMakeLists.txt
@@ -1,38 +1,43 @@
-# Generated from convert.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-cmake_minimum_required(VERSION 3.14)
+cmake_minimum_required(VERSION 3.16)
project(convert LANGUAGES CXX)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC 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)
-find_package(Qt6 COMPONENTS Core)
+qt_standard_project_setup()
-add_executable(convert
+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 80305deb39..14621ccc23 100644
--- a/examples/corelib/serialization/savegame/CMakeLists.txt
+++ b/examples/corelib/serialization/savegame/CMakeLists.txt
@@ -1,34 +1,37 @@
-# Generated from savegame.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-cmake_minimum_required(VERSION 3.14)
+cmake_minimum_required(VERSION 3.16)
project(savegame LANGUAGES CXX)
-set(CMAKE_INCLUDE_CURRENT_DIR ON)
-
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC 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)
-find_package(Qt6 COMPONENTS Core)
+qt_standard_project_setup()
-add_executable(savegame
+qt_add_executable(savegame
character.cpp character.h
game.cpp game.h
level.cpp level.h
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 7f138ff110..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 {https://tools.ietf.org/html/rfc7049} {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,48 +127,66 @@
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,
and \c "save.dat" for CBOR. We print a warning and return \c false if the
file couldn't be opened.
- Since QJsonDocument's \l{QJsonDocument::fromJson()}{fromJson()} and
- \l{QJsonDocument::fromBinaryData()}{fromBinaryData()} functions both take a
- QByteArray, we can read the entire contents of the save file into one,
+ Since \l QJsonDocument::fromJson() and \l QCborValue::fromCbor() both take
+ a QByteArray, we can read the entire contents of the save file into one,
regardless of the save format.
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():
@@ -183,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