Generated reference › API — ICoreEssentials/Serialization
kind: generated#api#icoreessentials-serialization

API — ICoreEssentials/Serialization

The public contract of 11 header(s) under ICoreEssentials/Serialization — 16 class/struct definition(s), 277 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.

ICoreBinaryStream.h#

ICoreEssentials/Serialization/ICoreBinaryStream.h

ICoreBinaryWriter / ICoreBinaryReader -- fixed-width binary records.

The writer appends integers of 8, 16, 32 and 64 bits and IEEE-754 float32 and float64 values in a chosen byte order; the reader takes them back out. They are for file formats: STL, PLY, glTF's .bin, a geometry map.

ICoreBinaryWriter w; // little-endian by default w.writeUInt32(0x49334D50u); w.writeFloat64(0.1); w.writeFloat64Array(points, 3 * count);

ICoreBinaryReader r(w.toByteArray()); std::uint32_t magic = r.readUInt32(); double x = r.readFloat64(); // the same bits that went in

ICoreBinaryWriter#

ICoreBinaryStream.h:52 · class · pImpl · 32 declaration(s)

class ICoreBinaryWriter {
public:
    explicit ICoreBinaryWriter(ICoreByteOrder order = ICoreByteOrder::LittleEndian);
    ~ICoreBinaryWriter();

    ICoreBinaryWriter(const ICoreBinaryWriter&) = delete;
    ICoreBinaryWriter& operator=(const ICoreBinaryWriter&) = delete;
    ICoreBinaryWriter(ICoreBinaryWriter&&) noexcept;
    ICoreBinaryWriter& operator=(ICoreBinaryWriter&&) noexcept;

    // The order of every later write; bytes already written stay as they are.
    void setByteOrder(ICoreByteOrder order) noexcept;
    [[nodiscard]] ICoreByteOrder byteOrder() const noexcept;

    void writeUInt8(std::uint8_t value);
    void writeInt8(std::int8_t value);
    void writeUInt16(std::uint16_t value);
    void writeInt16(std::int16_t value);
    void writeUInt32(std::uint32_t value);
    void writeInt32(std::int32_t value);
    void writeUInt64(std::uint64_t value);
    void writeInt64(std::int64_t value);
    void writeFloat32(float value);
    void writeFloat64(double value);

    // `count` values in a row, the same bytes as `count` single writes.
    void writeUInt16Array(const std::uint16_t* values, std::size_t count);
    void writeUInt32Array(const std::uint32_t* values, std::size_t count);
    void writeUInt64Array(const std::uint64_t* values, std::size_t count);
    void writeFloat32Array(const float* values, std::size_t count);
    void writeFloat64Array(const double* values, std::size_t count);

    // Raw bytes, as they are: byte order does not apply.
    void writeBytes(const void* data, std::size_t size);
    void writeBytes(const ICoreByteArray& data);

    // Overwrites a value already written at `offset`, for a length or a
    // checksum known only after what follows it. Returns false, and changes
    // nothing, when the value would not lie wholly inside what was written.
    [[nodiscard]] bool patchUInt32(std::size_t offset, std::uint32_t value);
    [[nodiscard]] bool patchUInt64(std::size_t offset, std::uint64_t value);

    [[nodiscard]] std::size_t size() const noexcept;
    void reserve(std::size_t size);
    void clear() noexcept;

    // The bytes written so far. constData() is valid until the next write.
    [[nodiscard]] const unsigned char* constData() const noexcept;
    [[nodiscard]] ICoreByteArray toByteArray() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreBinaryReader#

ICoreBinaryStream.h:107 · class · pImpl · 31 declaration(s)

class ICoreBinaryReader {
public:
    // Reads `data`. ICoreByteArray is implicitly shared, so this copies no bytes.
    explicit ICoreBinaryReader(const ICoreByteArray& data,
                               ICoreByteOrder order = ICoreByteOrder::LittleEndian);
    // Reads `size` bytes at `data`, which must stay valid for the reader's life.
    ICoreBinaryReader(const void* data, std::size_t size,
                      ICoreByteOrder order = ICoreByteOrder::LittleEndian);
    ~ICoreBinaryReader();

    ICoreBinaryReader(const ICoreBinaryReader&) = delete;
    ICoreBinaryReader& operator=(const ICoreBinaryReader&) = delete;
    ICoreBinaryReader(ICoreBinaryReader&&) noexcept;
    ICoreBinaryReader& operator=(ICoreBinaryReader&&) noexcept;

    void setByteOrder(ICoreByteOrder order) noexcept;
    [[nodiscard]] ICoreByteOrder byteOrder() const noexcept;

