#ifndef E57FORMAT_H_INCLUDED
#define E57FORMAT_H_INCLUDED

/*
 * E57Format.h - public header of E57 API for reading/writing .e57 files.
 *
 * Copyright 2009 - 2010 Kevin Ackley (kackley@gwi.net)
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

//! @file  E57Format.h header file for the E57 API

#include <cfloat>
#include <memory>
#include <vector>

#include "E57Exception.h"

namespace e57 {

using std::int8_t;
using std::uint8_t;
using std::int16_t;
using std::uint16_t;
using std::int32_t;
using std::uint32_t;
using std::int64_t;
using std::uint64_t;

// Shorthand for unicode string
//! @brief UTF-8 encodeded Unicode string
using ustring = std::string;

//! @brief Identifiers for types of E57 elements
enum NodeType
{
    E57_STRUCTURE         = 1,  //!< StructureNode class
    E57_VECTOR            = 2,  //!< VectorNode class
    E57_COMPRESSED_VECTOR = 3,  //!< CompressedVectorNode class
    E57_INTEGER           = 4,  //!< IntegerNode class
    E57_SCALED_INTEGER    = 5,  //!< ScaledIntegerNode class
    E57_FLOAT             = 6,  //!< FloatNode class
    E57_STRING            = 7,  //!< StringNode class
    E57_BLOB              = 8   //!< BlobNode class
};

//! @brief The IEEE floating point number precisions supported
enum FloatPrecision
{
    E57_SINGLE = 1,  //!< 32 bit IEEE floating point number format
    E57_DOUBLE = 2   //!< 64 bit IEEE floating point number format
};

//! @brief Identifies the representations of memory elements API can transfer data to/from
enum MemoryRepresentation
{
    E57_INT8     = 1,  //!< 8 bit signed integer
    E57_UINT8    = 2,  //!< 8 bit unsigned integer
    E57_INT16    = 3,  //!< 16 bit signed integer
    E57_UINT16   = 4,  //!< 16 bit unsigned integer
    E57_INT32    = 5,  //!< 32 bit signed integer
    E57_UINT32   = 6,  //!< 32 bit unsigned integer
    E57_INT64    = 7,  //!< 64 bit signed integer
    E57_BOOL     = 8,  //!< C++ boolean type
    E57_REAL32   = 9,  //!< C++ float type
    E57_REAL64   = 10, //!< C++ double type
    E57_USTRING  = 11  //!< Unicode UTF-8 std::string
};

//! @brief Specifies the percentage of checksums which are verified when reading an ImageFile (0-100%).
using ReadChecksumPolicy = int;

const ReadChecksumPolicy CHECKSUM_POLICY_NONE = 0;    //! Do not verify the checksums. (fast)
const ReadChecksumPolicy CHECKSUM_POLICY_SPARSE = 25; //! Only verify 25% of the checksums. The last block is always verified.
const ReadChecksumPolicy CHECKSUM_POLICY_HALF = 50;   //! Only verify 50% of the checksums. The last block is always verified.
const ReadChecksumPolicy CHECKSUM_POLICY_ALL = 100;   //! Verify all checksums. This is the default. (slow)

//! @brief The major version number of the Foundation API
const int E57_FOUNDATION_API_MAJOR = 0;

//! @brief The minor version number of the Foundation API
const int E57_FOUNDATION_API_MINOR = 51;

//! @brief The URI of ASTM E57 v1.0 standard XML namespace
// Used to identify the standard field names and the grammar that relates them.
// Will typically be associated with the default namespace in an E57 file.
#define E57_V1_0_URI "http://www.astm.org/COMMIT/E57/2010-e57-v1.0"

//! @cond documentNonPublic   The following aren't documented
// Minimum and maximum values for integers
const int8_t   E57_INT8_MIN   = -128;
const int8_t   E57_INT8_MAX   = 127;
const int16_t  E57_INT16_MIN  = -32768;
const int16_t  E57_INT16_MAX  = 32767;
const int32_t  E57_INT32_MIN  = -2147483647 - 1;
const int32_t  E57_INT32_MAX  = 2147483647;
const int64_t  E57_INT64_MIN  = -9223372036854775807LL - 1;
const int64_t  E57_INT64_MAX  = 9223372036854775807LL;
const uint8_t  E57_UINT8_MIN  = 0U;
const uint8_t  E57_UINT8_MAX  = 0xffU; /* 255U */
const uint16_t E57_UINT16_MIN = 0U;
const uint16_t E57_UINT16_MAX = 0xffffU; /* 65535U */
const uint32_t E57_UINT32_MIN = 0U;
const uint32_t E57_UINT32_MAX = 0xffffffffU;  /* 4294967295U */
const uint64_t E57_UINT64_MIN = 0ULL;
const uint64_t E57_UINT64_MAX = 0xffffffffffffffffULL; /* 18446744073709551615ULL */

