// 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}
    \ingroup corelib_examples
    \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 {Terminal output showing JSON conversion of game
           save data with levels, NPCs, and player information}

    \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
*/