    // False once any read, seek or skip has failed; it never turns true again.
    [[nodiscard]] bool ok() const noexcept;

    [[nodiscard]] std::size_t size() const noexcept;
    [[nodiscard]] std::size_t position() const noexcept;
    [[nodiscard]] std::size_t remaining() const noexcept;
    [[nodiscard]] bool atEnd() const noexcept;

    // Moves to `position` (at most size()) or forward by `count`. Past the end
    // they fail as a read does, and the position does not move.
    bool seek(std::size_t position);
    bool skip(std::size_t count);

    // Each returns the value read, or 0 when it failed (see the header note).
    std::uint8_t readUInt8();
    std::int8_t readInt8();
    std::uint16_t readUInt16();
    std::int16_t readInt16();
    std::uint32_t readUInt32();
    std::int32_t readInt32();
    std::uint64_t readUInt64();
    std::int64_t readInt64();
    float readFloat32();
    double readFloat64();

    // All-or-nothing: true and `count` values in `out`, or false and `out`
    // untouched.
    bool readUInt16Array(std::uint16_t* out, std::size_t count);
    bool readUInt32Array(std::uint32_t* out, std::size_t count);
    bool readUInt64Array(std::uint64_t* out, std::size_t count);
    bool readFloat32Array(float* out, std::size_t count);
    bool readFloat64Array(double* out, std::size_t count);

    // Raw bytes, as they are. The ICoreByteArray form returns an empty array
    // when it fails.
    bool readBytes(void* out, std::size_t size);
    [[nodiscard]] ICoreByteArray readByteArray(std::size_t size);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

File-scope declarations#

// Enumerator values are pinned (Platform SDK ABI rule).
enum class ICoreByteOrder : int {
    LittleEndian = 0,
    BigEndian    = 1,
};

ICoreCompression.h#

ICoreEssentials/Serialization/ICoreCompression.h

ICoreCompression -- deflate and inflate, raw or in zlib or gzip framing.

ICoreByteArray packed = ICoreCompression::compress(bytes, ICoreCompressionFormat::Gzip);

ICoreByteArray back; ICoreCompressionError why; if (!ICoreCompression::decompress(packed, ICoreCompressionFormat::Gzip, back, &why)) { // why says what was wrong; back is empty }

THE THREE FORMATS. RawDeflate is RFC 1951 with nothing around it (what ZIP entries hold). Zlib is RFC 1950: a two-byte header, the deflate stream and an Adler-32 of the data (what PNG and PDF hold). Gzip is RFC 1952: a ten-byte header, the deflate stream, then the CRC-32 and the length of the data (a

ICoreCompression#

ICoreCompression.h:65 · class · 2 declaration(s)

class ICoreCompression {
public:
    ICoreCompression() = delete;

    static constexpr int defaultLevel = 6;
    static constexpr std::size_t unlimited = static_cast<std::size_t>(-1);

    // The compressed bytes. Empty only when the level is outside 0..9 or memory
    // ran out: every valid stream, even of no data, is at least two bytes long.
    [[nodiscard]] static ICoreByteArray compress(const ICoreByteArray& data,
                                                 ICoreCompressionFormat format,
                                                 int level = defaultLevel);
    [[nodiscard]] static ICoreByteArray compress(const void* data, std::size_t size,
                                                 ICoreCompressionFormat format,
                                                 int level = defaultLevel);

    // True with the data in `out`, or false with `out` empty and the reason in
    // `*error` (when it is not null).
    [[nodiscard]] static bool decompress(const ICoreByteArray& data,
                                         ICoreCompressionFormat format,
                                         ICoreByteArray& out,
                                         ICoreCompressionError* error = nullptr,
                                         std::size_t maxSize = unlimited);
    [[nodiscard]] static bool decompress(const void* data, std::size_t size,
                                         ICoreCompressionFormat format,
                                         ICoreByteArray& out,
                                         ICoreCompressionError* error = nullptr,
                                         std::size_t maxSize = unlimited);

    // A short English phrase for the error, for a log line or a message.
    [[nodiscard]] static const char* errorText(ICoreCompressionError error) noexcept;
};
};

File-scope declarations#

// Enumerator values are pinned (Platform SDK ABI rule).
enum class ICoreCompressionFormat : int {
    RawDeflate = 0,
    Zlib       = 1,
    Gzip       = 2,
};

enum class ICoreCompressionError : int {
    None            = 0,
    InvalidArgument = 1,  // a level outside 0..9, or a null pointer with a size
    Truncated       = 2,  // the input ends inside the stream
    Corrupt         = 3,  // not a valid stream: a bad header or bad deflate data
    ChecksumMismatch= 4,  // Adler-32 (zlib), or CRC-32 or length (gzip), disagree
    TrailingData    = 5,  // bytes follow the end of the stream
    TooLarge        = 6,  // the output would pass maxSize
    OutOfMemory     = 7,
};

ICoreCsv.h#

ICoreEssentials/Serialization/ICoreCsv.h

ICoreCsv / ICoreCsvReader -- comma-separated values (RFC 4180).

Reading a whole document:

std::optional<std::vector<ICoreCsv::Row>> rows = ICoreCsv::parse(text);

Reading a large file in chunks, one row at a time:

ICoreCsvReader reader; reader.addData(chunk); // as many times as needed ICoreCsv::Row row; while (reader.readRow(row)) { ... } // rows complete so far reader.finish(); // at end of input while (reader.readRow(row)) { ... } // the last row, if unterminated

ICoreCsv#

ICoreCsv.h:54 · class · 6 declaration(s)

Opened by row PS5.12 of the Platform SDK product plan.

class ICoreCsv {
public:
    ICoreCsv() = delete;

    using Row = std::vector<std::string>;

    [[nodiscard]] static std::optional<std::vector<Row>> parse(std::string_view text);
    [[nodiscard]] static std::optional<std::vector<Row>> parse(std::string_view text, char delimiter);

    // std::nullopt only for a forbidden delimiter.
    [[nodiscard]] static std::optional<std::string> format(const std::vector<Row>& rows);
    [[nodiscard]] static std::optional<std::string> format(const std::vector<Row>& rows, char delimiter);

    // One row, CRLF-terminated.
    [[nodiscard]] static std::optional<std::string> formatRow(const Row& row, char delimiter);
};
};

ICoreCsvReader#

ICoreCsv.h:71 · class · pImpl · 11 declaration(s)

class ICoreCsvReader {
public:
    ICoreCsvReader();
    explicit ICoreCsvReader(char delimiter);
    ~ICoreCsvReader();