const float  E57_FLOAT_MIN  = -FLT_MAX;
const float  E57_FLOAT_MAX  = FLT_MAX;
const double E57_DOUBLE_MIN = -DBL_MAX;
const double E57_DOUBLE_MAX = DBL_MAX;
//! @endcond

//! @cond documentNonPublic   The following isn't part of the API, and isn't documented.
// Internal implementation files should include E57FormatImpl.h first which defines symbol E57_INTERNAL_IMPLEMENTATION_ENABLE.
// Normal API users should not define this symbol.
// Basically the internal version allows access to the pointer to the implementation (impl_)
#ifdef E57_INTERNAL_IMPLEMENTATION_ENABLE
#  define E57_OBJECT_IMPLEMENTATION(T)                              \
public:                                                             \
    std::shared_ptr<T##Impl> impl() const {return(impl_);};       \
protected:                                                          \
    std::shared_ptr<T##Impl> impl_;
#else
#  define E57_OBJECT_IMPLEMENTATION(T)                              \
protected:                                                          \
    std::shared_ptr<T##Impl> impl_;
#endif
//! @endcond

class BlobNode;
class BlobNodeImpl;
class CompressedVectorNode;
class CompressedVectorNodeImpl;
class CompressedVectorReader;
class CompressedVectorReaderImpl;
class CompressedVectorWriter;
class CompressedVectorWriterImpl;
class FloatNode;
class FloatNodeImpl;
class ImageFile;
class ImageFileImpl;
class IntegerNode;
class IntegerNodeImpl;
class Node;
class NodeImpl;
class ScaledIntegerNode;
class ScaledIntegerNodeImpl;
class SourceDestBuffer;
class SourceDestBufferImpl;
class StringNode;
class StringNodeImpl;
class StructureNode;
class StructureNodeImpl;
class VectorNode;
class VectorNodeImpl;

class Node
{
public:
    Node() = delete;

    NodeType    type() const;
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doDowncast=true);
    bool        operator==(Node n2) const;
    bool        operator!=(Node n2) const;

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
#ifdef E57_INTERNAL_IMPLEMENTATION_ENABLE
    explicit    Node(std::shared_ptr<NodeImpl>);  // internal use only
#endif

