diff options
Diffstat (limited to 'examples/corelib/serialization/cbordump')
-rw-r--r-- | examples/corelib/serialization/cbordump/CMakeLists.txt | 21 | ||||
-rwxr-xr-x | examples/corelib/serialization/cbordump/cbortag.py | 188 | ||||
-rw-r--r-- | examples/corelib/serialization/cbordump/doc/images/cbordump.png | bin | 48004 -> 9556 bytes | |||
-rw-r--r-- | examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc | 2 | ||||
-rw-r--r-- | examples/corelib/serialization/cbordump/main.cpp | 222 | ||||
-rw-r--r-- | examples/corelib/serialization/cbordump/tag-transform.xslt | 25 |
6 files changed, 339 insertions, 119 deletions
diff --git a/examples/corelib/serialization/cbordump/CMakeLists.txt b/examples/corelib/serialization/cbordump/CMakeLists.txt index 813b02b9c0..b2c3a536e3 100644 --- a/examples/corelib/serialization/cbordump/CMakeLists.txt +++ b/examples/corelib/serialization/cbordump/CMakeLists.txt @@ -1,15 +1,13 @@ # Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause cmake_minimum_required(VERSION 3.16) project(cbordump LANGUAGES CXX) -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") +if (ANDROID) + message(FATAL_ERROR "This project cannot be built on Android.") endif() -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/corelib/serialization/cbordump") - find_package(Qt6 REQUIRED COMPONENTS Core) qt_standard_project_setup() @@ -23,7 +21,14 @@ target_link_libraries(cbordump PRIVATE ) 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 Binary files differindex 72232c1a95..d5ff1da0bf 100644 --- a/examples/corelib/serialization/cbordump/doc/images/cbordump.png +++ b/examples/corelib/serialization/cbordump/doc/images/cbordump.png diff --git a/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc b/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc index af7ffb7149..a4dc01116f 100644 --- a/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc +++ b/examples/corelib/serialization/cbordump/doc/src/cbordump.qdoc @@ -3,6 +3,8 @@ /*! \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. diff --git a/examples/corelib/serialization/cbordump/main.cpp b/examples/corelib/serialization/cbordump/main.cpp index a53bbdebda..03c940452e 100644 --- a/examples/corelib/serialization/cbordump/main.cpp +++ b/examples/corelib/serialization/cbordump/main.cpp @@ -14,87 +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_); @@ -131,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)); @@ -179,7 +228,8 @@ 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 @@ -200,31 +250,32 @@ template <typename T> static inline bool canConvertTo(double v) 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()) { @@ -264,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(); @@ -273,7 +324,7 @@ void CborDumper::dumpOne(int nestingLevel) printStringWidthIndicator(r.data.toUtf8().size()); r = reader.readString(); - comma = QLatin1Char(',') + indented; + comma = u',' + indented; } } @@ -329,7 +380,7 @@ void CborDumper::dumpOne(int nestingLevel) if (reader.next()) { printWidthIndicator(quint64(tag)); printf("("); - dumpOne(nestingLevel); // same level! + dumpOne(nestingLevel); // same level! printf(")"); } @@ -361,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: @@ -394,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) @@ -422,13 +473,13 @@ 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 "); @@ -437,7 +488,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel) qsizetype size = reader.currentStringChunkSize(); if (size < 0) - return; // error + return; // error if (size >= ChunkSizeLimit) { fprintf(stderr, "String length too big, %lli\n", qint64(size)); exit(EXIT_FAILURE); @@ -482,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) @@ -494,7 +545,7 @@ void CborDumper::dumpOneDetailed(int nestingLevel) // get the next chunk size = reader.currentStringChunkSize(); if (size < 0) - return; // error + return; // error if (size >= ChunkSizeLimit) { fprintf(stderr, "String length too big, %lli\n", qint64(size)); exit(EXIT_FAILURE); @@ -633,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; } } @@ -674,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); 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> |