    ICoreCsvReader(const ICoreCsvReader&) = delete;
    ICoreCsvReader& operator=(const ICoreCsvReader&) = delete;

    // More input. Ignored after finish() or an error.
    void addData(std::string_view chunk);

    // Declares the end of input, completing an unterminated last row.
    void finish();

    // Moves the next complete row into `row` and returns true, or returns false
    // when no complete row is available yet (or an error stopped reading).
    [[nodiscard]] bool readRow(ICoreCsv::Row& row);

    [[nodiscard]] bool hasError() const noexcept;

    // The 1-based line of the first error, or 0 when there is none.
    [[nodiscard]] std::int64_t errorLine() const noexcept;

    // A sentence describing the first error; empty when there is none.
    [[nodiscard]] std::string errorString() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreJsonArray.h#

ICoreEssentials/Serialization/ICoreJsonArray.h

ICoreJsonArray#

ICoreJsonArray.h:44 · class · pImpl · nested const_iterator · 21 declaration(s)

ICoreJsonArray -- an ordered list of JSON values.

class ICoreJsonArray {
public:
    ICoreJsonArray();
    ~ICoreJsonArray();

    // ⚠ COPY ONLY, AND THE MOVES ARE ABSENT ON PURPOSE. Declaring the copy
    // suppresses the implicit moves, so `ICoreJsonArray b = std::move(a)`
    // copies and leaves `a` intact and usable. A pointer-stealing move would
    // leave `a` holding a null Impl, and every method here dereferences it --
    // where the old std::vector member left a moved-from array EMPTY and
    // perfectly valid. Nothing in the tree moves one of these.
    ICoreJsonArray(const ICoreJsonArray& other);
    ICoreJsonArray& operator=(const ICoreJsonArray& other);

    ICoreJsonArray(std::initializer_list<ICoreJsonValue> values);

    // --- reading ------------------------------------------------------------
    [[nodiscard]] bool isEmpty() const;
    [[nodiscard]] std::ptrdiff_t size() const;
    [[nodiscard]] std::ptrdiff_t count() const;

    // Out of range yields an undefined value, as QJsonArray::at() did rather
    // than reading past the end.
    [[nodiscard]] ICoreJsonValue at(std::ptrdiff_t i) const;
    [[nodiscard]] ICoreJsonValue first() const;
    [[nodiscard]] ICoreJsonValue last() const;
    [[nodiscard]] ICoreJsonValue operator[](std::ptrdiff_t i) const;

    [[nodiscard]] bool contains(const ICoreJsonValue& value) const;

    // --- writing ------------------------------------------------------------
    void append(const ICoreJsonValue& value);
    void removeAt(std::ptrdiff_t i);

