init
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
PROJECT(openvibe-module-ebml)
|
||||
|
||||
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
|
||||
SET(PROJECT_VERSION_MINOR ${OV_GLOBAL_VERSION_MINOR})
|
||||
SET(PROJECT_VERSION_PATCH ${OV_GLOBAL_VERSION_PATCH})
|
||||
SET(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
|
||||
|
||||
FILE(GLOB_RECURSE SRC_FILES src/*.cpp src/*.h src/*.hpp src/*.inl include/*.h)
|
||||
INCLUDE_DIRECTORIES(include)
|
||||
INCLUDE("FindSourceRCProperties")
|
||||
|
||||
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
|
||||
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${MODULES_FOLDER}
|
||||
COMPILE_FLAGS "-DEBML_Shared -DEBML_Exports")
|
||||
|
||||
ADD_LIBRARY(${PROJECT_NAME}-static STATIC ${SRC_FILES})
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
FOLDER ${MODULES_FOLDER}
|
||||
COMPILE_FLAGS "-DEBML_Static -DEBML_Exports")
|
||||
|
||||
IF(UNIX)
|
||||
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES COMPILE_FLAGS "-fPIC")
|
||||
ENDIF(UNIX)
|
||||
|
||||
INCLUDE("FindOpenViBECommon")
|
||||
|
||||
# ---------------------------------
|
||||
# Target macros
|
||||
# Defines target operating system, architecture and compiler
|
||||
# ---------------------------------
|
||||
SET_BUILD_PLATFORM()
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# Install files
|
||||
# -----------------------------
|
||||
INSTALL(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
INSTALL(TARGETS ${PROJECT_NAME}-static
|
||||
RUNTIME DESTINATION ${DIST_BINDIR}
|
||||
LIBRARY DESTINATION ${DIST_LIBDIR}
|
||||
ARCHIVE DESTINATION ${DIST_LIBDIR})
|
||||
INSTALL(DIRECTORY include/ DESTINATION ${DIST_INCLUDEDIR} FILES_MATCHING PATTERN "*.h")
|
||||
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* \page Doc_FormatingEBMLStreams Formating EBML streams
|
||||
*
|
||||
* \section Doc_FormatingEBMLStreams_Introduction Introduction
|
||||
*
|
||||
* This page tries to teach how a user of this library should use
|
||||
* the writing functions in order to build and format an EBML
|
||||
* stream correctly. For those who don't know what EBML is,
|
||||
* it is basically a binary XML created and used by the matroska
|
||||
* developpers. The libmatroska is based on the libebml
|
||||
* implementation of these guys. Fore more details, please read
|
||||
* the \ref Doc_WhatIsEBML page first and eventually visit the
|
||||
* EBML web page at http://ebml.sourceforge.net/
|
||||
*
|
||||
* \section Doc_FormatingEBMLStreams_Concept Concepts
|
||||
*
|
||||
* The idea of this formating library is to transform the data
|
||||
* provided by the user application into EBML buffers. Those EBML
|
||||
* buffers are then given to a user callback object which know
|
||||
* what to do with the computed data (maybe write it to a file,
|
||||
* send it on a socket, log it in a console, whatever...)
|
||||
*
|
||||
* The library is divided into three main components :
|
||||
* - The writer itself that does the formating stuff
|
||||
* - An implementation of the callback object (the implementation
|
||||
* is left to the user application developper)
|
||||
* - An optionnal helper object that knows more on the
|
||||
* content of the EBML stream.
|
||||
*
|
||||
* Here comes the organisation of the different modules and how
|
||||
* data go from one to another. Note that the user application
|
||||
* and the user callback object may share some information so the
|
||||
* callback object communicates with the application itself.
|
||||
*
|
||||
* \image html ebml_formating_concept.png "Concept"
|
||||
*
|
||||
* Here comes the UML class diagram, presenting the main classes
|
||||
* involved in the presented behavior.
|
||||
*
|
||||
* \image html ebml_formating_class.png "Class Diagram"
|
||||
*
|
||||
* See EBML::IWriter, EBML::IWriterCallback and EBML::IWriterHelper
|
||||
* for more details on each of these classes.
|
||||
*
|
||||
* \section Doc_FormatingEBMLStreams_SampleCode Sample code
|
||||
*
|
||||
* In this section, a sample of user application code is presented
|
||||
* that opens several child nodes and dumps the created stream
|
||||
* into a file for later use. This file can be parsed using
|
||||
* the sample code of the page named \ref Doc_ParsingEBMLStreams
|
||||
*
|
||||
* The callback object implementation looks something like this :
|
||||
*
|
||||
* \code
|
||||
* class CWriterCallback : public EBML::IWriterCallback
|
||||
* {
|
||||
* public:
|
||||
* CWriterCallback(char* filename) { m_file=fopen(filename, "wb"); }
|
||||
* virtual ~CWriterCallback() { if(m_file) fclose(m_file); }
|
||||
* virtual void write(const void* buffer, const size_t size) { if(m_file) fwrite(buffer, size, 1, m_file); }
|
||||
* FILE* m_file;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* Then in the user application code, we can write the
|
||||
* initialisation this way :
|
||||
*
|
||||
* \code
|
||||
* CWriterCallback oCallback("test.ebml");
|
||||
* EBML::IWriter* pWriter=EBML::createWriter(oCallback);
|
||||
* EBML::IWriterHelper* pWriterHelper=EBML::createWriterHelper();
|
||||
* pWriterHelper->connect(pWriter);
|
||||
* \endcode
|
||||
*
|
||||
* The use of the EBML writer looks something like this :
|
||||
*
|
||||
* \code
|
||||
* pWriterHelper->openChild(EBML_Identifier_Header);
|
||||
* pWriterHelper->openChild(EBML_Identifier_DocType);
|
||||
* pWriterHelper->setStr("EBML basic sample");
|
||||
* pWriterHelper->closeChild();
|
||||
* pWriterHelper->openChild(EBML_Identifier_DocTypeVersion);
|
||||
* pWriterHelper->setUInt(1);
|
||||
* pWriterHelper->closeChild();
|
||||
* pWriterHelper->closeChild();
|
||||
* \endcode
|
||||
*
|
||||
* Finally, we have to release the objects and to clean memory :
|
||||
*
|
||||
* \code
|
||||
* pWriterHelper->disconnect();
|
||||
* pWriterHelper->release();
|
||||
* pWriter->release();
|
||||
* \endcode
|
||||
*/
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* \page Doc_ParsingEBMLStreams Parsing EBML streams
|
||||
*
|
||||
* \section Doc_ParsingEBMLStreams_Introduction Introduction
|
||||
*
|
||||
* This page tries to teach how a user of this library should use
|
||||
* the reading functions in order to read and parse an EBML
|
||||
* stream correctly. For those who don't know what EBML is,
|
||||
* it is basically a binary XML created and used by the matroska
|
||||
* developpers. The libmatroska is based on the libebml
|
||||
* implementation of these guys. Fore more details, please read
|
||||
* the \ref Doc_WhatIsEBML page first and eventually visit the
|
||||
* EBML web page at http://ebml.sourceforge.net/
|
||||
*
|
||||
* \section Doc_ParsingEBMLStreams_Concept Concepts
|
||||
*
|
||||
* The idea of this parsing library is to transform the stream
|
||||
* data provided by the user application into understandable
|
||||
* EBML interpreted commands. Once the EBML nodes are found and
|
||||
* parsed, they are sent to a callback object that should know
|
||||
* what to do with them.
|
||||
*
|
||||
* The design of the parsing interface is closed to the one of
|
||||
* \c eXpat, an XML parser library (see http://expat.sourceforge.net
|
||||
* for more details on \c eXpat). Using such interface allows light
|
||||
* code and on-the-fly parsing, that means the parser does not
|
||||
* need to have all the data ready before starting the parsing
|
||||
* process... The data can arrive while the parsing is beeing
|
||||
* done.
|
||||
*
|
||||
* It is the responsability of the user application to read
|
||||
* the EBML stream from a file, a socket, a user input or
|
||||
* whatever, and then to send this to the parser...
|
||||
*
|
||||
* At least, the callback object may use a reader helper that
|
||||
* knows how to read standard EBML types such as integers,
|
||||
* floats, strings etc...
|
||||
*
|
||||
* The library is divided into three main components :
|
||||
* - The reader itself that does the parsing stuffs
|
||||
* - An implementation of the callback object (the implementation
|
||||
* is left to the user application developper)
|
||||
* - An optionnal helper object that knows more on the
|
||||
* content of the EBML stream.
|
||||
*
|
||||
* Here comes the organisation of the different modules and how
|
||||
* data go from one to another. Note that the user application
|
||||
* and the user callback object may share some information so the
|
||||
* callback object communicates with the application itself.
|
||||
*
|
||||
* \image html ebml_parsing_concept.png "Concept"
|
||||
*
|
||||
* Here comes the UML class diagram, presenting the main classes
|
||||
* involved in the presented behavior.
|
||||
*
|
||||
* \image html ebml_parsing_class.png "Class Diagram"
|
||||
*
|
||||
* See EBML::IReader, EBML::IReaderCallback and EBML::IReaderHelper
|
||||
* for more details on each of these classes.
|
||||
*
|
||||
* \section Doc_ParsingEBMLStreams_SampleCode Sample code
|
||||
*
|
||||
* In this section, a sample of user application code is presented
|
||||
* that parses the sample file created in the page named :
|
||||
* \ref Doc_FormatingEBMLStreams
|
||||
*
|
||||
* The parsed value are printed in the console.
|
||||
*
|
||||
* The callback object looks something like this :
|
||||
*
|
||||
* \code
|
||||
* class CReaderCallback : public EBML::IReaderCallback
|
||||
* {
|
||||
* public:
|
||||
* CReaderCallback()
|
||||
* {
|
||||
* m_helper=EBML::createReaderHelper();
|
||||
* }
|
||||
* virtual ~CReaderCallback()
|
||||
* {
|
||||
* if(m_helper) m_helper->release();
|
||||
* }
|
||||
* virtual bool isMasterChild(const EBML::CIdentifier& identifier)
|
||||
* {
|
||||
* if(identifier==EBML_Identifier_Header) return true;
|
||||
* if(identifier==EBML_Identifier_DocType) return true;
|
||||
* if(identifier==EBML_Identifier_DocTypeVersion) return true;
|
||||
* return false;
|
||||
* }
|
||||
* virtual void openChild(const EBML::CIdentifier& identifier)
|
||||
* {
|
||||
* m_oCurrent=identifier;
|
||||
* }
|
||||
* virtual void processChildData(const void* buffer, const size_t size)
|
||||
* {
|
||||
* if(m_oCurrent==EBML_Identifier_DocType)
|
||||
* std::cout << "Doc type:" << m_helper->getStr(buffer, size) << std::endl;
|
||||
* if(m_oCurrent==EBML_Identifier_DocTypeVersion)
|
||||
* std::cout << "Dox type version:" << m_helper->getUInt(buffer, size) << std::endl;
|
||||
* }
|
||||
* virtual void closeChild()
|
||||
* {
|
||||
* }
|
||||
* EBML::IReaderHelper* m_helper;
|
||||
* };
|
||||
* \endcode
|
||||
*
|
||||
* Then in the user application code, we can write the
|
||||
* initialisation this way :
|
||||
*
|
||||
* \code
|
||||
* CReaderCallback oCallback;
|
||||
* EBML::IReader* pReader=EBML::createReader(oCallback);
|
||||
* \endcode
|
||||
*
|
||||
* Now suppose the user application got some data from the file
|
||||
* in a \c buffer of size \c size ; it is sent to the
|
||||
* parser this way :
|
||||
*
|
||||
* \code
|
||||
* pReader->processData(buffer, size);
|
||||
* \endcode
|
||||
*
|
||||
* Finally, don't forget to release the object and to clean memory :
|
||||
*
|
||||
* \code
|
||||
* pReader->release();
|
||||
* \endcode
|
||||
*/
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* \page Doc_WhatIsEBML What is EBML
|
||||
*
|
||||
* This page tries to explain what EBML is and why it is usefull.
|
||||
*
|
||||
* - see http://ebml.sourceforge.net/ for more details
|
||||
* - see http://ebml.sourceforge.net/specs/ for specifications
|
||||
* - see http://www.matroska.org/technical/specs/ for even more details
|
||||
*
|
||||
* - check libebml for a sample implementation of EBML
|
||||
* - check libmatroska for a sample of library using libebml
|
||||
* and a concrete use of EBML
|
||||
*
|
||||
* \todo Write more documentation on what EBML is
|
||||
*/
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
#include "defines.h"
|
||||
#include <climits>
|
||||
|
||||
namespace EBML {
|
||||
/**
|
||||
* \class CIdentifier
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief Base class to work with EBML identifiers
|
||||
*
|
||||
* This class is used in order to work on EBML identifier.
|
||||
* It handles 64 bits values for now, but could easily be
|
||||
* changed to handle bigger values if needed.
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ in
|
||||
* order to understand what an identifier is and how it works
|
||||
*/
|
||||
class EBML_API CIdentifier
|
||||
{
|
||||
public:
|
||||
|
||||
/** \name Constructors */
|
||||
//@{
|
||||
|
||||
/**
|
||||
* \brief Basic constructor
|
||||
*
|
||||
* Initializes the identifier to 0.
|
||||
*/
|
||||
CIdentifier() : m_id(ULLONG_MAX) {}
|
||||
/**
|
||||
* \brief Integer based constructor
|
||||
* \param id [in] : The value to use
|
||||
*
|
||||
* Initializes the identifier to the given 64 bits value.
|
||||
*/
|
||||
CIdentifier(const uint64_t id) : m_id(id) {}
|
||||
/**
|
||||
* \brief 32 bits integer based constructor
|
||||
* \param id1 [in] : the first part of the identifier
|
||||
* \param id2 [in] : the second part of the identifier
|
||||
*
|
||||
* Builds up the 64 bits identifier given its two 32 bits
|
||||
* components.
|
||||
*/
|
||||
CIdentifier(const size_t id1, const size_t id2) : m_id((uint64_t(id1) << 32) + id2) {}
|
||||
/**
|
||||
* \brief Copy constructor
|
||||
* \param id [in] : The source identifier to use
|
||||
*
|
||||
* Initializes this identifier to the same value as
|
||||
* the given source identifier.
|
||||
*/
|
||||
CIdentifier(const CIdentifier& id) : m_id(id.m_id) {}
|
||||
|
||||
//@}
|
||||
/** \name Operators */
|
||||
//@{
|
||||
|
||||
/**
|
||||
* \brief Copy operator
|
||||
* \param id [in] : The source identifier to copy from
|
||||
* \return a const reference on this identifier
|
||||
*
|
||||
* Initializes this identifier to the same value as
|
||||
* the given source identifier.
|
||||
*/
|
||||
const CIdentifier& operator=(const CIdentifier& id);
|
||||
|
||||
/**
|
||||
* \brief Equality comparison operator
|
||||
* \param id1 [in] : The first identifier to compare
|
||||
* \param id2 [in] : The second identifier to compare
|
||||
* \return \e true when the identifiers are equal, \e false
|
||||
* when they are different.
|
||||
*
|
||||
* This function compares the two 64 bits values.
|
||||
*/
|
||||
friend EBML_API bool operator==(const CIdentifier& id1, const CIdentifier& id2);
|
||||
/**
|
||||
* \brief Difference comparison operator
|
||||
* \param id1 [in] : The first identifier to compare
|
||||
* \param id2 [in] : The second identifier to compare
|
||||
* \return \e true when the identifiers are different, \e false
|
||||
* when they are equal.
|
||||
*
|
||||
* This function compares the two 64 bits values.
|
||||
*/
|
||||
friend EBML_API bool operator!=(const CIdentifier& id1, const CIdentifier& id2);
|
||||
/**
|
||||
* \brief Ordering comparison operator
|
||||
* \param id1 [in] : The first identifier to compare
|
||||
* \param id2 [in] : The second identifier to compare
|
||||
* \return \e true when the first identifier is lesser or equal
|
||||
* to the second identifier, \e false in other cases.
|
||||
*
|
||||
* This function compares the two 64 bits values.
|
||||
*/
|
||||
friend EBML_API bool operator<=(const CIdentifier& id1, const CIdentifier& id2);
|
||||
/**
|
||||
* \brief Ordering comparison operator
|
||||
* \param id1 [in] : The first identifier to compare
|
||||
* \param id2 [in] : The second identifier to compare
|
||||
* \return \e true when the first identifier is greater or equal
|
||||
* to the second identifier, \e false in other cases.
|
||||
*
|
||||
* This function compares the two 64 bits values.
|
||||
*/
|
||||
friend EBML_API bool operator>=(const CIdentifier& id1, const CIdentifier& id2);
|
||||
/**
|
||||
* \brief Ordering comparison operator
|
||||
* \param id1 [in] : The first identifier to compare
|
||||
* \param id2 [in] : The second identifier to compare
|
||||
* \return \e true when the first identifier is lesser and not equal
|
||||
* to the second identifier, \e false in other cases.
|
||||
*
|
||||
* This function compares the two 64 bits values.
|
||||
*/
|
||||
friend EBML_API bool operator<(const CIdentifier& id1, const CIdentifier& id2);
|
||||
/**
|
||||
* \brief Ordering comparison operator
|
||||
* \param id1 [in] : The first identifier to compare
|
||||
* \param id2 [in] : The second identifier to compare
|
||||
* \return \e true when the first identifier is greater and not equal
|
||||
* to the second identifier, \e false in other cases.
|
||||
*
|
||||
* This function compares the two 64 bits values.
|
||||
*/
|
||||
friend EBML_API bool operator>(const CIdentifier& id1, const CIdentifier& id2);
|
||||
|
||||
/**
|
||||
* \brief Cast operator
|
||||
* \return \e the 64 bits value contained by this identifier.
|
||||
*/
|
||||
operator uint64_t() const { return this->id(); }
|
||||
|
||||
/**
|
||||
* \brief Conversion to 64 bits uint32_t (should be used instead of the cast)
|
||||
* \return \e the 64 bits value contained by this identifier.
|
||||
*/
|
||||
uint64_t id() const { return m_id; }
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
uint64_t m_id = 0; ///< The 64 bits value of this identifier
|
||||
};
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "IReader.h"
|
||||
|
||||
namespace EBML {
|
||||
class EBML_API CReader final : public IReader
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CReader(IReaderCallback& callback);
|
||||
~CReader() override;
|
||||
bool processData(const void* buffer, const size_t size) override;
|
||||
CIdentifier getCurrentNodeID() const override;
|
||||
size_t getCurrentNodeSize() const override;
|
||||
void release() override;
|
||||
|
||||
protected:
|
||||
|
||||
IReader* m_impl = nullptr;
|
||||
|
||||
private:
|
||||
|
||||
CReader() = delete;
|
||||
};
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "IReaderHelper.h"
|
||||
|
||||
namespace EBML {
|
||||
class EBML_API CReaderHelper final : public IReaderHelper
|
||||
{
|
||||
public:
|
||||
|
||||
CReaderHelper();
|
||||
~CReaderHelper() override;
|
||||
uint64_t getUInt(const void* buffer, const size_t size) override;
|
||||
int64_t getInt(const void* buffer, const size_t size) override;
|
||||
double getDouble(const void* buffer, const size_t size) override;
|
||||
const char* getStr(const void* buffer, const size_t size) override;
|
||||
void release() override;
|
||||
|
||||
protected:
|
||||
|
||||
IReaderHelper* m_impl = nullptr;
|
||||
};
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "IWriter.h"
|
||||
|
||||
namespace EBML {
|
||||
class EBML_API CWriter final : public IWriter
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CWriter(IWriterCallback& callback);
|
||||
~CWriter() override;
|
||||
bool openChild(const CIdentifier& identifier) override;
|
||||
bool setChildData(const void* buffer, const size_t size) override;
|
||||
bool closeChild() override;
|
||||
void release() override;
|
||||
|
||||
protected:
|
||||
|
||||
IWriter* m_impl = nullptr;
|
||||
|
||||
private:
|
||||
|
||||
CWriter() = delete;
|
||||
};
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "IWriterHelper.h"
|
||||
|
||||
namespace EBML {
|
||||
class EBML_API CWriterHelper final : public IWriterHelper
|
||||
{
|
||||
public:
|
||||
|
||||
CWriterHelper();
|
||||
~CWriterHelper() override;
|
||||
bool connect(IWriter* writer) override;
|
||||
bool disconnect() override;
|
||||
bool openChild(const CIdentifier& identifier) override;
|
||||
bool closeChild() override;
|
||||
bool setInt(const int64_t value) override;
|
||||
bool setUInt(const uint64_t value) override;
|
||||
bool setFloat(const float value) override;
|
||||
bool setDouble(const double value) override;
|
||||
bool setBinary(const void* buffer, const size_t size) override;
|
||||
bool setStr(const char* value) override;
|
||||
void release() override { }
|
||||
|
||||
protected:
|
||||
|
||||
IWriterHelper* m_impl = nullptr;
|
||||
};
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,135 @@
|
||||
#pragma once
|
||||
|
||||
#include "CIdentifier.h"
|
||||
#include <cstdlib> // fix Unix compatibility
|
||||
|
||||
namespace EBML {
|
||||
/**
|
||||
* \class IReaderCallback
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief Callback class to use when parsing the EBML stream
|
||||
*
|
||||
* This class is to be overloaded by the user in order to get rid of the parsing events. It will be notified
|
||||
* by the EBML::IReader object of what is found in the stream.
|
||||
*
|
||||
* \sa EBML::IReader
|
||||
*/
|
||||
class EBML_API IReaderCallback
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor
|
||||
*/
|
||||
virtual ~IReaderCallback() { }
|
||||
/**
|
||||
* \brief Kind of child querry
|
||||
* \param id [in] : The id which type has to be known
|
||||
* \return \e true when the node is a master node
|
||||
* \return \e false when it is a simple child node.
|
||||
*
|
||||
* When called by the reader, this function should tell it whether the node identified by \c id is a master
|
||||
* node (has child) or not (has data). For that, it has to return \e true when the node should have children, and \e false in other cases.
|
||||
*/
|
||||
virtual bool isMasterChild(const CIdentifier& id) = 0;
|
||||
/**
|
||||
* \brief Informs the callback object a new node parsing is starting
|
||||
* \param id [in] : The idenfier of the newly parsing node
|
||||
*
|
||||
* This is called to notify the callback object that the parser has started a new EBML node parsing. This EBML
|
||||
* node is identified by \c id. After this call will follow whether a new \c openChild if this node is
|
||||
* a master one, whher a processData if this node is a simple child one.
|
||||
*/
|
||||
virtual void openChild(const CIdentifier& id) = 0;
|
||||
/**
|
||||
* \brief Gives the callback object the data associated with the currently opened child node
|
||||
* \param buffer [in] : The buffer corresponding to the current simple child node
|
||||
* \param size [in] : The buffer size in bytes
|
||||
*
|
||||
* This function is called when the data reading is terminated for a simple child node and so the callback
|
||||
* object can process it. Whether the callback object knows how to process the data, whether it requests
|
||||
* a reader helper object to do the work... See EBML::IReaderHelper for more details on that subject.
|
||||
*/
|
||||
virtual void processChildData(const void* buffer, const size_t size) = 0;
|
||||
/**
|
||||
* \brief Informs the callback object the current node parsing is terminated
|
||||
*
|
||||
* This function tells the callback object the current node parsing is terminated. Thus the parsing continues for the
|
||||
* top level node, whether opening a new child or closing itself and so on...
|
||||
*/
|
||||
virtual void closeChild() = 0;
|
||||
};
|
||||
|
||||
class EBML_API IReaderCallBack : public IReaderCallback { };
|
||||
|
||||
/**
|
||||
* \class IReader
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief EBML processing class
|
||||
*
|
||||
* This class should be used in order to parse an EBML stream. It should be given a callback object that can handle the
|
||||
* content of the stream. The parser itself as no understanding of what is included in the EBML structure.
|
||||
*
|
||||
* The parsing interface looks like the eXpat XML parser, allowing on-the-fly parsing. See http://expat.sourceforge.net for more details.
|
||||
*
|
||||
* To create instances of this class, the user has to call EBML::createReader. To delete instances of this class, the user has to call EBML::IReader::release.
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ in order to understand what EBML is and how it should be used.
|
||||
*/
|
||||
class EBML_API IReader
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Processes a chunk of data
|
||||
* \param buffer [in] : The buffer of data to process
|
||||
* \param size [in] : The buffer size in bytes
|
||||
* \return \e true when data processing was ok
|
||||
* \return \e false in other cases.
|
||||
*
|
||||
* This function has to be called as soon as the stream reader (file, socket, whatever) has data. Those data
|
||||
* are sent to the parser and parsing for this chunk is started immediatly. The callback object is called
|
||||
* according to the EBML structure contained in the chunk and the previously parsed chunks. See
|
||||
* EBML::IReaderCallback for more details on the callback object.
|
||||
*/
|
||||
virtual bool processData(const void* buffer, const size_t size) = 0;
|
||||
/**
|
||||
* \brief Gets the identifier of the current node
|
||||
* \return the identifier of the current node
|
||||
*/
|
||||
virtual CIdentifier getCurrentNodeID() const = 0;
|
||||
/**
|
||||
* \brief Gets the size of the current node
|
||||
* \return the size of the current node
|
||||
*/
|
||||
virtual size_t getCurrentNodeSize() const = 0;
|
||||
/**
|
||||
* \brief Tells this object it won't be used anymore
|
||||
*
|
||||
* Instances of this class can not be instanciated another way than calling \c createReader. They can
|
||||
* not be deleted either because the destructor is. protected. The library knows how to create and
|
||||
* delete an instance of this class... Calling \c release will simply delete this instance and
|
||||
* handle necessary cleanings when needed.
|
||||
*
|
||||
* The current object is invalid after calling this function. It can not be used anymore.
|
||||
*/
|
||||
virtual void release() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor - should be overloaded
|
||||
*/
|
||||
virtual ~IReader() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instanciation function for EBML reader objects
|
||||
* \param callback [in] : The callback object the reader should use
|
||||
* \return a pointer to the created instance on success.
|
||||
* \return \c NULL when something went wrong.
|
||||
*/
|
||||
extern EBML_API IReader* createReader(IReaderCallback& callback);
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,93 @@
|
||||
#pragma once
|
||||
|
||||
#include "IReader.h"
|
||||
|
||||
namespace EBML {
|
||||
/**
|
||||
* \class IReaderHelper
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief Helper to read basic EBML types
|
||||
*
|
||||
* This class may be used by a IReaderCallback instance
|
||||
* in order to correctly parse simple types defined in the
|
||||
* EBML description such as integers, floats, strings etc...
|
||||
*
|
||||
* A similar class exists to help formating process...
|
||||
* See EBML::IWriterHelper for more details.
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ in
|
||||
* order to understand what EBML is and how it should be used.
|
||||
*
|
||||
* \todo long double reading implementation
|
||||
* \todo date reading implementation
|
||||
* \todo utf8 string reading implementation
|
||||
*/
|
||||
class EBML_API IReaderHelper
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \name Standard EBML value reading
|
||||
* \param buffer [in] : The buffer containing data
|
||||
* \param size [in] : The buffer size in bytes
|
||||
* \return The value contained in the buffer
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ in
|
||||
* order to understand standard EBML types.
|
||||
*/
|
||||
//@{
|
||||
/**
|
||||
* \brief Gets an unsigned integer from the given buffer
|
||||
*/
|
||||
virtual uint64_t getUInt(const void* buffer, const size_t size) = 0;
|
||||
/**
|
||||
* \brief Gets a signed integer from the given buffer
|
||||
*/
|
||||
virtual int64_t getInt(const void* buffer, const size_t size) = 0;
|
||||
/**
|
||||
* \brief Gets a float from the given buffer
|
||||
*/
|
||||
virtual double getDouble(const void* buffer, const size_t size) = 0;
|
||||
// virtual ??? getFloat80FromChildData(const void* buffer, const size_t size)=0;
|
||||
// virtual ??? getDateFromChildData(const void* buffer, const size_t size)=0;
|
||||
/**
|
||||
* \brief Gets an ASCII string from the given buffer
|
||||
* \warning The returned value is not permanent. It should be
|
||||
* copied immediatly somewhere else by the caller.
|
||||
*/
|
||||
virtual const char* getStr(const void* buffer, const size_t size) = 0;
|
||||
// virtual ??? getUTF8StringFromChildData(const void* buffer, const size_t size)=0;
|
||||
//@}
|
||||
|
||||
/**
|
||||
* \brief Tells this object it won't be used anymore
|
||||
*
|
||||
* Instances of this class can not be instanciated
|
||||
* another way than calling \c createReaderHelper. They
|
||||
* can not be deleted either because the destructor is.
|
||||
* protected. The library knows how to create and
|
||||
* delete an instance of this class... Calling
|
||||
* \c release will simply delete this instance and
|
||||
* handle necessary cleanings when needed.
|
||||
*
|
||||
* The current object is invalid after calling this
|
||||
* function. It can not be used anymore.
|
||||
*/
|
||||
virtual void release() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor - should be overloaded
|
||||
*/
|
||||
virtual ~IReaderHelper() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instanciation function for EBML reader helper objects
|
||||
* \return a pointer to the created instance on success.
|
||||
* \return \c NULL when something went wrong.
|
||||
*/
|
||||
extern EBML_API IReaderHelper* createReaderHelper();
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include "CIdentifier.h"
|
||||
#include <cstdlib> // fix Unix compatibility
|
||||
|
||||
namespace EBML {
|
||||
/**
|
||||
* \class IWriterCallback
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief Callback class to use when creating the EBML stream
|
||||
*
|
||||
* This class is to be overloaded by the user in order to get rid of the stream writing events. It will be
|
||||
* notified by the EBML::IWriter object of what is to be written in the stream while the user sends information to the writer.
|
||||
*
|
||||
* \sa EBML::IWriter
|
||||
*/
|
||||
class EBML_API IWriterCallback
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor
|
||||
*/
|
||||
virtual ~IWriterCallback() { }
|
||||
/**
|
||||
* \brief Gives the callback object a new stream chunk
|
||||
* \param buffer [in] : The buffer to write in the stream
|
||||
* \param size [in] : The buffer size in bytes
|
||||
*
|
||||
* This function tells the callback object new data are ready to send in the EBML stream. This function
|
||||
* may be called while the user sends data to the writer.
|
||||
*/
|
||||
virtual void write(const void* buffer, const size_t size) = 0;
|
||||
};
|
||||
|
||||
class EBML_API IWriterCallBack : public IWriterCallback { };
|
||||
|
||||
/**
|
||||
* \class IWriter
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief EBML formating class
|
||||
*
|
||||
* This class is used in order to format datas using EBML specifications. It gives a minimalistic interface to
|
||||
* allow creating new EBML nodes, and to insert data in simple child nodes.
|
||||
*
|
||||
* Basic usage of this class consists in :
|
||||
*
|
||||
* - Create child node
|
||||
* - Gives information about the node :
|
||||
* - Whether created node is master node (Goto 1)
|
||||
* - Whether created node is simple child node (set data for this child node)
|
||||
* - Close opened node
|
||||
*
|
||||
* The EBML::IWriterHelper class could be used in order to send EBML standard data such as integers, floats, strings, etc...
|
||||
*
|
||||
* To create instances of this class, the user has to call EBML::createWriter. To delete instances of this class, the user has to call EBML::IWriter::release.
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ in order to understand what EBML is and how it should be used.
|
||||
*/
|
||||
class EBML_API IWriter
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Starts a new child node
|
||||
* \param identifier [in] : The identifier of the new child node
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function is called when the user wants to add a child node to the currently opened master node.
|
||||
* A node containing data can not have child so if \c setChildData has been called before, this function returns \e false.
|
||||
*
|
||||
* Once the node has been opened, it should be closed calling \c closeChild.
|
||||
*/
|
||||
virtual bool openChild(const CIdentifier& identifier) = 0;
|
||||
/**
|
||||
* \brief Sets data for simple child node
|
||||
* \param buffer [in] : The buffer to set as child data
|
||||
* \param size [in] : The buffer size in bytes
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function is called by the user for setting data in the currently opened simple child node.
|
||||
* If the currently opened node has children, it is a master node so it can't receive data. In such case, the function returns \e false. However,
|
||||
* it the currently opened node already has data, it returns \e false too.
|
||||
*/
|
||||
virtual bool setChildData(const void* buffer, const size_t size) = 0;
|
||||
/**
|
||||
* \brief Closes currently opened child node
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function is called when the user wants to close a child node. The node should have received
|
||||
* either child nodes or data depending if it is a master node or a simple child node.
|
||||
*/
|
||||
virtual bool closeChild() = 0;
|
||||
/**
|
||||
* \brief Tells this object it won't be used anymore
|
||||
*
|
||||
* Instances of this class can not be instanciated another way than calling \c createWriter. They can
|
||||
* not be deleted either because the destructor is. protected. The library knows how to create and
|
||||
* delete an instance of this class... Calling \c release will simply delete this instance and
|
||||
* handle necessary cleanings when needed.
|
||||
*
|
||||
* The current object is invalid after calling this
|
||||
* function. It can not be used anymore.
|
||||
*/
|
||||
virtual void release() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor - should be overloaded
|
||||
*/
|
||||
virtual ~IWriter() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instanciation function for EBML writer objects
|
||||
* \param callback [in] : The callback object the writer should use
|
||||
* \return a pointer to the created instance on success.
|
||||
* \return \c NULL when something went wrong.
|
||||
*/
|
||||
extern EBML_API IWriter* createWriter(IWriterCallback& callback);
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,176 @@
|
||||
#pragma once
|
||||
|
||||
#include "IWriter.h"
|
||||
|
||||
namespace EBML {
|
||||
/**
|
||||
* \class IWriterHelper
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief Helper to write basic EBML types
|
||||
*
|
||||
* This class may be used by the user in order to correctly
|
||||
* format simple types defined in the EBML description such
|
||||
* as integers, floats, strings etc... It directly uses the
|
||||
* EBML::IWriter connected instance so one could simply
|
||||
* use the helper in order to write his EBML stream.
|
||||
*
|
||||
* A similar class exists to help parsing process...
|
||||
* See EBML::IReaderHelper for more details.
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ in
|
||||
* order to understand what EBML is and how it should be used.
|
||||
*
|
||||
* \todo long double formating implementation
|
||||
* \todo date formating implementation
|
||||
* \todo utf8 string formating implementation
|
||||
*/
|
||||
class EBML_API IWriterHelper
|
||||
{
|
||||
public:
|
||||
|
||||
/** \name Writer connection */
|
||||
//@{
|
||||
/**
|
||||
* \brief Connects an EBML writer to this helper
|
||||
* \param writer [in] : The writer to connect
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function gives the helper a handle to the writer
|
||||
* to use in order to forward requests. Thus, when the
|
||||
* user calls a helper function, the call is forwarded
|
||||
* to the correct writer that effictively does the work.
|
||||
* The aim of this helper is simply to transform standard
|
||||
* EBML types into bytes buffers.
|
||||
*
|
||||
* Once a writer is connected, it could be disconnected
|
||||
* thanks to the \c disconnect function. It must be done
|
||||
* before calling \c connect again.
|
||||
*/
|
||||
virtual bool connect(IWriter* writer) = 0;
|
||||
/**
|
||||
* \brief Disconnects the currently connected EBML writer
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function should be called to release the EBML
|
||||
* writer handle. The helper instance may then be used
|
||||
* with another EBML writer instance calling \c connect
|
||||
* again.
|
||||
*/
|
||||
virtual bool disconnect() = 0;
|
||||
//@}
|
||||
|
||||
/** \name Writer binding functions */
|
||||
//@{
|
||||
/**
|
||||
* \brief Child opening binding
|
||||
* \param identifier [in] : The identifier of the new child node
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function simply forwards the call to the
|
||||
* corresponding EBML::IWriter function. See
|
||||
* EBML::IWriter::openChild for more details.
|
||||
*/
|
||||
virtual bool openChild(const CIdentifier& identifier) = 0;
|
||||
/**
|
||||
* \brief Child closing binding
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* This function simply forwards the call to the
|
||||
* corresponding EBML::IWriter function. See
|
||||
* EBML::IWriter::closeChild for more details.
|
||||
*/
|
||||
virtual bool closeChild() = 0;
|
||||
//@}
|
||||
|
||||
/**
|
||||
* \name Standard EBML formating
|
||||
* \brief EBML::IWriter::setChildData replacement
|
||||
* \return \e true on success.
|
||||
* \return \e false on error.
|
||||
*
|
||||
* Those functions should be used in place of the
|
||||
* basic EBML::IWriter::setChildData function. They
|
||||
* format standard EBML types into corresponding
|
||||
* buffers and then send those built buffers to
|
||||
* the writer using the EBML::IWriter::setChildData
|
||||
* function.
|
||||
*/
|
||||
//@{
|
||||
/**
|
||||
* \brief Sets a signed integer as child data
|
||||
* \param value [in] : The integer value to set
|
||||
*/
|
||||
virtual bool setInt(const int64_t value) = 0;
|
||||
/**
|
||||
* \brief Sets an unsigned integer as child data
|
||||
* \param value [in] : The integer value to set
|
||||
*/
|
||||
virtual bool setUInt(const uint64_t value) = 0;
|
||||
/**
|
||||
* \brief Sets a 32 bits float value as child data
|
||||
* \param value [in] : The 32 bits float value to set
|
||||
*/
|
||||
virtual bool setFloat(const float value) = 0;
|
||||
/**
|
||||
* \brief Sets a 64 bits float value as child data
|
||||
* \param value [in] : The 64 bits float value to set
|
||||
*/
|
||||
virtual bool setDouble(const double value) = 0;
|
||||
// virtual bool setFloat80AsChildData( ??? value)=0;
|
||||
// virtual bool setDateAsChildData( ??? value)=0;
|
||||
/**
|
||||
* \brief Sets a buffer as child data
|
||||
* \param buffer [in] : The buffer to send to the writer
|
||||
* \param size [in] : The buffer size in bytes
|
||||
* \note This function simply calls the basic
|
||||
* EBML::IWriter::setChildData function with the
|
||||
* same two parameters.
|
||||
*/
|
||||
virtual bool setBinary(const void* buffer, const size_t size) = 0;
|
||||
/**
|
||||
* \brief Sets an ASCII string as child data
|
||||
* \param value [in] : The ASCII string value to set
|
||||
*/
|
||||
virtual bool setStr(const char* value) = 0;
|
||||
// virtual bool setUTF8StringAsChildData( ??? value)=0;
|
||||
//@}
|
||||
|
||||
/**
|
||||
* \brief Tells this object it won't be used anymore
|
||||
*
|
||||
* Instances of this class can not be instanciated
|
||||
* another way than calling \c createWriterHelper. They
|
||||
* can not be deleted either because the destructor is.
|
||||
* protected. The library knows how to create and
|
||||
* delete an instance of this class... Calling
|
||||
* \c release will simply delete this instance and
|
||||
* handle necessary cleanings when needed.
|
||||
*
|
||||
* The current object is invalid after calling this
|
||||
* function. It can not be used anymore.
|
||||
*
|
||||
* \warning Releasing this obbject does not release the
|
||||
* connected writer instance !
|
||||
*/
|
||||
virtual void release() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor - should be overloaded
|
||||
*/
|
||||
virtual ~IWriterHelper() { }
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instanciation function for EBML writer helper objects
|
||||
* \return a pointer to the created instance on success.
|
||||
* \return \c NULL when something went wrong.
|
||||
*/
|
||||
extern EBML_API IWriterHelper* createWriterHelper();
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "IReader.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
template <class TOwnerClass>
|
||||
class TReaderCallbackProxy1 final : public IReaderCallback
|
||||
{
|
||||
public:
|
||||
TReaderCallbackProxy1(TOwnerClass& ownerObject, bool (TOwnerClass::*mfpIsMasterChild)(const CIdentifier& identifier),
|
||||
void (TOwnerClass::*mfpOpenChild)(const CIdentifier& identifier),
|
||||
void (TOwnerClass::*mfpProcessChildData)(const void* buffer, const size_t size), void (TOwnerClass::*mfpCloseChild)())
|
||||
: m_ownerObject(ownerObject), m_mfpIsMasterChild(mfpIsMasterChild), m_mfpOpenChild(mfpOpenChild), m_mfpProcessChildData(mfpProcessChildData),
|
||||
m_mfpCloseChild(mfpCloseChild) { }
|
||||
|
||||
bool isMasterChild(const CIdentifier& identifier) override
|
||||
{
|
||||
if (m_mfpIsMasterChild) { return (m_ownerObject.*m_mfpIsMasterChild)(identifier); }
|
||||
return false;
|
||||
}
|
||||
|
||||
void openChild(const CIdentifier& identifier) override { if (m_mfpOpenChild) { (m_ownerObject.*m_mfpOpenChild)(identifier); } }
|
||||
|
||||
void processChildData(const void* buffer, const size_t size) override
|
||||
{
|
||||
if (m_mfpProcessChildData) { (m_ownerObject.*m_mfpProcessChildData)(buffer, size); }
|
||||
}
|
||||
|
||||
void closeChild() override { if (m_mfpCloseChild) { (m_ownerObject.*m_mfpCloseChild)(); } }
|
||||
|
||||
protected:
|
||||
TOwnerClass& m_ownerObject;
|
||||
bool (TOwnerClass::*m_mfpIsMasterChild)(const CIdentifier& identifier);
|
||||
void (TOwnerClass::*m_mfpOpenChild)(const CIdentifier& identifier);
|
||||
void (TOwnerClass::*m_mfpProcessChildData)(const void* buffer, size_t size);
|
||||
void (TOwnerClass::*m_mfpCloseChild)();
|
||||
};
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
template <class TOwnerClass, bool (TOwnerClass::*TMfpIsMasterChild)(const CIdentifier& identifier),
|
||||
void (TOwnerClass::*TMfpOpenChild)(const CIdentifier& identifier),
|
||||
void (TOwnerClass::*TMfpProcessChildData)(const void* buffer, size_t size), void (TOwnerClass::*TMfpCloseChild)()>
|
||||
class TReaderCallbackProxy2 final : public IReaderCallback
|
||||
{
|
||||
public:
|
||||
TReaderCallbackProxy2(TOwnerClass& ownerObject)
|
||||
: m_ownerObject(ownerObject), m_mfpIsMasterChild(TMfpIsMasterChild), m_mfpOpenChild(TMfpOpenChild), m_mfpProcessChildData(TMfpProcessChildData),
|
||||
m_mfpCloseChild(TMfpCloseChild) { }
|
||||
|
||||
bool isMasterChild(const CIdentifier& identifier) override
|
||||
{
|
||||
if (m_mfpIsMasterChild) { return (m_ownerObject.*m_mfpIsMasterChild)(identifier); }
|
||||
return false;
|
||||
}
|
||||
|
||||
void openChild(const CIdentifier& identifier) override { if (m_mfpOpenChild) { (m_ownerObject.*m_mfpOpenChild)(identifier); } }
|
||||
|
||||
void processChildData(const void* buffer, const size_t size) override
|
||||
{
|
||||
if (m_mfpProcessChildData) { (m_ownerObject.*m_mfpProcessChildData)(buffer, size); }
|
||||
}
|
||||
|
||||
void closeChild() override { if (m_mfpCloseChild) { (m_ownerObject.*m_mfpCloseChild)(); } }
|
||||
|
||||
protected:
|
||||
TOwnerClass& m_ownerObject;
|
||||
bool (TOwnerClass::*m_mfpIsMasterChild)(const CIdentifier& identifier);
|
||||
void (TOwnerClass::*m_mfpOpenChild)(const CIdentifier& identifier);
|
||||
void (TOwnerClass::*m_mfpProcessChildData)(const void* buffer, size_t size);
|
||||
void (TOwnerClass::*m_mfpCloseChild)();
|
||||
};
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "IWriter.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
template <class TOwnerClass>
|
||||
class TWriterCallbackProxy1 final : public IWriterCallback
|
||||
{
|
||||
public:
|
||||
TWriterCallbackProxy1(TOwnerClass& ownerObject, void (TOwnerClass::*mfpWrite)(const void* buffer, size_t size))
|
||||
: m_ownerObject(ownerObject), m_mfpWrite(mfpWrite) { }
|
||||
|
||||
void write(const void* buffer, const size_t size) override { if (m_mfpWrite) { (m_ownerObject.*m_mfpWrite)(buffer, size); } }
|
||||
|
||||
protected:
|
||||
TOwnerClass& m_ownerObject;
|
||||
void (TOwnerClass::*m_mfpWrite)(const void* buffer, size_t size);
|
||||
};
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
template <class TOwnerClass, void (TOwnerClass::*TMfpWrite)(const void* buffer, size_t size)>
|
||||
class TWriterCallbackProxy2 final : public IWriterCallback
|
||||
{
|
||||
public:
|
||||
TWriterCallbackProxy2(TOwnerClass& ownerObject) : m_ownerObject(ownerObject), m_mfpWrite(TMfpWrite) { }
|
||||
|
||||
void write(const void* buffer, const size_t size) override { if (m_mfpWrite) { (m_ownerObject.*m_mfpWrite)(buffer, size); } }
|
||||
|
||||
protected:
|
||||
TOwnerClass& m_ownerObject;
|
||||
void (TOwnerClass::*m_mfpWrite)(const void* buffer, size_t size);
|
||||
};
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* \file defines.h
|
||||
* \author Yann Renard (INRIA/IRISA)
|
||||
* \date 2006-08-07
|
||||
* \brief Contains basic type definitions and EBML standard identifiers
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ov_common_defines.h>
|
||||
#include <cstdlib> // For Unix Compatibility
|
||||
#include <cstdint>
|
||||
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
// EBML Standard identifiers definitions //
|
||||
//___________________________________________________________________//
|
||||
// //
|
||||
|
||||
/**
|
||||
* \name EBML standard identifiers definitions
|
||||
*
|
||||
* Be sure to look at http://ebml.sourceforge.net/specs/ to
|
||||
* have more information on EBML and its standard identifiers.
|
||||
*/
|
||||
|
||||
//@{
|
||||
|
||||
/**
|
||||
* EBML Header.
|
||||
* This is a master node.
|
||||
* It contains several information about the ebml stream.
|
||||
*/
|
||||
#define EBML_Identifier_Header EBML::CIdentifier(0x0A45DFA3)
|
||||
/**
|
||||
* EBML Version.
|
||||
* This is a child node of type \c integer.
|
||||
* It contains the EBML version.
|
||||
*/
|
||||
#define EBML_Identifier_EBMLVersion EBML::CIdentifier(0x0286)
|
||||
/**
|
||||
* EBML Read Version.
|
||||
* This is a child node of type \c integer.
|
||||
* Indicates the EBML version a parser has to support to read this file
|
||||
*/
|
||||
#define EBML_Identifier_EBMLReadVersion EBML::CIdentifier(0x02F7)
|
||||
/**
|
||||
* EBML Identifier Length.
|
||||
* This is a child node of type \c integer.
|
||||
* Indicates the parser the maximum number of bytes an identifier
|
||||
* can have.
|
||||
*/
|
||||
#define EBML_Identifier_EBMLIdLength EBML::CIdentifier(0x02F2)
|
||||
/**
|
||||
* EBML Size Length.
|
||||
* This is a child node of type \c integer.
|
||||
* Indicates the paser the maximum number of bytes a node
|
||||
* can have.
|
||||
*/
|
||||
#define EBML_Identifier_EBMLSizeLength EBML::CIdentifier(0x02F3)
|
||||
/**
|
||||
* EBML Document Type.
|
||||
* This is a child node of type \c string.
|
||||
* Indicates the parser the kind of document being parsed.
|
||||
*/
|
||||
#define EBML_Identifier_DocType EBML::CIdentifier(0x0282)
|
||||
/**
|
||||
* EBML Document Type Version.
|
||||
* This is a child node of type \c integer.
|
||||
* Indicates the parser the specification version of the document
|
||||
* being parsed.
|
||||
*/
|
||||
#define EBML_Identifier_DocTypeVersion EBML::CIdentifier(0x0287)
|
||||
/**
|
||||
* EBML Document Type Read Version.
|
||||
* This is a child node of type \c integer.
|
||||
* Indicates the parser the version of the reader to use in order
|
||||
* to understand the document content.
|
||||
*/
|
||||
#define EBML_Identifier_DocTypeReadVersion EBML::CIdentifier(0x0285)
|
||||
/**
|
||||
* EBML Void.
|
||||
* This is a child node of type \c binary.
|
||||
* Indicates an ununderstandable chunk of data to skip.
|
||||
*/
|
||||
#define EBML_Identifier_Void EBML::CIdentifier(0x6C)
|
||||
/**
|
||||
* EBML CRC32.
|
||||
* This is a child node of type \c binary.
|
||||
* This is a CRC32 checksum of the content between this CRC32
|
||||
* and the last one.
|
||||
*/
|
||||
#define EBML_Identifier_CRC32 EBML::CIdentifier(0x02FE)
|
||||
|
||||
//@}
|
||||
|
||||
#if defined EBML_Shared
|
||||
# if defined TARGET_OS_Windows
|
||||
# define EBML_API_Export __declspec(dllexport)
|
||||
# define EBML_API_Import __declspec(dllimport)
|
||||
# elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
|
||||
# define EBML_API_Export __attribute__((visibility("default")))
|
||||
# define EBML_API_Import __attribute__((visibility("default")))
|
||||
# else
|
||||
# define EBML_API_Export
|
||||
# define EBML_API_Import
|
||||
# endif
|
||||
#else
|
||||
# define EBML_API_Export
|
||||
# define EBML_API_Import
|
||||
#endif
|
||||
|
||||
#if defined EBML_Exports
|
||||
# define EBML_API EBML_API_Export
|
||||
#else
|
||||
# define EBML_API EBML_API_Import
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "ebml/CIdentifier.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
const CIdentifier& CIdentifier::operator=(const CIdentifier& id)
|
||||
{
|
||||
m_id = id.m_id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const CIdentifier& id1, const CIdentifier& id2) { return id1.m_id == id2.m_id; }
|
||||
bool operator!=(const CIdentifier& id1, const CIdentifier& id2) { return id1.m_id != id2.m_id; }
|
||||
bool operator<=(const CIdentifier& id1, const CIdentifier& id2) { return id1.m_id <= id2.m_id; }
|
||||
bool operator>=(const CIdentifier& id1, const CIdentifier& id2) { return id1.m_id >= id2.m_id; }
|
||||
bool operator<(const CIdentifier& id1, const CIdentifier& id2) { return id1.m_id < id2.m_id; }
|
||||
bool operator>(const CIdentifier& id1, const CIdentifier& id2) { return id1.m_id > id2.m_id; }
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "ebml/CReader.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
CReader::CReader(IReaderCallback& callback) { m_impl = createReader(callback); }
|
||||
CReader::~CReader() { m_impl->release(); }
|
||||
|
||||
bool CReader::processData(const void* buffer, const size_t size) { return m_impl->processData(buffer, size); }
|
||||
CIdentifier CReader::getCurrentNodeID() const { return m_impl->getCurrentNodeID(); }
|
||||
size_t CReader::getCurrentNodeSize() const { return m_impl->getCurrentNodeSize(); }
|
||||
|
||||
void CReader::release() {}
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "ebml/CReaderHelper.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
CReaderHelper::CReaderHelper() { m_impl = createReaderHelper(); }
|
||||
CReaderHelper::~CReaderHelper() { m_impl->release(); }
|
||||
|
||||
uint64_t CReaderHelper::getUInt(const void* buffer, const size_t size) { return m_impl->getUInt(buffer, size); }
|
||||
int64_t CReaderHelper::getInt(const void* buffer, const size_t size) { return m_impl->getInt(buffer, size); }
|
||||
double CReaderHelper::getDouble(const void* buffer, const size_t size) { return m_impl->getDouble(buffer, size); }
|
||||
const char* CReaderHelper::getStr(const void* buffer, const size_t size) { return m_impl->getStr(buffer, size); }
|
||||
|
||||
void CReaderHelper::release() {}
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "ebml/CWriter.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
CWriter::CWriter(IWriterCallback& callback) { m_impl = createWriter(callback); }
|
||||
CWriter::~CWriter() { m_impl->release(); }
|
||||
|
||||
bool CWriter::openChild(const CIdentifier& identifier) { return m_impl->openChild(identifier); }
|
||||
bool CWriter::setChildData(const void* buffer, const size_t size) { return m_impl->setChildData(buffer, size); }
|
||||
bool CWriter::closeChild() { return m_impl->closeChild(); }
|
||||
|
||||
void CWriter::release() {}
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "ebml/CWriterHelper.h"
|
||||
|
||||
namespace EBML {
|
||||
|
||||
CWriterHelper::CWriterHelper() { m_impl = createWriterHelper(); }
|
||||
CWriterHelper::~CWriterHelper() { m_impl->release(); }
|
||||
|
||||
bool CWriterHelper::connect(IWriter* writer) { return m_impl->connect(writer); }
|
||||
bool CWriterHelper::disconnect() { return m_impl->disconnect(); }
|
||||
|
||||
bool CWriterHelper::openChild(const CIdentifier& identifier) { return m_impl->openChild(identifier); }
|
||||
bool CWriterHelper::closeChild() { return m_impl->closeChild(); }
|
||||
|
||||
bool CWriterHelper::setInt(const int64_t value) { return m_impl->setInt(value); }
|
||||
bool CWriterHelper::setUInt(const uint64_t value) { return m_impl->setUInt(value); }
|
||||
bool CWriterHelper::setFloat(const float value) { return m_impl->setFloat(value); }
|
||||
bool CWriterHelper::setDouble(const double value) { return m_impl->setDouble(value); }
|
||||
bool CWriterHelper::setBinary(const void* buffer, const size_t size) { return m_impl->setBinary(buffer, size); }
|
||||
bool CWriterHelper::setStr(const char* value) { return m_impl->setStr(value); }
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,357 @@
|
||||
#include "ebml/IReader.h"
|
||||
#include <cstring>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#if 0
|
||||
#define _Debug_ _is_in_debug_mode_(m_totalBytes)
|
||||
static bool _is_in_debug_mode_(uint64_t value)
|
||||
{
|
||||
static int i=0;
|
||||
// bool result=i++>5500000;
|
||||
bool result=value>29605500;
|
||||
if (result) std::cout << "Arround " << value << std::endl;
|
||||
return result;
|
||||
|
||||
}
|
||||
#else
|
||||
#define _Debug_ false
|
||||
#endif
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
inline bool needsTwoBytesToGetCodedSizeLength(const unsigned char* buffer) { return buffer[0] == 0; }
|
||||
|
||||
inline size_t getCodedSizeLength(const unsigned char* buffer)
|
||||
{
|
||||
if (buffer[0] >> 7) { return 1; }
|
||||
if (buffer[0] >> 6) { return 2; }
|
||||
if (buffer[0] >> 5) { return 3; }
|
||||
if (buffer[0] >> 4) { return 4; }
|
||||
if (buffer[0] >> 3) { return 5; }
|
||||
if (buffer[0] >> 2) { return 6; }
|
||||
if (buffer[0] >> 1) { return 7; }
|
||||
if (buffer[0]) { return 8; }
|
||||
if (buffer[1] >> 7) { return 9; }
|
||||
return 10;
|
||||
}
|
||||
|
||||
inline uint64_t getValue(unsigned char* buffer)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
const size_t length = getCodedSizeLength(buffer);
|
||||
size_t ithBit = length;
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
{
|
||||
result = (result << 8) + (buffer[i]);
|
||||
result &= ~(ithBit > 0 && ithBit <= 8 ? (1 << (8 - ithBit)) : 0);
|
||||
ithBit -= 8;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
namespace EBML {
|
||||
namespace {
|
||||
class CReaderNode
|
||||
{
|
||||
public:
|
||||
CReaderNode(const CIdentifier& identifier, CReaderNode* parentNode) : m_ParentNode(parentNode), m_Id(identifier) { }
|
||||
|
||||
private:
|
||||
CReaderNode() = delete;
|
||||
|
||||
public:
|
||||
|
||||
CReaderNode* m_ParentNode = nullptr;
|
||||
CIdentifier m_Id;
|
||||
size_t m_ContentSize = 0;
|
||||
size_t m_ReadContentSize = 0;
|
||||
unsigned char* m_Buffer = nullptr;
|
||||
};
|
||||
} // namespace
|
||||
} // namespace EBML
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
namespace EBML {
|
||||
namespace {
|
||||
class CReader final : public IReader
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CReader(IReaderCallback& callback) : m_readerCB(callback) { }
|
||||
~CReader() override;
|
||||
bool processData(const void* buffer, const size_t size) override;
|
||||
CIdentifier getCurrentNodeID() const override;
|
||||
size_t getCurrentNodeSize() const override;
|
||||
void release() override;
|
||||
|
||||
protected:
|
||||
|
||||
enum EStatus
|
||||
{
|
||||
FillingIdentifier,
|
||||
FillingContentSize,
|
||||
FillingContent,
|
||||
};
|
||||
|
||||
IReaderCallback& m_readerCB;
|
||||
CReaderNode* m_currentNode = nullptr;
|
||||
size_t m_pendingSize = 0;
|
||||
size_t m_nPending = 0;
|
||||
unsigned char* m_pending = nullptr;
|
||||
EStatus m_status = FillingIdentifier;
|
||||
EStatus m_lastStatus = FillingIdentifier;
|
||||
CIdentifier m_currentID = 0;
|
||||
size_t m_currentContentSize = 0;
|
||||
size_t m_totalBytes = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
CReader::~CReader()
|
||||
{
|
||||
delete [] m_pending;
|
||||
while (m_currentNode)
|
||||
{
|
||||
CReaderNode* parentNode = m_currentNode->m_ParentNode;
|
||||
delete m_currentNode;
|
||||
m_currentNode = parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
bool CReader::processData(const void* buffer, const size_t size)
|
||||
{
|
||||
m_totalBytes += size;
|
||||
|
||||
if (_Debug_)
|
||||
{
|
||||
std::cout << "Received " << size << " byte(s) new buffer :";
|
||||
for (int i = 0; i < int(size) /* && i<4*/; ++i) { printf("[%02X]", ((unsigned char*)buffer)[i]); }
|
||||
std::cout << "...\n";
|
||||
}
|
||||
|
||||
if (!buffer || !size) { return true; }
|
||||
|
||||
unsigned char* tmpBuffer = (unsigned char*)buffer;
|
||||
size_t currentSize = size;
|
||||
bool finished = false;
|
||||
while (!finished)
|
||||
{
|
||||
size_t processedPendingBytes = 0;
|
||||
size_t processedBytes = 0;
|
||||
m_lastStatus = m_status;
|
||||
|
||||
if (_Debug_ && m_nPending)
|
||||
{
|
||||
std::cout << m_nPending << " byte(s) pending : ";
|
||||
for (int i = 0; i < int(m_nPending); ++i) { printf("[%02X]", m_pending[i]); }
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
// Processes data
|
||||
switch (m_status)
|
||||
{
|
||||
case FillingIdentifier:
|
||||
case FillingContentSize:
|
||||
{
|
||||
if (needsTwoBytesToGetCodedSizeLength(m_nPending ? m_pending : tmpBuffer))
|
||||
{
|
||||
if (m_nPending + currentSize < 2)
|
||||
{
|
||||
finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_nPending == 1)
|
||||
{
|
||||
// assumes (currentSize != 0) because (m_nPending + currentSize >= 2) and (m_nPending == 1)
|
||||
m_pending[1] = tmpBuffer[0];
|
||||
tmpBuffer++;
|
||||
m_nPending++;
|
||||
currentSize--;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t length = getCodedSizeLength(m_nPending ? m_pending : tmpBuffer);
|
||||
if (length > currentSize + m_nPending) { finished = true; }
|
||||
else
|
||||
{
|
||||
unsigned char* encodedBuffer = new unsigned char[length];
|
||||
const size_t pendingBytesToCopy = (length > m_nPending ? m_nPending : length);
|
||||
memcpy(encodedBuffer, m_pending, size_t(pendingBytesToCopy));
|
||||
memcpy(encodedBuffer + pendingBytesToCopy, tmpBuffer, size_t(length - pendingBytesToCopy));
|
||||
const uint64_t value = getValue(encodedBuffer);
|
||||
delete [] encodedBuffer;
|
||||
processedPendingBytes = pendingBytesToCopy;
|
||||
processedBytes = length;
|
||||
|
||||
switch (m_status)
|
||||
{
|
||||
case FillingIdentifier:
|
||||
{
|
||||
m_currentID = value;
|
||||
m_status = FillingContentSize;
|
||||
if (_Debug_)
|
||||
{
|
||||
printf("Found identifier 0x%llX - Changing status to FillingContentSize...\n", static_cast<unsigned long long>(m_currentID));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FillingContentSize:
|
||||
{
|
||||
m_currentContentSize = value;
|
||||
if (m_readerCB.isMasterChild(m_currentID))
|
||||
{
|
||||
m_status = FillingIdentifier;
|
||||
if (_Debug_)
|
||||
{
|
||||
std::cout << "Found content size " << m_currentContentSize << " of master node - Changing status to FillingIdentifier...\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_status = FillingContent;
|
||||
if (_Debug_)
|
||||
{
|
||||
std::cout << "Found content size " << m_currentContentSize <<
|
||||
" of *non* master node - Changing status to FillingContent...\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FillingContent:
|
||||
// Should never happen - avoids the warning
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case FillingContent:
|
||||
{
|
||||
if (m_currentNode->m_ContentSize == 0)
|
||||
{
|
||||
m_status = FillingIdentifier;
|
||||
if (_Debug_)
|
||||
{
|
||||
std::cout << "Finished with " << m_currentNode->m_ContentSize << " byte(s) content - Changing status to FillingIdentifier...\n";
|
||||
}
|
||||
m_readerCB.processChildData(nullptr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_currentNode->m_ReadContentSize == 0 && m_currentNode->m_ContentSize <= currentSize)
|
||||
{
|
||||
m_status = FillingIdentifier;
|
||||
|
||||
processedBytes = m_currentNode->m_ContentSize;
|
||||
if (_Debug_)
|
||||
{
|
||||
std::cout << "Optimized processing of " << m_currentNode->m_ContentSize <<
|
||||
" byte(s) content - Changing status to FillingIdentifier...\n";
|
||||
}
|
||||
m_readerCB.processChildData(tmpBuffer, m_currentNode->m_ContentSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_currentNode->m_ContentSize - m_currentNode->m_ReadContentSize > currentSize)
|
||||
{
|
||||
memcpy(m_currentNode->m_Buffer + m_currentNode->m_ReadContentSize, tmpBuffer, size_t(currentSize));
|
||||
processedBytes = currentSize;
|
||||
finished = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(m_currentNode->m_Buffer + m_currentNode->m_ReadContentSize, tmpBuffer,
|
||||
size_t(m_currentNode->m_ContentSize - m_currentNode->m_ReadContentSize));
|
||||
processedBytes = m_currentNode->m_ContentSize - m_currentNode->m_ReadContentSize;
|
||||
|
||||
m_status = FillingIdentifier;
|
||||
if (_Debug_)
|
||||
{
|
||||
std::cout << "Finished with " << m_currentNode->m_ContentSize << " byte(s) content - Changing status to FillingIdentifier...\n";
|
||||
}
|
||||
m_readerCB.processChildData(m_currentNode->m_Buffer, m_currentNode->m_ContentSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Updates buffer pointer and size
|
||||
const size_t processedBytesInBuffer = processedBytes - processedPendingBytes;
|
||||
tmpBuffer += processedBytesInBuffer;
|
||||
currentSize -= processedBytesInBuffer;
|
||||
m_nPending -= processedPendingBytes;
|
||||
|
||||
// Updates read size
|
||||
CReaderNode* node = m_currentNode;
|
||||
while (node)
|
||||
{
|
||||
node->m_ReadContentSize += processedBytes;
|
||||
node = node->m_ParentNode;
|
||||
}
|
||||
|
||||
// Creates new node when needed
|
||||
if (m_status != FillingContentSize && m_lastStatus == FillingContentSize)
|
||||
{
|
||||
m_currentNode = new CReaderNode(m_currentID, m_currentNode);
|
||||
m_currentNode->m_ContentSize = m_currentContentSize;
|
||||
m_currentNode->m_Buffer = new unsigned char[m_currentContentSize];
|
||||
m_readerCB.openChild(m_currentNode->m_Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Closes finished nodes
|
||||
while (m_currentNode && (m_currentNode->m_ContentSize == m_currentNode->m_ReadContentSize || m_currentNode->m_ContentSize == 0))
|
||||
{
|
||||
m_readerCB.closeChild();
|
||||
CReaderNode* parent = m_currentNode->m_ParentNode;
|
||||
delete [] m_currentNode->m_Buffer;
|
||||
delete m_currentNode;
|
||||
m_currentNode = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updates pending data
|
||||
if (m_nPending + currentSize > m_pendingSize)
|
||||
{
|
||||
unsigned char* pending = new unsigned char[m_nPending + currentSize + 1
|
||||
]; // Ugly hack, reserve 1 more byte on pending data so we are sure we can insert this additional pending byte when only one byte is pending and two bytes are needed for decoding identifier and/or buffer size
|
||||
memcpy(pending, m_pending, m_nPending);
|
||||
delete [] m_pending;
|
||||
m_pending = pending;
|
||||
m_pendingSize = m_nPending + currentSize;
|
||||
}
|
||||
memcpy(m_pending + m_nPending, tmpBuffer, currentSize);
|
||||
m_nPending += currentSize;
|
||||
|
||||
if (_Debug_) { std::cout << "\n"; }
|
||||
return true;
|
||||
}
|
||||
|
||||
CIdentifier CReader::getCurrentNodeID() const { return m_currentNode ? m_currentNode->m_Id : CIdentifier(); }
|
||||
size_t CReader::getCurrentNodeSize() const { return m_currentNode ? m_currentNode->m_ContentSize : 0; }
|
||||
|
||||
void CReader::release() { delete this; }
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
EBML_API IReader* createReader(IReaderCallback& callback) { return new CReader(callback); }
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,85 @@
|
||||
#include "ebml/IReaderHelper.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
namespace EBML {
|
||||
namespace {
|
||||
class CReaderHelper final : public IReaderHelper
|
||||
{
|
||||
public:
|
||||
CReaderHelper() { }
|
||||
uint64_t getUInt(const void* buffer, const size_t size) override;
|
||||
int64_t getInt(const void* buffer, const size_t size) override;
|
||||
double getDouble(const void* buffer, const size_t size) override;
|
||||
const char* getStr(const void* buffer, const size_t size) override;
|
||||
void release() override;
|
||||
|
||||
std::string m_Str;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
uint64_t CReaderHelper::getUInt(const void* buffer, const size_t size)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
result <<= 8;
|
||||
result |= reinterpret_cast<const unsigned char*>(buffer)[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t CReaderHelper::getInt(const void* buffer, const size_t size)
|
||||
{
|
||||
int64_t result = 0;
|
||||
if (size != 0 && reinterpret_cast<const unsigned char*>(buffer)[0] & 0x80) { result = -1; }
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
result <<= 8;
|
||||
result |= reinterpret_cast<const unsigned char*>(buffer)[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double CReaderHelper::getDouble(const void* buffer, const size_t size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case 4:
|
||||
{
|
||||
float res;
|
||||
uint32_t data;
|
||||
data = uint32_t(getUInt(buffer, size));
|
||||
memcpy(&res, &data, sizeof(res));
|
||||
return double(res);
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
double res;
|
||||
uint64_t data;
|
||||
data = getUInt(buffer, size);
|
||||
memcpy(&res, &data, sizeof(res));
|
||||
return res;
|
||||
}
|
||||
|
||||
case 0:
|
||||
case 10:
|
||||
default: return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
const char* CReaderHelper::getStr(const void* buffer, const size_t size)
|
||||
{
|
||||
if (size) { m_Str.assign(reinterpret_cast<const char*>(buffer), size_t(size)); }
|
||||
else { m_Str = ""; }
|
||||
return m_Str.c_str();
|
||||
}
|
||||
|
||||
void CReaderHelper::release() { delete this; }
|
||||
|
||||
EBML_API IReaderHelper* createReaderHelper() { return new CReaderHelper(); }
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,214 @@
|
||||
#include "ebml/IWriter.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
inline size_t getCodedSizeLength(const uint64_t value)
|
||||
{
|
||||
if (value < 0x000000000000007fLL) { return 1; }
|
||||
if (value < 0x0000000000003fffLL) { return 2; }
|
||||
if (value < 0x00000000001fffffLL) { return 3; }
|
||||
if (value < 0x000000000fffffffLL) { return 4; }
|
||||
if (value < 0x00000007ffffffffLL) { return 5; }
|
||||
if (value < 0x000003ffffffffffLL) { return 6; }
|
||||
if (value < 0x0001ffffffffffffLL) { return 7; }
|
||||
if (value < 0x00ffffffffffffffLL) { return 8; }
|
||||
if (value < 0x7fffffffffffffffLL) { return 9; }
|
||||
return 10;
|
||||
}
|
||||
|
||||
inline bool getCodedBuffer(const uint64_t value, unsigned char* buffer, size_t* size)
|
||||
{
|
||||
const size_t length = getCodedSizeLength(value);
|
||||
|
||||
if (length > *size) { return false; }
|
||||
|
||||
size_t bit = length;
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
{
|
||||
const size_t byteShift = length - i - 1;
|
||||
size_t byte = (byteShift >= 8 ? 0 : static_cast<unsigned char>((value >> (byteShift * 8)) & 0xff));
|
||||
byte |= (bit > 0 && bit <= 8 ? (1 << (8 - bit)) : 0);
|
||||
bit -= 8;
|
||||
|
||||
buffer[i] = static_cast<unsigned char>(byte);
|
||||
}
|
||||
|
||||
*size = length;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
namespace EBML {
|
||||
namespace {
|
||||
class CWriterNode final
|
||||
{
|
||||
public:
|
||||
|
||||
CWriterNode(const CIdentifier& identifier, CWriterNode* parentNode) : m_ID(identifier), m_ParentNode(parentNode) {}
|
||||
~CWriterNode();
|
||||
void process(IWriterCallback& callback);
|
||||
|
||||
protected:
|
||||
|
||||
size_t getTotalContentSize(bool identifierAndSize);
|
||||
|
||||
private:
|
||||
|
||||
CWriterNode() = delete;
|
||||
|
||||
public:
|
||||
|
||||
CIdentifier m_ID;
|
||||
CWriterNode* m_ParentNode = nullptr;
|
||||
size_t m_BufferLength = 0;
|
||||
unsigned char* m_Buffer = nullptr;
|
||||
bool m_Buffered = false;
|
||||
std::vector<CWriterNode*> m_Childrens;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
CWriterNode::~CWriterNode()
|
||||
{
|
||||
for (auto i = m_Childrens.begin(); i != m_Childrens.end(); ++i) { delete (*i); }
|
||||
|
||||
if (m_Buffer)
|
||||
{
|
||||
delete [] m_Buffer;
|
||||
m_Buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CWriterNode::process(IWriterCallback& callback)
|
||||
{
|
||||
unsigned char id[10];
|
||||
unsigned char pContentSize[10];
|
||||
size_t contentSizeLength = sizeof(pContentSize);
|
||||
size_t identifierLength = sizeof(id);
|
||||
const size_t contentSize = getTotalContentSize(false);
|
||||
|
||||
if (!getCodedBuffer(contentSize, pContentSize, &contentSizeLength)) { } // SHOULD NEVER HAPPEN
|
||||
if (!getCodedBuffer(m_ID, id, &identifierLength)) { } // SHOULD NEVER HAPPEN
|
||||
|
||||
callback.write(id, identifierLength);
|
||||
callback.write(pContentSize, contentSizeLength);
|
||||
|
||||
if (m_Childrens.empty()) { callback.write(m_Buffer, m_BufferLength); }
|
||||
else { for (auto i = m_Childrens.begin(); i != m_Childrens.end(); ++i) { (*i)->process(callback); } }
|
||||
}
|
||||
|
||||
size_t CWriterNode::getTotalContentSize(const bool identifierAndSize)
|
||||
{
|
||||
size_t contentSize = 0;
|
||||
if (m_Childrens.empty()) { contentSize = m_BufferLength; }
|
||||
else { for (auto i = m_Childrens.begin(); i != m_Childrens.end(); ++i) { contentSize += (*i)->getTotalContentSize(true); } }
|
||||
|
||||
size_t res = contentSize;
|
||||
if (identifierAndSize)
|
||||
{
|
||||
res += getCodedSizeLength(m_ID);
|
||||
res += getCodedSizeLength(contentSize);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
namespace {
|
||||
class CWriter final : public IWriter
|
||||
{
|
||||
public:
|
||||
|
||||
explicit CWriter(IWriterCallback& callback) : m_callback(callback) {}
|
||||
bool openChild(const CIdentifier& identifier) override;
|
||||
bool setChildData(const void* buffer, const size_t size) override;
|
||||
bool closeChild() override;
|
||||
void release() override;
|
||||
|
||||
protected:
|
||||
|
||||
CWriterNode* m_node = nullptr;
|
||||
IWriterCallback& m_callback;
|
||||
|
||||
private:
|
||||
CWriter() = delete;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool CWriter::openChild(const CIdentifier& identifier)
|
||||
{
|
||||
if (m_node) { if (m_node->m_Buffered) { return false; } }
|
||||
|
||||
CWriterNode* pResult = new CWriterNode(identifier, m_node);
|
||||
if (m_node) { m_node->m_Childrens.push_back(pResult); }
|
||||
m_node = pResult;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWriter::setChildData(const void* buffer, const size_t size)
|
||||
{
|
||||
if (!m_node) { return false; }
|
||||
|
||||
if (!m_node->m_Childrens.empty()) { return false; }
|
||||
|
||||
unsigned char* bufferCopy = nullptr;
|
||||
if (size)
|
||||
{
|
||||
if (!buffer) { return false; }
|
||||
bufferCopy = new unsigned char[size];
|
||||
if (!bufferCopy) { return false; }
|
||||
memcpy(bufferCopy, buffer, size);
|
||||
}
|
||||
|
||||
delete [] m_node->m_Buffer;
|
||||
|
||||
m_node->m_BufferLength = size;
|
||||
m_node->m_Buffer = bufferCopy;
|
||||
m_node->m_Buffered = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CWriter::closeChild()
|
||||
{
|
||||
if (!m_node) { return false; }
|
||||
|
||||
if ((!m_node->m_Buffered) && (m_node->m_Childrens.empty()))
|
||||
{
|
||||
m_node->m_BufferLength = 0;
|
||||
m_node->m_Buffer = nullptr;
|
||||
m_node->m_Buffered = true;
|
||||
}
|
||||
|
||||
CWriterNode* parent = m_node->m_ParentNode;
|
||||
if (!parent)
|
||||
{
|
||||
m_node->process(m_callback);
|
||||
delete m_node;
|
||||
}
|
||||
|
||||
m_node = parent;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CWriter::release()
|
||||
{
|
||||
while (m_node) { closeChild(); }
|
||||
delete this;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
EBML_API IWriter* createWriter(IWriterCallback& callback) { return new CWriter(callback); }
|
||||
|
||||
} // namespace EBML
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "ebml/IWriterHelper.h"
|
||||
#include "ebml/IWriter.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace EBML {
|
||||
namespace {
|
||||
class CWriterHelper final : public IWriterHelper
|
||||
{
|
||||
public:
|
||||
|
||||
CWriterHelper() { }
|
||||
bool connect(IWriter* writer) override;
|
||||
bool disconnect() override;
|
||||
bool openChild(const CIdentifier& identifier) override;
|
||||
bool closeChild() override;
|
||||
bool setInt(const int64_t value) override;
|
||||
bool setUInt(const uint64_t value) override;
|
||||
bool setFloat(const float value) override;
|
||||
bool setDouble(const double value) override;
|
||||
bool setBinary(const void* buffer, const size_t size) override;
|
||||
bool setStr(const char* value) override;
|
||||
void release() override;
|
||||
|
||||
protected:
|
||||
|
||||
IWriter* m_writer = nullptr;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool CWriterHelper::connect(IWriter* writer)
|
||||
{
|
||||
m_writer = writer;
|
||||
return m_writer ? true : false;
|
||||
}
|
||||
|
||||
bool CWriterHelper::disconnect()
|
||||
{
|
||||
if (!m_writer) { return false; }
|
||||
m_writer = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool CWriterHelper::openChild(const CIdentifier& identifier) { return m_writer ? m_writer->openChild(identifier) : false; }
|
||||
|
||||
bool CWriterHelper::closeChild() { return m_writer ? m_writer->closeChild() : false; }
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
bool CWriterHelper::setInt(const int64_t value)
|
||||
{
|
||||
unsigned char buffer[8];
|
||||
|
||||
size_t size = 8;
|
||||
if (value == 0x00000000000000LL) { size = 0; }
|
||||
else if (value >= -0x00000000000080LL && value <= 0x0000000000007fLL) { size = 1; }
|
||||
else if (value >= -0x00000000008000LL && value <= 0x00000000007fffLL) { size = 2; }
|
||||
else if (value >= -0x00000000800000LL && value <= 0x000000007fffffLL) { size = 3; }
|
||||
else if (value >= -0x00000080000000LL && value <= 0x0000007fffffffLL) { size = 4; }
|
||||
else if (value >= -0x00008000000000LL && value <= 0x00007fffffffffLL) { size = 5; }
|
||||
else if (value >= -0x00800000000000LL && value <= 0x007fffffffffffLL) { size = 6; }
|
||||
else if (value >= -0x80000000000000LL && value <= 0x7fffffffffffffLL) { size = 7; }
|
||||
//else { size = 8; }
|
||||
|
||||
for (size_t i = 0; i < size; ++i) { buffer[size - i - 1] = static_cast<unsigned char>((value >> (i * 8)) & 0xff); }
|
||||
|
||||
return m_writer->setChildData(buffer, size);
|
||||
}
|
||||
|
||||
bool CWriterHelper::setUInt(const uint64_t value)
|
||||
{
|
||||
size_t size = 8;
|
||||
unsigned char buffer[8];
|
||||
|
||||
if (value == 0x000000000000000LL) { size = 0; }
|
||||
else if (value < 0x000000000000100LL) { size = 1; }
|
||||
else if (value < 0x000000000010000LL) { size = 2; }
|
||||
else if (value < 0x000000001000000LL) { size = 3; }
|
||||
else if (value < 0x000000100000000LL) { size = 4; }
|
||||
else if (value < 0x000010000000000LL) { size = 5; }
|
||||
else if (value < 0x001000000000000LL) { size = 6; }
|
||||
else if (value < 0x100000000000000LL) { size = 7; }
|
||||
|
||||
for (size_t i = 0; i < size; ++i) { buffer[size - i - 1] = static_cast<unsigned char>((value >> (i * 8)) & 0xff); }
|
||||
|
||||
return m_writer->setChildData(buffer, size);
|
||||
}
|
||||
|
||||
bool CWriterHelper::setFloat(const float value)
|
||||
{
|
||||
uint32_t res;
|
||||
unsigned char buffer[8];
|
||||
memcpy(&res, &value, sizeof(value));
|
||||
|
||||
const size_t size = (value != 0 ? 4 : 0);
|
||||
for (size_t i = 0; i < size; ++i) { buffer[size - i - 1] = static_cast<unsigned char>((res >> (i * 8)) & 0xff); }
|
||||
return m_writer->setChildData(buffer, size);
|
||||
}
|
||||
|
||||
bool CWriterHelper::setDouble(const double value)
|
||||
{
|
||||
uint64_t res;
|
||||
unsigned char buffer[8];
|
||||
memcpy(&res, &value, sizeof(value));
|
||||
const size_t size = (value != 0 ? 8 : 0);
|
||||
for (size_t i = 0; i < size; ++i) { buffer[size - i - 1] = static_cast<unsigned char>((res >> (i * 8)) & 0xff); }
|
||||
return m_writer->setChildData(buffer, size);
|
||||
}
|
||||
|
||||
bool CWriterHelper::setBinary(const void* buffer, const size_t size) { return m_writer->setChildData(buffer, size); }
|
||||
|
||||
bool CWriterHelper::setStr(const char* value) { return m_writer->setChildData(value, strlen(value)); }
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
void CWriterHelper::release() { delete this; }
|
||||
|
||||
// ________________________________________________________________________________________________________________
|
||||
//
|
||||
|
||||
EBML_API IWriterHelper* createWriterHelper() { return new CWriterHelper(); }
|
||||
|
||||
} // namespace EBML
|
||||
Reference in New Issue
Block a user