private:
    friend class NodeImpl;

    E57_OBJECT_IMPLEMENTATION(Node)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class StructureNode
{
public:
    StructureNode() = delete;
    StructureNode(ImageFile destImageFile);

    int64_t     childCount() const;
    bool        isDefined(const ustring& pathName) const;
    Node        get(int64_t index) const;
    Node        get(const ustring& pathName) const;
    void        set(const ustring& pathName, const Node &n);

    // Up/Down cast conversion
                operator Node() const;
    explicit    StructureNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class ImageFile;

                StructureNode(std::shared_ptr<StructureNodeImpl> ni);    // internal use only
                StructureNode(std::weak_ptr<ImageFileImpl> fileParent);  // internal use only

    E57_OBJECT_IMPLEMENTATION(StructureNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};


class VectorNode
{
public:
    VectorNode() = delete;
    explicit    VectorNode(ImageFile destImageFile, bool allowHeteroChildren = false);

    bool        allowHeteroChildren() const;

    int64_t     childCount() const;
    bool        isDefined(const ustring& pathName) const;
    Node        get(int64_t index) const;
    Node        get(const ustring& pathName) const;
    void        append(Node n);

    // Up/Down cast conversion
                operator Node() const;
    explicit    VectorNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class CompressedVectorNode;

                VectorNode(std::shared_ptr<VectorNodeImpl> ni);  // internal use only

    E57_OBJECT_IMPLEMENTATION(VectorNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class SourceDestBuffer
{
public:
    SourceDestBuffer() = delete;
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, int8_t* b,   const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(int8_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, uint8_t* b,  const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(uint8_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, int16_t* b,  const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(int16_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, uint16_t* b, const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(uint16_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, int32_t* b,  const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(int32_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, uint32_t* b, const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(uint32_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, int64_t* b,  const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(int64_t));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, bool* b,     const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(bool));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, float* b,    const size_t  capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(float));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, double* b,   const size_t capacity,
                     bool doConversion = false, bool doScaling = false, size_t stride = sizeof(double));
    SourceDestBuffer(ImageFile destImageFile, const ustring &pathName, std::vector<ustring>* b);

    ustring         pathName() const;
    enum MemoryRepresentation  memoryRepresentation() const;
    size_t          capacity() const;
    bool            doConversion() const;
    bool            doScaling() const;
    size_t          stride() const;

    // Diagnostic functions:
    void            dump(int indent = 0, std::ostream& os = std::cout) const;
    void            checkInvariant(bool doRecurse = true) const;

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    E57_OBJECT_IMPLEMENTATION(SourceDestBuffer)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class CompressedVectorReader
{
public:
    CompressedVectorReader() = delete;

    unsigned    read();
    unsigned    read(std::vector<SourceDestBuffer>& dbufs);
    void        seek(int64_t recordNumber); // !!! not implemented yet
    void        close();
    bool        isOpen();
    CompressedVectorNode compressedVectorNode() const;

    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class CompressedVectorNode;

                CompressedVectorReader(std::shared_ptr<CompressedVectorReaderImpl> ni);

    E57_OBJECT_IMPLEMENTATION(CompressedVectorReader)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class CompressedVectorWriter
{
public:
    CompressedVectorWriter() = delete;

    void        write(const size_t recordCount);
    void        write(std::vector<SourceDestBuffer>& sbufs, const size_t recordCount);
    void        close();
    bool        isOpen();
    CompressedVectorNode compressedVectorNode() const;

    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class CompressedVectorNode;

                CompressedVectorWriter(std::shared_ptr<CompressedVectorWriterImpl> ni);

    E57_OBJECT_IMPLEMENTATION(CompressedVectorWriter)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class CompressedVectorNode
{
public:
    CompressedVectorNode() = delete;
    explicit CompressedVectorNode(ImageFile destImageFile, const Node &prototype, const VectorNode &codecs);

    int64_t     childCount() const;
    Node        prototype() const;
    VectorNode  codecs() const;

    // Iterators
    CompressedVectorWriter writer(std::vector<SourceDestBuffer>& sbufs);
    CompressedVectorReader reader(const std::vector<SourceDestBuffer>& dbufs);

    // Up/Down cast conversion
                operator Node() const;
    explicit    CompressedVectorNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class CompressedVectorReader;
    friend class CompressedVectorWriter;
    friend class E57XmlParser;

                CompressedVectorNode(std::shared_ptr<CompressedVectorNodeImpl> ni);  // internal use only

    E57_OBJECT_IMPLEMENTATION(CompressedVectorNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class IntegerNode
{
public:
    IntegerNode() = delete;
    explicit IntegerNode(ImageFile destImageFile, int64_t value = 0, int64_t minimum = E57_INT64_MIN, int64_t maximum = E57_INT64_MAX);

    int64_t     value() const;
    int64_t     minimum() const;
    int64_t     maximum() const;

    // Up/Down cast conversion
                operator Node() const;
    explicit    IntegerNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
                IntegerNode(std::shared_ptr<IntegerNodeImpl> ni);  // internal use only

    E57_OBJECT_IMPLEMENTATION(IntegerNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class ScaledIntegerNode
{
public:
    ScaledIntegerNode() = delete;
    explicit ScaledIntegerNode(ImageFile destImageFile, int64_t rawValue, int64_t minimum, int64_t maximum,
                               double scale = 1.0, double offset = 0.0);
    explicit ScaledIntegerNode(ImageFile destImageFile, int rawValue, int64_t minimum, int64_t maximum,
                               double scale = 1.0, double offset = 0.0);
    explicit ScaledIntegerNode(ImageFile destImageFile, int rawValue, int minimum, int maximum,
                               double scale = 1.0, double offset = 0.0);
    explicit ScaledIntegerNode(ImageFile destImageFile, double scaledValue, double scaledMinimum, double scaledMaximum,
                               double scale = 1.0, double offset = 0.0);

    int64_t     rawValue() const;
    double      scaledValue() const;
    int64_t     minimum() const;
    double      scaledMinimum() const;
    int64_t     maximum() const;
    double      scaledMaximum() const;
    double      scale() const;
    double      offset() const;

    // Up/Down cast conversion
                operator Node() const;
    explicit    ScaledIntegerNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
                ScaledIntegerNode(std::shared_ptr<ScaledIntegerNodeImpl> ni);  // internal use only

    E57_OBJECT_IMPLEMENTATION(ScaledIntegerNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class FloatNode
{
public:
    FloatNode() = delete;
    explicit FloatNode(ImageFile destImageFile, double value = 0.0, FloatPrecision precision = E57_DOUBLE,
                       double minimum = E57_DOUBLE_MIN, double  maximum = E57_DOUBLE_MAX);

    double      value() const;
    FloatPrecision precision() const;
    double      minimum() const;
    double      maximum() const;

    // Up/Down cast conversion
                operator Node() const;
    explicit    FloatNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
                FloatNode(std::shared_ptr<FloatNodeImpl> ni);  // internal use only

    E57_OBJECT_IMPLEMENTATION(FloatNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class StringNode
{
public:
    StringNode() = delete;
    explicit StringNode(ImageFile destImageFile, const ustring &value = "");

    ustring     value() const;

    // Up/Down cast conversion
                operator Node() const;
    explicit    StringNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class StringNodeImpl;
                StringNode(std::shared_ptr<StringNodeImpl> ni);  // internal use only

    E57_OBJECT_IMPLEMENTATION(StringNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class BlobNode
{
public:
    BlobNode() = delete;
    explicit BlobNode(ImageFile destImageFile, int64_t byteCount);

    int64_t     byteCount() const;
    void        read(uint8_t* buf,  int64_t start, size_t count);
    void        write(uint8_t* buf, int64_t start, size_t count);

    // Up/Down cast conversion
                operator Node() const;
    explicit    BlobNode(const Node& n);

    // Common generic Node functions
    bool        isRoot() const;
    Node        parent() const;
    ustring     pathName() const;
    ustring     elementName() const;
    ImageFile   destImageFile() const;
    bool        isAttached() const;

    // Diagnostic functions:
    void        dump(int indent = 0, std::ostream& os = std::cout) const;
    void        checkInvariant(bool doRecurse = true, bool doUpcast=true);

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
    friend class E57XmlParser;

                BlobNode(std::shared_ptr<BlobNodeImpl> ni);       // internal use only

                // Internal use only, create blob already in a file
                BlobNode(ImageFile destImageFile, int64_t fileOffset, int64_t length);

    E57_OBJECT_IMPLEMENTATION(BlobNode)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

class ImageFile
{
public:
    ImageFile() = delete;
    ImageFile(const ustring& fname, const ustring& mode, ReadChecksumPolicy checksumPolicy = CHECKSUM_POLICY_ALL );

    StructureNode   root() const;
    void            close();
    void            cancel();
    bool            isOpen() const;
    bool            isWritable() const;
    ustring         fileName() const;
    int             writerCount() const;
    int             readerCount() const;

    // Manipulate registered extensions in the file
    void            extensionsAdd(const ustring& prefix, const ustring& uri);
    bool            extensionsLookupPrefix(const ustring& prefix, ustring& uri) const;
    bool            extensionsLookupUri(const ustring& uri, ustring& prefix) const;
    size_t          extensionsCount() const;
    ustring         extensionsPrefix(const size_t index) const;
    ustring         extensionsUri(const size_t index) const;

    // Field name functions:
    bool            isElementNameExtended(const ustring& elementName) const;
    void            elementNameParse(const ustring& elementName, ustring& prefix, ustring& localPart) const;

    // Diagnostic functions:
    void            dump(int indent = 0, std::ostream& os = std::cout) const;
    void            checkInvariant(bool doRecurse = true) const;
    bool            operator==(ImageFile imf2) const;
    bool            operator!=(ImageFile imf2) const;

//! \cond documentNonPublic   The following isn't part of the API, and isn't documented.
private:
                    ImageFile(double);           // Give a second dummy constructor, better error msg for: ImageFile(0)

    friend class Node;
    friend class StructureNode;
    friend class VectorNode;
    friend class CompressedVectorNode;
    friend class IntegerNode;
    friend class ScaledIntegerNode;
    friend class FloatNode;
    friend class StringNode;
    friend class BlobNode;

                    ImageFile(std::shared_ptr<ImageFileImpl> imfi);  // internal use only

    E57_OBJECT_IMPLEMENTATION(ImageFile)  // Internal implementation details, not part of API, must be last in object
//! \endcond
};

} // end namespace e57

#endif // E57FORMAT_H_INCLUDED