    // --- iteration ----------------------------------------------------------
    class const_iterator {
    public:
        // The array pointer and the index, measured on this tree: two 8-byte
        // trivially-copyable members. Pinned by static_asserts in the .cpp, so
        // a change to either is a build error rather than a silent overrun.
        static constexpr std::size_t kStateSize = 16;
        static constexpr std::size_t kStateAlign = 8;

        const_iterator(const ICoreJsonArray* a, std::ptrdiff_t i);

        ICoreJsonValue operator*() const;
        const_iterator& operator++();
        bool operator==(const const_iterator& o) const;
        bool operator!=(const const_iterator& o) const;

    private:
        alignas(kStateAlign) std::byte m_storage[kStateSize];
    };

    [[nodiscard]] const_iterator begin() const;
    [[nodiscard]] const_iterator end() const;
    [[nodiscard]] const_iterator constBegin() const;
    [[nodiscard]] const_iterator constEnd() const;

    bool operator==(const ICoreJsonArray& other) const;
    bool operator!=(const ICoreJsonArray& other) const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreJsonDocument.h#

ICoreEssentials/Serialization/ICoreJsonDocument.h

ICoreJsonParseError#

ICoreJsonDocument.h:54 · class · pImpl · 6 declaration(s)

ICoreJsonDocument (+ ICoreJsonParseError) -- a whole JSON document, and the parser and writer for the family.

class ICoreJsonParseError {
public:
    ICoreJsonParseError();
    ~ICoreJsonParseError();

    // Copy only; see ICoreJsonArray.h on why the moves are not declared.
    ICoreJsonParseError(const ICoreJsonParseError& other);
    ICoreJsonParseError& operator=(const ICoreJsonParseError& other);

    [[nodiscard]] bool hasError() const;
    [[nodiscard]] ICoreString errorString() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreJsonDocument#

ICoreJsonDocument.h:80 · class · pImpl · 15 declaration(s)

class ICoreJsonDocument {
public:
    enum JsonFormat { Indented, Compact };

    ICoreJsonDocument();
    ~ICoreJsonDocument();

    // Copy only; see ICoreJsonArray.h on why the moves are not declared.
    // fromJson() returns a local by value, which C++17 elides.
    ICoreJsonDocument(const ICoreJsonDocument& other);
    ICoreJsonDocument& operator=(const ICoreJsonDocument& other);

    explicit ICoreJsonDocument(const ICoreJsonObject& o);
    explicit ICoreJsonDocument(const ICoreJsonArray& a);

    static ICoreJsonDocument fromJson(const ICoreByteArray& json);
    static ICoreJsonDocument fromJson(const ICoreByteArray& json, ICoreJsonParseError* error);

    [[nodiscard]] ICoreByteArray toJson(JsonFormat format = Indented) const;

    [[nodiscard]] bool isNull() const;
    [[nodiscard]] bool isEmpty() const;
    [[nodiscard]] bool isObject() const;
    [[nodiscard]] bool isArray() const;

    [[nodiscard]] ICoreJsonObject object() const;
    [[nodiscard]] ICoreJsonArray  array() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreJsonObject.h#

ICoreEssentials/Serialization/ICoreJsonObject.h

ICoreJsonObject#

ICoreJsonObject.h:73 · class · pImpl · nested Ref, const_iterator · 22 declaration(s)

ICoreJsonObject -- a JSON object: string keys to values.

class ICoreJsonObject {
public:
    ICoreJsonObject();
    ~ICoreJsonObject();

    // Copy only -- see the note on ICoreJsonArray's: declaring the copy
    // suppresses the implicit moves, and a moved-from object with a null Impl
    // would crash where the old vector member left it empty and valid.
    ICoreJsonObject(const ICoreJsonObject& other);
    ICoreJsonObject& operator=(const ICoreJsonObject& other);

    ICoreJsonObject(std::initializer_list<std::pair<ICoreString, ICoreJsonValue>> entries);

    // --- reading ------------------------------------------------------------
    [[nodiscard]] bool isEmpty() const;
    [[nodiscard]] std::ptrdiff_t size() const;
    [[nodiscard]] std::ptrdiff_t count() const;
    [[nodiscard]] bool contains(const ICoreString& key) const;

    // A missing key yields UNDEFINED, as QJsonObject::value() does. Call sites
    // lean on it: `obj.value(k).toString()` on an absent key gives "" rather
    // than inserting anything.
    [[nodiscard]] ICoreJsonValue value(const ICoreString& key) const;

    [[nodiscard]] ICoreList<ICoreString> keys() const;

    // --- writing ------------------------------------------------------------
    // Replaces an existing key rather than duplicating it, which is also what
    // makes a parsed document's duplicate keys resolve last-wins, as Qt's do.
    void insert(const ICoreString& key, const ICoreJsonValue& value);
    void remove(const ICoreString& key);
    ICoreJsonValue take(const ICoreString& key);

    // --- subscript ----------------------------------------------------------
    class Ref {
    public:
        Ref(ICoreJsonObject* owner, ICoreString key);
        ~Ref();

        // The full set, because a Ref had every one of these implicitly before
        // the unique_ptr member deleted them. It is a proxy call sites build,
        // assign through and drop on the same line, so none of them is hot.
        Ref(const Ref& other);
        Ref& operator=(const Ref& other);

        Ref& operator=(const ICoreJsonValue& value);
        operator ICoreJsonValue() const;

    private:
        class Impl;
        std::unique_ptr<Impl> impl;
    };

    Ref operator[](const ICoreString& key);
    [[nodiscard]] ICoreJsonValue operator[](const ICoreString& key) const;

    // --- iteration ----------------------------------------------------------
    class const_iterator {
    public:
        // The owner pointer and the index, measured on this tree: two 8-byte
        // trivially-copyable members. Pinned by static_asserts in the .cpp, so
        // a change to either is a build error rather than a silent overrun.
        static constexpr std::size_t kStateSize = 16;
        static constexpr std::size_t kStateAlign = 8;

        const_iterator(const ICoreJsonObject* o, std::ptrdiff_t i);

        [[nodiscard]] ICoreString    key() const;
        [[nodiscard]] ICoreJsonValue value() const;

        const_iterator& operator++();
        bool operator==(const const_iterator& o) const;
        bool operator!=(const const_iterator& o) const;

    private:
        alignas(kStateAlign) std::byte m_storage[kStateSize];
    };

    [[nodiscard]] const_iterator begin() const;
    [[nodiscard]] const_iterator end() const;
    [[nodiscard]] const_iterator constBegin() const;
    [[nodiscard]] const_iterator constEnd() const;

    bool operator==(const ICoreJsonObject& other) const;
    bool operator!=(const ICoreJsonObject& other) const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreJsonValue.h#

ICoreEssentials/Serialization/ICoreJsonValue.h

ICoreJsonValue#

ICoreJsonValue.h:71 · class · pImpl · 32 declaration(s)

class ICoreJsonValue {
public:
    // The two JSON "empties". Spelled as an enum so the call site reads
    // ICoreJsonValue::Null exactly as it read QJsonValue::Null.
    enum SpecialValue { Null, Undefined };

    ICoreJsonValue();
    ~ICoreJsonValue();

    ICoreJsonValue(const ICoreJsonValue& other);
    ICoreJsonValue(ICoreJsonValue&& other) noexcept;
    ICoreJsonValue& operator=(const ICoreJsonValue& other);
    ICoreJsonValue& operator=(ICoreJsonValue&& other) noexcept;

    explicit ICoreJsonValue(SpecialValue v);

    ICoreJsonValue(bool b);
    ICoreJsonValue(int n);
    ICoreJsonValue(std::int64_t n);
    ICoreJsonValue(double d);
    ICoreJsonValue(const char* s);
    ICoreJsonValue(const ICoreString& s);
    ICoreJsonValue(const ICoreJsonObject& o);
    ICoreJsonValue(const ICoreJsonArray& a);

    // --- interrogation ------------------------------------------------------
    [[nodiscard]] bool isNull() const;
    [[nodiscard]] bool isUndefined() const;
    [[nodiscard]] bool isBool() const;
    [[nodiscard]] bool isDouble() const;
    [[nodiscard]] bool isString() const;
    [[nodiscard]] bool isObject() const;
    [[nodiscard]] bool isArray() const;

    // --- extraction ---------------------------------------------------------
    [[nodiscard]] ICoreString toString() const;
    [[nodiscard]] ICoreString toString(const ICoreString& defaultValue) const;
    [[nodiscard]] bool toBool(bool defaultValue = false) const;

    // Integral doubles only -- see the coercion note.
    [[nodiscard]] int toInt(int defaultValue = 0) const;
    [[nodiscard]] std::int64_t toInteger(std::int64_t defaultValue = 0) const;
    [[nodiscard]] double toDouble(double defaultValue = 0.0) const;

    [[nodiscard]] ICoreJsonObject toObject() const;
    [[nodiscard]] ICoreJsonArray toArray() const;

    bool operator==(const ICoreJsonValue& other) const;
    bool operator!=(const ICoreJsonValue& other) const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreSettings.h#

ICoreEssentials/Serialization/ICoreSettings.h

ICoreSettings#

ICoreSettings.h:55 · class · pImpl · 16 declaration(s)

ICoreSettings -- a persisted key/value file, in QSettings' INI dialect.

class ICoreSettings {
public:
    explicit ICoreSettings(const ICoreString& path);
    ~ICoreSettings();

    ICoreSettings(const ICoreSettings&) = delete;
    ICoreSettings& operator=(const ICoreSettings&) = delete;

    [[nodiscard]] bool hasError() const;

    [[nodiscard]] bool contains(const ICoreString& key) const;

    [[nodiscard]] ICoreVariant value(const ICoreString& key) const;
    [[nodiscard]] ICoreVariant value(const ICoreString& key,
                                     const ICoreVariant& defaultValue) const;

    void setValue(const ICoreString& key, const ICoreVariant& value);

    void remove(const ICoreString& key);

    // --- groups and arrays --------------------------------------------------
    void beginGroup(const ICoreString& prefix);
    void endGroup();

    int beginReadArray(const ICoreString& prefix);
    void beginWriteArray(const ICoreString& prefix, int size = -1);
    void setArrayIndex(int i);
    void endArray();

    void sync();

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreXmlStreamReader.h#

ICoreEssentials/Serialization/ICoreXmlStreamReader.h

ICoreXmlStreamReader -- a pull parser for XML 1.0 with namespaces.

ICoreXmlStreamReader xml(text); while (xml.readNextStartElement()) { if (xml.name() == "item") { auto id = xml.attribute("id"); std::string label = xml.readElementText(); } else { xml.skipCurrentElement(); } } if (xml.hasError()) { ... xml.errorString(), xml.lineNumber() ... }

readNext() moves to the next token and returns its type. A start tag and an

ICoreXmlAttribute#

ICoreXmlStreamReader.h:52 · struct · 0 declaration(s)

Opened by row PS5.22 of the Platform SDK product plan.

struct ICoreXmlAttribute {
public:
    std::string qualifiedName;
    std::string name;           // local name
    std::string prefix;
    std::string namespaceUri;
    std::string value;          // decoded
};
};

ICoreXmlStreamReader#

ICoreXmlStreamReader.h:60 · class · pImpl · 28 declaration(s)

class ICoreXmlStreamReader {
public:
    enum class Token {
        NoToken               = 0,
        Invalid               = 1,
        StartDocument         = 2,
        EndDocument           = 3,
        StartElement          = 4,
        EndElement            = 5,
        Characters            = 6,
        Comment               = 7,
        ProcessingInstruction = 8,
        DTD                   = 9
    };

    enum class Error {
        NoError                = 0,
        NotWellFormed          = 1,
        PrematureEndOfDocument = 2,
        UnsupportedEncoding    = 3,
        UnexpectedElement      = 4    // readElementText() met a child element
    };

    ICoreXmlStreamReader();
    explicit ICoreXmlStreamReader(std::string_view document);   // complete input
    ~ICoreXmlStreamReader();

    ICoreXmlStreamReader(const ICoreXmlStreamReader&) = delete;
    ICoreXmlStreamReader& operator=(const ICoreXmlStreamReader&) = delete;

    void addData(std::string_view chunk);
    void finish();

    Token readNext();
    [[nodiscard]] Token tokenType() const noexcept;
    [[nodiscard]] bool atEnd() const noexcept;

    // Advances to the next StartElement inside the current element; false at
    // the current element's end (or at an error).
    bool readNextStartElement();

    // At a StartElement: skips to its matching EndElement.
    void skipCurrentElement();

    // At a StartElement: the concatenated text up to the matching EndElement,
    // which becomes the current token. A child element is an error.
    std::string readElementText();

    [[nodiscard]] std::string name() const;
    [[nodiscard]] std::string prefix() const;
    [[nodiscard]] std::string qualifiedName() const;
    [[nodiscard]] std::string namespaceUri() const;

    // Characters, Comment, DTD and the data of a ProcessingInstruction.
    [[nodiscard]] std::string text() const;
    [[nodiscard]] bool isCDATA() const noexcept;
    [[nodiscard]] bool isWhitespace() const noexcept;

    // The target of a ProcessingInstruction.
    [[nodiscard]] std::string processingInstructionTarget() const;

    // The attributes of the current StartElement, xmlns declarations excluded.
    [[nodiscard]] std::vector<ICoreXmlAttribute> attributes() const;
    [[nodiscard]] std::optional<std::string> attribute(std::string_view qualifiedName) const;

    // From the XML declaration, when there is one.
    [[nodiscard]] std::string documentVersion() const;

    [[nodiscard]] bool hasError() const noexcept;
    [[nodiscard]] Error error() const noexcept;
    [[nodiscard]] std::string errorString() const;

    // 1-based position of the current token, or of the error.
    [[nodiscard]] std::int64_t lineNumber() const noexcept;
    [[nodiscard]] std::int64_t columnNumber() const noexcept;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreXmlStreamWriter.h#

ICoreEssentials/Serialization/ICoreXmlStreamWriter.h

ICoreXmlStreamWriter -- builds a well-formed XML 1.0 document.

ICoreXmlStreamWriter xml; xml.setAutoFormatting(true); xml.writeStartDocument(); xml.writeStartElement("library"); xml.writeAttribute("version", "2"); xml.writeTextElement("title", "Fish & Chips"); xml.writeEndDocument(); // closes every open element std::string text = xml.toString();

Text and attribute values are escaped for you: & < > in text, and also " and the line-break and tab characters in attributes (as &#10; &#13; &#9;), so a value reads back exactly as written. writeCDATA() splits a "]]>" in its

ICoreXmlStreamWriter#

ICoreXmlStreamWriter.h:43 · class · pImpl · 23 declaration(s)

Opened by row PS5.22 of the Platform SDK product plan.

class ICoreXmlStreamWriter {
public:
    ICoreXmlStreamWriter();
    ~ICoreXmlStreamWriter();

    ICoreXmlStreamWriter(const ICoreXmlStreamWriter&) = delete;
    ICoreXmlStreamWriter& operator=(const ICoreXmlStreamWriter&) = delete;

    void setAutoFormatting(bool enabled);
    [[nodiscard]] bool autoFormatting() const noexcept;
    void setIndent(int spaces);
    [[nodiscard]] int indent() const noexcept;

    // <?xml version="1.0" encoding="UTF-8"?>
    void writeStartDocument();
    void writeEndDocument();

    void writeStartElement(std::string_view qualifiedName);
    void writeEmptyElement(std::string_view qualifiedName);
    void writeEndElement();
    void writeTextElement(std::string_view qualifiedName, std::string_view text);

    void writeAttribute(std::string_view qualifiedName, std::string_view value);
    void writeNamespace(std::string_view namespaceUri, std::string_view prefix);
    void writeDefaultNamespace(std::string_view namespaceUri);

    void writeCharacters(std::string_view text);
    void writeCDATA(std::string_view text);
    void writeComment(std::string_view text);
    void writeProcessingInstruction(std::string_view target, std::string_view data);

    [[nodiscard]] bool hasError() const noexcept;

    // The document so far.
    [[nodiscard]] std::string toString() const;

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreZipArchive.h#

ICoreEssentials/Serialization/ICoreZipArchive.h

ICoreZipReader / ICoreZipWriter -- ZIP archives, in memory.

ICoreZipWriter w; w.addFile("[Content_Types].xml", types); w.addFile("3D/3dmodel.model", model); ICoreByteArray archive = w.finish();

ICoreZipReader r; if (!r.open(archive)) { ... r.error() ... } for (std::size_t i = 0; i < r.count(); ++i) { r.name(i); r.size(i); } ICoreByteArray model; if (!r.read("3D/3dmodel.model", model)) { ... }

What 3MF (an OPC package) and USDZ need, and what any .zip holds: entries

ICoreZipReader#

ICoreZipArchive.h:78 · class · pImpl · 20 declaration(s)

class ICoreZipReader {
public:
    static constexpr std::uint64_t unlimited = static_cast<std::uint64_t>(-1);

    ICoreZipReader();
    ~ICoreZipReader();

    ICoreZipReader(const ICoreZipReader&) = delete;
    ICoreZipReader& operator=(const ICoreZipReader&) = delete;
    ICoreZipReader(ICoreZipReader&&) noexcept;
    ICoreZipReader& operator=(ICoreZipReader&&) noexcept;

    // Reads the central directory of `archive`, which the reader keeps (the
    // array is implicitly shared, so no bytes are copied). False, and nothing
    // open, when it is not a readable ZIP archive.
    [[nodiscard]] bool open(const ICoreByteArray& archive);
    void close();
    [[nodiscard]] bool isOpen() const noexcept;

    // The last failure of open() or read(); None after a success.
    [[nodiscard]] ICoreZipError error() const noexcept;

    // The entries, in central-directory order. An index out of range answers
    // an empty name, zeros and Other.
    [[nodiscard]] std::size_t count() const noexcept;
    [[nodiscard]] ICoreString name(std::size_t index) const;
    [[nodiscard]] std::uint64_t size(std::size_t index) const noexcept;
    [[nodiscard]] std::uint64_t compressedSize(std::size_t index) const noexcept;
    [[nodiscard]] std::uint32_t crc32(std::size_t index) const noexcept;
    [[nodiscard]] ICoreZipMethod method(std::size_t index) const noexcept;
    [[nodiscard]] bool isDirectory(std::size_t index) const noexcept;
    [[nodiscard]] bool isEncrypted(std::size_t index) const noexcept;
    // Where the entry's data starts, in bytes from the start of the archive
    // (past its local header); 0 when the local header cannot be read.
    [[nodiscard]] std::uint64_t dataOffset(std::size_t index) const noexcept;

    // The index of the first entry named exactly `name`, or -1.
    [[nodiscard]] std::ptrdiff_t indexOf(const ICoreString& name) const;

    // True with the entry's data in `out`, or false with `out` empty and the
    // reason in error().
    [[nodiscard]] bool read(std::size_t index, ICoreByteArray& out,
                            std::uint64_t maxSize = unlimited);
    [[nodiscard]] bool read(const ICoreString& name, ICoreByteArray& out,
                            std::uint64_t maxSize = unlimited);

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

ICoreZipWriter#

ICoreZipArchive.h:129 · class · pImpl · 12 declaration(s)

class ICoreZipWriter {
public:
    ICoreZipWriter();
    ~ICoreZipWriter();

    ICoreZipWriter(const ICoreZipWriter&) = delete;
    ICoreZipWriter& operator=(const ICoreZipWriter&) = delete;
    ICoreZipWriter(ICoreZipWriter&&) noexcept;
    ICoreZipWriter& operator=(ICoreZipWriter&&) noexcept;

    // The time stamp of every entry added after this call, as the ZIP format
    // stores it (MS-DOS form: years 1980..2107, even seconds -- an odd second
    // is written one lower). False, and nothing changed, when out of range.
    [[nodiscard]] bool setModifiedTime(int year, int month, int day,
                                       int hour, int minute, int second);

    // 0 or 1: no alignment. Otherwise a power of two up to 32,768: every entry
    // added after this call has its data start on a multiple of it. False, and
    // nothing changed, for any other value.
    [[nodiscard]] bool setDataAlignment(std::uint32_t alignment);

    // Writes ZIP64 records for every entry and for the end of the archive even
    // when nothing needs them. They are written anyway where the archive needs
    // them; this is for readers that must be shown ZIP64 without 4 GiB of data.
    void setForceZip64(bool force) noexcept;

    // Adds one entry. False, and nothing added, for an invalid or duplicate
    // name, a level outside 0..9, or a writer already finished. Deflated
    // entries are deflated even when that makes them larger.
    [[nodiscard]] bool addFile(const ICoreString& name, const ICoreByteArray& data,
                               ICoreZipMethod method = ICoreZipMethod::Deflated,
                               int level = 6);
    // A directory entry; a trailing '/' is added when `name` has none.
    [[nodiscard]] bool addDirectory(const ICoreString& name);

    [[nodiscard]] std::size_t count() const noexcept;
    [[nodiscard]] ICoreZipError error() const noexcept;

    // Writes the central directory and returns the whole archive. The writer is
    // finished afterwards: every later add fails with NotOpen and finish()
    // returns an empty array.
    [[nodiscard]] ICoreByteArray finish();

private:
    class Impl;                    // the two-line residue; state lives here
    std::unique_ptr<Impl> impl;
};

File-scope declarations#

// Enumerator values are pinned (Platform SDK ABI rule). The two methods carry
// their numbers from the ZIP specification (APPNOTE.TXT 4.4.5).
enum class ICoreZipMethod : int {
    Stored   = 0,
    Deflated = 8,
    Other    = -1,  // the reader's answer for any other method; read() refuses it
};

enum class ICoreZipError : int {
    None              = 0,
    InvalidArgument   = 1,   // a level outside 0..9, an index out of range, a bad alignment
    NotAnArchive      = 2,   // no end-of-central-directory record, or one that cannot describe this data
    Corrupt           = 3,   // a damaged directory, local header or deflate stream
    ChecksumMismatch  = 4,   // the data's CRC-32 or size disagrees with the directory
    UnsupportedMethod = 5,
    Encrypted         = 6,
    NotFound          = 7,   // read(name): no entry has that name
    TooLarge          = 8,   // the entry is larger than maxSize
    InvalidName       = 9,   // empty, absolute, a backslash, a NUL, or over 65,535 bytes
    DuplicateName     = 10,
    NotOpen           = 11,  // the reader holds no archive, or the writer already finished
    OutOfMemory       = 12,
};