Merge remote-tracking branch 'official/master' into contrib
commit
6eebf8455a
|
@ -10,8 +10,8 @@ endif(NOT BUILD_SHARED_LIBS)
|
||||||
|
|
||||||
# Define here the needed parameters
|
# Define here the needed parameters
|
||||||
set (ASSIMP_VERSION_MAJOR 3)
|
set (ASSIMP_VERSION_MAJOR 3)
|
||||||
set (ASSIMP_VERSION_MINOR 1)
|
set (ASSIMP_VERSION_MINOR 2)
|
||||||
set (ASSIMP_VERSION_PATCH 1) # subversion revision?
|
set (ASSIMP_VERSION_PATCH 0) # subversion revision?
|
||||||
set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
|
set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
|
||||||
set (ASSIMP_SOVERSION 3)
|
set (ASSIMP_SOVERSION 3)
|
||||||
set (PROJECT_VERSION "${ASSIMP_VERSION}")
|
set (PROJECT_VERSION "${ASSIMP_VERSION}")
|
||||||
|
@ -27,6 +27,7 @@ execute_process(
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
OUTPUT_VARIABLE GIT_BRANCH
|
OUTPUT_VARIABLE GIT_BRANCH
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the latest abbreviated commit hash of the working branch
|
# Get the latest abbreviated commit hash of the working branch
|
||||||
|
@ -35,6 +36,7 @@ execute_process(
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
)
|
)
|
||||||
|
|
||||||
if(NOT GIT_COMMIT_HASH)
|
if(NOT GIT_COMMIT_HASH)
|
||||||
|
@ -63,7 +65,9 @@ if( CMAKE_COMPILER_IS_MINGW )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
|
if((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") # this is a very important switch and some libraries seem now to have it....
|
if (BUILD_SHARED_LIBS AND CMAKE_SIZEOF_VOID_P EQUAL 8) # -fPIC is only required for shared libs on 64 bit
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||||
|
endif()
|
||||||
# hide all not-exported symbols
|
# hide all not-exported symbols
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall" )
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall" )
|
||||||
elseif(MSVC)
|
elseif(MSVC)
|
||||||
|
@ -119,7 +123,9 @@ IF ( ASSIMP_ENABLE_BOOST_WORKAROUND )
|
||||||
MESSAGE( STATUS "Building a non-boost version of Assimp." )
|
MESSAGE( STATUS "Building a non-boost version of Assimp." )
|
||||||
ELSE ( ASSIMP_ENABLE_BOOST_WORKAROUND )
|
ELSE ( ASSIMP_ENABLE_BOOST_WORKAROUND )
|
||||||
SET( Boost_DETAILED_FAILURE_MSG ON )
|
SET( Boost_DETAILED_FAILURE_MSG ON )
|
||||||
SET( Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48.0" "1.48" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52.0" "1.53.0" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" )
|
IF ( NOT Boost_ADDITIONAL_VERSIONS )
|
||||||
|
SET( Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48.0" "1.48" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52.0" "1.53.0" "1.54.0" "1.55" "1.55.0" "1.56" "1.56.0" "1.57" "1.57.0" "1.58" "1.58.0" "1.59" "1.59.0")
|
||||||
|
ENDIF ( NOT Boost_ADDITIONAL_VERSIONS )
|
||||||
FIND_PACKAGE( Boost )
|
FIND_PACKAGE( Boost )
|
||||||
IF ( NOT Boost_FOUND )
|
IF ( NOT Boost_FOUND )
|
||||||
MESSAGE( FATAL_ERROR
|
MESSAGE( FATAL_ERROR
|
||||||
|
|
15
INSTALL
15
INSTALL
|
@ -33,13 +33,12 @@ CMake is the preferred build system for Assimp. The minimum required version
|
||||||
is 2.6. If you don't have it yet, downloads for CMake can be found on
|
is 2.6. If you don't have it yet, downloads for CMake can be found on
|
||||||
http://www.cmake.org/.
|
http://www.cmake.org/.
|
||||||
|
|
||||||
Building Assimp with CMake is 'business as usual' if you've used CMake
|
For Unix:
|
||||||
before. All steps can be done either on the command line / shell or
|
|
||||||
by using the CMake GUI tool, the choice is up to you.
|
|
||||||
|
|
||||||
First, invoke CMake to generate build files for a particular
|
|
||||||
toolchain (for standard GNU makefiles: cmake -G 'Unix Makefiles').
|
|
||||||
Afterwards, use the generated build files to perform the actual
|
|
||||||
build.
|
|
||||||
|
|
||||||
|
1. cmake CMakeLists.txt -G 'Unix Makefiles'
|
||||||
|
2. make
|
||||||
|
|
||||||
|
For Windows:
|
||||||
|
1. Open a command prompt
|
||||||
|
2. cmake CMakeLists.txt
|
||||||
|
2. Open your default IDE and build it
|
||||||
|
|
|
@ -61,6 +61,7 @@ __Importers__:
|
||||||
- Ogre XML
|
- Ogre XML
|
||||||
- Q3D
|
- Q3D
|
||||||
- ASSBIN (Assimp custom format)
|
- ASSBIN (Assimp custom format)
|
||||||
|
- glTF
|
||||||
|
|
||||||
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
|
Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
|
||||||
|
|
||||||
|
@ -76,6 +77,7 @@ __Exporters__:
|
||||||
- 3DS
|
- 3DS
|
||||||
- JSON (for WebGl, via https://github.com/acgessler/assimp2json)
|
- JSON (for WebGl, via https://github.com/acgessler/assimp2json)
|
||||||
- ASSBIN
|
- ASSBIN
|
||||||
|
- glTF
|
||||||
|
|
||||||
### Building ###
|
### Building ###
|
||||||
|
|
||||||
|
@ -113,6 +115,9 @@ If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflo
|
||||||
For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
|
For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
|
||||||
[(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
|
[(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
|
||||||
|
|
||||||
|
And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type
|
||||||
|
> /join #assetimporterlib
|
||||||
|
|
||||||
### Contributing ###
|
### Contributing ###
|
||||||
|
|
||||||
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
|
Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
|
||||||
|
@ -126,3 +131,6 @@ An _informal_ summary is: do whatever you want, but include Assimp's license tex
|
||||||
and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp.
|
and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp.
|
||||||
For the legal details, see the `LICENSE` file.
|
For the legal details, see the `LICENSE` file.
|
||||||
|
|
||||||
|
### Why this name ###
|
||||||
|
|
||||||
|
Sorry, we're germans :-), no english native speakers ...
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# AppVeyor file
|
# AppVeyor file
|
||||||
# http://www.appveyor.com/docs/appveyor-yml
|
# http://www.appveyor.com/docs/appveyor-yml
|
||||||
|
|
||||||
# Operating system (build VM template)
|
|
||||||
os: Previous Windows Server 2012 R2 # using previous worker images since default worker has problem installing DART-Prerequisites.msi
|
|
||||||
|
|
||||||
# clone directory
|
# clone directory
|
||||||
clone_folder: c:\projects\assimp
|
clone_folder: c:\projects\assimp
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ if(WIN32) # The only platform it makes sense to check for DirectX SDK
|
||||||
"C:/Program Files (x86)/Microsoft DirectX SDK*"
|
"C:/Program Files (x86)/Microsoft DirectX SDK*"
|
||||||
"C:/apps/Microsoft DirectX SDK*"
|
"C:/apps/Microsoft DirectX SDK*"
|
||||||
"C:/Program Files/Microsoft DirectX SDK*"
|
"C:/Program Files/Microsoft DirectX SDK*"
|
||||||
|
"C:/Program Files (x86)/Windows Kits/8.1"
|
||||||
"$ENV{ProgramFiles}/Microsoft DirectX SDK*"
|
"$ENV{ProgramFiles}/Microsoft DirectX SDK*"
|
||||||
)
|
)
|
||||||
create_search_paths(DirectX)
|
create_search_paths(DirectX)
|
||||||
|
|
|
@ -138,7 +138,7 @@ struct Bone
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Construction from an existing name
|
//! Construction from an existing name
|
||||||
Bone( const std::string& name)
|
explicit Bone( const std::string& name)
|
||||||
: mName (name)
|
: mName (name)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ struct BaseNode
|
||||||
enum Type {Light, Camera, Mesh, Dummy} mType;
|
enum Type {Light, Camera, Mesh, Dummy} mType;
|
||||||
|
|
||||||
//! Constructor. Creates a default name for the node
|
//! Constructor. Creates a default name for the node
|
||||||
BaseNode(Type _mType)
|
explicit BaseNode(Type _mType)
|
||||||
: mType (_mType)
|
: mType (_mType)
|
||||||
, mProcessed (false)
|
, mProcessed (false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,7 +110,7 @@ static boost::mutex gLogStreamMutex;
|
||||||
class LogToCallbackRedirector : public LogStream
|
class LogToCallbackRedirector : public LogStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LogToCallbackRedirector(const aiLogStream& s)
|
explicit LogToCallbackRedirector(const aiLogStream& s)
|
||||||
: stream (s) {
|
: stream (s) {
|
||||||
ai_assert(NULL != s.callback);
|
ai_assert(NULL != s.callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,13 +59,38 @@ ASSIMP_API size_t aiGetExportFormatCount(void)
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex)
|
ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index)
|
||||||
{
|
{
|
||||||
// Note: this is valid as the index always pertains to a builtin exporter,
|
// Note: this is valid as the index always pertains to a built-in exporter,
|
||||||
// for which the returned structure is guaranteed to be of static storage duration.
|
// for which the returned structure is guaranteed to be of static storage duration.
|
||||||
return Exporter().GetExportFormatDescription(pIndex);
|
Exporter exporter;
|
||||||
|
const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) );
|
||||||
|
if (NULL == orig) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aiExportFormatDesc *desc = new aiExportFormatDesc;
|
||||||
|
desc->description = new char[ strlen( orig->description ) + 1 ];
|
||||||
|
::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) );
|
||||||
|
desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ];
|
||||||
|
::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) );
|
||||||
|
desc->id = new char[ strlen( orig->id ) + 1 ];
|
||||||
|
::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) );
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) {
|
||||||
|
if (NULL == desc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] desc->description;
|
||||||
|
delete [] desc->fileExtension;
|
||||||
|
delete [] desc->id;
|
||||||
|
delete desc;
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
|
ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
|
||||||
|
|
|
@ -83,7 +83,7 @@ class BVHLoader : public BaseImporter
|
||||||
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
|
||||||
|
|
||||||
Node() { }
|
Node() { }
|
||||||
Node( const aiNode* pNode) : mNode( pNode) { }
|
explicit Node( const aiNode* pNode) : mNode( pNode) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -63,7 +63,7 @@ using namespace Assimp;
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
BaseImporter::BaseImporter()
|
BaseImporter::BaseImporter()
|
||||||
: progress()
|
: m_progress()
|
||||||
{
|
{
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ BaseImporter::~BaseImporter()
|
||||||
// Imports the given file and returns the imported data.
|
// Imports the given file and returns the imported data.
|
||||||
aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
|
aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
progress = pImp->GetProgressHandler();
|
m_progress = pImp->GetProgressHandler();
|
||||||
ai_assert(progress);
|
ai_assert(m_progress);
|
||||||
|
|
||||||
// Gather configuration properties for this run
|
// Gather configuration properties for this run
|
||||||
SetupProperties( pImp );
|
SetupProperties( pImp );
|
||||||
|
@ -98,8 +98,8 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
|
||||||
|
|
||||||
} catch( const std::exception& err ) {
|
} catch( const std::exception& err ) {
|
||||||
// extract error description
|
// extract error description
|
||||||
mErrorText = err.what();
|
m_ErrorText = err.what();
|
||||||
DefaultLogger::get()->error(mErrorText);
|
DefaultLogger::get()->error(m_ErrorText);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
|
||||||
|
|
||||||
for (unsigned int i = 0; i < num; ++i) {
|
for (unsigned int i = 0; i < num; ++i) {
|
||||||
// also check against big endian versions of tokens with size 2,4
|
// also check against big endian versions of tokens with size 2,4
|
||||||
// that's just for convinience, the chance that we cause conflicts
|
// that's just for convenience, the chance that we cause conflicts
|
||||||
// is quite low and it can save some lines and prevent nasty bugs
|
// is quite low and it can save some lines and prevent nasty bugs
|
||||||
if (2 == size) {
|
if (2 == size) {
|
||||||
uint16_t rev = *magic_u16;
|
uint16_t rev = *magic_u16;
|
||||||
|
|
|
@ -70,7 +70,7 @@ class IOStream;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ScopeGuard
|
struct ScopeGuard
|
||||||
{
|
{
|
||||||
ScopeGuard(T* obj) : obj(obj), mdismiss() {}
|
explicit ScopeGuard(T* obj) : obj(obj), mdismiss() {}
|
||||||
~ScopeGuard () throw() {
|
~ScopeGuard () throw() {
|
||||||
if (!mdismiss) {
|
if (!mdismiss) {
|
||||||
delete obj;
|
delete obj;
|
||||||
|
@ -181,7 +181,7 @@ public:
|
||||||
* string if there was no error.
|
* string if there was no error.
|
||||||
*/
|
*/
|
||||||
const std::string& GetErrorText() const {
|
const std::string& GetErrorText() const {
|
||||||
return mErrorText;
|
return m_ErrorText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
@ -359,13 +359,34 @@ public: // static utilities
|
||||||
IOStream* stream,
|
IOStream* stream,
|
||||||
std::vector<char>& data);
|
std::vector<char>& data);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Utility function to move a std::vector into a aiScene array
|
||||||
|
* @param vec The vector to be moved
|
||||||
|
* @param out The output pointer to the allocated array.
|
||||||
|
* @param numOut The output count of elements copied. */
|
||||||
|
template<typename T>
|
||||||
|
AI_FORCE_INLINE
|
||||||
|
static void CopyVector(
|
||||||
|
std::vector<T>& vec,
|
||||||
|
T*& out,
|
||||||
|
unsigned int& outLength)
|
||||||
|
{
|
||||||
|
outLength = vec.size();
|
||||||
|
if (outLength) {
|
||||||
|
out = new T[outLength];
|
||||||
|
std::swap_ranges(vec.begin(), vec.end(), out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** Error description in case there was one. */
|
/** Error description in case there was one. */
|
||||||
std::string mErrorText;
|
std::string m_ErrorText;
|
||||||
|
|
||||||
/** Currently set progress handler */
|
/** Currently set progress handler */
|
||||||
ProgressHandler* progress;
|
ProgressHandler* m_progress;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct THeapData : public Base
|
struct THeapData : public Base
|
||||||
{
|
{
|
||||||
THeapData(T* in)
|
explicit THeapData(T* in)
|
||||||
: data (in)
|
: data (in)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct TStaticData : public Base
|
struct TStaticData : public Base
|
||||||
{
|
{
|
||||||
TStaticData(T in)
|
explicit TStaticData(T in)
|
||||||
: data (in)
|
: data (in)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,12 @@ namespace Assimp {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline std::size_t Copy(uint8_t* data, T& field) {
|
inline std::size_t Copy(uint8_t* data, T& field) {
|
||||||
|
#ifdef AI_BUILD_BIG_ENDIAN
|
||||||
|
T field_swapped=AI_BE(field);
|
||||||
|
std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field);
|
||||||
|
#else
|
||||||
std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
|
std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bitmap::WriteHeader(Header& header, IOStream* file) {
|
void Bitmap::WriteHeader(Header& header, IOStream* file) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ class CIOStreamWrapper : public IOStream
|
||||||
friend class CIOSystemWrapper;
|
friend class CIOSystemWrapper;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CIOStreamWrapper(aiFile* pFile)
|
explicit CIOStreamWrapper(aiFile* pFile)
|
||||||
: mFile(pFile)
|
: mFile(pFile)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ private:
|
||||||
class CIOSystemWrapper : public IOSystem
|
class CIOSystemWrapper : public IOSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CIOSystemWrapper(aiFileIO* pFile)
|
explicit CIOSystemWrapper(aiFileIO* pFile)
|
||||||
: mFileSystem(pFile)
|
: mFileSystem(pFile)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -562,6 +562,19 @@ ADD_ASSIMP_IMPORTER(X
|
||||||
XFileExporter.cpp
|
XFileExporter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ADD_ASSIMP_IMPORTER(GLTF
|
||||||
|
glTFAsset.h
|
||||||
|
glTFAsset.inl
|
||||||
|
glTFAssetWriter.h
|
||||||
|
glTFAssetWriter.inl
|
||||||
|
|
||||||
|
glTFImporter.cpp
|
||||||
|
glTFImporter.h
|
||||||
|
|
||||||
|
glTFExporter.h
|
||||||
|
glTFExporter.cpp
|
||||||
|
)
|
||||||
|
|
||||||
SET( Step_SRCS
|
SET( Step_SRCS
|
||||||
StepExporter.h
|
StepExporter.h
|
||||||
StepExporter.cpp
|
StepExporter.cpp
|
||||||
|
@ -632,15 +645,20 @@ SOURCE_GROUP( unzip FILES ${unzip_SRCS})
|
||||||
SET ( openddl_parser_SRCS
|
SET ( openddl_parser_SRCS
|
||||||
../contrib/openddlparser/code/OpenDDLParser.cpp
|
../contrib/openddlparser/code/OpenDDLParser.cpp
|
||||||
../contrib/openddlparser/code/DDLNode.cpp
|
../contrib/openddlparser/code/DDLNode.cpp
|
||||||
|
../contrib/openddlparser/code/OpenDDLCommon.cpp
|
||||||
|
../contrib/openddlparser/code/OpenDDLExport.cpp
|
||||||
../contrib/openddlparser/code/Value.cpp
|
../contrib/openddlparser/code/Value.cpp
|
||||||
../contrib/openddlparser/include/openddlparser/OpenDDLParser.h
|
../contrib/openddlparser/include/openddlparser/OpenDDLParser.h
|
||||||
../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
|
../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
|
||||||
../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
|
../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
|
||||||
|
../contrib/openddlparser/include/openddlparser/OpenDDLExport.h
|
||||||
../contrib/openddlparser/include/openddlparser/DDLNode.h
|
../contrib/openddlparser/include/openddlparser/DDLNode.h
|
||||||
../contrib/openddlparser/include/openddlparser/Value.h
|
../contrib/openddlparser/include/openddlparser/Value.h
|
||||||
)
|
)
|
||||||
SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
|
SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" )
|
||||||
|
|
||||||
# VC2010 fixes
|
# VC2010 fixes
|
||||||
if(MSVC10)
|
if(MSVC10)
|
||||||
option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
|
option( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF )
|
||||||
|
@ -766,7 +784,7 @@ INSTALL( TARGETS assimp
|
||||||
INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
|
INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
|
||||||
INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
|
INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
|
||||||
if (ASSIMP_ANDROID_JNIIOSYSTEM)
|
if (ASSIMP_ANDROID_JNIIOSYSTEM)
|
||||||
INSTALL(FILES ${HEADER_PATH}/../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
|
INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
|
||||||
DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
|
DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
|
||||||
COMPONENT assimp-dev)
|
COMPONENT assimp-dev)
|
||||||
endif(ASSIMP_ANDROID_JNIIOSYSTEM)
|
endif(ASSIMP_ANDROID_JNIIOSYSTEM)
|
||||||
|
|
|
@ -65,27 +65,46 @@ using namespace Assimp::Collada;
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
|
ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
|
||||||
: mFileName( pFile )
|
: mFileName( pFile )
|
||||||
|
, mReader( NULL )
|
||||||
|
, mDataLibrary()
|
||||||
|
, mAccessorLibrary()
|
||||||
|
, mMeshLibrary()
|
||||||
|
, mNodeLibrary()
|
||||||
|
, mImageLibrary()
|
||||||
|
, mEffectLibrary()
|
||||||
|
, mMaterialLibrary()
|
||||||
|
, mLightLibrary()
|
||||||
|
, mCameraLibrary()
|
||||||
|
, mControllerLibrary()
|
||||||
|
, mRootNode( NULL )
|
||||||
|
, mAnims()
|
||||||
|
, mUnitSize( 1.0f )
|
||||||
|
, mUpDirection( UP_Y )
|
||||||
|
, mFormat(FV_1_5_n ) // We assume the newest file format by default
|
||||||
{
|
{
|
||||||
mRootNode = NULL;
|
// validate io-handler instance
|
||||||
mUnitSize = 1.0f;
|
if ( NULL == pIOHandler ) {
|
||||||
mUpDirection = UP_Y;
|
throw DeadlyImportError("IOSystem is NULL." );
|
||||||
|
}
|
||||||
// We assume the newest file format by default
|
|
||||||
mFormat = FV_1_5_n;
|
|
||||||
|
|
||||||
// open the file
|
// open the file
|
||||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile ) );
|
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile ) );
|
||||||
if( file.get() == NULL)
|
if ( file.get() == NULL ) {
|
||||||
throw DeadlyImportError( "Failed to open file " + pFile + "." );
|
throw DeadlyImportError( "Failed to open file " + pFile + "." );
|
||||||
|
}
|
||||||
|
|
||||||
// generate a XML reader for it
|
// generate a XML reader for it
|
||||||
boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
|
boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
|
||||||
mReader = irr::io::createIrrXMLReader( mIOWrapper.get());
|
mReader = irr::io::createIrrXMLReader( mIOWrapper.get());
|
||||||
if( !mReader)
|
if (!mReader) {
|
||||||
ThrowException("Collada: Unable to open file.");
|
ThrowException("Collada: Unable to open file.");
|
||||||
|
}
|
||||||
|
|
||||||
// start reading
|
// start reading
|
||||||
ReadContents();
|
ReadContents();
|
||||||
|
|
||||||
|
// release file after import
|
||||||
|
//pIOHandler->Close( file.get() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1514,7 +1533,7 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
|
||||||
// don't care for remaining stuff
|
// don't care for remaining stuff
|
||||||
SkipElement( "surface");
|
SkipElement( "surface");
|
||||||
}
|
}
|
||||||
else if( IsElement( "sampler2D"))
|
else if( IsElement( "sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat))
|
||||||
{
|
{
|
||||||
// surface ID is given inside <source> tags
|
// surface ID is given inside <source> tags
|
||||||
TestOpening( "source");
|
TestOpening( "source");
|
||||||
|
@ -1525,6 +1544,19 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam)
|
||||||
|
|
||||||
// don't care for remaining stuff
|
// don't care for remaining stuff
|
||||||
SkipElement( "sampler2D");
|
SkipElement( "sampler2D");
|
||||||
|
}
|
||||||
|
else if( IsElement( "sampler2D"))
|
||||||
|
{
|
||||||
|
// surface ID is given inside <instance_image> tags
|
||||||
|
TestOpening( "instance_image");
|
||||||
|
int attrURL = GetAttribute("url");
|
||||||
|
const char* url = mReader->getAttributeValue( attrURL);
|
||||||
|
if( url[0] != '#')
|
||||||
|
ThrowException( "Unsupported URL format in instance_image");
|
||||||
|
url++;
|
||||||
|
pParam.mType = Param_Sampler;
|
||||||
|
pParam.mReference = url;
|
||||||
|
SkipElement( "sampler2D");
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
// ignore unknown element
|
// ignore unknown element
|
||||||
|
|
|
@ -125,7 +125,7 @@ private:
|
||||||
// temporary structure to describe a mapping
|
// temporary structure to describe a mapping
|
||||||
struct MappingInfo
|
struct MappingInfo
|
||||||
{
|
{
|
||||||
MappingInfo(aiTextureMapping _type)
|
explicit MappingInfo(aiTextureMapping _type)
|
||||||
: type (_type)
|
: type (_type)
|
||||||
, axis (0.f,1.f,0.f)
|
, axis (0.f,1.f,0.f)
|
||||||
, uv (0u)
|
, uv (0u)
|
||||||
|
|
|
@ -135,7 +135,7 @@ inline void MakeAbsolutePath (const char* in, char* _out)
|
||||||
{
|
{
|
||||||
ai_assert(in && _out);
|
ai_assert(in && _out);
|
||||||
char* ret;
|
char* ret;
|
||||||
#ifdef _WIN32
|
#if defined( _MSC_VER ) || defined( __MINGW32__ )
|
||||||
ret = ::_fullpath( _out, in, PATHLIMIT );
|
ret = ::_fullpath( _out, in, PATHLIMIT );
|
||||||
#else
|
#else
|
||||||
// use realpath
|
// use realpath
|
||||||
|
@ -167,8 +167,8 @@ bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const
|
||||||
return !ASSIMP_stricmp(temp1,temp2);
|
return !ASSIMP_stricmp(temp1,temp2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string DefaultIOSystem::fileName(std::string path)
|
std::string DefaultIOSystem::fileName( const std::string &path )
|
||||||
{
|
{
|
||||||
std::string ret = path;
|
std::string ret = path;
|
||||||
std::size_t last = ret.find_last_of("\\/");
|
std::size_t last = ret.find_last_of("\\/");
|
||||||
|
@ -176,8 +176,8 @@ std::string DefaultIOSystem::fileName(std::string path)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string DefaultIOSystem::completeBaseName(std::string path)
|
std::string DefaultIOSystem::completeBaseName( const std::string &path )
|
||||||
{
|
{
|
||||||
std::string ret = fileName(path);
|
std::string ret = fileName(path);
|
||||||
std::size_t pos = ret.find_last_of('.');
|
std::size_t pos = ret.find_last_of('.');
|
||||||
|
@ -185,8 +185,8 @@ std::string DefaultIOSystem::completeBaseName(std::string path)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
std::string DefaultIOSystem::absolutePath(std::string path)
|
std::string DefaultIOSystem::absolutePath( const std::string &path )
|
||||||
{
|
{
|
||||||
std::string ret = path;
|
std::string ret = path;
|
||||||
std::size_t last = ret.find_last_of("\\/");
|
std::size_t last = ret.find_last_of("\\/");
|
||||||
|
@ -194,4 +194,6 @@ std::string DefaultIOSystem::absolutePath(std::string path)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#undef PATHLIMIT
|
#undef PATHLIMIT
|
||||||
|
|
|
@ -80,17 +80,17 @@ public:
|
||||||
/** @brief get the file name of a full filepath
|
/** @brief get the file name of a full filepath
|
||||||
* example: /tmp/archive.tar.gz -> archive.tar.gz
|
* example: /tmp/archive.tar.gz -> archive.tar.gz
|
||||||
*/
|
*/
|
||||||
static std::string fileName(std::string path);
|
static std::string fileName( const std::string &path );
|
||||||
|
|
||||||
/** @brief get the complete base name of a full filepath
|
/** @brief get the complete base name of a full filepath
|
||||||
* example: /tmp/archive.tar.gz -> archive.tar
|
* example: /tmp/archive.tar.gz -> archive.tar
|
||||||
*/
|
*/
|
||||||
static std::string completeBaseName(std::string path);
|
static std::string completeBaseName( const std::string &path);
|
||||||
|
|
||||||
/** @brief get the path of a full filepath
|
/** @brief get the path of a full filepath
|
||||||
* example: /tmp/archive.tar.gz -> /tmp/
|
* example: /tmp/archive.tar.gz -> /tmp/
|
||||||
*/
|
*/
|
||||||
static std::string absolutePath(std::string path);
|
static std::string absolutePath( const std::string &path);
|
||||||
};
|
};
|
||||||
|
|
||||||
} //!ns Assimp
|
} //!ns Assimp
|
||||||
|
|
|
@ -87,6 +87,8 @@ void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportPro
|
||||||
void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
|
void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
|
void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||||
|
|
||||||
|
@ -135,6 +137,13 @@ Exporter::ExportFormatEntry gExporters[] =
|
||||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
|
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||||
|
Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
|
||||||
|
aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/),
|
||||||
|
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
|
||||||
|
aiProcess_JoinIdenticalVertices /*| aiProcess_SortByPType*/),
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||||
Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
|
Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "FBXUtil.h"
|
#include "FBXUtil.h"
|
||||||
#include "FBXProperties.h"
|
#include "FBXProperties.h"
|
||||||
#include "FBXImporter.h"
|
#include "FBXImporter.h"
|
||||||
|
#include "StringComparison.h"
|
||||||
#include "../include/assimp/scene.h"
|
#include "../include/assimp/scene.h"
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
#include <boost/scoped_array.hpp>
|
#include <boost/scoped_array.hpp>
|
||||||
|
@ -148,6 +149,7 @@ public:
|
||||||
std::for_each(animations.begin(),animations.end(),Util::delete_fun<aiAnimation>());
|
std::for_each(animations.begin(),animations.end(),Util::delete_fun<aiAnimation>());
|
||||||
std::for_each(lights.begin(),lights.end(),Util::delete_fun<aiLight>());
|
std::for_each(lights.begin(),lights.end(),Util::delete_fun<aiLight>());
|
||||||
std::for_each(cameras.begin(),cameras.end(),Util::delete_fun<aiCamera>());
|
std::for_each(cameras.begin(),cameras.end(),Util::delete_fun<aiCamera>());
|
||||||
|
std::for_each(textures.begin(),textures.end(),Util::delete_fun<aiTexture>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1449,6 +1451,36 @@ private:
|
||||||
return static_cast<unsigned int>(materials.size() - 1);
|
return static_cast<unsigned int>(materials.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Video -> aiTexture
|
||||||
|
unsigned int ConvertVideo(const Video& video)
|
||||||
|
{
|
||||||
|
// generate empty output texture
|
||||||
|
aiTexture* out_tex = new aiTexture();
|
||||||
|
textures.push_back(out_tex);
|
||||||
|
|
||||||
|
// assuming the texture is compressed
|
||||||
|
out_tex->mWidth = static_cast<unsigned int>(video.ContentLength()); // total data size
|
||||||
|
out_tex->mHeight = 0; // fixed to 0
|
||||||
|
|
||||||
|
// steal the data from the Video to avoid an additional copy
|
||||||
|
out_tex->pcData = reinterpret_cast<aiTexel*>( const_cast<Video&>(video).RelinquishContent() );
|
||||||
|
|
||||||
|
// try to extract a hint from the file extension
|
||||||
|
const std::string& filename = video.FileName().empty() ? video.RelativeFilename() : video.FileName();
|
||||||
|
std::string ext = BaseImporter::GetExtension(filename);
|
||||||
|
|
||||||
|
if(ext == "jpeg") {
|
||||||
|
ext = "jpg";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ext.size() <= 3) {
|
||||||
|
memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<unsigned int>(textures.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
|
||||||
|
@ -1466,6 +1498,24 @@ private:
|
||||||
aiString path;
|
aiString path;
|
||||||
path.Set(tex->RelativeFilename());
|
path.Set(tex->RelativeFilename());
|
||||||
|
|
||||||
|
const Video* media = tex->Media();
|
||||||
|
if(media != 0 && media->ContentLength() > 0) {
|
||||||
|
unsigned int index;
|
||||||
|
|
||||||
|
VideoMap::const_iterator it = textures_converted.find(media);
|
||||||
|
if(it != textures_converted.end()) {
|
||||||
|
index = (*it).second;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
index = ConvertVideo(*media);
|
||||||
|
textures_converted[media] = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||||
|
path.data[0] = '*';
|
||||||
|
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
|
||||||
|
}
|
||||||
|
|
||||||
out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0);
|
out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0);
|
||||||
|
|
||||||
aiUVTransform uvTrafo;
|
aiUVTransform uvTrafo;
|
||||||
|
@ -2496,8 +2546,9 @@ private:
|
||||||
// need to convert from TRS order to SRT?
|
// need to convert from TRS order to SRT?
|
||||||
if(reverse_order) {
|
if(reverse_order) {
|
||||||
|
|
||||||
aiVector3D def_scale, def_translate;
|
aiVector3D def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f));
|
||||||
aiQuaternion def_rot;
|
aiVector3D def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f));
|
||||||
|
aiVector3D def_rot = PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f));
|
||||||
|
|
||||||
KeyFrameListList scaling;
|
KeyFrameListList scaling;
|
||||||
KeyFrameListList translation;
|
KeyFrameListList translation;
|
||||||
|
@ -2506,24 +2557,14 @@ private:
|
||||||
if(chain[TransformationComp_Scaling] != iter_end) {
|
if(chain[TransformationComp_Scaling] != iter_end) {
|
||||||
scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop);
|
scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
def_scale = PropertyGet(props,"Lcl Scaling",aiVector3D(1.f,1.f,1.f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(chain[TransformationComp_Translation] != iter_end) {
|
if(chain[TransformationComp_Translation] != iter_end) {
|
||||||
translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop);
|
translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
def_translate = PropertyGet(props,"Lcl Translation",aiVector3D(0.f,0.f,0.f));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(chain[TransformationComp_Rotation] != iter_end) {
|
if(chain[TransformationComp_Rotation] != iter_end) {
|
||||||
rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop);
|
rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
def_rot = EulerToQuaternion(PropertyGet(props,"Lcl Rotation",aiVector3D(0.f,0.f,0.f)),
|
|
||||||
target.RotationOrder());
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyFrameListList joined;
|
KeyFrameListList joined;
|
||||||
joined.insert(joined.end(), scaling.begin(), scaling.end());
|
joined.insert(joined.end(), scaling.begin(), scaling.end());
|
||||||
|
@ -2740,7 +2781,7 @@ private:
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void InterpolateKeys(aiVectorKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs,
|
void InterpolateKeys(aiVectorKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs,
|
||||||
const bool geom,
|
const aiVector3D& def_value,
|
||||||
double& max_time,
|
double& max_time,
|
||||||
double& min_time)
|
double& min_time)
|
||||||
|
|
||||||
|
@ -2754,10 +2795,7 @@ private:
|
||||||
next_pos.resize(inputs.size(),0);
|
next_pos.resize(inputs.size(),0);
|
||||||
|
|
||||||
BOOST_FOREACH(KeyTimeList::value_type time, keys) {
|
BOOST_FOREACH(KeyTimeList::value_type time, keys) {
|
||||||
float result[3] = {0.0f, 0.0f, 0.0f};
|
float result[3] = {def_value.x, def_value.y, def_value.z};
|
||||||
if(geom) {
|
|
||||||
result[0] = result[1] = result[2] = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
for (size_t i = 0; i < count; ++i) {
|
||||||
const KeyFrameList& kfl = inputs[i];
|
const KeyFrameList& kfl = inputs[i];
|
||||||
|
@ -2782,12 +2820,7 @@ private:
|
||||||
const double factor = timeB == timeA ? 0. : static_cast<double>((time - timeA) / (timeB - timeA));
|
const double factor = timeB == timeA ? 0. : static_cast<double>((time - timeA) / (timeB - timeA));
|
||||||
const float interpValue = static_cast<float>(valueA + (valueB - valueA) * factor);
|
const float interpValue = static_cast<float>(valueA + (valueB - valueA) * factor);
|
||||||
|
|
||||||
if(geom) {
|
result[kfl.get<2>()] = interpValue;
|
||||||
result[kfl.get<2>()] *= interpValue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
result[kfl.get<2>()] += interpValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// magic value to convert fbx times to seconds
|
// magic value to convert fbx times to seconds
|
||||||
|
@ -2807,7 +2840,7 @@ private:
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void InterpolateKeys(aiQuatKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs,
|
void InterpolateKeys(aiQuatKey* valOut,const KeyTimeList& keys, const KeyFrameListList& inputs,
|
||||||
const bool geom,
|
const aiVector3D& def_value,
|
||||||
double& maxTime,
|
double& maxTime,
|
||||||
double& minTime,
|
double& minTime,
|
||||||
Model::RotOrder order)
|
Model::RotOrder order)
|
||||||
|
@ -2816,7 +2849,7 @@ private:
|
||||||
ai_assert(valOut);
|
ai_assert(valOut);
|
||||||
|
|
||||||
boost::scoped_array<aiVectorKey> temp(new aiVectorKey[keys.size()]);
|
boost::scoped_array<aiVectorKey> temp(new aiVectorKey[keys.size()]);
|
||||||
InterpolateKeys(temp.get(),keys,inputs,geom,maxTime, minTime);
|
InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime);
|
||||||
|
|
||||||
aiMatrix4x4 m;
|
aiMatrix4x4 m;
|
||||||
|
|
||||||
|
@ -2858,20 +2891,20 @@ private:
|
||||||
Model::RotOrder order,
|
Model::RotOrder order,
|
||||||
const aiVector3D& def_scale,
|
const aiVector3D& def_scale,
|
||||||
const aiVector3D& def_translate,
|
const aiVector3D& def_translate,
|
||||||
const aiQuaternion& def_rotation)
|
const aiVector3D& def_rotation)
|
||||||
{
|
{
|
||||||
if (rotation.size()) {
|
if (rotation.size()) {
|
||||||
InterpolateKeys(out_quat, times, rotation, false, maxTime, minTime, order);
|
InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (size_t i = 0; i < times.size(); ++i) {
|
for (size_t i = 0; i < times.size(); ++i) {
|
||||||
out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps;
|
out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps;
|
||||||
out_quat[i].mValue = def_rotation;
|
out_quat[i].mValue = EulerToQuaternion(def_rotation, order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scaling.size()) {
|
if (scaling.size()) {
|
||||||
InterpolateKeys(out_scale, times, scaling, true, maxTime, minTime);
|
InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (size_t i = 0; i < times.size(); ++i) {
|
for (size_t i = 0; i < times.size(); ++i) {
|
||||||
|
@ -2881,7 +2914,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translation.size()) {
|
if (translation.size()) {
|
||||||
InterpolateKeys(out_translation, times, translation, false, maxTime, minTime);
|
InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (size_t i = 0; i < times.size(); ++i) {
|
for (size_t i = 0; i < times.size(); ++i) {
|
||||||
|
@ -2935,7 +2968,7 @@ private:
|
||||||
na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
|
na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
|
||||||
na->mScalingKeys = new aiVectorKey[keys.size()];
|
na->mScalingKeys = new aiVectorKey[keys.size()];
|
||||||
if (keys.size() > 0)
|
if (keys.size() > 0)
|
||||||
InterpolateKeys(na->mScalingKeys, keys, inputs, true, maxTime, minTime);
|
InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2955,7 +2988,7 @@ private:
|
||||||
na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
|
na->mNumPositionKeys = static_cast<unsigned int>(keys.size());
|
||||||
na->mPositionKeys = new aiVectorKey[keys.size()];
|
na->mPositionKeys = new aiVectorKey[keys.size()];
|
||||||
if (keys.size() > 0)
|
if (keys.size() > 0)
|
||||||
InterpolateKeys(na->mPositionKeys, keys, inputs, false, maxTime, minTime);
|
InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2976,7 +3009,7 @@ private:
|
||||||
na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
|
na->mNumRotationKeys = static_cast<unsigned int>(keys.size());
|
||||||
na->mRotationKeys = new aiQuatKey[keys.size()];
|
na->mRotationKeys = new aiQuatKey[keys.size()];
|
||||||
if (keys.size() > 0)
|
if (keys.size() > 0)
|
||||||
InterpolateKeys(na->mRotationKeys, keys, inputs, false, maxTime, minTime, order);
|
InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3024,6 +3057,13 @@ private:
|
||||||
|
|
||||||
std::swap_ranges(cameras.begin(),cameras.end(),out->mCameras);
|
std::swap_ranges(cameras.begin(),cameras.end(),out->mCameras);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(textures.size()) {
|
||||||
|
out->mTextures = new aiTexture*[textures.size()]();
|
||||||
|
out->mNumTextures = static_cast<unsigned int>(textures.size());
|
||||||
|
|
||||||
|
std::swap_ranges(textures.begin(),textures.end(),out->mTextures);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3037,10 +3077,14 @@ private:
|
||||||
std::vector<aiAnimation*> animations;
|
std::vector<aiAnimation*> animations;
|
||||||
std::vector<aiLight*> lights;
|
std::vector<aiLight*> lights;
|
||||||
std::vector<aiCamera*> cameras;
|
std::vector<aiCamera*> cameras;
|
||||||
|
std::vector<aiTexture*> textures;
|
||||||
|
|
||||||
typedef std::map<const Material*, unsigned int> MaterialMap;
|
typedef std::map<const Material*, unsigned int> MaterialMap;
|
||||||
MaterialMap materials_converted;
|
MaterialMap materials_converted;
|
||||||
|
|
||||||
|
typedef std::map<const Video*, unsigned int> VideoMap;
|
||||||
|
VideoMap textures_converted;
|
||||||
|
|
||||||
typedef std::map<const Geometry*, std::vector<unsigned int> > MeshMap;
|
typedef std::map<const Geometry*, std::vector<unsigned int> > MeshMap;
|
||||||
MeshMap meshes_converted;
|
MeshMap meshes_converted;
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,9 @@ const Object* LazyObject::Get(bool dieOnError)
|
||||||
else if (!strncmp(obtype,"LayeredTexture",length)) {
|
else if (!strncmp(obtype,"LayeredTexture",length)) {
|
||||||
object.reset(new LayeredTexture(id,element,doc,name));
|
object.reset(new LayeredTexture(id,element,doc,name));
|
||||||
}
|
}
|
||||||
|
else if (!strncmp(obtype,"Video",length)) {
|
||||||
|
object.reset(new Video(id,element,doc,name));
|
||||||
|
}
|
||||||
else if (!strncmp(obtype,"AnimationStack",length)) {
|
else if (!strncmp(obtype,"AnimationStack",length)) {
|
||||||
object.reset(new AnimationStack(id,element,name,doc));
|
object.reset(new AnimationStack(id,element,name,doc));
|
||||||
}
|
}
|
||||||
|
@ -483,6 +486,11 @@ void Document::ReadConnections()
|
||||||
for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) {
|
||||||
const Element& el = *(*it).second;
|
const Element& el = *(*it).second;
|
||||||
const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
|
const std::string& type = ParseTokenAsString(GetRequiredToken(el,0));
|
||||||
|
|
||||||
|
// PP = property-property connection, ignored for now
|
||||||
|
// (tokens: "PP", ID1, "Property1", ID2, "Property2")
|
||||||
|
if(type == "PP") continue;
|
||||||
|
|
||||||
const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
|
const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1));
|
||||||
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
|
const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2));
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,8 @@ namespace FBX {
|
||||||
class Material;
|
class Material;
|
||||||
class Geometry;
|
class Geometry;
|
||||||
|
|
||||||
|
class Video;
|
||||||
|
|
||||||
class AnimationCurve;
|
class AnimationCurve;
|
||||||
class AnimationCurveNode;
|
class AnimationCurveNode;
|
||||||
class AnimationLayer;
|
class AnimationLayer;
|
||||||
|
@ -571,6 +573,10 @@ public:
|
||||||
return crop;
|
return crop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Video* Media() const {
|
||||||
|
return media;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
aiVector2D uvTrans;
|
aiVector2D uvTrans;
|
||||||
|
@ -583,6 +589,8 @@ private:
|
||||||
boost::shared_ptr<const PropertyTable> props;
|
boost::shared_ptr<const PropertyTable> props;
|
||||||
|
|
||||||
unsigned int crop[4];
|
unsigned int crop[4];
|
||||||
|
|
||||||
|
const Video* media;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** DOM class for layered FBX textures */
|
/** DOM class for layered FBX textures */
|
||||||
|
@ -654,6 +662,59 @@ typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
|
||||||
typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
|
typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
|
||||||
|
|
||||||
|
|
||||||
|
/** DOM class for generic FBX videos */
|
||||||
|
class Video : public Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Video(uint64_t id, const Element& element, const Document& doc, const std::string& name);
|
||||||
|
~Video();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
const std::string& Type() const {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& FileName() const {
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& RelativeFilename() const {
|
||||||
|
return relativeFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PropertyTable& Props() const {
|
||||||
|
ai_assert(props.get());
|
||||||
|
return *props.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t* Content() const {
|
||||||
|
ai_assert(content);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t ContentLength() const {
|
||||||
|
return contentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* RelinquishContent() {
|
||||||
|
uint8_t* ptr = content;
|
||||||
|
content = 0;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string type;
|
||||||
|
std::string relativeFileName;
|
||||||
|
std::string fileName;
|
||||||
|
boost::shared_ptr<const PropertyTable> props;
|
||||||
|
|
||||||
|
uint32_t contentLength;
|
||||||
|
uint8_t* content;
|
||||||
|
};
|
||||||
|
|
||||||
/** DOM class for generic FBX materials */
|
/** DOM class for generic FBX materials */
|
||||||
class Material : public Object
|
class Material : public Object
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct ImportSettings
|
||||||
, readAllLayers(true)
|
, readAllLayers(true)
|
||||||
, readAllMaterials(false)
|
, readAllMaterials(false)
|
||||||
, readMaterials(true)
|
, readMaterials(true)
|
||||||
|
, readTextures(true)
|
||||||
, readCameras(true)
|
, readCameras(true)
|
||||||
, readLights(true)
|
, readLights(true)
|
||||||
, readAnimations(true)
|
, readAnimations(true)
|
||||||
|
@ -92,6 +93,9 @@ struct ImportSettings
|
||||||
* material. The default value is true.*/
|
* material. The default value is true.*/
|
||||||
bool readMaterials;
|
bool readMaterials;
|
||||||
|
|
||||||
|
/** import embedded textures? Default value is true.*/
|
||||||
|
bool readTextures;
|
||||||
|
|
||||||
/** import cameras? Default value is true.*/
|
/** import cameras? Default value is true.*/
|
||||||
bool readCameras;
|
bool readCameras;
|
||||||
|
|
||||||
|
|
|
@ -126,6 +126,7 @@ void FBXImporter::SetupProperties(const Importer* pImp)
|
||||||
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
|
||||||
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||||
|
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||||
|
|
|
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "FBXImportSettings.h"
|
#include "FBXImportSettings.h"
|
||||||
#include "FBXDocumentUtil.h"
|
#include "FBXDocumentUtil.h"
|
||||||
#include "FBXProperties.h"
|
#include "FBXProperties.h"
|
||||||
|
#include "ByteSwapper.h"
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
@ -147,6 +148,7 @@ Material::~Material()
|
||||||
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||||
: Object(id,element,name)
|
: Object(id,element,name)
|
||||||
, uvScaling(1.0f,1.0f)
|
, uvScaling(1.0f,1.0f)
|
||||||
|
, media(0)
|
||||||
{
|
{
|
||||||
const Scope& sc = GetRequiredScope(element);
|
const Scope& sc = GetRequiredScope(element);
|
||||||
|
|
||||||
|
@ -199,6 +201,23 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const
|
||||||
}
|
}
|
||||||
|
|
||||||
props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
|
props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc);
|
||||||
|
|
||||||
|
// resolve video links
|
||||||
|
if(doc.Settings().readTextures) {
|
||||||
|
const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
|
||||||
|
BOOST_FOREACH(const Connection* con, conns) {
|
||||||
|
const Object* const ob = con->SourceObject();
|
||||||
|
if(!ob) {
|
||||||
|
DOMWarning("failed to read source object for texture link, ignoring",&element);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Video* const video = dynamic_cast<const Video*>(ob);
|
||||||
|
if(video) {
|
||||||
|
media = video;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,6 +272,68 @@ void LayeredTexture::fillTexture(const Document& doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name)
|
||||||
|
: Object(id,element,name)
|
||||||
|
, contentLength(0)
|
||||||
|
, content(0)
|
||||||
|
{
|
||||||
|
const Scope& sc = GetRequiredScope(element);
|
||||||
|
|
||||||
|
const Element* const Type = sc["Type"];
|
||||||
|
const Element* const FileName = sc["FileName"];
|
||||||
|
const Element* const RelativeFilename = sc["RelativeFilename"];
|
||||||
|
const Element* const Content = sc["Content"];
|
||||||
|
|
||||||
|
if(Type) {
|
||||||
|
type = ParseTokenAsString(GetRequiredToken(*Type,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(FileName) {
|
||||||
|
fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(RelativeFilename) {
|
||||||
|
relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Content) {
|
||||||
|
const Token& token = GetRequiredToken(*Content, 0);
|
||||||
|
const char* data = token.begin();
|
||||||
|
if(!token.IsBinary()) {
|
||||||
|
DOMWarning("video content is not binary data, ignoring", &element);
|
||||||
|
}
|
||||||
|
else if(static_cast<size_t>(token.end() - data) < 5) {
|
||||||
|
DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
|
||||||
|
}
|
||||||
|
else if(*data != 'R') {
|
||||||
|
DOMWarning("video content is not raw binary data, ignoring", &element);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// read number of elements
|
||||||
|
uint32_t len = 0;
|
||||||
|
::memcpy(&len, data + 1, sizeof(len));
|
||||||
|
AI_SWAP4(len);
|
||||||
|
|
||||||
|
contentLength = len;
|
||||||
|
|
||||||
|
content = new uint8_t[len];
|
||||||
|
::memcpy(content, data + 5, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Video::~Video()
|
||||||
|
{
|
||||||
|
if(content) {
|
||||||
|
delete[] content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} //!FBX
|
} //!FBX
|
||||||
} //!Assimp
|
} //!Assimp
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class TypedProperty : public Property
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TypedProperty(const T& value)
|
explicit TypedProperty(const T& value)
|
||||||
: value(value)
|
: value(value)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ private:
|
||||||
|
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
Animator(AT t = UNKNOWN)
|
explicit Animator(AT t = UNKNOWN)
|
||||||
: type (t)
|
: type (t)
|
||||||
, speed (0.001f)
|
, speed (0.001f)
|
||||||
, direction (0.f,1.f,0.f)
|
, direction (0.f,1.f,0.f)
|
||||||
|
@ -163,7 +163,7 @@ private:
|
||||||
ANIMMESH
|
ANIMMESH
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
Node(ET t)
|
explicit Node(ET t)
|
||||||
: type (t)
|
: type (t)
|
||||||
, scaling (1.f,1.f,1.f) // assume uniform scaling by default
|
, scaling (1.f,1.f,1.f) // assume uniform scaling by default
|
||||||
, parent()
|
, parent()
|
||||||
|
|
|
@ -491,7 +491,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
|
||||||
pHint = "";
|
pHint = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pBuffer || !pLength || strlen(pHint) > 100) {
|
if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
|
||||||
pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
|
pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -503,7 +503,8 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
|
||||||
SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength));
|
SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength));
|
||||||
|
|
||||||
// read the file and recover the previous IOSystem
|
// read the file and recover the previous IOSystem
|
||||||
char fbuff[128];
|
static const size_t BufferSize(Importer::MaxLenHint + 28);
|
||||||
|
char fbuff[ BufferSize ];
|
||||||
sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
|
sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
|
||||||
|
|
||||||
ReadFile(fbuff,pFlags);
|
ReadFile(fbuff,pFlags);
|
||||||
|
|
|
@ -167,7 +167,7 @@ public:
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Construct a batch loader from a given IO system to be used
|
/** Construct a batch loader from a given IO system to be used
|
||||||
* to acess external files */
|
* to acess external files */
|
||||||
BatchLoader(IOSystem* pIO);
|
explicit BatchLoader(IOSystem* pIO);
|
||||||
~BatchLoader();
|
~BatchLoader();
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -170,7 +170,9 @@ corresponding preprocessor flag to selectively disable formats.
|
||||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
|
||||||
# include "AssbinLoader.h"
|
# include "AssbinLoader.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||||
|
# include "glTFImporter.h"
|
||||||
|
#endif
|
||||||
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
|
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
|
||||||
# include "C4DImporter.h"
|
# include "C4DImporter.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -305,8 +307,10 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
||||||
#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
|
#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER )
|
||||||
out.push_back( new AssbinImporter() );
|
out.push_back( new AssbinImporter() );
|
||||||
#endif
|
#endif
|
||||||
|
#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER )
|
||||||
#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
|
out.push_back( new glTFImporter() );
|
||||||
|
#endif
|
||||||
|
#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER )
|
||||||
out.push_back( new C4DImporter() );
|
out.push_back( new C4DImporter() );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ struct Face : public aiFace
|
||||||
{}
|
{}
|
||||||
|
|
||||||
//! Construction from given type
|
//! Construction from given type
|
||||||
Face(uint32_t _type)
|
explicit Face(uint32_t _type)
|
||||||
: surfaceIndex (0)
|
: surfaceIndex (0)
|
||||||
, smoothGroup (0)
|
, smoothGroup (0)
|
||||||
, type (_type)
|
, type (_type)
|
||||||
|
@ -305,7 +305,7 @@ struct Face : public aiFace
|
||||||
*/
|
*/
|
||||||
struct VMapEntry
|
struct VMapEntry
|
||||||
{
|
{
|
||||||
VMapEntry(unsigned int _dims)
|
explicit VMapEntry(unsigned int _dims)
|
||||||
: dims(_dims)
|
: dims(_dims)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
|
@ -285,9 +285,6 @@ void MD5Importer::AttachChilds_Mesh(int iParentID,aiNode* piParent, BoneList& bo
|
||||||
aiQuaternion quat;
|
aiQuaternion quat;
|
||||||
MD5::ConvertQuaternion ( bones[i].mRotationQuat, quat );
|
MD5::ConvertQuaternion ( bones[i].mRotationQuat, quat );
|
||||||
|
|
||||||
// FIX to get to Assimp's quaternion conventions
|
|
||||||
quat.w *= -1.f;
|
|
||||||
|
|
||||||
bones[i].mTransform = aiMatrix4x4 ( quat.GetMatrix());
|
bones[i].mTransform = aiMatrix4x4 ( quat.GetMatrix());
|
||||||
bones[i].mTransform.a4 = bones[i].mPositionXYZ.x;
|
bones[i].mTransform.a4 = bones[i].mPositionXYZ.x;
|
||||||
bones[i].mTransform.b4 = bones[i].mPositionXYZ.y;
|
bones[i].mTransform.b4 = bones[i].mPositionXYZ.y;
|
||||||
|
@ -656,9 +653,6 @@ void MD5Importer::LoadMD5AnimFile ()
|
||||||
|
|
||||||
MD5::ConvertQuaternion(vTemp, qKey->mValue);
|
MD5::ConvertQuaternion(vTemp, qKey->mValue);
|
||||||
qKey->mTime = vKey->mTime = dTime;
|
qKey->mTime = vKey->mTime = dTime;
|
||||||
|
|
||||||
// we need this to get to Assimp quaternion conventions
|
|
||||||
qKey->mValue.w *= -1.f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,9 @@ inline void ConvertQuaternion (const aiVector3D& in, aiQuaternion& out) {
|
||||||
if (t < 0.0f)
|
if (t < 0.0f)
|
||||||
out.w = 0.0f;
|
out.w = 0.0f;
|
||||||
else out.w = std::sqrt (t);
|
else out.w = std::sqrt (t);
|
||||||
|
|
||||||
|
// Assimp convention.
|
||||||
|
out.w *= -1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -277,7 +280,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param mSections List of file sections (output of MD5Parser)
|
* @param mSections List of file sections (output of MD5Parser)
|
||||||
*/
|
*/
|
||||||
MD5MeshParser(SectionList& mSections);
|
explicit MD5MeshParser(SectionList& mSections);
|
||||||
|
|
||||||
//! List of all meshes
|
//! List of all meshes
|
||||||
MeshList mMeshes;
|
MeshList mMeshes;
|
||||||
|
@ -302,7 +305,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param mSections List of file sections (output of MD5Parser)
|
* @param mSections List of file sections (output of MD5Parser)
|
||||||
*/
|
*/
|
||||||
MD5AnimParser(SectionList& mSections);
|
explicit MD5AnimParser(SectionList& mSections);
|
||||||
|
|
||||||
|
|
||||||
//! Output frame rate
|
//! Output frame rate
|
||||||
|
@ -334,7 +337,7 @@ public:
|
||||||
*
|
*
|
||||||
* @param mSections List of file sections (output of MD5Parser)
|
* @param mSections List of file sections (output of MD5Parser)
|
||||||
*/
|
*/
|
||||||
MD5CameraParser(SectionList& mSections);
|
explicit MD5CameraParser(SectionList& mSections);
|
||||||
|
|
||||||
|
|
||||||
//! Output frame rate
|
//! Output frame rate
|
||||||
|
|
|
@ -138,9 +138,15 @@ void OFFImporter::InternReadFile( const std::string& pFile,
|
||||||
throw DeadlyImportError("OFF: There are no valid faces");
|
throw DeadlyImportError("OFF: There are no valid faces");
|
||||||
}
|
}
|
||||||
|
|
||||||
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = 1 ];
|
pScene->mNumMeshes = 1;
|
||||||
aiMesh* mesh = pScene->mMeshes[0] = new aiMesh();
|
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
|
||||||
aiFace* faces = mesh->mFaces = new aiFace [mesh->mNumFaces = numFaces];
|
|
||||||
|
aiMesh* mesh = new aiMesh();
|
||||||
|
pScene->mMeshes[0] = mesh;
|
||||||
|
|
||||||
|
mesh->mNumFaces = numFaces;
|
||||||
|
aiFace* faces = new aiFace [mesh->mNumFaces];
|
||||||
|
mesh->mFaces = faces;
|
||||||
|
|
||||||
std::vector<aiVector3D> tempPositions(numVertices);
|
std::vector<aiVector3D> tempPositions(numVertices);
|
||||||
|
|
||||||
|
@ -171,7 +177,8 @@ void OFFImporter::InternReadFile( const std::string& pFile,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sz = line;SkipSpaces(&sz);
|
sz = line;SkipSpaces(&sz);
|
||||||
if(!(faces->mNumIndices = strtoul10(sz,&sz)) || faces->mNumIndices > 9)
|
faces->mNumIndices = strtoul10(sz,&sz);
|
||||||
|
if(!(faces->mNumIndices) || faces->mNumIndices > 9)
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
|
DefaultLogger::get()->error("OFF: Faces with zero indices aren't allowed");
|
||||||
--mesh->mNumFaces;
|
--mesh->mNumFaces;
|
||||||
|
@ -185,43 +192,54 @@ void OFFImporter::InternReadFile( const std::string& pFile,
|
||||||
throw DeadlyImportError("OFF: There are no valid faces");
|
throw DeadlyImportError("OFF: There are no valid faces");
|
||||||
|
|
||||||
// allocate storage for the output vertices
|
// allocate storage for the output vertices
|
||||||
aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
std::vector<aiVector3D> verts;
|
||||||
|
verts.reserve(mesh->mNumVertices);
|
||||||
|
|
||||||
// second: now parse all face indices
|
// second: now parse all face indices
|
||||||
buffer = old;faces = mesh->mFaces;
|
buffer = old;
|
||||||
|
faces = mesh->mFaces;
|
||||||
for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
|
for (unsigned int i = 0, p = 0; i< mesh->mNumFaces;)
|
||||||
{
|
{
|
||||||
if(!GetNextLine(buffer,line))break;
|
if(!GetNextLine(buffer,line))break;
|
||||||
|
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
sz = line;SkipSpaces(&sz);
|
sz = line;SkipSpaces(&sz);
|
||||||
if(!(idx = strtoul10(sz,&sz)) || idx > 9)
|
idx = strtoul10(sz,&sz);
|
||||||
|
if(!(idx) || idx > 9)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
faces->mIndices = new unsigned int [faces->mNumIndices];
|
faces->mIndices = new unsigned int [faces->mNumIndices];
|
||||||
for (unsigned int m = 0; m < faces->mNumIndices;++m)
|
for (unsigned int m = 0; m < faces->mNumIndices;++m)
|
||||||
{
|
{
|
||||||
SkipSpaces(&sz);
|
SkipSpaces(&sz);
|
||||||
if ((idx = strtoul10(sz,&sz)) >= numVertices)
|
idx = strtoul10(sz,&sz);
|
||||||
|
if ((idx) >= numVertices)
|
||||||
{
|
{
|
||||||
DefaultLogger::get()->error("OFF: Vertex index is out of range");
|
DefaultLogger::get()->error("OFF: Vertex index is out of range");
|
||||||
idx = numVertices-1;
|
idx = numVertices-1;
|
||||||
}
|
}
|
||||||
faces->mIndices[m] = p++;
|
faces->mIndices[m] = p++;
|
||||||
*verts++ = tempPositions[idx];
|
verts.push_back(tempPositions[idx]);
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
++faces;
|
++faces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mesh->mNumVertices != verts.size()) {
|
||||||
|
throw DeadlyImportError("OFF: Vertex count mismatch");
|
||||||
|
}
|
||||||
|
mesh->mVertices = new aiVector3D[verts.size()];
|
||||||
|
memcpy(mesh->mVertices, &verts[0], verts.size() * sizeof(aiVector3D));
|
||||||
// generate the output node graph
|
// generate the output node graph
|
||||||
pScene->mRootNode = new aiNode();
|
pScene->mRootNode = new aiNode();
|
||||||
pScene->mRootNode->mName.Set("<OFFRoot>");
|
pScene->mRootNode->mName.Set("<OFFRoot>");
|
||||||
pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes = 1];
|
pScene->mRootNode->mNumMeshes = 1;
|
||||||
|
pScene->mRootNode->mMeshes = new unsigned int [pScene->mRootNode->mNumMeshes];
|
||||||
pScene->mRootNode->mMeshes[0] = 0;
|
pScene->mRootNode->mMeshes[0] = 0;
|
||||||
|
|
||||||
// generate a default material
|
// generate a default material
|
||||||
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = 1];
|
pScene->mNumMaterials = 1;
|
||||||
|
pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
|
||||||
aiMaterial* pcMat = new aiMaterial();
|
aiMaterial* pcMat = new aiMaterial();
|
||||||
|
|
||||||
aiColor4D clr(0.6f,0.6f,0.6f,1.0f);
|
aiColor4D clr(0.6f,0.6f,0.6f,1.0f);
|
||||||
|
|
|
@ -156,6 +156,7 @@ struct Material
|
||||||
aiString textureEmissive;
|
aiString textureEmissive;
|
||||||
aiString textureBump;
|
aiString textureBump;
|
||||||
aiString textureNormal;
|
aiString textureNormal;
|
||||||
|
aiString textureReflection[6];
|
||||||
aiString textureSpecularity;
|
aiString textureSpecularity;
|
||||||
aiString textureOpacity;
|
aiString textureOpacity;
|
||||||
aiString textureDisp;
|
aiString textureDisp;
|
||||||
|
@ -167,6 +168,13 @@ struct Material
|
||||||
TextureEmissiveType,
|
TextureEmissiveType,
|
||||||
TextureBumpType,
|
TextureBumpType,
|
||||||
TextureNormalType,
|
TextureNormalType,
|
||||||
|
TextureReflectionSphereType,
|
||||||
|
TextureReflectionCubeTopType,
|
||||||
|
TextureReflectionCubeBottomType,
|
||||||
|
TextureReflectionCubeFrontType,
|
||||||
|
TextureReflectionCubeBackType,
|
||||||
|
TextureReflectionCubeLeftType,
|
||||||
|
TextureReflectionCubeRightType,
|
||||||
TextureSpecularityType,
|
TextureSpecularityType,
|
||||||
TextureOpacityType,
|
TextureOpacityType,
|
||||||
TextureDispType,
|
TextureDispType,
|
||||||
|
@ -234,7 +242,7 @@ struct Mesh {
|
||||||
bool m_hasNormals;
|
bool m_hasNormals;
|
||||||
|
|
||||||
/// Constructor
|
/// Constructor
|
||||||
Mesh( const std::string &name )
|
explicit Mesh( const std::string &name )
|
||||||
: m_name( name )
|
: m_name( name )
|
||||||
, m_pMaterial(NULL)
|
, m_pMaterial(NULL)
|
||||||
, m_uiNumIndices(0)
|
, m_uiNumIndices(0)
|
||||||
|
|
|
@ -138,7 +138,7 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
if ( pos != std::string::npos ) {
|
if ( pos != std::string::npos ) {
|
||||||
modelName = pFile.substr(pos+1, pFile.size() - pos - 1);
|
modelName = pFile.substr(pos+1, pFile.size() - pos - 1);
|
||||||
folderName = pFile.substr( 0, pos );
|
folderName = pFile.substr( 0, pos );
|
||||||
if ( folderName.empty() ) {
|
if ( !folderName.empty() ) {
|
||||||
pIOHandler->PushDirectory( folderName );
|
pIOHandler->PushDirectory( folderName );
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -636,6 +636,22 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( 0 != pCurrentMaterial->textureReflection[0].length )
|
||||||
|
{
|
||||||
|
ObjFile::Material::TextureType type = 0 != pCurrentMaterial->textureReflection[1].length ?
|
||||||
|
ObjFile::Material::TextureReflectionCubeTopType :
|
||||||
|
ObjFile::Material::TextureReflectionSphereType;
|
||||||
|
|
||||||
|
unsigned count = type == ObjFile::Material::TextureReflectionSphereType ? 1 : 6;
|
||||||
|
for( unsigned i = 0; i < count; i++ )
|
||||||
|
mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i));
|
||||||
|
|
||||||
|
if(pCurrentMaterial->clamp[type])
|
||||||
|
//TODO addTextureMappingModeProperty should accept an index to handle clamp option for each
|
||||||
|
//texture of a cubemap
|
||||||
|
addTextureMappingModeProperty(mat, aiTextureType_REFLECTION);
|
||||||
|
}
|
||||||
|
|
||||||
if ( 0 != pCurrentMaterial->textureDisp.length )
|
if ( 0 != pCurrentMaterial->textureDisp.length )
|
||||||
{
|
{
|
||||||
mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
|
mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) );
|
||||||
|
|
|
@ -64,6 +64,7 @@ static const std::string BumpTexture1 = "map_bump";
|
||||||
static const std::string BumpTexture2 = "map_Bump";
|
static const std::string BumpTexture2 = "map_Bump";
|
||||||
static const std::string BumpTexture3 = "bump";
|
static const std::string BumpTexture3 = "bump";
|
||||||
static const std::string NormalTexture = "map_Kn";
|
static const std::string NormalTexture = "map_Kn";
|
||||||
|
static const std::string ReflectionTexture = "refl";
|
||||||
static const std::string DisplacementTexture = "disp";
|
static const std::string DisplacementTexture = "disp";
|
||||||
static const std::string SpecularityTexture = "map_ns";
|
static const std::string SpecularityTexture = "map_ns";
|
||||||
|
|
||||||
|
@ -200,6 +201,7 @@ void ObjFileMtlImporter::load()
|
||||||
|
|
||||||
case 'm': // Texture
|
case 'm': // Texture
|
||||||
case 'b': // quick'n'dirty - for 'bump' sections
|
case 'b': // quick'n'dirty - for 'bump' sections
|
||||||
|
case 'r': // quick'n'dirty - for 'refl' sections
|
||||||
{
|
{
|
||||||
getTexture();
|
getTexture();
|
||||||
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
|
m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
|
||||||
|
@ -332,6 +334,9 @@ void ObjFileMtlImporter::getTexture() {
|
||||||
// Normal map
|
// Normal map
|
||||||
out = & m_pModel->m_pCurrentMaterial->textureNormal;
|
out = & m_pModel->m_pCurrentMaterial->textureNormal;
|
||||||
clampIndex = ObjFile::Material::TextureNormalType;
|
clampIndex = ObjFile::Material::TextureNormalType;
|
||||||
|
} else if(!ASSIMP_strincmp( pPtr, ReflectionTexture.c_str(), ReflectionTexture.size() ) ) {
|
||||||
|
// Reflection texture(s)
|
||||||
|
//Do nothing here
|
||||||
} else if (!ASSIMP_strincmp( pPtr, DisplacementTexture.c_str(), DisplacementTexture.size() ) ) {
|
} else if (!ASSIMP_strincmp( pPtr, DisplacementTexture.c_str(), DisplacementTexture.size() ) ) {
|
||||||
// Displacement texture
|
// Displacement texture
|
||||||
out = &m_pModel->m_pCurrentMaterial->textureDisp;
|
out = &m_pModel->m_pCurrentMaterial->textureDisp;
|
||||||
|
@ -346,7 +351,7 @@ void ObjFileMtlImporter::getTexture() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool clamp = false;
|
bool clamp = false;
|
||||||
getTextureOption(clamp);
|
getTextureOption(clamp, clampIndex, out);
|
||||||
m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
|
m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
|
||||||
|
|
||||||
std::string texture;
|
std::string texture;
|
||||||
|
@ -369,7 +374,7 @@ void ObjFileMtlImporter::getTexture() {
|
||||||
* Because aiMaterial supports clamp option, so we also want to return it
|
* Because aiMaterial supports clamp option, so we also want to return it
|
||||||
* /////////////////////////////////////////////////////////////////////////////
|
* /////////////////////////////////////////////////////////////////////////////
|
||||||
*/
|
*/
|
||||||
void ObjFileMtlImporter::getTextureOption(bool &clamp)
|
void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString *&out)
|
||||||
{
|
{
|
||||||
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||||
|
|
||||||
|
@ -392,13 +397,55 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp)
|
||||||
|
|
||||||
skipToken = 2;
|
skipToken = 2;
|
||||||
}
|
}
|
||||||
|
else if( !ASSIMP_strincmp( pPtr, TypeOption.c_str(), TypeOption.size() ) )
|
||||||
|
{
|
||||||
|
DataArrayIt it = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
|
||||||
|
char value[ 12 ];
|
||||||
|
CopyNextWord( it, m_DataItEnd, value, sizeof( value ) / sizeof( *value ) );
|
||||||
|
if( !ASSIMP_strincmp( value, "cube_top", 8 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
|
||||||
|
}
|
||||||
|
else if( !ASSIMP_strincmp( value, "cube_bottom", 11 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[1];
|
||||||
|
}
|
||||||
|
else if( !ASSIMP_strincmp( value, "cube_front", 10 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[2];
|
||||||
|
}
|
||||||
|
else if( !ASSIMP_strincmp( value, "cube_back", 9 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[3];
|
||||||
|
}
|
||||||
|
else if( !ASSIMP_strincmp( value, "cube_left", 9 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[4];
|
||||||
|
}
|
||||||
|
else if( !ASSIMP_strincmp( value, "cube_right", 10 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[5];
|
||||||
|
}
|
||||||
|
else if( !ASSIMP_strincmp( value, "sphere", 6 ) )
|
||||||
|
{
|
||||||
|
clampIndex = ObjFile::Material::TextureReflectionSphereType;
|
||||||
|
out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
skipToken = 2;
|
||||||
|
}
|
||||||
else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), BlendUOption.size())
|
else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), BlendUOption.size())
|
||||||
|| !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), BlendVOption.size())
|
|| !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), BlendVOption.size())
|
||||||
|| !ASSIMP_strincmp(pPtr, BoostOption.c_str(), BoostOption.size())
|
|| !ASSIMP_strincmp(pPtr, BoostOption.c_str(), BoostOption.size())
|
||||||
|| !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), ResolutionOption.size())
|
|| !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), ResolutionOption.size())
|
||||||
|| !ASSIMP_strincmp(pPtr, BumpOption.c_str(), BumpOption.size())
|
|| !ASSIMP_strincmp(pPtr, BumpOption.c_str(), BumpOption.size())
|
||||||
|| !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), ChannelOption.size())
|
|| !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), ChannelOption.size()))
|
||||||
|| !ASSIMP_strincmp(pPtr, TypeOption.c_str(), TypeOption.size()) )
|
|
||||||
{
|
{
|
||||||
skipToken = 2;
|
skipToken = 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct aiColor3D;
|
struct aiColor3D;
|
||||||
|
struct aiString;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -89,7 +90,7 @@ private:
|
||||||
void createMaterial();
|
void createMaterial();
|
||||||
/// Get texture name from loaded data.
|
/// Get texture name from loaded data.
|
||||||
void getTexture();
|
void getTexture();
|
||||||
void getTextureOption(bool &clamp);
|
void getTextureOption(bool &clamp, int &clampIndex, aiString *&out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//! Absolute pathname
|
//! Absolute pathname
|
||||||
|
|
|
@ -539,7 +539,10 @@ void ObjFileParser::getMaterialLib()
|
||||||
const std::string strMatName(pStart, &(*m_DataIt));
|
const std::string strMatName(pStart, &(*m_DataIt));
|
||||||
std::string absName;
|
std::string absName;
|
||||||
if ( m_pIO->StackSize() > 0 ) {
|
if ( m_pIO->StackSize() > 0 ) {
|
||||||
const std::string &path = m_pIO->CurrentDirectory();
|
std::string path = m_pIO->CurrentDirectory();
|
||||||
|
if ( '/' != *path.rbegin() ) {
|
||||||
|
path += '/';
|
||||||
|
}
|
||||||
absName = path + strMatName;
|
absName = path + strMatName;
|
||||||
} else {
|
} else {
|
||||||
absName = strMatName;
|
absName = strMatName;
|
||||||
|
|
|
@ -381,8 +381,8 @@ typedef std::vector<VertexAnimationTrack> VertexAnimationTrackList;
|
||||||
class Animation
|
class Animation
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Animation(Skeleton *parent);
|
explicit Animation(Skeleton *parent);
|
||||||
Animation(Mesh *parent);
|
explicit Animation(Mesh *parent);
|
||||||
|
|
||||||
/// Returns the associated vertex data for a track in this animation.
|
/// Returns the associated vertex data for a track in this animation.
|
||||||
/** @note Only valid to call when parent Mesh is set. */
|
/** @note Only valid to call when parent Mesh is set. */
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OgreXmlSerializer(XmlReader *reader) :
|
explicit OgreXmlSerializer(XmlReader *reader) :
|
||||||
m_reader(reader)
|
m_reader(reader)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -801,6 +801,19 @@ void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------
|
||||||
|
bool isSpecialRootDir(aiString &texName) {
|
||||||
|
if (texName.length < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texName.data[0] = '/' || texName.data[1] == '/') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------
|
||||||
void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
|
void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
|
||||||
if( NULL == node ) {
|
if( NULL == node ) {
|
||||||
|
|
|
@ -857,7 +857,7 @@ bool PLY::PropertyInstance::ParseValueBinary(
|
||||||
|
|
||||||
case EDT_UShort:
|
case EDT_UShort:
|
||||||
{
|
{
|
||||||
int16_t i = *((uint16_t*)pCur);
|
uint16_t i = *((uint16_t*)pCur);
|
||||||
|
|
||||||
// Swap endianess
|
// Swap endianess
|
||||||
if (p_bBE)ByteSwap::Swap(&i);
|
if (p_bBE)ByteSwap::Swap(&i);
|
||||||
|
|
|
@ -325,7 +325,7 @@ void Q3BSPFileImporter::CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* p
|
||||||
matIdx++;
|
matIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pScene->mNumMeshes = MeshArray.size();
|
pScene->mNumMeshes = static_cast<unsigned int>( MeshArray.size() );
|
||||||
if ( pScene->mNumMeshes > 0 )
|
if ( pScene->mNumMeshes > 0 )
|
||||||
{
|
{
|
||||||
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
|
pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes ];
|
||||||
|
|
|
@ -90,7 +90,7 @@ class ZipFile : public IOStream {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ZipFile(size_t size);
|
explicit ZipFile(size_t size);
|
||||||
|
|
||||||
~ZipFile();
|
~ZipFile();
|
||||||
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ private:
|
||||||
|
|
||||||
struct Face
|
struct Face
|
||||||
{
|
{
|
||||||
Face(unsigned int s)
|
explicit Face(unsigned int s)
|
||||||
: indices (s)
|
: indices (s)
|
||||||
, uvindices (s)
|
, uvindices (s)
|
||||||
, mat (0)
|
, mat (0)
|
||||||
|
|
|
@ -88,7 +88,7 @@ private:
|
||||||
|
|
||||||
struct MeshInformation
|
struct MeshInformation
|
||||||
{
|
{
|
||||||
MeshInformation(const std::string& _name)
|
explicit MeshInformation(const std::string& _name)
|
||||||
: name(_name)
|
: name(_name)
|
||||||
{
|
{
|
||||||
vertices.reserve(100);
|
vertices.reserve(100);
|
||||||
|
@ -103,7 +103,7 @@ private:
|
||||||
|
|
||||||
struct GroupInformation
|
struct GroupInformation
|
||||||
{
|
{
|
||||||
GroupInformation(const std::string& _name)
|
explicit GroupInformation(const std::string& _name)
|
||||||
: name(_name)
|
: name(_name)
|
||||||
{
|
{
|
||||||
meshes.reserve(10);
|
meshes.reserve(10);
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
/** Construction from a given face array, handling smoothing groups
|
/** Construction from a given face array, handling smoothing groups
|
||||||
* properly
|
* properly
|
||||||
*/
|
*/
|
||||||
SGSpatialSort(const std::vector<aiVector3D>& vPositions);
|
explicit SGSpatialSort(const std::vector<aiVector3D>& vPositions);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Add a vertex to the spatial sort
|
/** Add a vertex to the spatial sort
|
||||||
|
|
|
@ -74,7 +74,7 @@ static const aiImporterDesc desc = {
|
||||||
// 1) 80 byte header
|
// 1) 80 byte header
|
||||||
// 2) 4 byte face count
|
// 2) 4 byte face count
|
||||||
// 3) 50 bytes per face
|
// 3) 50 bytes per face
|
||||||
bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
|
static bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
|
||||||
if( fileSize < 84 ) {
|
if( fileSize < 84 ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
|
||||||
// An ascii STL buffer will begin with "solid NAME", where NAME is optional.
|
// An ascii STL buffer will begin with "solid NAME", where NAME is optional.
|
||||||
// Note: The "solid NAME" check is necessary, but not sufficient, to determine
|
// Note: The "solid NAME" check is necessary, but not sufficient, to determine
|
||||||
// if the buffer is ASCII; a binary header could also begin with "solid NAME".
|
// if the buffer is ASCII; a binary header could also begin with "solid NAME".
|
||||||
bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
|
static bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
|
||||||
if (IsBinarySTL(buffer, fileSize))
|
if (IsBinarySTL(buffer, fileSize))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ struct SceneHelper
|
||||||
id[0] = 0;
|
id[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneHelper (aiScene* _scene)
|
explicit SceneHelper (aiScene* _scene)
|
||||||
: scene (_scene)
|
: scene (_scene)
|
||||||
, idlen (0)
|
, idlen (0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,7 +16,7 @@ public:
|
||||||
/** @brief Construction from an existing std::ostream
|
/** @brief Construction from an existing std::ostream
|
||||||
* @param _ostream Output stream to be used
|
* @param _ostream Output stream to be used
|
||||||
*/
|
*/
|
||||||
StdOStreamLogStream(std::ostream& _ostream);
|
explicit StdOStreamLogStream(std::ostream& _ostream);
|
||||||
|
|
||||||
/** @brief Destructor */
|
/** @brief Destructor */
|
||||||
~StdOStreamLogStream();
|
~StdOStreamLogStream();
|
||||||
|
|
|
@ -97,7 +97,7 @@ public:
|
||||||
// being bound to const ref& function parameters. Copying streams is not permitted, though.
|
// being bound to const ref& function parameters. Copying streams is not permitted, though.
|
||||||
// This workaround avoids this by manually specifying a copy ctor.
|
// This workaround avoids this by manually specifying a copy ctor.
|
||||||
#if !defined(__GNUC__) || !defined(__APPLE__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
#if !defined(__GNUC__) || !defined(__APPLE__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||||
basic_formatter(const basic_formatter& other) {
|
explicit basic_formatter(const basic_formatter& other) {
|
||||||
underlying << (string)other;
|
underlying << (string)other;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct TempMat {
|
||||||
, numFaces (0)
|
, numFaces (0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TempMat(const Triangle& in)
|
explicit TempMat(const Triangle& in)
|
||||||
: type ((Unreal::MeshFlags)in.mType)
|
: type ((Unreal::MeshFlags)in.mType)
|
||||||
, tex (in.mTextureNum)
|
, tex (in.mTextureNum)
|
||||||
, numFaces (0)
|
, numFaces (0)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include "ScenePrivate.h"
|
#include "ScenePrivate.h"
|
||||||
|
|
||||||
static const unsigned int MajorVersion = 3;
|
static const unsigned int MajorVersion = 3;
|
||||||
static const unsigned int MinorVersion = 1;
|
static const unsigned int MinorVersion = 2;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------
|
||||||
// Legal information string - dont't remove this.
|
// Legal information string - dont't remove this.
|
||||||
|
|
|
@ -129,7 +129,7 @@ struct Mesh
|
||||||
|
|
||||||
std::vector<Bone> mBones;
|
std::vector<Bone> mBones;
|
||||||
|
|
||||||
Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; }
|
explicit Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Helper structure to represent a XFile frame */
|
/** Helper structure to represent a XFile frame */
|
||||||
|
@ -142,7 +142,7 @@ struct Node
|
||||||
std::vector<Mesh*> mMeshes;
|
std::vector<Mesh*> mMeshes;
|
||||||
|
|
||||||
Node() { mParent = NULL; }
|
Node() { mParent = NULL; }
|
||||||
Node( Node* pParent) { mParent = pParent; }
|
explicit Node( Node* pParent) { mParent = pParent; }
|
||||||
~Node()
|
~Node()
|
||||||
{
|
{
|
||||||
for( unsigned int a = 0; a < mChildren.size(); a++)
|
for( unsigned int a = 0; a < mChildren.size(); a++)
|
||||||
|
|
|
@ -68,7 +68,7 @@ public:
|
||||||
/** Constructor. Creates a data structure out of the XFile given in the memory block.
|
/** Constructor. Creates a data structure out of the XFile given in the memory block.
|
||||||
* @param pBuffer Null-terminated memory buffer containing the XFile
|
* @param pBuffer Null-terminated memory buffer containing the XFile
|
||||||
*/
|
*/
|
||||||
XFileParser( const std::vector<char>& pBuffer);
|
explicit XFileParser( const std::vector<char>& pBuffer);
|
||||||
|
|
||||||
/** Destructor. Destroys all imported data along with it */
|
/** Destructor. Destroys all imported data along with it */
|
||||||
~XFileParser();
|
~XFileParser();
|
||||||
|
|
|
@ -0,0 +1,945 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file glTFAsset.h
|
||||||
|
* Declares a glTF class to handle gltf/glb files
|
||||||
|
*
|
||||||
|
* glTF Extensions Support:
|
||||||
|
* KHR_binary_glTF: full
|
||||||
|
* KHR_materials_common: full
|
||||||
|
*/
|
||||||
|
#ifndef glTFAsset_H_INC
|
||||||
|
#define glTFAsset_H_INC
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#define RAPIDJSON_HAS_STDSTRING 1
|
||||||
|
#include <rapidjson/rapidjson.h>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
#include <rapidjson/error/en.h>
|
||||||
|
|
||||||
|
#ifdef ASSIMP_API
|
||||||
|
# include "boost/shared_ptr.hpp"
|
||||||
|
# include "DefaultIOSystem.h"
|
||||||
|
# include "ByteSwapper.h"
|
||||||
|
#else
|
||||||
|
# include <memory>
|
||||||
|
# define AI_SWAP4(p)
|
||||||
|
# define ai_assert
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||||
|
# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
|
||||||
|
# else
|
||||||
|
# define gltf_unordered_map map
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP
|
||||||
|
# include <unordered_map>
|
||||||
|
# if _MSC_VER > 1600
|
||||||
|
# define gltf_unordered_map unordered_map
|
||||||
|
# else
|
||||||
|
# define gltf_unordered_map tr1::unordered_map
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace glTF
|
||||||
|
{
|
||||||
|
#ifdef ASSIMP_API
|
||||||
|
using Assimp::IOStream;
|
||||||
|
using Assimp::IOSystem;
|
||||||
|
using boost::shared_ptr;
|
||||||
|
#else
|
||||||
|
using std::shared_ptr;
|
||||||
|
|
||||||
|
typedef std::runtime_error DeadlyImportError;
|
||||||
|
typedef std::runtime_error DeadlyExportError;
|
||||||
|
|
||||||
|
enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 };
|
||||||
|
class IOSystem;
|
||||||
|
class IOStream
|
||||||
|
{
|
||||||
|
FILE* f;
|
||||||
|
public:
|
||||||
|
IOStream(FILE* file) : f(file) {}
|
||||||
|
~IOStream() { fclose(f); f = 0; }
|
||||||
|
|
||||||
|
size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); }
|
||||||
|
size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); }
|
||||||
|
int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); }
|
||||||
|
size_t Tell() const { return ftell(f); }
|
||||||
|
|
||||||
|
size_t FileSize() {
|
||||||
|
long p = Tell(), len = (Seek(0, aiOrigin_END), Tell());
|
||||||
|
return size_t((Seek(p, aiOrigin_SET), len));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using rapidjson::Value;
|
||||||
|
using rapidjson::Document;
|
||||||
|
|
||||||
|
class Asset;
|
||||||
|
class AssetWriter;
|
||||||
|
|
||||||
|
struct BufferView; // here due to cross-reference
|
||||||
|
struct Texture;
|
||||||
|
struct Light;
|
||||||
|
|
||||||
|
|
||||||
|
// Vec/matrix types, as raw float arrays
|
||||||
|
typedef float (vec3)[3];
|
||||||
|
typedef float (vec4)[4];
|
||||||
|
typedef float (mat4)[16];
|
||||||
|
|
||||||
|
|
||||||
|
namespace Util
|
||||||
|
{
|
||||||
|
void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out);
|
||||||
|
|
||||||
|
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
|
||||||
|
|
||||||
|
inline size_t DecodeBase64(const char* in, uint8_t*& out)
|
||||||
|
{
|
||||||
|
return DecodeBase64(in, strlen(in), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DataURI
|
||||||
|
{
|
||||||
|
const char* mediaType;
|
||||||
|
const char* charset;
|
||||||
|
bool base64;
|
||||||
|
const char* data;
|
||||||
|
size_t dataLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Check if a uri is a data URI
|
||||||
|
inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! Magic number for GLB files
|
||||||
|
#define AI_GLB_MAGIC_NUMBER "glTF"
|
||||||
|
|
||||||
|
#ifdef ASSIMP_API
|
||||||
|
#include "./../include/assimp/Compiler/pushpack1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! For the KHR_binary_glTF extension (binary .glb file)
|
||||||
|
//! 20-byte header (+ the JSON + a "body" data section)
|
||||||
|
struct GLB_Header
|
||||||
|
{
|
||||||
|
uint8_t magic[4]; //!< Magic number: "glTF"
|
||||||
|
uint32_t version; //!< Version number (always 1 as of the last update)
|
||||||
|
uint32_t length; //!< Total length of the Binary glTF, including header, scene, and body, in bytes
|
||||||
|
uint32_t sceneLength; //!< Length, in bytes, of the glTF scene
|
||||||
|
uint32_t sceneFormat; //!< Specifies the format of the glTF scene (see the SceneFormat enum)
|
||||||
|
} PACK_STRUCT;
|
||||||
|
|
||||||
|
#ifdef ASSIMP_API
|
||||||
|
#include "./../include/assimp/Compiler/poppack1.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//! Values for the GLB_Header::sceneFormat field
|
||||||
|
enum SceneFormat
|
||||||
|
{
|
||||||
|
SceneFormat_JSON = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Values for the mesh primitive modes
|
||||||
|
enum PrimitiveMode
|
||||||
|
{
|
||||||
|
PrimitiveMode_POINTS = 0,
|
||||||
|
PrimitiveMode_LINES = 1,
|
||||||
|
PrimitiveMode_LINE_LOOP = 2,
|
||||||
|
PrimitiveMode_LINE_STRIP = 3,
|
||||||
|
PrimitiveMode_TRIANGLES = 4,
|
||||||
|
PrimitiveMode_TRIANGLE_STRIP = 5,
|
||||||
|
PrimitiveMode_TRIANGLE_FAN = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Values for the Accessor::componentType field
|
||||||
|
enum ComponentType
|
||||||
|
{
|
||||||
|
ComponentType_BYTE = 5120,
|
||||||
|
ComponentType_UNSIGNED_BYTE = 5121,
|
||||||
|
ComponentType_SHORT = 5122,
|
||||||
|
ComponentType_UNSIGNED_SHORT = 5123,
|
||||||
|
ComponentType_FLOAT = 5126
|
||||||
|
};
|
||||||
|
|
||||||
|
inline size_t ComponentTypeSize(ComponentType t)
|
||||||
|
{
|
||||||
|
switch (t) {
|
||||||
|
case ComponentType_SHORT:
|
||||||
|
case ComponentType_UNSIGNED_SHORT:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case ComponentType_FLOAT:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
//case Accessor::ComponentType_BYTE:
|
||||||
|
//case Accessor::ComponentType_UNSIGNED_BYTE:
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Values for the BufferView::target field
|
||||||
|
enum BufferViewTarget
|
||||||
|
{
|
||||||
|
BufferViewTarget_ARRAY_BUFFER = 34962,
|
||||||
|
BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Values for the Texture::format and Texture::internalFormat fields
|
||||||
|
enum TextureFormat
|
||||||
|
{
|
||||||
|
TextureFormat_ALPHA = 6406,
|
||||||
|
TextureFormat_RGB = 6407,
|
||||||
|
TextureFormat_RGBA = 6408,
|
||||||
|
TextureFormat_LUMINANCE = 6409,
|
||||||
|
TextureFormat_LUMINANCE_ALPHA = 6410
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Values for the Texture::target field
|
||||||
|
enum TextureTarget
|
||||||
|
{
|
||||||
|
TextureTarget_TEXTURE_2D = 3553
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Values for the Texture::type field
|
||||||
|
enum TextureType
|
||||||
|
{
|
||||||
|
TextureType_UNSIGNED_BYTE = 5121,
|
||||||
|
TextureType_UNSIGNED_SHORT_5_6_5 = 33635,
|
||||||
|
TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819,
|
||||||
|
TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! Values for the Accessor::type field (helper class)
|
||||||
|
class AttribType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Value
|
||||||
|
{ SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 };
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const size_t NUM_VALUES = static_cast<size_t>(MAT4)+1;
|
||||||
|
|
||||||
|
struct Info
|
||||||
|
{ const char* name; unsigned int numComponents; };
|
||||||
|
|
||||||
|
template<int N> struct data
|
||||||
|
{ static const Info infos[NUM_VALUES]; };
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline static Value FromString(const char* str)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < NUM_VALUES; ++i) {
|
||||||
|
if (strcmp(data<0>::infos[i].name, str) == 0) {
|
||||||
|
return static_cast<Value>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SCALAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static const char* ToString(Value type)
|
||||||
|
{
|
||||||
|
return data<0>::infos[static_cast<size_t>(type)].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static unsigned int GetNumComponents(Value type)
|
||||||
|
{
|
||||||
|
return data<0>::infos[static_cast<size_t>(type)].numComponents;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// must match the order of the AttribTypeTraits::Value enum!
|
||||||
|
template<int N> const AttribType::Info
|
||||||
|
AttribType::data<N>::infos[AttribType::NUM_VALUES] = {
|
||||||
|
{ "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//! A reference to one top-level object, which is valid
|
||||||
|
//! until the Asset instance is destroyed
|
||||||
|
template<class T>
|
||||||
|
class Ref
|
||||||
|
{
|
||||||
|
std::vector<T*>* vector;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Ref() : vector(0), index(0) {}
|
||||||
|
Ref(std::vector<T*>& vec, int idx) : vector(&vec), index(idx) {}
|
||||||
|
|
||||||
|
inline size_t GetIndex() const
|
||||||
|
{ return index; }
|
||||||
|
|
||||||
|
operator bool() const
|
||||||
|
{ return vector != 0; }
|
||||||
|
|
||||||
|
T* operator->()
|
||||||
|
{ return (*vector)[index]; }
|
||||||
|
|
||||||
|
T& operator*()
|
||||||
|
{ return *((*vector)[index]); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Helper struct to represent values that might not be present
|
||||||
|
template<class T>
|
||||||
|
struct Nullable
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
bool isPresent;
|
||||||
|
|
||||||
|
Nullable() : isPresent(false) {}
|
||||||
|
Nullable(T& val) : value(val), isPresent(true) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! Base classe for all glTF top-level objects
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
std::string id; //!< The globally unique ID used to reference this object
|
||||||
|
std::string name; //!< The user-defined name of this object
|
||||||
|
|
||||||
|
//! Objects marked as special are not exported (used to emulate the binary body buffer)
|
||||||
|
virtual bool IsSpecial() const
|
||||||
|
{ return false; }
|
||||||
|
|
||||||
|
virtual ~Object() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Classes for each glTF top-level object type
|
||||||
|
//
|
||||||
|
|
||||||
|
//! A typed view into a BufferView. A BufferView contains raw binary data.
|
||||||
|
//! An accessor provides a typed view into a BufferView or a subset of a BufferView
|
||||||
|
// !similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer.
|
||||||
|
struct Accessor : public Object
|
||||||
|
{
|
||||||
|
Ref<BufferView> bufferView; //!< The ID of the bufferView. (required)
|
||||||
|
unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required)
|
||||||
|
unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0)
|
||||||
|
ComponentType componentType; //!< The datatype of components in the attribute. (required)
|
||||||
|
unsigned int count; //!< The number of attributes referenced by this accessor. (required)
|
||||||
|
AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required)
|
||||||
|
//std::vector<float> max; //!< Maximum value of each component in this attribute.
|
||||||
|
//std::vector<float> min; //!< Minimum value of each component in this attribute.
|
||||||
|
|
||||||
|
unsigned int GetNumComponents();
|
||||||
|
unsigned int GetBytesPerComponent();
|
||||||
|
unsigned int GetElementSize();
|
||||||
|
|
||||||
|
inline uint8_t* GetPointer();
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void ExtractData(T*& outData);
|
||||||
|
|
||||||
|
void WriteData(size_t count, const void* src_buffer, size_t src_stride);
|
||||||
|
|
||||||
|
//! Helper class to iterate the data
|
||||||
|
class Indexer
|
||||||
|
{
|
||||||
|
friend struct Accessor;
|
||||||
|
|
||||||
|
Accessor& accessor;
|
||||||
|
uint8_t* data;
|
||||||
|
size_t elemSize, stride;
|
||||||
|
|
||||||
|
Indexer(Accessor& acc);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Accesses the i-th value as defined by the accessor
|
||||||
|
template<class T>
|
||||||
|
T GetValue(int i);
|
||||||
|
|
||||||
|
//! Accesses the i-th value as defined by the accessor
|
||||||
|
inline unsigned int GetUInt(int i)
|
||||||
|
{
|
||||||
|
return GetValue<unsigned int>(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Indexer GetIndexer()
|
||||||
|
{
|
||||||
|
return Indexer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Accessor() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Animation : public Object
|
||||||
|
{
|
||||||
|
struct Channel
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Target
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sampler
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A buffer points to binary geometry, animation, or skins.
|
||||||
|
struct Buffer : public Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Type_arraybuffer,
|
||||||
|
Type_text
|
||||||
|
};
|
||||||
|
|
||||||
|
//std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required)
|
||||||
|
size_t byteLength; //!< The length of the buffer in bytes. (default: 0)
|
||||||
|
//std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer")
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
shared_ptr<uint8_t> mData; //!< Pointer to the data
|
||||||
|
bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer)
|
||||||
|
|
||||||
|
public:
|
||||||
|
Buffer();
|
||||||
|
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
|
||||||
|
void LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0);
|
||||||
|
|
||||||
|
size_t AppendData(uint8_t* data, size_t length);
|
||||||
|
void Grow(size_t amount);
|
||||||
|
|
||||||
|
uint8_t* GetPointer()
|
||||||
|
{ return mData.get(); }
|
||||||
|
|
||||||
|
void MarkAsSpecial()
|
||||||
|
{ mIsSpecial = true; }
|
||||||
|
|
||||||
|
bool IsSpecial() const
|
||||||
|
{ return mIsSpecial; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! A view into a buffer generally representing a subset of the buffer.
|
||||||
|
struct BufferView : public Object
|
||||||
|
{
|
||||||
|
Ref<Buffer> buffer; //! The ID of the buffer. (required)
|
||||||
|
size_t byteOffset; //! The offset into the buffer in bytes. (required)
|
||||||
|
size_t byteLength; //! The length of the bufferView in bytes. (default: 0)
|
||||||
|
|
||||||
|
BufferViewTarget target; //! The target that the WebGL buffer should be bound to.
|
||||||
|
|
||||||
|
BufferView() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Camera : public Object
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Perspective,
|
||||||
|
Orthographic
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
float aspectRatio; //!<The floating - point aspect ratio of the field of view. (0 = undefined = use the canvas one)
|
||||||
|
float yfov; //!<The floating - point vertical field of view in radians. (required)
|
||||||
|
float zfar; //!<The floating - point distance to the far clipping plane. (required)
|
||||||
|
float znear; //!< The floating - point distance to the near clipping plane. (required)
|
||||||
|
} perspective;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
float xmag; //! The floating-point horizontal magnification of the view. (required)
|
||||||
|
float ymag; //! The floating-point vertical magnification of the view. (required)
|
||||||
|
float zfar; //! The floating-point distance to the far clipping plane. (required)
|
||||||
|
float znear; //! The floating-point distance to the near clipping plane. (required)
|
||||||
|
} ortographic;
|
||||||
|
};
|
||||||
|
|
||||||
|
Camera() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! Image data used to create a texture.
|
||||||
|
struct Image : public Object
|
||||||
|
{
|
||||||
|
std::string uri; //! The uri of the image, that can be a file path, a data URI, etc.. (required)
|
||||||
|
|
||||||
|
Ref<BufferView> bufferView;
|
||||||
|
|
||||||
|
std::string mimeType;
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t* mData;
|
||||||
|
size_t mDataLength;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Image();
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
|
||||||
|
inline bool HasData() const
|
||||||
|
{ return mDataLength > 0; }
|
||||||
|
|
||||||
|
inline size_t GetDataLength() const
|
||||||
|
{ return mDataLength; }
|
||||||
|
|
||||||
|
inline const uint8_t* GetData() const
|
||||||
|
{ return mData; }
|
||||||
|
|
||||||
|
inline uint8_t* StealData();
|
||||||
|
|
||||||
|
inline void SetData(uint8_t* data, size_t length, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Holds a material property that can be a texture or a color
|
||||||
|
struct TexProperty
|
||||||
|
{
|
||||||
|
Ref<Texture> texture;
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! The material appearance of a primitive.
|
||||||
|
struct Material : public Object
|
||||||
|
{
|
||||||
|
//Ref<Sampler> source; //!< The ID of the technique.
|
||||||
|
//std::gltf_unordered_map<std::string, std::string> values; //!< A dictionary object of parameter values.
|
||||||
|
|
||||||
|
//! Techniques defined by KHR_materials_common
|
||||||
|
enum Technique
|
||||||
|
{
|
||||||
|
Technique_undefined = 0,
|
||||||
|
Technique_BLINN,
|
||||||
|
Technique_PHONG,
|
||||||
|
Technique_LAMBERT,
|
||||||
|
Technique_CONSTANT
|
||||||
|
};
|
||||||
|
|
||||||
|
TexProperty ambient;
|
||||||
|
TexProperty diffuse;
|
||||||
|
TexProperty specular;
|
||||||
|
TexProperty emission;
|
||||||
|
|
||||||
|
bool doubleSided;
|
||||||
|
bool transparent;
|
||||||
|
float transparency;
|
||||||
|
float shininess;
|
||||||
|
|
||||||
|
Technique technique;
|
||||||
|
|
||||||
|
Material() { SetDefaults(); }
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
void SetDefaults();
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene.
|
||||||
|
struct Mesh : public Object
|
||||||
|
{
|
||||||
|
typedef std::vector< Ref<Accessor> > AccessorList;
|
||||||
|
|
||||||
|
struct Primitive
|
||||||
|
{
|
||||||
|
PrimitiveMode mode;
|
||||||
|
|
||||||
|
struct Attributes {
|
||||||
|
AccessorList position, normal, texcoord, color, joint, jointmatrix, weight;
|
||||||
|
} attributes;
|
||||||
|
|
||||||
|
Ref<Accessor> indices;
|
||||||
|
|
||||||
|
Ref<Material> material;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Primitive> primitives;
|
||||||
|
|
||||||
|
Mesh() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node : public Object
|
||||||
|
{
|
||||||
|
std::vector< Ref<Node> > children;
|
||||||
|
std::vector< Ref<Mesh> > meshes;
|
||||||
|
|
||||||
|
Nullable<mat4> matrix;
|
||||||
|
Nullable<vec3> translation;
|
||||||
|
Nullable<vec4> rotation;
|
||||||
|
Nullable<vec3> scale;
|
||||||
|
|
||||||
|
Ref<Camera> camera;
|
||||||
|
Ref<Light> light;
|
||||||
|
|
||||||
|
Node() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Program : public Object
|
||||||
|
{
|
||||||
|
Program() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Sampler : public Object
|
||||||
|
{
|
||||||
|
Sampler() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Scene : public Object
|
||||||
|
{
|
||||||
|
std::vector< Ref<Node> > nodes;
|
||||||
|
|
||||||
|
Scene() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Shader : public Object
|
||||||
|
{
|
||||||
|
Shader() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Skin : public Object
|
||||||
|
{
|
||||||
|
Skin() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Technique : public Object
|
||||||
|
{
|
||||||
|
struct Parameters
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct States
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Functions
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Technique() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A texture and its sampler.
|
||||||
|
struct Texture : public Object
|
||||||
|
{
|
||||||
|
//Ref<Sampler> source; //!< The ID of the sampler used by this texture. (required)
|
||||||
|
Ref<Image> source; //!< The ID of the image used by this texture. (required)
|
||||||
|
|
||||||
|
//TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA)
|
||||||
|
//TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA)
|
||||||
|
|
||||||
|
//TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D)
|
||||||
|
//TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE)
|
||||||
|
|
||||||
|
Texture() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! A light (from KHR_materials_common extension)
|
||||||
|
struct Light : public Object
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Type_undefined,
|
||||||
|
Type_ambient,
|
||||||
|
Type_directional,
|
||||||
|
Type_point,
|
||||||
|
Type_spot
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
vec4 color;
|
||||||
|
float distance;
|
||||||
|
float constantAttenuation;
|
||||||
|
float linearAttenuation;
|
||||||
|
float quadraticAttenuation;
|
||||||
|
float falloffAngle;
|
||||||
|
float falloffExponent;
|
||||||
|
|
||||||
|
Light() {}
|
||||||
|
void Read(Value& obj, Asset& r);
|
||||||
|
|
||||||
|
void SetDefaults();
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Base class for LazyDict that acts as an interface
|
||||||
|
class LazyDictBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~LazyDictBase() {}
|
||||||
|
|
||||||
|
virtual void AttachToDocument(Document& doc) = 0;
|
||||||
|
virtual void DetachFromDocument() = 0;
|
||||||
|
|
||||||
|
virtual void WriteObjects(AssetWriter& writer) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! (Stub class that is specialized in glTFAssetWriter.h)
|
||||||
|
template<class T>
|
||||||
|
struct LazyDictWriter
|
||||||
|
{
|
||||||
|
static void Write(T& d, AssetWriter& w) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID
|
||||||
|
//! It is the owner the loaded objects, so when it is destroyed it also deletes them
|
||||||
|
template<class T>
|
||||||
|
class LazyDict : public LazyDictBase
|
||||||
|
{
|
||||||
|
friend class Asset;
|
||||||
|
friend class AssetWriter;
|
||||||
|
|
||||||
|
typedef typename std::gltf_unordered_map< std::string, size_t > Dict;
|
||||||
|
|
||||||
|
std::vector<T*> mObjs; //! The read objects
|
||||||
|
Dict mObjsById; //! The read objects accesible by id
|
||||||
|
const char* mDictId; //! ID of the dictionary object
|
||||||
|
const char* mExtId; //! ID of the extension defining the dictionary
|
||||||
|
Value* mDict; //! JSON dictionary object
|
||||||
|
Asset& mAsset; //! The asset instance
|
||||||
|
|
||||||
|
void AttachToDocument(Document& doc);
|
||||||
|
void DetachFromDocument();
|
||||||
|
|
||||||
|
void WriteObjects(AssetWriter& writer)
|
||||||
|
{ LazyDictWriter< LazyDict >::Write(*this, writer); }
|
||||||
|
|
||||||
|
Ref<T> Add(T* obj);
|
||||||
|
|
||||||
|
public:
|
||||||
|
LazyDict(Asset& asset, const char* dictId, const char* extId = 0);
|
||||||
|
~LazyDict();
|
||||||
|
|
||||||
|
Ref<T> Get(const char* id);
|
||||||
|
Ref<T> Get(size_t i);
|
||||||
|
|
||||||
|
Ref<T> Create(const char* id);
|
||||||
|
Ref<T> Create(const std::string& id)
|
||||||
|
{ return Create(id.c_str()); }
|
||||||
|
|
||||||
|
inline size_t Size() const
|
||||||
|
{ return mObjs.size(); }
|
||||||
|
|
||||||
|
inline T& operator[](size_t i)
|
||||||
|
{ return *mObjs[i]; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct AssetMetadata
|
||||||
|
{
|
||||||
|
std::string copyright; //!< A copyright message suitable for display to credit the content creator.
|
||||||
|
std::string generator; //!< Tool that generated this glTF model.Useful for debugging.
|
||||||
|
bool premultipliedAlpha; //!< Specifies if the shaders were generated with premultiplied alpha. (default: false)
|
||||||
|
|
||||||
|
struct {
|
||||||
|
std::string api; //!< Specifies the target rendering API (default: "WebGL")
|
||||||
|
std::string version; //!< Specifies the target rendering API (default: "1.0.3")
|
||||||
|
} profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {})
|
||||||
|
|
||||||
|
int version; //!< The glTF format version (should be 1)
|
||||||
|
|
||||||
|
void Read(Document& doc);
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// glTF Asset class
|
||||||
|
//
|
||||||
|
|
||||||
|
//! Root object for a glTF asset
|
||||||
|
class Asset
|
||||||
|
{
|
||||||
|
typedef std::gltf_unordered_map<std::string, int> IdMap;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
friend class LazyDict;
|
||||||
|
|
||||||
|
friend struct Buffer; // To access OpenFile
|
||||||
|
|
||||||
|
friend class AssetWriter;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IOSystem* mIOSystem;
|
||||||
|
|
||||||
|
std::string mCurrentAssetDir;
|
||||||
|
|
||||||
|
size_t mSceneLength;
|
||||||
|
size_t mBodyOffset, mBodyLength;
|
||||||
|
|
||||||
|
std::vector<LazyDictBase*> mDicts;
|
||||||
|
|
||||||
|
IdMap mUsedIds;
|
||||||
|
|
||||||
|
Ref<Buffer> mBodyBuffer;
|
||||||
|
|
||||||
|
Asset(Asset&);
|
||||||
|
Asset& operator=(const Asset&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! Keeps info about the enabled extensions
|
||||||
|
struct Extensions
|
||||||
|
{
|
||||||
|
bool KHR_binary_glTF;
|
||||||
|
bool KHR_materials_common;
|
||||||
|
|
||||||
|
} extensionsUsed;
|
||||||
|
|
||||||
|
AssetMetadata asset;
|
||||||
|
|
||||||
|
|
||||||
|
// Dictionaries for each type of object
|
||||||
|
|
||||||
|
LazyDict<Accessor> accessors;
|
||||||
|
LazyDict<Animation> animations;
|
||||||
|
LazyDict<Buffer> buffers;
|
||||||
|
LazyDict<BufferView> bufferViews;
|
||||||
|
LazyDict<Camera> cameras;
|
||||||
|
LazyDict<Image> images;
|
||||||
|
LazyDict<Material> materials;
|
||||||
|
LazyDict<Mesh> meshes;
|
||||||
|
LazyDict<Node> nodes;
|
||||||
|
//LazyDict<Program> programs;
|
||||||
|
//LazyDict<Sampler> samplers;
|
||||||
|
LazyDict<Scene> scenes;
|
||||||
|
//LazyDict<Shader> shaders;
|
||||||
|
//LazyDict<Skin> skins;
|
||||||
|
//LazyDict<Technique> techniques;
|
||||||
|
LazyDict<Texture> textures;
|
||||||
|
|
||||||
|
LazyDict<Light> lights; // KHR_materials_common ext
|
||||||
|
|
||||||
|
Ref<Scene> scene;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Asset(IOSystem* io = 0)
|
||||||
|
: mIOSystem(io)
|
||||||
|
, accessors (*this, "accessors")
|
||||||
|
, animations (*this, "animations")
|
||||||
|
, buffers (*this, "buffers")
|
||||||
|
, bufferViews (*this, "bufferViews")
|
||||||
|
, cameras (*this, "cameras")
|
||||||
|
, images (*this, "images")
|
||||||
|
, materials (*this, "materials")
|
||||||
|
, meshes (*this, "meshes")
|
||||||
|
, nodes (*this, "nodes")
|
||||||
|
//, programs (*this, "programs")
|
||||||
|
//, samplers (*this, "samplers")
|
||||||
|
, scenes (*this, "scenes")
|
||||||
|
//, shaders (*this, "shaders")
|
||||||
|
//, skins (*this, "skins")
|
||||||
|
//, techniques (*this, "techniques")
|
||||||
|
, textures (*this, "textures")
|
||||||
|
, lights (*this, "lights", "KHR_materials_common")
|
||||||
|
{
|
||||||
|
memset(&extensionsUsed, 0, sizeof(extensionsUsed));
|
||||||
|
memset(&asset, 0, sizeof(asset));
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Main function
|
||||||
|
void Load(const std::string& file, bool isBinary = false);
|
||||||
|
|
||||||
|
//! Enables the "KHR_binary_glTF" extension on the asset
|
||||||
|
void SetAsBinary();
|
||||||
|
|
||||||
|
//! Search for an available name, starting from the given strings
|
||||||
|
std::string FindUniqueID(const std::string& str, const char* suffix);
|
||||||
|
|
||||||
|
Ref<Buffer> GetBodyBuffer()
|
||||||
|
{ return mBodyBuffer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ReadBinaryHeader(IOStream& stream);
|
||||||
|
|
||||||
|
void ReadExtensionsUsed(Document& doc);
|
||||||
|
|
||||||
|
|
||||||
|
IOStream* OpenFile(std::string path, const char* mode, bool absolute = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the implementation of the methods
|
||||||
|
#include "glTFAsset.inl"
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file glTFWriter.h
|
||||||
|
* Declares a class to write gltf/glb files
|
||||||
|
*
|
||||||
|
* glTF Extensions Support:
|
||||||
|
* KHR_binary_glTF: full
|
||||||
|
* KHR_materials_common: full
|
||||||
|
*/
|
||||||
|
#ifndef glTFAssetWriter_H_INC
|
||||||
|
#define glTFAssetWriter_H_INC
|
||||||
|
|
||||||
|
#include "glTFAsset.h"
|
||||||
|
|
||||||
|
namespace glTF
|
||||||
|
{
|
||||||
|
|
||||||
|
using rapidjson::MemoryPoolAllocator;
|
||||||
|
|
||||||
|
class AssetWriter
|
||||||
|
{
|
||||||
|
template<class T>
|
||||||
|
friend struct LazyDictWriter;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void WriteBinaryData(IOStream* outfile, size_t sceneLength);
|
||||||
|
|
||||||
|
void WriteMetadata();
|
||||||
|
void WriteExtensionsUsed();
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void WriteObjects(LazyDict<T>& d);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Document mDoc;
|
||||||
|
Asset& mAsset;
|
||||||
|
|
||||||
|
MemoryPoolAllocator<>& mAl;
|
||||||
|
|
||||||
|
AssetWriter(Asset& asset);
|
||||||
|
|
||||||
|
void WriteFile(const char* path);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the implementation of the methods
|
||||||
|
#include "glTFAssetWriter.inl"
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,497 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rapidjson/stringbuffer.h>
|
||||||
|
#include <rapidjson/writer.h>
|
||||||
|
#include <rapidjson/prettywriter.h>
|
||||||
|
|
||||||
|
namespace glTF {
|
||||||
|
|
||||||
|
using rapidjson::StringBuffer;
|
||||||
|
using rapidjson::PrettyWriter;
|
||||||
|
using rapidjson::Writer;
|
||||||
|
using rapidjson::StringRef;
|
||||||
|
using rapidjson::StringRef;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) {
|
||||||
|
val.SetArray();
|
||||||
|
val.Reserve(N, al);
|
||||||
|
for (int i = 0; i < N; ++i) {
|
||||||
|
val.PushBack(r[i], al);
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref<T> >& v, MemoryPoolAllocator<>& al) {
|
||||||
|
if (v.empty()) return;
|
||||||
|
Value lst;
|
||||||
|
lst.SetArray();
|
||||||
|
lst.Reserve(v.size(), al);
|
||||||
|
for (size_t i = 0; i < v.size(); ++i) {
|
||||||
|
lst.PushBack(StringRef(v[i]->id), al);
|
||||||
|
}
|
||||||
|
obj.AddMember(StringRef(fieldId), lst, al);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Accessor& a, AssetWriter& w)
|
||||||
|
{
|
||||||
|
obj.AddMember("bufferView", Value(a.bufferView->id, w.mAl).Move(), w.mAl);
|
||||||
|
obj.AddMember("byteOffset", a.byteOffset, w.mAl);
|
||||||
|
obj.AddMember("byteStride", a.byteStride, w.mAl);
|
||||||
|
obj.AddMember("componentType", int(a.componentType), w.mAl);
|
||||||
|
obj.AddMember("count", a.count, w.mAl);
|
||||||
|
obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Animation& a, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Buffer& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
std::string dataURI = "data:application/octet-stream;base64,";
|
||||||
|
Util::EncodeBase64(b.GetPointer(), b.byteLength, dataURI);
|
||||||
|
|
||||||
|
const char* type;
|
||||||
|
switch (b.type) {
|
||||||
|
case Buffer::Type_text:
|
||||||
|
type = "text"; break;
|
||||||
|
default:
|
||||||
|
type = "arraybuffer";
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.AddMember("byteLength", b.byteLength, w.mAl);
|
||||||
|
obj.AddMember("type", StringRef(type), w.mAl);
|
||||||
|
obj.AddMember("uri", Value(dataURI, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, BufferView& bv, AssetWriter& w)
|
||||||
|
{
|
||||||
|
obj.AddMember("buffer", Value(bv.buffer->id, w.mAl).Move(), w.mAl);
|
||||||
|
obj.AddMember("byteOffset", bv.byteOffset, w.mAl);
|
||||||
|
obj.AddMember("byteLength", bv.byteLength, w.mAl);
|
||||||
|
obj.AddMember("target", int(bv.target), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Camera& c, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Image& img, AssetWriter& w)
|
||||||
|
{
|
||||||
|
std::string uri;
|
||||||
|
if (w.mAsset.extensionsUsed.KHR_binary_glTF && img.bufferView) {
|
||||||
|
Value exts, ext;
|
||||||
|
exts.SetObject();
|
||||||
|
ext.SetObject();
|
||||||
|
|
||||||
|
ext.AddMember("bufferView", StringRef(img.bufferView->id), w.mAl);
|
||||||
|
|
||||||
|
if (!img.mimeType.empty())
|
||||||
|
ext.AddMember("mimeType", StringRef(img.mimeType), w.mAl);
|
||||||
|
|
||||||
|
exts.AddMember("KHR_binary_glTF", ext, w.mAl);
|
||||||
|
obj.AddMember("extensions", exts, w.mAl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (img.HasData()) {
|
||||||
|
uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType);
|
||||||
|
uri += ";base64,";
|
||||||
|
Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
uri = img.uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
inline void WriteColorOrTex(Value& obj, TexProperty& prop, const char* propName, MemoryPoolAllocator<>& al)
|
||||||
|
{
|
||||||
|
if (prop.texture)
|
||||||
|
obj.AddMember(StringRef(propName), Value(prop.texture->id, al).Move(), al);
|
||||||
|
else {
|
||||||
|
Value col;
|
||||||
|
obj.AddMember(StringRef(propName), MakeValue(col, prop.color, al), al);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Material& m, AssetWriter& w)
|
||||||
|
{
|
||||||
|
Value v;
|
||||||
|
v.SetObject();
|
||||||
|
{
|
||||||
|
WriteColorOrTex(v, m.ambient, "ambient", w.mAl);
|
||||||
|
WriteColorOrTex(v, m.diffuse, "diffuse", w.mAl);
|
||||||
|
WriteColorOrTex(v, m.specular, "specular", w.mAl);
|
||||||
|
WriteColorOrTex(v, m.emission, "emission", w.mAl);
|
||||||
|
|
||||||
|
v.AddMember("shininess", m.shininess, w.mAl);
|
||||||
|
}
|
||||||
|
obj.AddMember("values", v, w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst,
|
||||||
|
const char* semantic, bool forceNumber = false)
|
||||||
|
{
|
||||||
|
if (lst.empty()) return;
|
||||||
|
if (lst.size() == 1 && !forceNumber) {
|
||||||
|
attrs.AddMember(StringRef(semantic), Value(lst[0]->id, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (size_t i = 0; i < lst.size(); ++i) {
|
||||||
|
char buffer[32];
|
||||||
|
sprintf(buffer, "%s_%d", semantic, int(i));
|
||||||
|
attrs.AddMember(Value(buffer, w.mAl).Move(), Value(lst[i]->id, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Mesh& m, AssetWriter& w)
|
||||||
|
{
|
||||||
|
Value primitives;
|
||||||
|
primitives.SetArray();
|
||||||
|
primitives.Reserve(m.primitives.size(), w.mAl);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m.primitives.size(); ++i) {
|
||||||
|
Mesh::Primitive& p = m.primitives[i];
|
||||||
|
Value prim;
|
||||||
|
prim.SetObject();
|
||||||
|
{
|
||||||
|
prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl);
|
||||||
|
|
||||||
|
if (p.material)
|
||||||
|
prim.AddMember("material", p.material->id, w.mAl);
|
||||||
|
|
||||||
|
if (p.indices)
|
||||||
|
prim.AddMember("indices", Value(p.indices->id, w.mAl).Move(), w.mAl);
|
||||||
|
|
||||||
|
Value attrs;
|
||||||
|
attrs.SetObject();
|
||||||
|
{
|
||||||
|
WriteAttrs(w, attrs, p.attributes.position, "POSITION");
|
||||||
|
WriteAttrs(w, attrs, p.attributes.normal, "NORMAL");
|
||||||
|
WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true);
|
||||||
|
WriteAttrs(w, attrs, p.attributes.color, "COLOR");
|
||||||
|
WriteAttrs(w, attrs, p.attributes.joint, "JOINT");
|
||||||
|
WriteAttrs(w, attrs, p.attributes.jointmatrix, "JOINTMATRIX");
|
||||||
|
WriteAttrs(w, attrs, p.attributes.weight, "WEIGHT");
|
||||||
|
}
|
||||||
|
prim.AddMember("attributes", attrs, w.mAl);
|
||||||
|
}
|
||||||
|
primitives.PushBack(prim, w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.AddMember("primitives", primitives, w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Node& n, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (n.matrix.isPresent) {
|
||||||
|
Value val;
|
||||||
|
obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.translation.isPresent) {
|
||||||
|
Value val;
|
||||||
|
obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n.scale.isPresent) {
|
||||||
|
Value val;
|
||||||
|
obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
if (n.rotation.isPresent) {
|
||||||
|
Value val;
|
||||||
|
obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRefsVector(obj, "children", n.children, w.mAl);
|
||||||
|
|
||||||
|
AddRefsVector(obj, "meshes", n.meshes, w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Program& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Sampler& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& scene, Scene& s, AssetWriter& w)
|
||||||
|
{
|
||||||
|
AddRefsVector(scene, "nodes", s.nodes, w.mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Shader& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Skin& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Technique& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Texture& tex, AssetWriter& w)
|
||||||
|
{
|
||||||
|
if (tex.source) {
|
||||||
|
obj.AddMember("source", Value(tex.source->id, w.mAl).Move(), w.mAl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Write(Value& obj, Light& b, AssetWriter& w)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AssetWriter::AssetWriter(Asset& a)
|
||||||
|
: mDoc()
|
||||||
|
, mAsset(a)
|
||||||
|
, mAl(mDoc.GetAllocator())
|
||||||
|
{
|
||||||
|
mDoc.SetObject();
|
||||||
|
|
||||||
|
WriteMetadata();
|
||||||
|
WriteExtensionsUsed();
|
||||||
|
|
||||||
|
// Dump the contents of the dictionaries
|
||||||
|
for (size_t i = 0; i < a.mDicts.size(); ++i) {
|
||||||
|
a.mDicts[i]->WriteObjects(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the target scene field
|
||||||
|
if (mAsset.scene) {
|
||||||
|
mDoc.AddMember("scene", StringRef(mAsset.scene->id), mAl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetWriter::WriteFile(const char* path)
|
||||||
|
{
|
||||||
|
bool isBinary = mAsset.extensionsUsed.KHR_binary_glTF;
|
||||||
|
|
||||||
|
boost::scoped_ptr<IOStream> outfile
|
||||||
|
(mAsset.OpenFile(path, isBinary ? "wb" : "wt", true));
|
||||||
|
|
||||||
|
if (outfile == 0) {
|
||||||
|
throw DeadlyExportError("Could not open output file: " + std::string(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBinary) {
|
||||||
|
// we will write the header later, skip its size
|
||||||
|
outfile->Seek(sizeof(GLB_Header), aiOrigin_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer docBuffer;
|
||||||
|
|
||||||
|
bool pretty = true;
|
||||||
|
if (!isBinary && pretty) {
|
||||||
|
PrettyWriter<StringBuffer> writer(docBuffer);
|
||||||
|
mDoc.Accept(writer);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Writer<StringBuffer> writer(docBuffer);
|
||||||
|
mDoc.Accept(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outfile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) {
|
||||||
|
throw DeadlyExportError("Failed to write scene data!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBinary) {
|
||||||
|
WriteBinaryData(outfile.get(), docBuffer.GetSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetWriter::WriteBinaryData(IOStream* outfile, size_t sceneLength)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// write the body data
|
||||||
|
//
|
||||||
|
|
||||||
|
size_t bodyLength = 0;
|
||||||
|
if (Ref<Buffer> b = mAsset.GetBodyBuffer()) {
|
||||||
|
bodyLength = b->byteLength;
|
||||||
|
|
||||||
|
if (bodyLength > 0) {
|
||||||
|
size_t bodyOffset = sizeof(GLB_Header) + sceneLength;
|
||||||
|
bodyOffset = (bodyOffset + 3) & ~3; // Round up to next multiple of 4
|
||||||
|
|
||||||
|
outfile->Seek(bodyOffset, aiOrigin_SET);
|
||||||
|
|
||||||
|
if (outfile->Write(b->GetPointer(), b->byteLength, 1) != 1) {
|
||||||
|
throw DeadlyExportError("Failed to write body data!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// write the header
|
||||||
|
//
|
||||||
|
|
||||||
|
GLB_Header header;
|
||||||
|
memcpy(header.magic, AI_GLB_MAGIC_NUMBER, sizeof(header.magic));
|
||||||
|
|
||||||
|
header.version = 1;
|
||||||
|
AI_SWAP4(header.version);
|
||||||
|
|
||||||
|
header.length = sizeof(header) + sceneLength + bodyLength;
|
||||||
|
AI_SWAP4(header.length);
|
||||||
|
|
||||||
|
header.sceneLength = sceneLength;
|
||||||
|
AI_SWAP4(header.sceneLength);
|
||||||
|
|
||||||
|
header.sceneFormat = SceneFormat_JSON;
|
||||||
|
AI_SWAP4(header.sceneFormat);
|
||||||
|
|
||||||
|
outfile->Seek(0, aiOrigin_SET);
|
||||||
|
|
||||||
|
if (outfile->Write(&header, 1, sizeof(header)) != sizeof(header)) {
|
||||||
|
throw DeadlyExportError("Failed to write the header!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AssetWriter::WriteMetadata()
|
||||||
|
{
|
||||||
|
Value asset;
|
||||||
|
asset.SetObject();
|
||||||
|
{
|
||||||
|
asset.AddMember("version", mAsset.asset.version, mAl);
|
||||||
|
|
||||||
|
asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl);
|
||||||
|
}
|
||||||
|
mDoc.AddMember("asset", asset, mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetWriter::WriteExtensionsUsed()
|
||||||
|
{
|
||||||
|
Value exts;
|
||||||
|
exts.SetArray();
|
||||||
|
{
|
||||||
|
if (false)
|
||||||
|
exts.PushBack(StringRef("KHR_binary_glTF"), mAl);
|
||||||
|
|
||||||
|
if (false)
|
||||||
|
exts.PushBack(StringRef("KHR_materials_common"), mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exts.Empty())
|
||||||
|
mDoc.AddMember("extensionsUsed", exts, mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void AssetWriter::WriteObjects(LazyDict<T>& d)
|
||||||
|
{
|
||||||
|
if (d.mObjs.empty()) return;
|
||||||
|
|
||||||
|
Value* container = &mDoc;
|
||||||
|
|
||||||
|
if (d.mExtId) {
|
||||||
|
Value* exts = FindObject(mDoc, "extensions");
|
||||||
|
if (!exts) {
|
||||||
|
mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator());
|
||||||
|
exts = FindObject(mDoc, "extensions");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(container = FindObject(*exts, d.mExtId))) {
|
||||||
|
exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator());
|
||||||
|
container = FindObject(*exts, d.mExtId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Value* dict;
|
||||||
|
if (!(dict = FindObject(*container, d.mDictId))) {
|
||||||
|
container->AddMember(StringRef(d.mDictId), Value().SetObject().Move(), mDoc.GetAllocator());
|
||||||
|
dict = FindObject(*container, d.mDictId);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < d.mObjs.size(); ++i) {
|
||||||
|
if (d.mObjs[i]->IsSpecial()) continue;
|
||||||
|
|
||||||
|
Value obj;
|
||||||
|
obj.SetObject();
|
||||||
|
|
||||||
|
if (!d.mObjs[i]->name.empty()) {
|
||||||
|
obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(obj, *d.mObjs[i], *this);
|
||||||
|
|
||||||
|
dict->AddMember(StringRef(d.mObjs[i]->id), obj, mAl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct LazyDictWriter< LazyDict<T> >
|
||||||
|
{
|
||||||
|
static void Write(LazyDict<T>& d, AssetWriter& w)
|
||||||
|
{
|
||||||
|
w.WriteObjects(d);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,367 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
|
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||||
|
|
||||||
|
#include "glTFExporter.h"
|
||||||
|
#include "Exceptional.h"
|
||||||
|
#include "StringComparison.h"
|
||||||
|
#include "ByteSwapper.h"
|
||||||
|
|
||||||
|
#include <assimp/version.h>
|
||||||
|
#include <assimp/IOSystem.hpp>
|
||||||
|
#include <assimp/Exporter.hpp>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/scoped_ptr.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include "glTFAssetWriter.h"
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
using namespace Assimp;
|
||||||
|
using namespace glTF;
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp
|
||||||
|
void ExportSceneGLTF(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
||||||
|
{
|
||||||
|
// invoke the exporter
|
||||||
|
glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Worker function for exporting a scene to GLB. Prototyped and registered in Exporter.cpp
|
||||||
|
void ExportSceneGLB(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
|
||||||
|
{
|
||||||
|
// invoke the exporter
|
||||||
|
glTFExporter exporter(pFile, pIOSystem, pScene, pProperties, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene,
|
||||||
|
const ExportProperties* pProperties, bool isBinary)
|
||||||
|
: mFilename(filename)
|
||||||
|
, mIOSystem(pIOSystem)
|
||||||
|
, mScene(pScene)
|
||||||
|
, mProperties(pProperties)
|
||||||
|
{
|
||||||
|
boost::scoped_ptr<Asset> asset(new glTF::Asset(pIOSystem));
|
||||||
|
mAsset = asset.get();
|
||||||
|
|
||||||
|
if (isBinary) {
|
||||||
|
asset->SetAsBinary();
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportMetadata();
|
||||||
|
|
||||||
|
//for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) {}
|
||||||
|
|
||||||
|
//for (unsigned int i = 0; i < pScene->mNumCameras; ++i) {}
|
||||||
|
|
||||||
|
//for (unsigned int i = 0; i < pScene->mNumLights; ++i) {}
|
||||||
|
|
||||||
|
|
||||||
|
ExportMaterials();
|
||||||
|
|
||||||
|
ExportMeshes();
|
||||||
|
|
||||||
|
//for (unsigned int i = 0; i < pScene->mNumTextures; ++i) {}
|
||||||
|
|
||||||
|
|
||||||
|
if (mScene->mRootNode) {
|
||||||
|
ExportNode(mScene->mRootNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportScene();
|
||||||
|
|
||||||
|
|
||||||
|
glTF::AssetWriter writer(*mAsset);
|
||||||
|
writer.WriteFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CopyValue(const aiMatrix4x4& v, glTF::mat4& o)
|
||||||
|
{
|
||||||
|
o[ 0] = v.a1; o[ 1] = v.b1; o[ 2] = v.c1; o[ 3] = v.d1;
|
||||||
|
o[ 4] = v.a2; o[ 5] = v.b2; o[ 6] = v.c2; o[ 7] = v.d2;
|
||||||
|
o[ 8] = v.a3; o[ 9] = v.b3; o[10] = v.c3; o[11] = v.d3;
|
||||||
|
o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Ref<Accessor> ExportData(Asset& a, std::string& meshName, Ref<Buffer>& buffer,
|
||||||
|
unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false)
|
||||||
|
{
|
||||||
|
if (!count || !data) return Ref<Accessor>();
|
||||||
|
|
||||||
|
unsigned int numCompsIn = AttribType::GetNumComponents(typeIn);
|
||||||
|
unsigned int numCompsOut = AttribType::GetNumComponents(typeOut);
|
||||||
|
unsigned int bytesPerComp = ComponentTypeSize(compType);
|
||||||
|
|
||||||
|
size_t offset = buffer->byteLength;
|
||||||
|
size_t length = count * numCompsOut * bytesPerComp;
|
||||||
|
buffer->Grow(length);
|
||||||
|
|
||||||
|
// bufferView
|
||||||
|
Ref<BufferView> bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view"));
|
||||||
|
bv->buffer = buffer;
|
||||||
|
bv->byteOffset = 0;
|
||||||
|
bv->byteLength = length; //! The target that the WebGL buffer should be bound to.
|
||||||
|
bv->target = isIndices ? BufferViewTarget_ELEMENT_ARRAY_BUFFER : BufferViewTarget_ARRAY_BUFFER;
|
||||||
|
|
||||||
|
// accessor
|
||||||
|
Ref<Accessor> acc = a.accessors.Create(a.FindUniqueID(meshName, "accessor"));
|
||||||
|
acc->bufferView = bv;
|
||||||
|
acc->byteOffset = offset;
|
||||||
|
acc->byteStride = 0;
|
||||||
|
acc->componentType = compType;
|
||||||
|
acc->count = count;
|
||||||
|
acc->type = typeOut;
|
||||||
|
|
||||||
|
// copy the data
|
||||||
|
acc->WriteData(count, data, numCompsIn*bytesPerComp);
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) {
|
||||||
|
if (mat->Get(propName, type, idx, val) == AI_SUCCESS) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFExporter::GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt)
|
||||||
|
{
|
||||||
|
aiString tex;
|
||||||
|
aiColor4D col;
|
||||||
|
if (mat->GetTextureCount(tt) > 0) {
|
||||||
|
if (mat->Get(AI_MATKEY_TEXTURE(tt, 0), tex) == AI_SUCCESS) {
|
||||||
|
std::string path = tex.C_Str();
|
||||||
|
|
||||||
|
if (path.size() > 0) {
|
||||||
|
if (path[0] != '*') {
|
||||||
|
std::map<std::string, size_t>::iterator it = mTexturesByPath.find(path);
|
||||||
|
if (it != mTexturesByPath.end()) {
|
||||||
|
prop.texture = mAsset->textures.Get(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prop.texture) {
|
||||||
|
std::string texId = mAsset->FindUniqueID("", "texture");
|
||||||
|
prop.texture = mAsset->textures.Create(texId);
|
||||||
|
mTexturesByPath[path] = prop.texture.GetIndex();
|
||||||
|
|
||||||
|
std::string imgId = mAsset->FindUniqueID("", "image");
|
||||||
|
prop.texture->source = mAsset->images.Create(imgId);
|
||||||
|
|
||||||
|
if (path[0] == '*') { // embedded
|
||||||
|
aiTexture* tex = mScene->mTextures[atoi(&path[1])];
|
||||||
|
|
||||||
|
uint8_t* data = reinterpret_cast<uint8_t*>(tex->pcData);
|
||||||
|
prop.texture->source->SetData(data, tex->mWidth, *mAsset);
|
||||||
|
|
||||||
|
if (tex->achFormatHint[0]) {
|
||||||
|
std::string mimeType = "image/";
|
||||||
|
mimeType += (memcmp(tex->achFormatHint, "jpg", 3) == 0) ? "jpeg" : tex->achFormatHint;
|
||||||
|
prop.texture->source->mimeType = mimeType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prop.texture->source->uri = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mat->Get(propName, type, idx, col) == AI_SUCCESS) {
|
||||||
|
prop.color[0] = col.r; prop.color[1] = col.g; prop.color[2] = col.b; prop.color[3] = col.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFExporter::ExportMaterials()
|
||||||
|
{
|
||||||
|
aiString aiName;
|
||||||
|
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
|
||||||
|
const aiMaterial* mat = mScene->mMaterials[i];
|
||||||
|
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) {
|
||||||
|
name = aiName.C_Str();
|
||||||
|
}
|
||||||
|
name = mAsset->FindUniqueID(name, "material");
|
||||||
|
|
||||||
|
Ref<Material> m = mAsset->materials.Create(name);
|
||||||
|
|
||||||
|
GetMatColorOrTex(mat, m->ambient, AI_MATKEY_COLOR_AMBIENT, aiTextureType_AMBIENT);
|
||||||
|
GetMatColorOrTex(mat, m->diffuse, AI_MATKEY_COLOR_DIFFUSE, aiTextureType_DIFFUSE);
|
||||||
|
GetMatColorOrTex(mat, m->specular, AI_MATKEY_COLOR_SPECULAR, aiTextureType_SPECULAR);
|
||||||
|
GetMatColorOrTex(mat, m->emission, AI_MATKEY_COLOR_EMISSIVE, aiTextureType_EMISSIVE);
|
||||||
|
|
||||||
|
GetMatScalar(mat, m->shininess, AI_MATKEY_SHININESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFExporter::ExportMeshes()
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < mScene->mNumMeshes; ++i) {
|
||||||
|
const aiMesh* aim = mScene->mMeshes[i];
|
||||||
|
|
||||||
|
std::string meshId = mAsset->FindUniqueID(aim->mName.C_Str(), "mesh");
|
||||||
|
Ref<Mesh> m = mAsset->meshes.Create(meshId);
|
||||||
|
m->primitives.resize(1);
|
||||||
|
Mesh::Primitive& p = m->primitives.back();
|
||||||
|
|
||||||
|
p.material = mAsset->materials.Get(aim->mMaterialIndex);
|
||||||
|
|
||||||
|
std::string bufferId = mAsset->FindUniqueID(meshId, "buffer");
|
||||||
|
|
||||||
|
Ref<Buffer> b = mAsset->GetBodyBuffer();
|
||||||
|
if (!b) {
|
||||||
|
b = mAsset->buffers.Create(bufferId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Accessor> v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||||
|
if (v) p.attributes.position.push_back(v);
|
||||||
|
|
||||||
|
Ref<Accessor> n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT);
|
||||||
|
if (n) p.attributes.normal.push_back(n);
|
||||||
|
|
||||||
|
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||||
|
if (aim->mNumUVComponents[i] > 0) {
|
||||||
|
AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3;
|
||||||
|
Ref<Accessor> tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, true);
|
||||||
|
if (tc) p.attributes.texcoord.push_back(tc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aim->mNumFaces > 0) {
|
||||||
|
unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices;
|
||||||
|
std::vector<uint16_t> indices;
|
||||||
|
indices.resize(aim->mNumFaces * nIndicesPerFace);
|
||||||
|
for (size_t i = 0; i < aim->mNumFaces; ++i) {
|
||||||
|
for (size_t j = 0; j < nIndicesPerFace; ++j) {
|
||||||
|
indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (aim->mPrimitiveTypes) {
|
||||||
|
case aiPrimitiveType_POLYGON:
|
||||||
|
p.mode = PrimitiveMode_TRIANGLES; break; // TODO implement this
|
||||||
|
case aiPrimitiveType_LINE:
|
||||||
|
p.mode = PrimitiveMode_LINES; break;
|
||||||
|
case aiPrimitiveType_POINT:
|
||||||
|
p.mode = PrimitiveMode_POINTS; break;
|
||||||
|
default: // aiPrimitiveType_TRIANGLE
|
||||||
|
p.mode = PrimitiveMode_TRIANGLES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t glTFExporter::ExportNode(const aiNode* n)
|
||||||
|
{
|
||||||
|
Ref<Node> node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node"));
|
||||||
|
|
||||||
|
if (!n->mTransformation.IsIdentity()) {
|
||||||
|
node->matrix.isPresent = true;
|
||||||
|
CopyValue(n->mTransformation, node->matrix.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n->mNumMeshes; ++i) {
|
||||||
|
node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < n->mNumChildren; ++i) {
|
||||||
|
size_t idx = ExportNode(n->mChildren[i]);
|
||||||
|
node->children.push_back(mAsset->nodes.Get(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.GetIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void glTFExporter::ExportScene()
|
||||||
|
{
|
||||||
|
const char* sceneName = "defaultScene";
|
||||||
|
Ref<Scene> scene = mAsset->scenes.Create(sceneName);
|
||||||
|
|
||||||
|
// root node will be the first one exported (idx 0)
|
||||||
|
if (mAsset->nodes.Size() > 0) {
|
||||||
|
scene->nodes.push_back(mAsset->nodes.Get(size_t(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set as the default scene
|
||||||
|
mAsset->scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFExporter::ExportMetadata()
|
||||||
|
{
|
||||||
|
glTF::AssetMetadata& asset = mAsset->asset;
|
||||||
|
asset.version = 1;
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
sprintf(buffer, "Open Asset Import Library (assimp v%d.%d.%d)",
|
||||||
|
aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision());
|
||||||
|
|
||||||
|
asset.generator = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||||
|
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file GltfExporter.h
|
||||||
|
* Declares the exporter class to write a scene to a gltf/glb file
|
||||||
|
*/
|
||||||
|
#ifndef AI_GLTFEXPORTER_H_INC
|
||||||
|
#define AI_GLTFEXPORTER_H_INC
|
||||||
|
|
||||||
|
#include <assimp/types.h>
|
||||||
|
#include <assimp/material.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "boost/scoped_ptr.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
struct aiScene;
|
||||||
|
struct aiNode;
|
||||||
|
struct aiMaterial;
|
||||||
|
|
||||||
|
namespace glTF
|
||||||
|
{
|
||||||
|
class Asset;
|
||||||
|
|
||||||
|
struct TexProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
class IOSystem;
|
||||||
|
class IOStream;
|
||||||
|
class ExportProperties;
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
/** Helper class to export a given scene to an glTF file. */
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
class glTFExporter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Constructor for a specific scene to export
|
||||||
|
glTFExporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene,
|
||||||
|
const ExportProperties* pProperties, bool binary);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
const char* mFilename;
|
||||||
|
IOSystem* mIOSystem;
|
||||||
|
const aiScene* mScene;
|
||||||
|
const ExportProperties* mProperties;
|
||||||
|
|
||||||
|
std::map<std::string, size_t> mTexturesByPath;
|
||||||
|
|
||||||
|
glTF::Asset* mAsset;
|
||||||
|
|
||||||
|
std::vector<unsigned char> mBodyData;
|
||||||
|
|
||||||
|
void WriteBinaryData(IOStream* outfile, std::size_t sceneLength);
|
||||||
|
|
||||||
|
void GetMatColorOrTex(const aiMaterial* mat, glTF::TexProperty& prop, const char* propName, int type, int idx, aiTextureType tt);
|
||||||
|
void ExportMetadata();
|
||||||
|
void ExportMaterials();
|
||||||
|
void ExportMeshes();
|
||||||
|
size_t ExportNode(const aiNode* node);
|
||||||
|
void ExportScene();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,629 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||||
|
|
||||||
|
#include "glTFImporter.h"
|
||||||
|
|
||||||
|
#include "StringComparison.h"
|
||||||
|
|
||||||
|
#include "boost/scoped_ptr.hpp"
|
||||||
|
|
||||||
|
#include <assimp/Importer.hpp>
|
||||||
|
#include <assimp/scene.h>
|
||||||
|
#include <assimp/ai_assert.h>
|
||||||
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include "glTFAsset.h"
|
||||||
|
|
||||||
|
using namespace Assimp;
|
||||||
|
using namespace glTF;
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// glTFImporter
|
||||||
|
//
|
||||||
|
|
||||||
|
static const aiImporterDesc desc = {
|
||||||
|
"glTF Importer",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportCompressedFlavour
|
||||||
|
| aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
"gltf glb"
|
||||||
|
};
|
||||||
|
|
||||||
|
glTFImporter::glTFImporter()
|
||||||
|
: BaseImporter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
glTFImporter::~glTFImporter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiImporterDesc* glTFImporter::GetInfo() const
|
||||||
|
{
|
||||||
|
return &desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||||
|
{
|
||||||
|
const std::string& extension = GetExtension(pFile);
|
||||||
|
|
||||||
|
if (extension == "gltf" || extension == "glb")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((checkSig || !extension.length()) && pIOHandler) {
|
||||||
|
char buffer[4];
|
||||||
|
|
||||||
|
boost::scoped_ptr<IOStream> pStream(pIOHandler->Open(pFile));
|
||||||
|
if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) {
|
||||||
|
if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) {
|
||||||
|
return true; // Has GLB header
|
||||||
|
}
|
||||||
|
else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0
|
||||||
|
|| memcmp(buffer, "{\n ", sizeof(buffer)) == 0) {
|
||||||
|
// seems a JSON file, and we're the only format that can read them
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//static void CopyValue(const glTF::vec3& v, aiColor3D& out)
|
||||||
|
//{
|
||||||
|
// out.r = v[0]; out.g = v[1]; out.b = v[2];
|
||||||
|
//}
|
||||||
|
|
||||||
|
static void CopyValue(const glTF::vec4& v, aiColor4D& out)
|
||||||
|
{
|
||||||
|
out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyValue(const glTF::vec4& v, aiColor3D& out)
|
||||||
|
{
|
||||||
|
out.r = v[0]; out.g = v[1]; out.b = v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyValue(const glTF::vec3& v, aiVector3D& out)
|
||||||
|
{
|
||||||
|
out.x = v[0]; out.y = v[1]; out.z = v[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyValue(const glTF::vec4& v, aiQuaternion& out)
|
||||||
|
{
|
||||||
|
out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o)
|
||||||
|
{
|
||||||
|
o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3];
|
||||||
|
o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7];
|
||||||
|
o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11];
|
||||||
|
o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetMaterialColorProperty(std::vector<int>& embeddedTexIdxs, Asset& r, glTF::TexProperty prop, aiMaterial* mat,
|
||||||
|
aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx)
|
||||||
|
{
|
||||||
|
if (prop.texture) {
|
||||||
|
if (prop.texture->source) {
|
||||||
|
aiString uri(prop.texture->source->uri);
|
||||||
|
|
||||||
|
int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()];
|
||||||
|
if (texIdx != -1) { // embedded
|
||||||
|
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||||
|
uri.data[0] = '*';
|
||||||
|
uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
aiColor4D col;
|
||||||
|
CopyValue(prop.color, col);
|
||||||
|
if (col.r != 1.f || col.g != 1.f || col.b != 1.f || col.a != 1.f) {
|
||||||
|
mat->AddProperty(&col, 1, pKey, type, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::ImportMaterials(glTF::Asset& r)
|
||||||
|
{
|
||||||
|
mScene->mNumMaterials = r.materials.Size();
|
||||||
|
mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) {
|
||||||
|
aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial();
|
||||||
|
|
||||||
|
Material& mat = r.materials[i];
|
||||||
|
|
||||||
|
/*if (!mat.name.empty())*/ {
|
||||||
|
aiString str(mat.id /*mat.name*/);
|
||||||
|
aimat->AddProperty(&str, AI_MATKEY_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.diffuse, aimat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
|
||||||
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.specular, aimat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR);
|
||||||
|
SetMaterialColorProperty(embeddedTexIdxs, r, mat.ambient, aimat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
|
||||||
|
|
||||||
|
if (mat.shininess > 0.f) {
|
||||||
|
aimat->AddProperty(&mat.shininess, 1, AI_MATKEY_SHININESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mScene->mNumMaterials == 0) {
|
||||||
|
mScene->mNumMaterials = 1;
|
||||||
|
mScene->mMaterials = new aiMaterial*[1];
|
||||||
|
mScene->mMaterials[0] = new aiMaterial();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void SetFace(aiFace& face, int a)
|
||||||
|
{
|
||||||
|
face.mNumIndices = 1;
|
||||||
|
face.mIndices = new unsigned int[1];
|
||||||
|
face.mIndices[0] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetFace(aiFace& face, int a, int b)
|
||||||
|
{
|
||||||
|
face.mNumIndices = 2;
|
||||||
|
face.mIndices = new unsigned int[2];
|
||||||
|
face.mIndices[0] = a;
|
||||||
|
face.mIndices[1] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetFace(aiFace& face, int a, int b, int c)
|
||||||
|
{
|
||||||
|
face.mNumIndices = 3;
|
||||||
|
face.mIndices = new unsigned int[3];
|
||||||
|
face.mIndices[0] = a;
|
||||||
|
face.mIndices[1] = b;
|
||||||
|
face.mIndices[2] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::ImportMeshes(glTF::Asset& r)
|
||||||
|
{
|
||||||
|
std::vector<aiMesh*> meshes;
|
||||||
|
|
||||||
|
unsigned int k = 0;
|
||||||
|
|
||||||
|
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
|
||||||
|
Mesh& mesh = r.meshes[m];
|
||||||
|
|
||||||
|
meshOffsets.push_back(k);
|
||||||
|
k += mesh.primitives.size();
|
||||||
|
|
||||||
|
for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
|
||||||
|
Mesh::Primitive& prim = mesh.primitives[p];
|
||||||
|
|
||||||
|
aiMesh* aim = new aiMesh();
|
||||||
|
meshes.push_back(aim);
|
||||||
|
|
||||||
|
aim->mName = mesh.id;
|
||||||
|
if (mesh.primitives.size() > 1) {
|
||||||
|
size_t& len = aim->mName.length;
|
||||||
|
aim->mName.data[len] = '-';
|
||||||
|
len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, MAXLEN - len - 1, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (prim.mode) {
|
||||||
|
case PrimitiveMode_POINTS:
|
||||||
|
aim->mPrimitiveTypes |= aiPrimitiveType_POINT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PrimitiveMode_LINES:
|
||||||
|
case PrimitiveMode_LINE_LOOP:
|
||||||
|
case PrimitiveMode_LINE_STRIP:
|
||||||
|
aim->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PrimitiveMode_TRIANGLES:
|
||||||
|
case PrimitiveMode_TRIANGLE_STRIP:
|
||||||
|
case PrimitiveMode_TRIANGLE_FAN:
|
||||||
|
aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mesh::Primitive::Attributes& attr = prim.attributes;
|
||||||
|
if (attr.position.size() > 0 && attr.position[0]) {
|
||||||
|
aim->mNumVertices = attr.position[0]->count;
|
||||||
|
attr.position[0]->ExtractData(aim->mVertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attr.normal.size() > 0 && attr.normal[0]) {
|
||||||
|
attr.normal[0]->ExtractData(aim->mNormals);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t tc = 0; tc < attr.texcoord.size() && tc <= AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
|
||||||
|
attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
|
||||||
|
aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (prim.indices) {
|
||||||
|
aiFace* faces = 0;
|
||||||
|
size_t nFaces = 0;
|
||||||
|
|
||||||
|
unsigned int count = prim.indices->count;
|
||||||
|
|
||||||
|
Accessor::Indexer data = prim.indices->GetIndexer();
|
||||||
|
|
||||||
|
switch (prim.mode) {
|
||||||
|
case PrimitiveMode_POINTS: {
|
||||||
|
nFaces = count;
|
||||||
|
faces = new aiFace[nFaces];
|
||||||
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
|
SetFace(faces[i], data.GetUInt(i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PrimitiveMode_LINES: {
|
||||||
|
nFaces = count / 2;
|
||||||
|
faces = new aiFace[nFaces];
|
||||||
|
for (unsigned int i = 0; i < count; i += 2) {
|
||||||
|
SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PrimitiveMode_LINE_LOOP:
|
||||||
|
case PrimitiveMode_LINE_STRIP: {
|
||||||
|
nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
|
||||||
|
faces = new aiFace[nFaces];
|
||||||
|
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1));
|
||||||
|
for (unsigned int i = 2; i < count; ++i) {
|
||||||
|
SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i));
|
||||||
|
}
|
||||||
|
if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
|
||||||
|
SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PrimitiveMode_TRIANGLES: {
|
||||||
|
nFaces = count / 3;
|
||||||
|
faces = new aiFace[nFaces];
|
||||||
|
for (unsigned int i = 0; i < count; i += 3) {
|
||||||
|
SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PrimitiveMode_TRIANGLE_STRIP: {
|
||||||
|
nFaces = count - 2;
|
||||||
|
faces = new aiFace[nFaces];
|
||||||
|
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||||
|
for (unsigned int i = 3; i < count; ++i) {
|
||||||
|
SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PrimitiveMode_TRIANGLE_FAN:
|
||||||
|
nFaces = count - 2;
|
||||||
|
faces = new aiFace[nFaces];
|
||||||
|
SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
|
||||||
|
for (unsigned int i = 3; i < count; ++i) {
|
||||||
|
SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faces) {
|
||||||
|
aim->mFaces = faces;
|
||||||
|
aim->mNumFaces = nFaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (prim.material) {
|
||||||
|
aim->mMaterialIndex = prim.material.GetIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meshOffsets.push_back(k);
|
||||||
|
|
||||||
|
CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::ImportCameras(glTF::Asset& r)
|
||||||
|
{
|
||||||
|
if (!r.cameras.Size()) return;
|
||||||
|
|
||||||
|
mScene->mNumCameras = r.cameras.Size();
|
||||||
|
mScene->mCameras = new aiCamera*[r.cameras.Size()];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < r.cameras.Size(); ++i) {
|
||||||
|
Camera& cam = r.cameras[i];
|
||||||
|
|
||||||
|
aiCamera* aicam = mScene->mCameras[i] = new aiCamera();
|
||||||
|
|
||||||
|
if (cam.type == Camera::Perspective) {
|
||||||
|
|
||||||
|
aicam->mAspect = cam.perspective.aspectRatio;
|
||||||
|
aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect;
|
||||||
|
aicam->mClipPlaneFar = cam.perspective.zfar;
|
||||||
|
aicam->mClipPlaneNear = cam.perspective.znear;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// assimp does not support orthographic cameras
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::ImportLights(glTF::Asset& r)
|
||||||
|
{
|
||||||
|
if (!r.lights.Size()) return;
|
||||||
|
|
||||||
|
mScene->mNumLights = r.lights.Size();
|
||||||
|
mScene->mLights = new aiLight*[r.lights.Size()];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < r.lights.Size(); ++i) {
|
||||||
|
Light& l = r.lights[i];
|
||||||
|
|
||||||
|
aiLight* ail = mScene->mLights[i] = new aiLight();
|
||||||
|
|
||||||
|
switch (l.type) {
|
||||||
|
case Light::Type_directional:
|
||||||
|
ail->mType = aiLightSource_DIRECTIONAL; break;
|
||||||
|
|
||||||
|
case Light::Type_spot:
|
||||||
|
ail->mType = aiLightSource_SPOT; break;
|
||||||
|
|
||||||
|
case Light::Type_ambient:
|
||||||
|
ail->mType = aiLightSource_AMBIENT; break;
|
||||||
|
|
||||||
|
default: // Light::Type_point
|
||||||
|
ail->mType = aiLightSource_POINT; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyValue(l.color, ail->mColorAmbient);
|
||||||
|
CopyValue(l.color, ail->mColorDiffuse);
|
||||||
|
CopyValue(l.color, ail->mColorSpecular);
|
||||||
|
|
||||||
|
ail->mAngleOuterCone = l.falloffAngle;
|
||||||
|
ail->mAngleInnerCone = l.falloffExponent; // TODO fix this, it does not look right at all
|
||||||
|
|
||||||
|
ail->mAttenuationConstant = l.constantAttenuation;
|
||||||
|
ail->mAttenuationLinear = l.linearAttenuation;
|
||||||
|
ail->mAttenuationQuadratic = l.quadraticAttenuation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
aiNode* ImportNode(aiScene* pScene, glTF::Asset& r, std::vector<unsigned int>& meshOffsets, glTF::Ref<glTF::Node>& ptr)
|
||||||
|
{
|
||||||
|
Node& node = *ptr;
|
||||||
|
|
||||||
|
aiNode* ainode = new aiNode(node.id);
|
||||||
|
|
||||||
|
if (!node.children.empty()) {
|
||||||
|
ainode->mNumChildren = node.children.size();
|
||||||
|
ainode->mChildren = new aiNode*[ainode->mNumChildren];
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
|
||||||
|
aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]);
|
||||||
|
child->mParent = ainode;
|
||||||
|
ainode->mChildren[i] = child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aiMatrix4x4 matrix = ainode->mTransformation;
|
||||||
|
if (node.matrix.isPresent) {
|
||||||
|
CopyValue(node.matrix.value, matrix);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (node.translation.isPresent) {
|
||||||
|
aiVector3D trans;
|
||||||
|
CopyValue(node.translation.value, trans);
|
||||||
|
aiMatrix4x4 t;
|
||||||
|
aiMatrix4x4::Translation(trans, t);
|
||||||
|
matrix = t * matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.scale.isPresent) {
|
||||||
|
aiVector3D scal(1.f);
|
||||||
|
CopyValue(node.scale.value, scal);
|
||||||
|
aiMatrix4x4 s;
|
||||||
|
aiMatrix4x4::Scaling(scal, s);
|
||||||
|
matrix = s * matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (node.rotation.isPresent) {
|
||||||
|
aiQuaternion rot;
|
||||||
|
CopyValue(node.rotation.value, rot);
|
||||||
|
matrix = aiMatrix4x4(rot.GetMatrix()) * matrix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.meshes.empty()) {
|
||||||
|
int count = 0;
|
||||||
|
for (size_t i = 0; i < node.meshes.size(); ++i) {
|
||||||
|
int idx = node.meshes[i].GetIndex();
|
||||||
|
count += meshOffsets[idx + 1] - meshOffsets[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
ainode->mNumMeshes = count;
|
||||||
|
ainode->mMeshes = new unsigned int[count];
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
for (size_t i = 0; i < node.meshes.size(); ++i) {
|
||||||
|
int idx = node.meshes[i].GetIndex();
|
||||||
|
for (size_t j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) {
|
||||||
|
ainode->mMeshes[k] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.camera) {
|
||||||
|
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.light) {
|
||||||
|
pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ainode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::ImportNodes(glTF::Asset& r)
|
||||||
|
{
|
||||||
|
if (!r.scene) return;
|
||||||
|
|
||||||
|
std::vector< Ref<Node> > rootNodes = r.scene->nodes;
|
||||||
|
|
||||||
|
// The root nodes
|
||||||
|
unsigned int numRootNodes = rootNodes.size();
|
||||||
|
if (numRootNodes == 1) { // a single root node: use it
|
||||||
|
mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]);
|
||||||
|
}
|
||||||
|
else if (numRootNodes > 1) { // more than one root node: create a fake root
|
||||||
|
aiNode* root = new aiNode("ROOT");
|
||||||
|
root->mChildren = new aiNode*[numRootNodes];
|
||||||
|
for (unsigned int i = 0; i < numRootNodes; ++i) {
|
||||||
|
aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]);
|
||||||
|
node->mParent = root;
|
||||||
|
root->mChildren[root->mNumChildren++] = node;
|
||||||
|
}
|
||||||
|
mScene->mRootNode = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (!mScene->mRootNode) {
|
||||||
|
// mScene->mRootNode = new aiNode("EMPTY");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r)
|
||||||
|
{
|
||||||
|
embeddedTexIdxs.resize(r.images.Size(), -1);
|
||||||
|
|
||||||
|
int numEmbeddedTexs = 0;
|
||||||
|
for (size_t i = 0; i < r.images.Size(); ++i) {
|
||||||
|
if (r.images[i].HasData())
|
||||||
|
numEmbeddedTexs += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numEmbeddedTexs == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mScene->mTextures = new aiTexture*[numEmbeddedTexs];
|
||||||
|
|
||||||
|
// Add the embedded textures
|
||||||
|
for (size_t i = 0; i < r.images.Size(); ++i) {
|
||||||
|
Image img = r.images[i];
|
||||||
|
if (!img.HasData()) continue;
|
||||||
|
|
||||||
|
int idx = mScene->mNumTextures++;
|
||||||
|
embeddedTexIdxs[i] = idx;
|
||||||
|
|
||||||
|
aiTexture* tex = mScene->mTextures[idx] = new aiTexture();
|
||||||
|
|
||||||
|
size_t length = img.GetDataLength();
|
||||||
|
void* data = img.StealData();
|
||||||
|
|
||||||
|
tex->mWidth = static_cast<unsigned int>(length);
|
||||||
|
tex->mHeight = 0;
|
||||||
|
tex->pcData = reinterpret_cast<aiTexel*>(data);
|
||||||
|
|
||||||
|
if (!img.mimeType.empty()) {
|
||||||
|
const char* ext = strchr(img.mimeType.c_str(), '/') + 1;
|
||||||
|
if (ext) {
|
||||||
|
if (strcmp(ext, "jpeg") == 0) ext = "jpg";
|
||||||
|
|
||||||
|
size_t len = strlen(ext);
|
||||||
|
if (len <= 3) {
|
||||||
|
strcpy(tex->achFormatHint, ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
|
||||||
|
|
||||||
|
this->mScene = pScene;
|
||||||
|
|
||||||
|
// read the asset file
|
||||||
|
glTF::Asset asset(pIOHandler);
|
||||||
|
asset.Load(pFile, GetExtension(pFile) == "glb");
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Copy the data out
|
||||||
|
//
|
||||||
|
|
||||||
|
ImportEmbeddedTextures(asset);
|
||||||
|
ImportMaterials(asset);
|
||||||
|
|
||||||
|
ImportMeshes(asset);
|
||||||
|
|
||||||
|
ImportCameras(asset);
|
||||||
|
ImportLights(asset);
|
||||||
|
|
||||||
|
ImportNodes(asset);
|
||||||
|
|
||||||
|
// TODO: it does not split the loaded vertices, should it?
|
||||||
|
pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
|
||||||
|
|
||||||
|
if (pScene->mNumMeshes == 0) {
|
||||||
|
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
Open Asset Import Library (assimp)
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, assimp team
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
with or without modification, are permitted provided that the
|
||||||
|
following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the
|
||||||
|
following disclaimer in the documentation and/or other
|
||||||
|
materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the assimp team, nor the names of its
|
||||||
|
contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior
|
||||||
|
written permission of the assimp team.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef AI_GLTFIMPORTER_H_INC
|
||||||
|
#define AI_GLTFIMPORTER_H_INC
|
||||||
|
|
||||||
|
#include "BaseImporter.h"
|
||||||
|
#include "DefaultIOSystem.h"
|
||||||
|
|
||||||
|
struct aiNode;
|
||||||
|
|
||||||
|
|
||||||
|
namespace glTF
|
||||||
|
{
|
||||||
|
class Asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the glTF format.
|
||||||
|
* https://github.com/KhronosGroup/glTF/tree/master/specification
|
||||||
|
*/
|
||||||
|
class glTFImporter : public BaseImporter{
|
||||||
|
public:
|
||||||
|
glTFImporter();
|
||||||
|
virtual ~glTFImporter();
|
||||||
|
virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual const aiImporterDesc* GetInfo() const;
|
||||||
|
virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<unsigned int> meshOffsets;
|
||||||
|
|
||||||
|
std::vector<int> embeddedTexIdxs;
|
||||||
|
|
||||||
|
aiScene* mScene;
|
||||||
|
|
||||||
|
void ImportEmbeddedTextures(glTF::Asset& a);
|
||||||
|
void ImportMaterials(glTF::Asset& a);
|
||||||
|
void ImportMeshes(glTF::Asset& a);
|
||||||
|
void ImportCameras(glTF::Asset& a);
|
||||||
|
void ImportLights(glTF::Asset& a);
|
||||||
|
void ImportNodes(glTF::Asset& a);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Namespace assimp
|
||||||
|
|
||||||
|
#endif // AI_GLTFIMPORTER_H_INC
|
||||||
|
|
|
@ -76,7 +76,7 @@ public:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
//! Construction from an existing IOStream
|
//! Construction from an existing IOStream
|
||||||
CIrrXML_IOStreamReader(IOStream* _stream)
|
explicit CIrrXML_IOStreamReader(IOStream* _stream)
|
||||||
: stream (_stream)
|
: stream (_stream)
|
||||||
, t (0)
|
, t (0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* Paper no. DETC2005-85513 pp. 565-575 *
|
* Paper no. DETC2005-85513 pp. 565-575 *
|
||||||
* ASME 2005 International Design Engineering Technical Conferences *
|
* ASME 2005 International Design Engineering Technical Conferences *
|
||||||
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
||||||
* September 24–28, 2005 , Long Beach, California, USA *
|
* September 24–28, 2005 , Long Beach, California, USA *
|
||||||
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
||||||
* *
|
* *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* Paper no. DETC2005-85513 pp. 565-575 *
|
* Paper no. DETC2005-85513 pp. 565-575 *
|
||||||
* ASME 2005 International Design Engineering Technical Conferences *
|
* ASME 2005 International Design Engineering Technical Conferences *
|
||||||
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
|
||||||
* September 24–28, 2005 , Long Beach, California, USA *
|
* September 24–28, 2005 , Long Beach, California, USA *
|
||||||
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
|
||||||
* *
|
* *
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
|
@ -49,11 +49,7 @@ static void releaseReferencedNames( Reference *ref ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ref->m_referencedName ) {
|
delete ref;
|
||||||
for( size_t i = 0; i < ref->m_numRefs; i++ ) {
|
|
||||||
delete ref->m_referencedName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent )
|
DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent )
|
||||||
|
@ -121,7 +117,6 @@ const std::string &DDLNode::getType() const {
|
||||||
return m_type;
|
return m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DDLNode::setName( const std::string &name ) {
|
void DDLNode::setName( const std::string &name ) {
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +138,10 @@ bool DDLNode::hasProperty( const std::string &name ) {
|
||||||
return ( ddl_nullptr != prop );
|
return ( ddl_nullptr != prop );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DDLNode::hasProperties() const {
|
||||||
|
return( ddl_nullptr != m_properties );
|
||||||
|
}
|
||||||
|
|
||||||
Property *DDLNode::findPropertyByName( const std::string &name ) {
|
Property *DDLNode::findPropertyByName( const std::string &name ) {
|
||||||
if( name.empty() ) {
|
if( name.empty() ) {
|
||||||
return ddl_nullptr;
|
return ddl_nullptr;
|
||||||
|
@ -151,6 +150,7 @@ Property *DDLNode::findPropertyByName( const std::string &name ) {
|
||||||
if( ddl_nullptr == m_properties ) {
|
if( ddl_nullptr == m_properties ) {
|
||||||
return ddl_nullptr;
|
return ddl_nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Property *current( m_properties );
|
Property *current( m_properties );
|
||||||
while( ddl_nullptr != current ) {
|
while( ddl_nullptr != current ) {
|
||||||
int res = strncmp( current->m_key->m_text.m_buffer, name.c_str(), name.size() );
|
int res = strncmp( current->m_key->m_text.m_buffer, name.c_str(), name.size() );
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*-----------------------------------------------------------------------------------------------
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2015 Kim Kulling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
-----------------------------------------------------------------------------------------------*/
|
||||||
|
#include <openddlparser/OpenDDLCommon.h>
|
||||||
|
#include <openddlparser/DDLNode.h>
|
||||||
|
|
||||||
|
BEGIN_ODDLPARSER_NS
|
||||||
|
|
||||||
|
Text::Text( const char *buffer, size_t numChars )
|
||||||
|
: m_capacity( 0 )
|
||||||
|
, m_len( 0 )
|
||||||
|
, m_buffer( ddl_nullptr ) {
|
||||||
|
set( buffer, numChars );
|
||||||
|
}
|
||||||
|
|
||||||
|
Text::~Text() {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Text::clear() {
|
||||||
|
delete[] m_buffer;
|
||||||
|
m_buffer = ddl_nullptr;
|
||||||
|
m_capacity = 0;
|
||||||
|
m_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Text::set( const char *buffer, size_t numChars ) {
|
||||||
|
clear();
|
||||||
|
if( numChars > 0 ) {
|
||||||
|
m_len = numChars;
|
||||||
|
m_capacity = m_len + 1;
|
||||||
|
m_buffer = new char[ m_capacity ];
|
||||||
|
strncpy( m_buffer, buffer, numChars );
|
||||||
|
m_buffer[ numChars ] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Text::operator == ( const std::string &name ) const {
|
||||||
|
if( m_len != name.size() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const int res( strncmp( m_buffer, name.c_str(), name.size() ) );
|
||||||
|
|
||||||
|
return ( 0 == res );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Text::operator == ( const Text &rhs ) const {
|
||||||
|
if( m_len != rhs.m_len ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) );
|
||||||
|
|
||||||
|
return ( 0 == res );
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier::Identifier( const char buffer[], size_t len )
|
||||||
|
: m_text( buffer, len ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier::Identifier( const char buffer[] )
|
||||||
|
: m_text( buffer, strlen( buffer ) ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier::~Identifier() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Identifier::operator == ( const Identifier &rhs ) const {
|
||||||
|
return m_text == rhs.m_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
Name::Name( NameType type, Identifier *id )
|
||||||
|
: m_type( type )
|
||||||
|
, m_id( id ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Name::~Name() {
|
||||||
|
m_id = ddl_nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference::Reference()
|
||||||
|
: m_numRefs( 0 )
|
||||||
|
, m_referencedName( ddl_nullptr ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference::Reference( size_t numrefs, Name **names )
|
||||||
|
: m_numRefs( numrefs )
|
||||||
|
, m_referencedName( ddl_nullptr ) {
|
||||||
|
m_referencedName = new Name *[ numrefs ];
|
||||||
|
for( size_t i = 0; i < numrefs; i++ ) {
|
||||||
|
Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id );
|
||||||
|
m_referencedName[ i ] = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference::~Reference() {
|
||||||
|
for( size_t i = 0; i < m_numRefs; i++ ) {
|
||||||
|
delete m_referencedName[ i ];
|
||||||
|
}
|
||||||
|
m_numRefs = 0;
|
||||||
|
m_referencedName = ddl_nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Property::Property( Identifier *id )
|
||||||
|
: m_key( id )
|
||||||
|
, m_value( ddl_nullptr )
|
||||||
|
, m_ref( ddl_nullptr )
|
||||||
|
, m_next( ddl_nullptr ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Property::~Property() {
|
||||||
|
m_key = ddl_nullptr;
|
||||||
|
m_value = ddl_nullptr;
|
||||||
|
m_ref = ddl_nullptr;;
|
||||||
|
m_next = ddl_nullptr;;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataArrayList::DataArrayList()
|
||||||
|
: m_numItems( 0 )
|
||||||
|
, m_dataList( ddl_nullptr )
|
||||||
|
, m_next( ddl_nullptr ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
DataArrayList::~DataArrayList() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Context::Context()
|
||||||
|
: m_root( ddl_nullptr ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
Context::~Context() {
|
||||||
|
m_root = ddl_nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::clear() {
|
||||||
|
delete m_root;
|
||||||
|
m_root = ddl_nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
END_ODDLPARSER_NS
|
|
@ -0,0 +1,412 @@
|
||||||
|
/*-----------------------------------------------------------------------------------------------
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2015 Kim Kulling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
-----------------------------------------------------------------------------------------------*/
|
||||||
|
#include <openddlparser/OpenDDLExport.h>
|
||||||
|
#include <openddlparser/DDLNode.h>
|
||||||
|
#include <openddlparser/Value.h>
|
||||||
|
#include <openddlparser/OpenDDLParser.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
BEGIN_ODDLPARSER_NS
|
||||||
|
|
||||||
|
IOStreamBase::IOStreamBase()
|
||||||
|
: m_file( ddl_nullptr ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
IOStreamBase::~IOStreamBase() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IOStreamBase::open( const std::string &name ) {
|
||||||
|
m_file = ::fopen( name.c_str(), "a" );
|
||||||
|
if (m_file == ddl_nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IOStreamBase::close() {
|
||||||
|
if (ddl_nullptr == m_file) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
::fclose( m_file );
|
||||||
|
m_file = ddl_nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOStreamBase::write( const std::string &statement ) {
|
||||||
|
if (ddl_nullptr == m_file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::fwrite( statement.c_str(), sizeof( char ), statement.size(), m_file );
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DDLNodeIterator {
|
||||||
|
const DDLNode::DllNodeList &m_childs;
|
||||||
|
size_t m_idx;
|
||||||
|
|
||||||
|
DDLNodeIterator( const DDLNode::DllNodeList &childs )
|
||||||
|
: m_childs( childs )
|
||||||
|
, m_idx( 0 ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
~DDLNodeIterator() {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getNext( DDLNode **node ) {
|
||||||
|
if( m_childs.size() > (m_idx+1) ) {
|
||||||
|
m_idx++;
|
||||||
|
*node = m_childs[ m_idx ];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void writeLineEnd( std::string &statement ) {
|
||||||
|
statement += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenDDLExport::OpenDDLExport( IOStreamBase *stream )
|
||||||
|
: m_stream( stream ) {
|
||||||
|
if (ddl_nullptr == m_stream) {
|
||||||
|
m_stream = new IOStreamBase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenDDLExport::~OpenDDLExport() {
|
||||||
|
if (ddl_nullptr != m_stream) {
|
||||||
|
m_stream->close();
|
||||||
|
}
|
||||||
|
delete m_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::exportContext( Context *ctx, const std::string &filename ) {
|
||||||
|
if( ddl_nullptr == ctx ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DDLNode *root( ctx->m_root );
|
||||||
|
if ( ddl_nullptr == root ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filename.empty()) {
|
||||||
|
if (!m_stream->open( filename )) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool retValue( handleNode( root ) );
|
||||||
|
|
||||||
|
return retValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::handleNode( DDLNode *node ) {
|
||||||
|
if( ddl_nullptr == node ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DDLNode::DllNodeList &childs = node->getChildNodeList();
|
||||||
|
if( childs.empty() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
DDLNode *current( ddl_nullptr );
|
||||||
|
DDLNodeIterator it( childs );
|
||||||
|
std::string statement;
|
||||||
|
bool success( true );
|
||||||
|
while( it.getNext( ¤t ) ) {
|
||||||
|
if( ddl_nullptr != current ) {
|
||||||
|
success |= writeNode( current, statement );
|
||||||
|
if( !handleNode( current ) ) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeToStream( const std::string &statement ) {
|
||||||
|
if (ddl_nullptr == m_stream ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !statement.empty()) {
|
||||||
|
m_stream->write( statement );
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) {
|
||||||
|
bool success( true );
|
||||||
|
writeNodeHeader( node, statement );
|
||||||
|
if (node->hasProperties()) {
|
||||||
|
success |= writeProperties( node, statement );
|
||||||
|
}
|
||||||
|
writeLineEnd( statement );
|
||||||
|
|
||||||
|
statement = "}";
|
||||||
|
DataArrayList *al( node->getDataArrayList() );
|
||||||
|
if ( ddl_nullptr != al ) {
|
||||||
|
writeValueType( al->m_dataList->m_type, al->m_numItems, statement );
|
||||||
|
writeValueArray( al, statement );
|
||||||
|
}
|
||||||
|
Value *v( node->getValue() );
|
||||||
|
if (ddl_nullptr != v ) {
|
||||||
|
writeValueType( v->m_type, 1, statement );
|
||||||
|
statement = "{";
|
||||||
|
writeLineEnd( statement );
|
||||||
|
writeValue( v, statement );
|
||||||
|
statement = "}";
|
||||||
|
writeLineEnd( statement );
|
||||||
|
}
|
||||||
|
statement = "}";
|
||||||
|
writeLineEnd( statement );
|
||||||
|
|
||||||
|
writeToStream( statement );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeNodeHeader( DDLNode *node, std::string &statement ) {
|
||||||
|
if (ddl_nullptr == node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement += node->getType();
|
||||||
|
const std::string &name( node->getName() );
|
||||||
|
if ( !name.empty() ) {
|
||||||
|
statement += " ";
|
||||||
|
statement += "$";
|
||||||
|
statement += name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeProperties( DDLNode *node, std::string &statement ) {
|
||||||
|
if ( ddl_nullptr == node ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Property *prop( node->getProperties() );
|
||||||
|
// if no properties are there, return
|
||||||
|
if ( ddl_nullptr == prop ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ddl_nullptr != prop ) {
|
||||||
|
// for instance (attrib = "position", bla=2)
|
||||||
|
statement += "(";
|
||||||
|
bool first( true );
|
||||||
|
while ( ddl_nullptr != prop ) {
|
||||||
|
if (!first) {
|
||||||
|
statement += ", ";
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
statement += std::string( prop->m_key->m_text.m_buffer );
|
||||||
|
statement += " = ";
|
||||||
|
writeValue( prop->m_value, statement );
|
||||||
|
prop = prop->m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement += ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std::string &statement ) {
|
||||||
|
if ( Value::ddl_types_max == type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string typeStr( getTypeToken( type ) );
|
||||||
|
statement += typeStr;
|
||||||
|
// if we have an array to write
|
||||||
|
if ( numItems > 1 ) {
|
||||||
|
statement += "[";
|
||||||
|
char buffer[ 256 ];
|
||||||
|
::memset( buffer, '\0', 256 * sizeof( char ) );
|
||||||
|
sprintf( buffer, "%d", numItems );
|
||||||
|
statement += buffer;
|
||||||
|
statement += "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeValue( Value *val, std::string &statement ) {
|
||||||
|
if (ddl_nullptr == val) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( val->m_type ) {
|
||||||
|
case Value::ddl_bool:
|
||||||
|
if ( true == val->getBool() ) {
|
||||||
|
statement += "true";
|
||||||
|
} else {
|
||||||
|
statement += "false";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_int8:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
const int i = static_cast<int>( val->getInt8() );
|
||||||
|
stream << i;
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_int16:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
char buffer[ 256 ];
|
||||||
|
::memset( buffer, '\0', 256 * sizeof( char ) );
|
||||||
|
sprintf( buffer, "%d", val->getInt16() );
|
||||||
|
statement += buffer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_int32:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
char buffer[ 256 ];
|
||||||
|
::memset( buffer, '\0', 256 * sizeof( char ) );
|
||||||
|
const int i = static_cast< int >( val->getInt32() );
|
||||||
|
sprintf( buffer, "%d", i );
|
||||||
|
statement += buffer;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_int64:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
const int i = static_cast< int >( val->getInt64() );
|
||||||
|
stream << i;
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_unsigned_int8:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
const int i = static_cast< unsigned int >( val->getUnsignedInt8() );
|
||||||
|
stream << i;
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_unsigned_int16:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
const int i = static_cast< unsigned int >( val->getUnsignedInt16() );
|
||||||
|
stream << i;
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_unsigned_int32:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
const int i = static_cast< unsigned int >( val->getUnsignedInt32() );
|
||||||
|
stream << i;
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_unsigned_int64:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
const int i = static_cast< unsigned int >( val->getUnsignedInt64() );
|
||||||
|
stream << i;
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_half:
|
||||||
|
break;
|
||||||
|
case Value::ddl_float:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << val->getFloat();
|
||||||
|
statement += stream.str();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_double:
|
||||||
|
break;
|
||||||
|
case Value::ddl_string:
|
||||||
|
{
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << val->getString();
|
||||||
|
statement += "\"";
|
||||||
|
statement += stream.str();
|
||||||
|
statement += "\"";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Value::ddl_ref:
|
||||||
|
break;
|
||||||
|
case Value::ddl_none:
|
||||||
|
case Value::ddl_types_max:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement ) {
|
||||||
|
if (ddl_nullptr == al) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == al->m_numItems) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DataArrayList *nextDataArrayList = al ;
|
||||||
|
Value *nextValue( nextDataArrayList->m_dataList );
|
||||||
|
while (ddl_nullptr != nextDataArrayList) {
|
||||||
|
if (ddl_nullptr != nextDataArrayList) {
|
||||||
|
statement += "{ ";
|
||||||
|
nextValue = nextDataArrayList->m_dataList;
|
||||||
|
size_t idx( 0 );
|
||||||
|
while (ddl_nullptr != nextValue) {
|
||||||
|
if (idx > 0) {
|
||||||
|
statement += ", ";
|
||||||
|
}
|
||||||
|
writeValue( nextValue, statement );
|
||||||
|
nextValue = nextValue->m_next;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
statement += " }";
|
||||||
|
}
|
||||||
|
nextDataArrayList = nextDataArrayList->m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
END_ODDLPARSER_NS
|
|
@ -21,6 +21,7 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
-----------------------------------------------------------------------------------------------*/
|
-----------------------------------------------------------------------------------------------*/
|
||||||
#include <openddlparser/OpenDDLParser.h>
|
#include <openddlparser/OpenDDLParser.h>
|
||||||
|
#include <openddlparser/OpenDDLExport.h>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -36,17 +37,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
BEGIN_ODDLPARSER_NS
|
BEGIN_ODDLPARSER_NS
|
||||||
|
|
||||||
static const char *Version = "0.1.0";
|
static const char *Version = "0.3.0";
|
||||||
|
|
||||||
namespace Grammar {
|
namespace Grammar {
|
||||||
static const char * const OpenBracketToken = "{";
|
static const char *OpenBracketToken = "{";
|
||||||
static const char * const CloseBracketToken = "}";
|
static const char *CloseBracketToken = "}";
|
||||||
static const char * const OpenPropertyToken = "(";
|
static const char *OpenPropertyToken = "(";
|
||||||
static const char * const ClosePropertyToken = ")";
|
static const char *ClosePropertyToken = ")";
|
||||||
static const char * const BoolTrue = "true";
|
static const char *OpenArrayToken = "[";
|
||||||
static const char * const BoolFalse = "false";
|
static const char *CloseArrayToken = "]";
|
||||||
static const char * const RefToken = "ref";
|
static const char *BoolTrue = "true";
|
||||||
static const char * const CommaSeparator = ",";
|
static const char *BoolFalse = "false";
|
||||||
|
static const char *CommaSeparator = ",";
|
||||||
|
|
||||||
static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = {
|
static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = {
|
||||||
"bool",
|
"bool",
|
||||||
|
@ -66,6 +68,9 @@ namespace Grammar {
|
||||||
};
|
};
|
||||||
} // Namespace Grammar
|
} // Namespace Grammar
|
||||||
|
|
||||||
|
const char *getTypeToken( Value::ValueType type ) {
|
||||||
|
return Grammar::PrimitiveTypeToken[ type ];
|
||||||
|
}
|
||||||
|
|
||||||
static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) {
|
static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) {
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
|
@ -206,6 +211,17 @@ bool OpenDDLParser::parse() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenDDLParser::exportContext( Context *ctx, const std::string &filename ) {
|
||||||
|
if( ddl_nullptr == ctx ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenDDLExport myExporter;
|
||||||
|
return myExporter.exportContext( ctx, filename );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
char *OpenDDLParser::parseNextNode( char *in, char *end ) {
|
char *OpenDDLParser::parseNextNode( char *in, char *end ) {
|
||||||
in = parseHeader( in, end );
|
in = parseHeader( in, end );
|
||||||
in = parseStructure( in, end );
|
in = parseStructure( in, end );
|
||||||
|
@ -215,6 +231,7 @@ char *OpenDDLParser::parseNextNode( char *in, char *end ) {
|
||||||
|
|
||||||
static void dumpId( Identifier *id ) {
|
static void dumpId( Identifier *id ) {
|
||||||
if( ddl_nullptr != id ) {
|
if( ddl_nullptr != id ) {
|
||||||
|
if ( ddl_nullptr != id->m_text.m_buffer ) { }
|
||||||
std::cout << id->m_text.m_buffer << std::endl;
|
std::cout << id->m_text.m_buffer << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,19 +251,19 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) {
|
||||||
in = lookForNextToken( in, end );
|
in = lookForNextToken( in, end );
|
||||||
Property *first( ddl_nullptr );
|
Property *first( ddl_nullptr );
|
||||||
if( ddl_nullptr != id ) {
|
if( ddl_nullptr != id ) {
|
||||||
if( *in == '(' ) {
|
if( *in == Grammar::OpenPropertyToken[ 0 ] ) {
|
||||||
in++;
|
in++;
|
||||||
Property *prop( ddl_nullptr ), *prev( ddl_nullptr );
|
Property *prop( ddl_nullptr ), *prev( ddl_nullptr );
|
||||||
while( *in != ')' && in != end ) {
|
while( *in != Grammar::ClosePropertyToken[ 0 ] && in != end ) {
|
||||||
in = OpenDDLParser::parseProperty( in, end, &prop );
|
in = OpenDDLParser::parseProperty( in, end, &prop );
|
||||||
in = lookForNextToken( in, end );
|
in = lookForNextToken( in, end );
|
||||||
|
|
||||||
if( *in != ',' && *in != ')' ) {
|
if( *in != Grammar::CommaSeparator[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] ) {
|
||||||
logInvalidTokenError( in, ")", m_logCallback );
|
logInvalidTokenError( in, Grammar::ClosePropertyToken, m_logCallback );
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ddl_nullptr != prop && *in != ',' ) {
|
if( ddl_nullptr != prop && *in != Grammar::CommaSeparator[ 0 ] ) {
|
||||||
if( ddl_nullptr == first ) {
|
if( ddl_nullptr == first ) {
|
||||||
first = prop;
|
first = prop;
|
||||||
}
|
}
|
||||||
|
@ -348,13 +365,13 @@ char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) {
|
||||||
if( Value::ddl_none != type ) {
|
if( Value::ddl_none != type ) {
|
||||||
// parse a primitive data type
|
// parse a primitive data type
|
||||||
in = lookForNextToken( in, end );
|
in = lookForNextToken( in, end );
|
||||||
if( *in == '{' ) {
|
if( *in == Grammar::OpenBracketToken[ 0 ] ) {
|
||||||
Reference *refs( ddl_nullptr );
|
Reference *refs( ddl_nullptr );
|
||||||
DataArrayList *dtArrayList( ddl_nullptr );
|
DataArrayList *dtArrayList( ddl_nullptr );
|
||||||
Value *values( ddl_nullptr );
|
Value *values( ddl_nullptr );
|
||||||
if( 1 == arrayLen ) {
|
if( 1 == arrayLen ) {
|
||||||
size_t numRefs( 0 ), numValues( 0 );
|
size_t numRefs( 0 ), numValues( 0 );
|
||||||
in = parseDataList( in, end, &values, numValues, &refs, numRefs );
|
in = parseDataList( in, end, type, &values, numValues, &refs, numRefs );
|
||||||
setNodeValues( top(), values );
|
setNodeValues( top(), values );
|
||||||
setNodeReferences( top(), refs );
|
setNodeReferences( top(), refs );
|
||||||
} else if( arrayLen > 1 ) {
|
} else if( arrayLen > 1 ) {
|
||||||
|
@ -435,10 +452,10 @@ void OpenDDLParser::normalizeBuffer( std::vector<char> &buffer) {
|
||||||
newBuffer.push_back( buffer[ readIdx ] );
|
newBuffer.push_back( buffer[ readIdx ] );
|
||||||
} else {
|
} else {
|
||||||
if( isComment<char>( c, end ) ) {
|
if( isComment<char>( c, end ) ) {
|
||||||
readIdx++;
|
++readIdx;
|
||||||
// skip the comment and the rest of the line
|
// skip the comment and the rest of the line
|
||||||
while( !isEndofLine( buffer[ readIdx ] ) ) {
|
while( !isEndofLine( buffer[ readIdx ] ) ) {
|
||||||
readIdx++;
|
++readIdx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -493,9 +510,9 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Identifier **id ) {
|
||||||
// get size of id
|
// get size of id
|
||||||
size_t idLen( 0 );
|
size_t idLen( 0 );
|
||||||
char *start( in );
|
char *start( in );
|
||||||
while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != '(' && *in != ')' ) {
|
while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] ) {
|
||||||
in++;
|
++in;
|
||||||
idLen++;
|
++idLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t len( idLen );
|
const size_t len( idLen );
|
||||||
|
@ -529,14 +546,14 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok( true );
|
bool ok( true );
|
||||||
if( *in == '[' ) {
|
if( *in == Grammar::OpenArrayToken[ 0 ] ) {
|
||||||
ok = false;
|
ok = false;
|
||||||
in++;
|
in++;
|
||||||
char *start( in );
|
char *start( in );
|
||||||
while ( in != end ) {
|
while ( in != end ) {
|
||||||
in++;
|
in++;
|
||||||
if( *in == ']' ) {
|
if( *in == Grammar::CloseArrayToken[ 0 ] ) {
|
||||||
len = atoi( start );
|
len = ::atoi( start );
|
||||||
ok = true;
|
ok = true;
|
||||||
in++;
|
in++;
|
||||||
break;
|
break;
|
||||||
|
@ -562,9 +579,9 @@ char *OpenDDLParser::parseReference( char *in, char *end, std::vector<Name*> &na
|
||||||
if( nextName ) {
|
if( nextName ) {
|
||||||
names.push_back( nextName );
|
names.push_back( nextName );
|
||||||
}
|
}
|
||||||
while( ',' == *in ) {
|
while( Grammar::CommaSeparator[ 0 ] == *in ) {
|
||||||
in = getNextSeparator( in, end );
|
in = getNextSeparator( in, end );
|
||||||
if( ',' == *in ) {
|
if( Grammar::CommaSeparator[ 0 ] == *in ) {
|
||||||
in = parseName( in, end, &nextName );
|
in = parseName( in, end, &nextName );
|
||||||
if( nextName ) {
|
if( nextName ) {
|
||||||
names.push_back( nextName );
|
names.push_back( nextName );
|
||||||
|
@ -802,7 +819,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) {
|
char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) {
|
||||||
*data = ddl_nullptr;
|
*data = ddl_nullptr;
|
||||||
numValues = numRefs = 0;
|
numValues = numRefs = 0;
|
||||||
if( ddl_nullptr == in || in == end ) {
|
if( ddl_nullptr == in || in == end ) {
|
||||||
|
@ -816,15 +833,20 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n
|
||||||
while( '}' != *in ) {
|
while( '}' != *in ) {
|
||||||
current = ddl_nullptr;
|
current = ddl_nullptr;
|
||||||
in = lookForNextToken( in, end );
|
in = lookForNextToken( in, end );
|
||||||
|
if (Value::ddl_none == type) {
|
||||||
if (isInteger( in, end )) {
|
if (isInteger( in, end )) {
|
||||||
in = parseIntegerLiteral( in, end, ¤t );
|
in = parseIntegerLiteral( in, end, ¤t );
|
||||||
} else if( isFloat( in, end ) ) {
|
}
|
||||||
|
else if (isFloat( in, end )) {
|
||||||
in = parseFloatingLiteral( in, end, ¤t );
|
in = parseFloatingLiteral( in, end, ¤t );
|
||||||
} else if( isStringLiteral( *in ) ) {
|
}
|
||||||
|
else if (isStringLiteral( *in )) {
|
||||||
in = parseStringLiteral( in, end, ¤t );
|
in = parseStringLiteral( in, end, ¤t );
|
||||||
} else if( isHexLiteral( in, end ) ) {
|
}
|
||||||
|
else if (isHexLiteral( in, end )) {
|
||||||
in = parseHexaLiteral( in, end, ¤t );
|
in = parseHexaLiteral( in, end, ¤t );
|
||||||
} else { // reference data
|
}
|
||||||
|
else { // reference data
|
||||||
std::vector<Name*> names;
|
std::vector<Name*> names;
|
||||||
in = parseReference( in, end, names );
|
in = parseReference( in, end, names );
|
||||||
if (!names.empty()) {
|
if (!names.empty()) {
|
||||||
|
@ -833,6 +855,15 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n
|
||||||
numRefs = names.size();
|
numRefs = names.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (Value::ddl_int32 == type) {
|
||||||
|
in = parseIntegerLiteral( in, end, ¤t );
|
||||||
|
} else if (Value::ddl_float == type) {
|
||||||
|
in = parseFloatingLiteral( in, end, ¤t );
|
||||||
|
} else if (Value::ddl_string == type) {
|
||||||
|
in = parseStringLiteral( in, end, ¤t );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( ddl_nullptr != current ) {
|
if( ddl_nullptr != current ) {
|
||||||
if( ddl_nullptr == *data ) {
|
if( ddl_nullptr == *data ) {
|
||||||
|
@ -846,7 +877,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value **data, size_t &n
|
||||||
}
|
}
|
||||||
|
|
||||||
in = getNextSeparator( in, end );
|
in = getNextSeparator( in, end );
|
||||||
if( ',' != *in && '}' != *in && !isSpace( *in ) ) {
|
if( ',' != *in && Grammar::CloseBracketToken[ 0 ] != *in && !isSpace( *in ) ) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -879,7 +910,8 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end, DataArrayList **da
|
||||||
do {
|
do {
|
||||||
size_t numRefs( 0 ), numValues( 0 );
|
size_t numRefs( 0 ), numValues( 0 );
|
||||||
currentValue = ddl_nullptr;
|
currentValue = ddl_nullptr;
|
||||||
in = parseDataList( in, end, ¤tValue, numValues, &refs, numRefs );
|
Value::ValueType type( Value::ddl_none );
|
||||||
|
in = parseDataList( in, end, type, ¤tValue, numValues, &refs, numRefs );
|
||||||
if( ddl_nullptr != currentValue ) {
|
if( ddl_nullptr != currentValue ) {
|
||||||
if( ddl_nullptr == prev ) {
|
if( ddl_nullptr == prev ) {
|
||||||
*dataList = createDataArrayList( currentValue, numValues );
|
*dataList = createDataArrayList( currentValue, numValues );
|
||||||
|
|
|
@ -27,6 +27,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
BEGIN_ODDLPARSER_NS
|
BEGIN_ODDLPARSER_NS
|
||||||
|
|
||||||
|
static Value::Iterator end( ddl_nullptr );
|
||||||
|
|
||||||
Value::Iterator::Iterator()
|
Value::Iterator::Iterator()
|
||||||
: m_start( ddl_nullptr )
|
: m_start( ddl_nullptr )
|
||||||
, m_current( ddl_nullptr ) {
|
, m_current( ddl_nullptr ) {
|
||||||
|
@ -39,6 +41,12 @@ Value::Iterator::Iterator( Value *start )
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::Iterator::Iterator( const Iterator &rhs )
|
||||||
|
: m_start( rhs.m_start )
|
||||||
|
, m_current( rhs.m_current ) {
|
||||||
|
// empty
|
||||||
|
}
|
||||||
|
|
||||||
Value::Iterator::~Iterator() {
|
Value::Iterator::~Iterator() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
@ -61,6 +69,38 @@ Value *Value::Iterator::getNext() {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Value::Iterator Value::Iterator::operator++( int ) {
|
||||||
|
if( ddl_nullptr == m_current ) {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_current = m_current->getNext();
|
||||||
|
Iterator inst( m_current );
|
||||||
|
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value::Iterator &Value::Iterator::operator++( ) {
|
||||||
|
if( ddl_nullptr == m_current ) {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_current = m_current->getNext();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Value::Iterator::operator == ( const Iterator &rhs ) const {
|
||||||
|
return ( m_current == rhs.m_current );
|
||||||
|
}
|
||||||
|
|
||||||
|
Value *Value::Iterator::operator->( ) const {
|
||||||
|
if(ddl_nullptr == m_current ) {
|
||||||
|
return ddl_nullptr;
|
||||||
|
}
|
||||||
|
return m_current;
|
||||||
|
}
|
||||||
|
|
||||||
Value::Value( ValueType type )
|
Value::Value( ValueType type )
|
||||||
: m_type( type )
|
: m_type( type )
|
||||||
, m_size( 0 )
|
, m_size( 0 )
|
||||||
|
@ -80,7 +120,7 @@ void Value::setBool( bool value ) {
|
||||||
|
|
||||||
bool Value::getBool() {
|
bool Value::getBool() {
|
||||||
assert( ddl_bool == m_type );
|
assert( ddl_bool == m_type );
|
||||||
return ( *m_data ) ? true : false;
|
return ( *m_data == 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setInt8( int8 value ) {
|
void Value::setInt8( int8 value ) {
|
||||||
|
@ -100,7 +140,9 @@ void Value::setInt16( int16 value ) {
|
||||||
|
|
||||||
int16 Value::getInt16() {
|
int16 Value::getInt16() {
|
||||||
assert( ddl_int16 == m_type );
|
assert( ddl_int16 == m_type );
|
||||||
return ( int16 ) ( *m_data );
|
int16 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setInt32( int32 value ) {
|
void Value::setInt32( int32 value ) {
|
||||||
|
@ -110,16 +152,21 @@ void Value::setInt32( int32 value ) {
|
||||||
|
|
||||||
int32 Value::getInt32() {
|
int32 Value::getInt32() {
|
||||||
assert( ddl_int32 == m_type );
|
assert( ddl_int32 == m_type );
|
||||||
return ( int32 ) ( *m_data );
|
int32 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setInt64( int64 value ) {
|
void Value::setInt64( int64 value ) {
|
||||||
assert( ddl_int32 == m_type );
|
assert( ddl_int64 == m_type );
|
||||||
::memcpy( m_data, &value, m_size );
|
::memcpy( m_data, &value, m_size );
|
||||||
}
|
}
|
||||||
|
|
||||||
int64 Value::getInt64() {
|
int64 Value::getInt64() {
|
||||||
return ( int64 ) ( *m_data );
|
assert( ddl_int64 == m_type );
|
||||||
|
int64 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setUnsignedInt8( uint8 value ) {
|
void Value::setUnsignedInt8( uint8 value ) {
|
||||||
|
@ -129,7 +176,9 @@ void Value::setUnsignedInt8( uint8 value ) {
|
||||||
|
|
||||||
uint8 Value::getUnsignedInt8() const {
|
uint8 Value::getUnsignedInt8() const {
|
||||||
assert( ddl_unsigned_int8 == m_type );
|
assert( ddl_unsigned_int8 == m_type );
|
||||||
return ( uint8 ) ( *m_data );
|
uint8 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setUnsignedInt16( uint16 value ) {
|
void Value::setUnsignedInt16( uint16 value ) {
|
||||||
|
@ -139,7 +188,9 @@ void Value::setUnsignedInt16( uint16 value ) {
|
||||||
|
|
||||||
uint16 Value::getUnsignedInt16() const {
|
uint16 Value::getUnsignedInt16() const {
|
||||||
assert( ddl_unsigned_int16 == m_type );
|
assert( ddl_unsigned_int16 == m_type );
|
||||||
return ( uint8 ) ( *m_data );
|
uint16 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setUnsignedInt32( uint32 value ) {
|
void Value::setUnsignedInt32( uint32 value ) {
|
||||||
|
@ -149,7 +200,9 @@ void Value::setUnsignedInt32( uint32 value ) {
|
||||||
|
|
||||||
uint32 Value::getUnsignedInt32() const {
|
uint32 Value::getUnsignedInt32() const {
|
||||||
assert( ddl_unsigned_int32 == m_type );
|
assert( ddl_unsigned_int32 == m_type );
|
||||||
return ( uint8 ) ( *m_data );
|
uint32 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setUnsignedInt64( uint64 value ) {
|
void Value::setUnsignedInt64( uint64 value ) {
|
||||||
|
@ -159,7 +212,9 @@ void Value::setUnsignedInt64( uint64 value ) {
|
||||||
|
|
||||||
uint64 Value::getUnsignedInt64() const {
|
uint64 Value::getUnsignedInt64() const {
|
||||||
assert( ddl_unsigned_int64 == m_type );
|
assert( ddl_unsigned_int64 == m_type );
|
||||||
return ( uint64 ) ( *m_data );
|
uint64 i;
|
||||||
|
::memcpy( &i, m_data, m_size );
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::setFloat( float value ) {
|
void Value::setFloat( float value ) {
|
||||||
|
@ -185,6 +240,7 @@ void Value::setDouble( double value ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
double Value::getDouble() const {
|
double Value::getDouble() const {
|
||||||
|
assert( ddl_double == m_type );
|
||||||
double v;
|
double v;
|
||||||
::memcpy( &v, m_data, m_size );
|
::memcpy( &v, m_data, m_size );
|
||||||
return v;
|
return v;
|
||||||
|
@ -196,6 +252,7 @@ void Value::setString( const std::string &str ) {
|
||||||
m_data[ str.size() ] = '\0';
|
m_data[ str.size() ] = '\0';
|
||||||
}
|
}
|
||||||
const char *Value::getString() const {
|
const char *Value::getString() const {
|
||||||
|
assert( ddl_string == m_type );
|
||||||
return (const char*) m_data;
|
return (const char*) m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,22 +328,25 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) {
|
||||||
data->m_size = sizeof( bool );
|
data->m_size = sizeof( bool );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_int8:
|
case Value::ddl_int8:
|
||||||
data->m_size = sizeof( char );
|
data->m_size = sizeof( int8 );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_int16:
|
case Value::ddl_int16:
|
||||||
data->m_size = sizeof( short );
|
data->m_size = sizeof( int16 );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_int32:
|
case Value::ddl_int32:
|
||||||
data->m_size = sizeof( int );
|
data->m_size = sizeof( int32 );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_int64:
|
case Value::ddl_int64:
|
||||||
data->m_size = sizeof( int64 );
|
data->m_size = sizeof( int64 );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_unsigned_int8:
|
case Value::ddl_unsigned_int8:
|
||||||
data->m_size = sizeof( unsigned char );
|
data->m_size = sizeof( uint8 );
|
||||||
|
break;
|
||||||
|
case Value::ddl_unsigned_int16:
|
||||||
|
data->m_size = sizeof( uint16 );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_unsigned_int32:
|
case Value::ddl_unsigned_int32:
|
||||||
data->m_size = sizeof( unsigned int );
|
data->m_size = sizeof( uint32 );
|
||||||
break;
|
break;
|
||||||
case Value::ddl_unsigned_int64:
|
case Value::ddl_unsigned_int64:
|
||||||
data->m_size = sizeof( uint64 );
|
data->m_size = sizeof( uint64 );
|
||||||
|
|
|
@ -101,6 +101,10 @@ public:
|
||||||
/// @return true, if a corresponding property is assigned to the node, false if not.
|
/// @return true, if a corresponding property is assigned to the node, false if not.
|
||||||
bool hasProperty( const std::string &name );
|
bool hasProperty( const std::string &name );
|
||||||
|
|
||||||
|
/// @brief Will return true, if any properties are assigned to the node instance.
|
||||||
|
/// @return True, if properties are assigned.
|
||||||
|
bool hasProperties() const;
|
||||||
|
|
||||||
/// @brief Search for a given property and returns it. Will return ddl_nullptr if no property was found.
|
/// @brief Search for a given property and returns it. Will return ddl_nullptr if no property was found.
|
||||||
/// @param name [in] The name for the property to look for.
|
/// @param name [in] The name for the property to look for.
|
||||||
/// @return The property or ddl_nullptr if no property was found.
|
/// @return The property or ddl_nullptr if no property was found.
|
||||||
|
|
|
@ -26,6 +26,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# include <inttypes.h>
|
# include <inttypes.h>
|
||||||
|
@ -56,10 +57,11 @@ BEGIN_ODDLPARSER_NS
|
||||||
// All C++11 constructs
|
// All C++11 constructs
|
||||||
# define ddl_nullptr nullptr
|
# define ddl_nullptr nullptr
|
||||||
#else
|
#else
|
||||||
// Fallback for older compilers
|
// Fall-back for older compilers
|
||||||
# define ddl_nullptr NULL
|
# define ddl_nullptr NULL
|
||||||
#endif // OPENDDL_NO_USE_CPP11
|
#endif // OPENDDL_NO_USE_CPP11
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
class DDLNode;
|
class DDLNode;
|
||||||
class Value;
|
class Value;
|
||||||
|
|
||||||
|
@ -69,6 +71,7 @@ struct Reference;
|
||||||
struct Property;
|
struct Property;
|
||||||
struct DataArrayList;
|
struct DataArrayList;
|
||||||
|
|
||||||
|
// Platform-specific typedefs
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
typedef signed __int64 int64_impl;
|
typedef signed __int64 int64_impl;
|
||||||
typedef unsigned __int64 uint64_impl;
|
typedef unsigned __int64 uint64_impl;
|
||||||
|
@ -87,65 +90,36 @@ typedef unsigned short uint16; ///< Unsigned integer, 2 byte
|
||||||
typedef unsigned int uint32; ///< Unsigned integer, 4 byte
|
typedef unsigned int uint32; ///< Unsigned integer, 4 byte
|
||||||
typedef uint64_impl uint64; ///< Unsigned integer, 8 byte
|
typedef uint64_impl uint64; ///< Unsigned integer, 8 byte
|
||||||
|
|
||||||
/// @brief Description of the type of a name.
|
/// @brief Stores a text.
|
||||||
enum NameType {
|
///
|
||||||
GlobalName, ///< Name is global.
|
/// A text is stored in a simple character buffer. Texts buffer can be
|
||||||
LocalName ///< Name is local.
|
/// greater than the number of stored characters in them.
|
||||||
};
|
struct DLL_ODDLPARSER_EXPORT Text {
|
||||||
|
size_t m_capacity; ///< The capacity of the text.
|
||||||
|
size_t m_len; ///< The length of the text.
|
||||||
|
char *m_buffer; ///< The buffer with the text.
|
||||||
|
|
||||||
/// @brief Stores a text
|
/// @brief The constructor with a given text buffer.
|
||||||
struct Text {
|
/// @param buffer [in] The buffer.
|
||||||
size_t m_capacity;
|
/// @param numChars [in] The number of characters in the buffer.
|
||||||
size_t m_len;
|
Text( const char *buffer, size_t numChars );
|
||||||
char *m_buffer;
|
|
||||||
|
|
||||||
Text( const char *buffer, size_t numChars )
|
/// @brief The destructor.
|
||||||
: m_capacity( 0 )
|
~Text();
|
||||||
, m_len( 0 )
|
|
||||||
, m_buffer( ddl_nullptr ) {
|
|
||||||
set( buffer, numChars );
|
|
||||||
}
|
|
||||||
|
|
||||||
~Text() {
|
/// @brief Clears the text.
|
||||||
clear();
|
void clear();
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
/// @brief Set a new text.
|
||||||
delete[] m_buffer;
|
/// @param buffer [in] The buffer.
|
||||||
m_buffer = ddl_nullptr;
|
/// @param numChars [in] The number of characters in the buffer.
|
||||||
m_capacity = 0;
|
void set( const char *buffer, size_t numChars );
|
||||||
m_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set( const char *buffer, size_t numChars ) {
|
/// @brief The compare operator for std::strings.
|
||||||
clear();
|
bool operator == ( const std::string &name ) const;
|
||||||
if( numChars > 0 ) {
|
|
||||||
m_len = numChars;
|
|
||||||
m_capacity = m_len + 1;
|
|
||||||
m_buffer = new char[ m_capacity ];
|
|
||||||
strncpy( m_buffer, buffer, numChars );
|
|
||||||
m_buffer[ numChars ] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator == ( const std::string &name ) const {
|
/// @brief The compare operator for Texts.
|
||||||
if( m_len != name.size() ) {
|
bool operator == ( const Text &rhs ) const;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const int res( strncmp( m_buffer, name.c_str(), name.size() ) );
|
|
||||||
|
|
||||||
return ( 0 == res );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator == ( const Text &rhs ) const {
|
|
||||||
if( m_len != rhs.m_len ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) );
|
|
||||||
|
|
||||||
return ( 0 == res );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Text( const Text & );
|
Text( const Text & );
|
||||||
|
@ -153,38 +127,48 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Stores an OpenDDL-specific identifier type.
|
/// @brief Stores an OpenDDL-specific identifier type.
|
||||||
struct Identifier {
|
struct DLL_ODDLPARSER_EXPORT Identifier {
|
||||||
Text m_text;
|
Text m_text; ///< The text element.
|
||||||
|
|
||||||
Identifier( char buffer[], size_t len )
|
/// @brief The constructor with a sized buffer full of characters.
|
||||||
: m_text( buffer, len ) {
|
/// @param buffer [in] The identifier buffer.
|
||||||
// empty
|
/// @param len [in] The length of the buffer
|
||||||
}
|
Identifier( const char buffer[], size_t len );
|
||||||
|
|
||||||
Identifier( char buffer[] )
|
/// @brief The constructor with a buffer full of characters.
|
||||||
: m_text( buffer, strlen( buffer ) ) {
|
/// @param buffer [in] The identifier buffer.
|
||||||
// empty
|
/// @remark Buffer must be null-terminated.
|
||||||
}
|
Identifier( const char buffer[] );
|
||||||
|
|
||||||
bool operator == ( const Identifier &rhs ) const {
|
/// @brief The destructor.
|
||||||
return m_text == rhs.m_text;
|
~Identifier();
|
||||||
}
|
|
||||||
|
/// @brief The compare operator.
|
||||||
|
bool operator == ( const Identifier &rhs ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Identifier( const Identifier & );
|
Identifier( const Identifier & );
|
||||||
Identifier &operator = ( const Identifier & );
|
Identifier &operator = ( const Identifier & );
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Stores an OpenDDL-specific name
|
/// @brief Description of the type of a name.
|
||||||
struct Name {
|
enum NameType {
|
||||||
NameType m_type;
|
GlobalName, ///< Name is global.
|
||||||
Identifier *m_id;
|
LocalName ///< Name is local.
|
||||||
|
};
|
||||||
|
|
||||||
Name( NameType type, Identifier *id )
|
/// @brief Stores an OpenDDL-specific name
|
||||||
: m_type( type )
|
struct DLL_ODDLPARSER_EXPORT Name {
|
||||||
, m_id( id ) {
|
NameType m_type; ///< The type of the name ( @see NameType ).
|
||||||
// empty
|
Identifier *m_id; ///< The id.
|
||||||
}
|
|
||||||
|
/// @brief The constructor with the type and the id.
|
||||||
|
/// @param type [in] The name type.
|
||||||
|
/// @param id [in] The id.
|
||||||
|
Name( NameType type, Identifier *id );
|
||||||
|
|
||||||
|
/// @brief The destructor.
|
||||||
|
~Name();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Name( const Name & );
|
Name( const Name & );
|
||||||
|
@ -192,33 +176,20 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Stores a bundle of references.
|
/// @brief Stores a bundle of references.
|
||||||
struct Reference {
|
struct DLL_ODDLPARSER_EXPORT Reference {
|
||||||
size_t m_numRefs;
|
size_t m_numRefs; ///< The number of stored references.
|
||||||
Name **m_referencedName;
|
Name **m_referencedName; ///< The reference names.
|
||||||
|
|
||||||
Reference()
|
/// @brief The default constructor.
|
||||||
: m_numRefs( 0 )
|
Reference();
|
||||||
, m_referencedName( ddl_nullptr ) {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference( size_t numrefs, Name **names )
|
/// @brief The constructor with an array of ref names.
|
||||||
: m_numRefs( numrefs )
|
/// @param numrefs [in] The number of ref names.
|
||||||
, m_referencedName( ddl_nullptr ) {
|
/// @param names [in] The ref names.
|
||||||
m_referencedName = new Name *[ numrefs ];
|
Reference( size_t numrefs, Name **names );
|
||||||
for( size_t i = 0; i < numrefs; i++ ) {
|
|
||||||
Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id );
|
|
||||||
m_referencedName[ i ] = name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Reference() {
|
/// @brief The destructor.
|
||||||
for( size_t i = 0; i < m_numRefs; i++ ) {
|
~Reference();
|
||||||
delete m_referencedName[ i ];
|
|
||||||
}
|
|
||||||
m_numRefs = 0;
|
|
||||||
m_referencedName = ddl_nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Reference( const Reference & );
|
Reference( const Reference & );
|
||||||
|
@ -226,26 +197,21 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Stores a property list.
|
/// @brief Stores a property list.
|
||||||
struct Property {
|
struct DLL_ODDLPARSER_EXPORT Property {
|
||||||
Identifier *m_key;
|
Identifier *m_key; ///< The identifier / key of the property.
|
||||||
Value *m_value;
|
Value *m_value; ///< The value assigned to its key / id ( ddl_nullptr if none ).
|
||||||
Reference *m_ref;
|
Reference *m_ref; ///< References assigned to its key / id ( ddl_nullptr if none ).
|
||||||
Property *m_next;
|
Property *m_next; ///< The next property ( ddl_nullptr if none ).
|
||||||
|
|
||||||
Property( Identifier *id )
|
/// @brief The default constructor.
|
||||||
: m_key( id )
|
Property();
|
||||||
, m_value( ddl_nullptr )
|
|
||||||
, m_ref( ddl_nullptr )
|
|
||||||
, m_next( ddl_nullptr ) {
|
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
~Property() {
|
/// @brief The constructor for initialization.
|
||||||
m_key = ddl_nullptr;
|
/// @param id [in] The identifier
|
||||||
m_value = ddl_nullptr;
|
Property( Identifier *id );
|
||||||
m_ref = ddl_nullptr;;
|
|
||||||
m_next = ddl_nullptr;;
|
/// @brief The destructor.
|
||||||
}
|
~Property();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Property( const Property & );
|
Property( const Property & );
|
||||||
|
@ -253,17 +219,16 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Stores a data array list.
|
/// @brief Stores a data array list.
|
||||||
struct DataArrayList {
|
struct DLL_ODDLPARSER_EXPORT DataArrayList {
|
||||||
size_t m_numItems;
|
size_t m_numItems; ///< The number of items in the list.
|
||||||
Value *m_dataList;
|
Value *m_dataList; ///< The data list ( ee Value ).
|
||||||
DataArrayList *m_next;
|
DataArrayList *m_next; ///< The next data array list ( ddl_nullptr if last ).
|
||||||
|
|
||||||
DataArrayList()
|
/// @brief The default constructor for initialization.
|
||||||
: m_numItems( 0 )
|
DataArrayList();
|
||||||
, m_dataList( ddl_nullptr )
|
|
||||||
, m_next( ddl_nullptr ) {
|
/// @brief The destructor.
|
||||||
// empty
|
~DataArrayList();
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DataArrayList( const DataArrayList & );
|
DataArrayList( const DataArrayList & );
|
||||||
|
@ -271,17 +236,17 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Stores the context of a parsed OpenDDL declaration.
|
/// @brief Stores the context of a parsed OpenDDL declaration.
|
||||||
struct Context {
|
struct DLL_ODDLPARSER_EXPORT Context {
|
||||||
DDLNode *m_root;
|
DDLNode *m_root; ///< The root node of the OpenDDL node tree.
|
||||||
|
|
||||||
Context()
|
/// @brief Constructor for initialization.
|
||||||
: m_root( ddl_nullptr ) {
|
Context();
|
||||||
// empty
|
|
||||||
}
|
|
||||||
|
|
||||||
~Context() {
|
/// @brief Destructor.
|
||||||
m_root = ddl_nullptr;
|
~Context();
|
||||||
}
|
|
||||||
|
/// @brief Clears the whole node tree.
|
||||||
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Context( const Context & );
|
Context( const Context & );
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*-----------------------------------------------------------------------------------------------
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2015 Kim Kulling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
-----------------------------------------------------------------------------------------------*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <openddlparser/OpenDDLCommon.h>
|
||||||
|
#include <openddlparser/Value.h>
|
||||||
|
|
||||||
|
BEGIN_ODDLPARSER_NS
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
/// @ingroup IOStreamBase
|
||||||
|
/// @brief This class represents the stream to write out.
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
class DLL_ODDLPARSER_EXPORT IOStreamBase {
|
||||||
|
public:
|
||||||
|
IOStreamBase();
|
||||||
|
virtual ~IOStreamBase();
|
||||||
|
virtual bool open( const std::string &anme );
|
||||||
|
virtual bool close();
|
||||||
|
virtual void write( const std::string &statement );
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *m_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
/// @ingroup OpenDDLParser
|
||||||
|
/// @brief This class represents the OpenDDLExporter.
|
||||||
|
///
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
class DLL_ODDLPARSER_EXPORT OpenDDLExport {
|
||||||
|
public:
|
||||||
|
/// @brief The class constructor
|
||||||
|
OpenDDLExport( IOStreamBase *stream = ddl_nullptr );
|
||||||
|
|
||||||
|
/// @brief The class destructor.
|
||||||
|
~OpenDDLExport();
|
||||||
|
|
||||||
|
/// @brief Export the data of a parser context.
|
||||||
|
/// @param ctx [in] Pointer to the context.
|
||||||
|
/// @param filename [in] The filename for the export.
|
||||||
|
/// @return True in case of success, false in case of an error.
|
||||||
|
bool exportContext( Context *ctx, const std::string &filename );
|
||||||
|
|
||||||
|
/// @brief Handles a node export.
|
||||||
|
/// @param node [in] The node to handle with.
|
||||||
|
/// @return True in case of success, false in case of an error.
|
||||||
|
bool handleNode( DDLNode *node );
|
||||||
|
|
||||||
|
/// @brief Writes the statement to the stream.
|
||||||
|
/// @param statement [in] The content to write.
|
||||||
|
/// @return True in case of success, false in case of an error.
|
||||||
|
bool writeToStream( const std::string &statement );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool writeNode( DDLNode *node, std::string &statement );
|
||||||
|
bool writeNodeHeader( DDLNode *node, std::string &statement );
|
||||||
|
bool writeProperties( DDLNode *node, std::string &statement );
|
||||||
|
bool writeValueType( Value::ValueType type, size_t numItems, std::string &statement );
|
||||||
|
bool writeValue( Value *val, std::string &statement );
|
||||||
|
bool writeValueArray( DataArrayList *al, std::string &statement );
|
||||||
|
|
||||||
|
private:
|
||||||
|
IOStreamBase *m_stream;
|
||||||
|
};
|
||||||
|
|
||||||
|
END_ODDLPARSER_NS
|
|
@ -39,6 +39,11 @@ struct Identifier;
|
||||||
struct Reference;
|
struct Reference;
|
||||||
struct Property;
|
struct Property;
|
||||||
|
|
||||||
|
/// @brief Utility function to search for the next token or the end of the buffer.
|
||||||
|
/// @param in [in] The start position in the buffer.
|
||||||
|
/// @param end [in] The end position in the buffer.
|
||||||
|
/// @return Pointer showing to the next token or the end of the buffer.
|
||||||
|
/// @detail Will not increase buffer when already a valid buffer was found.
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
inline
|
||||||
T *lookForNextToken( T *in, T *end ) {
|
T *lookForNextToken( T *in, T *end ) {
|
||||||
|
@ -48,13 +53,19 @@ T *lookForNextToken( T *in, T *end ) {
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Utility function to go for the next token or the end of the buffer.
|
||||||
|
/// @param in [in] The start position in the buffer.
|
||||||
|
/// @param end [in] The end position in the buffer.
|
||||||
|
/// @return Pointer showing to the next token or the end of the buffer.
|
||||||
|
/// @detail Will increase buffer by a minimum of one.
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
inline
|
||||||
T *getNextToken( T *in, T *end ) {
|
T *getNextToken( T *in, T *end ) {
|
||||||
T *tmp( in );
|
T *tmp( in );
|
||||||
while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
|
in = lookForNextToken( in, end );
|
||||||
|
/*while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) {
|
||||||
in++;
|
in++;
|
||||||
}
|
}*/
|
||||||
if( tmp == in ) {
|
if( tmp == in ) {
|
||||||
in++;
|
in++;
|
||||||
}
|
}
|
||||||
|
@ -69,22 +80,78 @@ enum LogSeverity {
|
||||||
ddl_error_msg ///< Parser errors
|
ddl_error_msg ///< Parser errors
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DLL_ODDLPARSER_EXPORT const char *getTypeToken( Value::ValueType type );
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
|
/// @class OpenDDLParser
|
||||||
|
/// @ingroup OpenDDLParser
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief This is the main API for the OpenDDL-parser.
|
||||||
|
///
|
||||||
|
/// Use instances of this class to manage the parsing and handling of your parser contexts.
|
||||||
|
//-------------------------------------------------------------------------------------------------
|
||||||
class DLL_ODDLPARSER_EXPORT OpenDDLParser {
|
class DLL_ODDLPARSER_EXPORT OpenDDLParser {
|
||||||
public:
|
public:
|
||||||
|
/// @brief The log callback function pointer.
|
||||||
typedef void( *logCallback )( LogSeverity severity, const std::string &msg );
|
typedef void( *logCallback )( LogSeverity severity, const std::string &msg );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// @brief The default class constructor.
|
||||||
OpenDDLParser();
|
OpenDDLParser();
|
||||||
|
|
||||||
|
/// @brief The class constructor.
|
||||||
|
/// @param buffer [in] The buffer
|
||||||
|
/// @param len [in] Size of the buffer
|
||||||
OpenDDLParser( char *buffer, size_t len );
|
OpenDDLParser( char *buffer, size_t len );
|
||||||
|
|
||||||
|
/// @brief The class destructor.
|
||||||
~OpenDDLParser();
|
~OpenDDLParser();
|
||||||
|
|
||||||
|
/// @brief Setter for an own log callback function.
|
||||||
|
/// @param callback [in] The own callback.
|
||||||
void setLogCallback( logCallback callback );
|
void setLogCallback( logCallback callback );
|
||||||
|
|
||||||
|
/// @brief Getter for the log callback.
|
||||||
|
/// @return The current log callback.
|
||||||
logCallback getLogCallback() const;
|
logCallback getLogCallback() const;
|
||||||
|
|
||||||
|
/// @brief Assigns a new buffer to parse.
|
||||||
|
/// @param buffer [in] The buffer
|
||||||
|
/// @param len [in] Size of the buffer
|
||||||
void setBuffer( char *buffer, size_t len );
|
void setBuffer( char *buffer, size_t len );
|
||||||
|
|
||||||
|
/// @brief Assigns a new buffer to parse.
|
||||||
|
/// @param buffer [in] The buffer as a std::vector.
|
||||||
void setBuffer( const std::vector<char> &buffer );
|
void setBuffer( const std::vector<char> &buffer );
|
||||||
|
|
||||||
|
/// @brief Returns the buffer pointer.
|
||||||
|
/// @return The buffer pointer.
|
||||||
const char *getBuffer() const;
|
const char *getBuffer() const;
|
||||||
|
|
||||||
|
/// @brief Returns the size of the buffer.
|
||||||
|
/// @return The buffer size.
|
||||||
size_t getBufferSize() const;
|
size_t getBufferSize() const;
|
||||||
|
|
||||||
|
/// @brief Clears all parser data, including buffer and active context.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
/// @brief Starts the parsing of the OpenDDL-file.
|
||||||
|
/// @return True in case of success, false in case of an error.
|
||||||
|
/// @remark In case of errors check log.
|
||||||
bool parse();
|
bool parse();
|
||||||
|
|
||||||
|
bool exportContext( Context *ctx, const std::string &filename );
|
||||||
|
|
||||||
|
/// @brief Returns the root node.
|
||||||
|
/// @return The root node.
|
||||||
|
DDLNode *getRoot() const;
|
||||||
|
|
||||||
|
/// @brief Returns the parser context, only available in case of a succeeded parsing.
|
||||||
|
/// @return Pointer to the active context or ddl_nullptr.
|
||||||
|
Context *getContext() const;
|
||||||
|
|
||||||
|
public: // parser helpers
|
||||||
char *parseNextNode( char *current, char *end );
|
char *parseNextNode( char *current, char *end );
|
||||||
char *parseHeader( char *in, char *end );
|
char *parseHeader( char *in, char *end );
|
||||||
char *parseStructure( char *in, char *end );
|
char *parseStructure( char *in, char *end );
|
||||||
|
@ -92,10 +159,6 @@ public:
|
||||||
void pushNode( DDLNode *node );
|
void pushNode( DDLNode *node );
|
||||||
DDLNode *popNode();
|
DDLNode *popNode();
|
||||||
DDLNode *top();
|
DDLNode *top();
|
||||||
DDLNode *getRoot() const;
|
|
||||||
Context *getContext() const;
|
|
||||||
|
|
||||||
public: // static parser helpers
|
|
||||||
static void normalizeBuffer( std::vector<char> &buffer );
|
static void normalizeBuffer( std::vector<char> &buffer );
|
||||||
static char *parseName( char *in, char *end, Name **name );
|
static char *parseName( char *in, char *end, Name **name );
|
||||||
static char *parseIdentifier( char *in, char *end, Identifier **id );
|
static char *parseIdentifier( char *in, char *end, Identifier **id );
|
||||||
|
@ -107,7 +170,7 @@ public: // static parser helpers
|
||||||
static char *parseStringLiteral( char *in, char *end, Value **stringData );
|
static char *parseStringLiteral( char *in, char *end, Value **stringData );
|
||||||
static char *parseHexaLiteral( char *in, char *end, Value **data );
|
static char *parseHexaLiteral( char *in, char *end, Value **data );
|
||||||
static char *parseProperty( char *in, char *end, Property **prop );
|
static char *parseProperty( char *in, char *end, Property **prop );
|
||||||
static char *parseDataList( char *in, char *end, Value **data, size_t &numValues, Reference **refs, size_t &numRefs );
|
static char *parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs );
|
||||||
static char *parseDataArrayList( char *in, char *end, DataArrayList **dataList );
|
static char *parseDataArrayList( char *in, char *end, DataArrayList **dataList );
|
||||||
static const char *getVersion();
|
static const char *getVersion();
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ public:
|
||||||
/// @param start [in] The first value for iteration,
|
/// @param start [in] The first value for iteration,
|
||||||
Iterator( Value *start );
|
Iterator( Value *start );
|
||||||
|
|
||||||
|
Iterator( const Iterator &rhs );
|
||||||
|
|
||||||
/// @brief The class destructor.
|
/// @brief The class destructor.
|
||||||
~Iterator();
|
~Iterator();
|
||||||
|
|
||||||
|
@ -72,12 +74,26 @@ public:
|
||||||
/// @return The next value, is ddl_nullptr in case of being the last item.
|
/// @return The next value, is ddl_nullptr in case of being the last item.
|
||||||
Value *getNext();
|
Value *getNext();
|
||||||
|
|
||||||
|
/// @brief The post-increment operator.
|
||||||
|
const Iterator operator++( int );
|
||||||
|
|
||||||
|
/// @brief The pre-increment operator.
|
||||||
|
Iterator &operator++( );
|
||||||
|
|
||||||
|
/// @brief The compare operator.
|
||||||
|
/// @param rhs [in] The instance to compare.
|
||||||
|
/// @return true if equal.
|
||||||
|
bool operator == ( const Iterator &rhs ) const;
|
||||||
|
|
||||||
|
/// @brief The * operator.
|
||||||
|
/// @return The instance or ddl_nullptr if end of list is reached.
|
||||||
|
Value *operator->( ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Value *m_start;
|
Value *m_start;
|
||||||
Value *m_current;
|
Value *m_current;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Iterator( const Iterator & );
|
|
||||||
Iterator &operator = ( const Iterator & );
|
Iterator &operator = ( const Iterator & );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -135,11 +151,23 @@ public:
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
unsigned char *m_data;
|
unsigned char *m_data;
|
||||||
Value *m_next;
|
Value *m_next;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Value &operator =( const Value & );
|
||||||
|
Value( const Value & );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
///------------------------------------------------------------------------------------------------
|
||||||
|
/// @brief This class implements the value allocator.
|
||||||
|
///------------------------------------------------------------------------------------------------
|
||||||
struct DLL_ODDLPARSER_EXPORT ValueAllocator {
|
struct DLL_ODDLPARSER_EXPORT ValueAllocator {
|
||||||
static Value *allocPrimData( Value::ValueType type, size_t len = 1 );
|
static Value *allocPrimData( Value::ValueType type, size_t len = 1 );
|
||||||
static void releasePrimData( Value **data );
|
static void releasePrimData( Value **data );
|
||||||
|
|
||||||
|
private:
|
||||||
|
ValueAllocator();
|
||||||
|
ValueAllocator( const ValueAllocator & );
|
||||||
|
ValueAllocator &operator = ( const ValueAllocator & );
|
||||||
};
|
};
|
||||||
|
|
||||||
END_ODDLPARSER_NS
|
END_ODDLPARSER_NS
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||||
|
#define RAPIDJSON_ALLOCATORS_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Allocator
|
||||||
|
|
||||||
|
/*! \class rapidjson::Allocator
|
||||||
|
\brief Concept for allocating, resizing and freeing memory block.
|
||||||
|
|
||||||
|
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||||
|
|
||||||
|
So if an allocator need to support Free(), it needs to put its pointer in
|
||||||
|
the header of memory block.
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Allocator {
|
||||||
|
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||||
|
|
||||||
|
// Allocate a memory block.
|
||||||
|
// \param size of the memory block in bytes.
|
||||||
|
// \returns pointer to the memory block.
|
||||||
|
void* Malloc(size_t size);
|
||||||
|
|
||||||
|
// Resize a memory block.
|
||||||
|
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||||
|
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||||
|
// \param newSize the new size in bytes.
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||||
|
|
||||||
|
// Free a memory block.
|
||||||
|
// \param pointer to the memory block. Null pointer is permitted.
|
||||||
|
static void Free(void *ptr);
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CrtAllocator
|
||||||
|
|
||||||
|
//! C-runtime library allocator.
|
||||||
|
/*! This class is just wrapper for standard C library memory routines.
|
||||||
|
\note implements Allocator concept
|
||||||
|
*/
|
||||||
|
class CrtAllocator {
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = true;
|
||||||
|
void* Malloc(size_t size) {
|
||||||
|
if (size) // behavior of malloc(0) is implementation defined.
|
||||||
|
return std::malloc(size);
|
||||||
|
else
|
||||||
|
return NULL; // standardize to returning NULL.
|
||||||
|
}
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
|
(void)originalSize;
|
||||||
|
if (newSize == 0) {
|
||||||
|
std::free(originalPtr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return std::realloc(originalPtr, newSize);
|
||||||
|
}
|
||||||
|
static void Free(void *ptr) { std::free(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MemoryPoolAllocator
|
||||||
|
|
||||||
|
//! Default memory allocator used by the parser and DOM.
|
||||||
|
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||||
|
|
||||||
|
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||||
|
|
||||||
|
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||||
|
|
||||||
|
User may also supply a buffer as the first chunk.
|
||||||
|
|
||||||
|
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||||
|
|
||||||
|
The user-buffer is not deallocated by this allocator.
|
||||||
|
|
||||||
|
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||||
|
\note implements Allocator concept
|
||||||
|
*/
|
||||||
|
template <typename BaseAllocator = CrtAllocator>
|
||||||
|
class MemoryPoolAllocator {
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||||
|
|
||||||
|
//! Constructor with chunkSize.
|
||||||
|
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||||
|
\param baseAllocator The allocator for allocating memory chunks.
|
||||||
|
*/
|
||||||
|
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||||
|
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Constructor with user-supplied buffer.
|
||||||
|
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||||
|
|
||||||
|
The user buffer will not be deallocated when this allocator is destructed.
|
||||||
|
|
||||||
|
\param buffer User supplied buffer.
|
||||||
|
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||||
|
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||||
|
\param baseAllocator The allocator for allocating memory chunks.
|
||||||
|
*/
|
||||||
|
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||||
|
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||||
|
{
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
|
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||||
|
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||||
|
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||||
|
chunkHead_->size = 0;
|
||||||
|
chunkHead_->next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor.
|
||||||
|
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||||
|
*/
|
||||||
|
~MemoryPoolAllocator() {
|
||||||
|
Clear();
|
||||||
|
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||||
|
void Clear() {
|
||||||
|
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||||
|
ChunkHeader* next = chunkHead_->next;
|
||||||
|
baseAllocator_->Free(chunkHead_);
|
||||||
|
chunkHead_ = next;
|
||||||
|
}
|
||||||
|
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||||
|
chunkHead_->size = 0; // Clear user buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Computes the total capacity of allocated memory chunks.
|
||||||
|
/*! \return total capacity in bytes.
|
||||||
|
*/
|
||||||
|
size_t Capacity() const {
|
||||||
|
size_t capacity = 0;
|
||||||
|
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||||
|
capacity += c->capacity;
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Computes the memory blocks allocated.
|
||||||
|
/*! \return total used bytes.
|
||||||
|
*/
|
||||||
|
size_t Size() const {
|
||||||
|
size_t size = 0;
|
||||||
|
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||||
|
size += c->size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Allocates a memory block. (concept Allocator)
|
||||||
|
void* Malloc(size_t size) {
|
||||||
|
if (!size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size = RAPIDJSON_ALIGN(size);
|
||||||
|
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||||
|
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
|
||||||
|
|
||||||
|
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||||
|
chunkHead_->size += size;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Resizes a memory block (concept Allocator)
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
|
if (originalPtr == 0)
|
||||||
|
return Malloc(newSize);
|
||||||
|
|
||||||
|
if (newSize == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// Do not shrink if new size is smaller than original
|
||||||
|
if (originalSize >= newSize)
|
||||||
|
return originalPtr;
|
||||||
|
|
||||||
|
// Simply expand it if it is the last allocation and there is sufficient space
|
||||||
|
if (originalPtr == (char *)(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||||
|
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||||
|
increment = RAPIDJSON_ALIGN(increment);
|
||||||
|
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||||
|
chunkHead_->size += increment;
|
||||||
|
return originalPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||||
|
void* newBuffer = Malloc(newSize);
|
||||||
|
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
|
||||||
|
if (originalSize)
|
||||||
|
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||||
|
return newBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Frees a memory block (concept Allocator)
|
||||||
|
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Copy constructor is not permitted.
|
||||||
|
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||||
|
//! Copy assignment operator is not permitted.
|
||||||
|
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||||
|
|
||||||
|
//! Creates a new chunk.
|
||||||
|
/*! \param capacity Capacity of the chunk in bytes.
|
||||||
|
*/
|
||||||
|
void AddChunk(size_t capacity) {
|
||||||
|
if (!baseAllocator_)
|
||||||
|
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||||
|
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity));
|
||||||
|
chunk->capacity = capacity;
|
||||||
|
chunk->size = 0;
|
||||||
|
chunk->next = chunkHead_;
|
||||||
|
chunkHead_ = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||||
|
|
||||||
|
//! Chunk header for perpending to each chunk.
|
||||||
|
/*! Chunks are stored as a singly linked list.
|
||||||
|
*/
|
||||||
|
struct ChunkHeader {
|
||||||
|
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||||
|
size_t size; //!< Current size of allocated memory in bytes.
|
||||||
|
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||||
|
};
|
||||||
|
|
||||||
|
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||||
|
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||||
|
void *userBuffer_; //!< User supplied buffer.
|
||||||
|
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||||
|
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ENCODINGS_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,261 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||||
|
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Input byte stream wrapper with a statically bound encoding.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||||
|
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename InputByteStream>
|
||||||
|
class EncodedInputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||||
|
current_ = Encoding::TakeBOM(is_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Peek() const { return current_; }
|
||||||
|
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||||
|
size_t Tell() const { return is_.Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedInputStream(const EncodedInputStream&);
|
||||||
|
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||||
|
|
||||||
|
InputByteStream& is_;
|
||||||
|
Ch current_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Output byte stream wrapper with statically bound encoding.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||||
|
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename OutputByteStream>
|
||||||
|
class EncodedOutputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||||
|
if (putBOM)
|
||||||
|
Encoding::PutBOM(os_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||||
|
void Flush() { os_.Flush(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedOutputStream(const EncodedOutputStream&);
|
||||||
|
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||||
|
|
||||||
|
OutputByteStream& os_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||||
|
|
||||||
|
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
|
/*!
|
||||||
|
\tparam CharType Type of character for reading.
|
||||||
|
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||||
|
*/
|
||||||
|
template <typename CharType, typename InputByteStream>
|
||||||
|
class AutoUTFInputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param is input stream to be wrapped.
|
||||||
|
\param type UTF encoding type if it is not detected from the stream.
|
||||||
|
*/
|
||||||
|
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||||
|
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||||
|
DetectType();
|
||||||
|
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||||
|
takeFunc_ = f[type_];
|
||||||
|
current_ = takeFunc_(*is_);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTFType GetType() const { return type_; }
|
||||||
|
bool HasBOM() const { return hasBOM_; }
|
||||||
|
|
||||||
|
Ch Peek() const { return current_; }
|
||||||
|
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||||
|
size_t Tell() const { return is_->Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||||
|
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||||
|
|
||||||
|
// Detect encoding type with BOM or RFC 4627
|
||||||
|
void DetectType() {
|
||||||
|
// BOM (Byte Order Mark):
|
||||||
|
// 00 00 FE FF UTF-32BE
|
||||||
|
// FF FE 00 00 UTF-32LE
|
||||||
|
// FE FF UTF-16BE
|
||||||
|
// FF FE UTF-16LE
|
||||||
|
// EF BB BF UTF-8
|
||||||
|
|
||||||
|
const unsigned char* c = (const unsigned char *)is_->Peek4();
|
||||||
|
if (!c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||||
|
hasBOM_ = false;
|
||||||
|
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
|
||||||
|
// RFC 4627: Section 3
|
||||||
|
// "Since the first two characters of a JSON text will always be ASCII
|
||||||
|
// characters [RFC0020], it is possible to determine whether an octet
|
||||||
|
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||||
|
// at the pattern of nulls in the first four octets."
|
||||||
|
// 00 00 00 xx UTF-32BE
|
||||||
|
// 00 xx 00 xx UTF-16BE
|
||||||
|
// xx 00 00 00 UTF-32LE
|
||||||
|
// xx 00 xx 00 UTF-16LE
|
||||||
|
// xx xx xx xx UTF-8
|
||||||
|
|
||||||
|
if (!hasBOM_) {
|
||||||
|
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||||
|
switch (pattern) {
|
||||||
|
case 0x08: type_ = kUTF32BE; break;
|
||||||
|
case 0x0A: type_ = kUTF16BE; break;
|
||||||
|
case 0x01: type_ = kUTF32LE; break;
|
||||||
|
case 0x05: type_ = kUTF16LE; break;
|
||||||
|
case 0x0F: type_ = kUTF8; break;
|
||||||
|
default: break; // Use type defined by user.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||||
|
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||||
|
InputByteStream* is_;
|
||||||
|
UTFType type_;
|
||||||
|
Ch current_;
|
||||||
|
TakeFunc takeFunc_;
|
||||||
|
bool hasBOM_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
|
/*!
|
||||||
|
\tparam CharType Type of character for writing.
|
||||||
|
\tparam InputByteStream type of output byte stream to be wrapped.
|
||||||
|
*/
|
||||||
|
template <typename CharType, typename OutputByteStream>
|
||||||
|
class AutoUTFOutputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param os output stream to be wrapped.
|
||||||
|
\param type UTF encoding type.
|
||||||
|
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||||
|
*/
|
||||||
|
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||||
|
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||||
|
|
||||||
|
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||||
|
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
|
||||||
|
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||||
|
putFunc_ = f[type_];
|
||||||
|
|
||||||
|
if (putBOM)
|
||||||
|
PutBOM();
|
||||||
|
}
|
||||||
|
|
||||||
|
UTFType GetType() const { return type_; }
|
||||||
|
|
||||||
|
void Put(Ch c) { putFunc_(*os_, c); }
|
||||||
|
void Flush() { os_->Flush(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||||
|
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||||
|
|
||||||
|
void PutBOM() {
|
||||||
|
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||||
|
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||||
|
f[type_](*os_);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||||
|
|
||||||
|
OutputByteStream* os_;
|
||||||
|
UTFType type_;
|
||||||
|
PutFunc putFunc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
|
@ -0,0 +1,625 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ENCODINGS_H_
|
||||||
|
#define RAPIDJSON_ENCODINGS_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||||
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
RAPIDJSON_DIAG_OFF(overflow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Encoding
|
||||||
|
|
||||||
|
/*! \class rapidjson::Encoding
|
||||||
|
\brief Concept for encoding of Unicode characters.
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Encoding {
|
||||||
|
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||||
|
|
||||||
|
//! \brief Encode a Unicode codepoint to an output stream.
|
||||||
|
//! \param os Output stream.
|
||||||
|
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint);
|
||||||
|
|
||||||
|
//! \brief Decode a Unicode codepoint from an input stream.
|
||||||
|
//! \param is Input stream.
|
||||||
|
//! \param codepoint Output of the unicode codepoint.
|
||||||
|
//! \return true if a valid codepoint can be decoded from the stream.
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||||
|
|
||||||
|
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||||
|
//! \param is Input stream to obtain codepoint.
|
||||||
|
//! \param os Output for copying one codepoint.
|
||||||
|
//! \return true if it is valid.
|
||||||
|
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os);
|
||||||
|
|
||||||
|
// The following functions are deal with byte streams.
|
||||||
|
|
||||||
|
//! Take a character from input byte stream, skip BOM if exist.
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is);
|
||||||
|
|
||||||
|
//! Take a character from input byte stream.
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is);
|
||||||
|
|
||||||
|
//! Put BOM to output byte stream.
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os);
|
||||||
|
|
||||||
|
//! Put a character to output byte stream.
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c);
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF8
|
||||||
|
|
||||||
|
//! UTF-8 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
http://tools.ietf.org/html/rfc3629
|
||||||
|
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||||
|
\note implements Encoding concept
|
||||||
|
*/
|
||||||
|
template<typename CharType = char>
|
||||||
|
struct UTF8 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
if (codepoint <= 0x7F)
|
||||||
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
|
||||||
|
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||||
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
|
Ch c = is.Take();
|
||||||
|
if (!(c & 0x80)) {
|
||||||
|
*codepoint = (unsigned char)c;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char type = GetRange((unsigned char)c);
|
||||||
|
*codepoint = (0xFF >> type) & (unsigned char)c;
|
||||||
|
bool result = true;
|
||||||
|
switch (type) {
|
||||||
|
case 2: TAIL(); return result;
|
||||||
|
case 3: TAIL(); TAIL(); return result;
|
||||||
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||||
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||||
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||||
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
#undef COPY
|
||||||
|
#undef TRANS
|
||||||
|
#undef TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
#define COPY() os.Put(c = is.Take())
|
||||||
|
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
|
||||||
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
|
Ch c;
|
||||||
|
COPY();
|
||||||
|
if (!(c & 0x80))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
switch (GetRange((unsigned char)c)) {
|
||||||
|
case 2: TAIL(); return result;
|
||||||
|
case 3: TAIL(); TAIL(); return result;
|
||||||
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||||
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||||
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||||
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
#undef COPY
|
||||||
|
#undef TRANS
|
||||||
|
#undef TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char GetRange(unsigned char c) {
|
||||||
|
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||||
|
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||||
|
static const unsigned char type[] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||||
|
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||||
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||||
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||||
|
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||||
|
};
|
||||||
|
return type[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
Ch c = Take(is);
|
||||||
|
if ((unsigned char)c != 0xEFu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
if ((unsigned char)c != 0xBBu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
if ((unsigned char)c != 0xBFu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
return is.Take();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF16
|
||||||
|
|
||||||
|
//! UTF-16 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||||
|
http://tools.ietf.org/html/rfc2781
|
||||||
|
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||||
|
\note implements Encoding concept
|
||||||
|
|
||||||
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||||
|
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||||
|
*/
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
if (codepoint <= 0xFFFF) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
unsigned v = codepoint - 0x10000;
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||||
|
os.Put((v & 0x3FF) | 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
|
Ch c = is.Take();
|
||||||
|
if (c < 0xD800 || c > 0xDFFF) {
|
||||||
|
*codepoint = c;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (c <= 0xDBFF) {
|
||||||
|
*codepoint = (c & 0x3FF) << 10;
|
||||||
|
c = is.Take();
|
||||||
|
*codepoint |= (c & 0x3FF);
|
||||||
|
*codepoint += 0x10000;
|
||||||
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
Ch c;
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
if (c < 0xD800 || c > 0xDFFF)
|
||||||
|
return true;
|
||||||
|
else if (c <= 0xDBFF) {
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-16 little endian encoding.
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16LE : UTF16<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = (unsigned char)is.Take();
|
||||||
|
c |= (unsigned char)is.Take() << 8;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(0xFFu); os.Put(0xFEu);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(c & 0xFFu);
|
||||||
|
os.Put((c >> 8) & 0xFFu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-16 big endian encoding.
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16BE : UTF16<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = (unsigned char)is.Take() << 8;
|
||||||
|
c |= (unsigned char)is.Take();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(0xFEu); os.Put(0xFFu);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put((c >> 8) & 0xFFu);
|
||||||
|
os.Put(c & 0xFFu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF32
|
||||||
|
|
||||||
|
//! UTF-32 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||||
|
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||||
|
\note implements Encoding concept
|
||||||
|
|
||||||
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||||
|
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||||
|
*/
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
os.Put(codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
|
Ch c = is.Take();
|
||||||
|
*codepoint = c;
|
||||||
|
return c <= 0x10FFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
|
Ch c;
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
return c <= 0x10FFFF;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-32 little endian enocoding.
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32LE : UTF32<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = (unsigned char)is.Take();
|
||||||
|
c |= (unsigned char)is.Take() << 8;
|
||||||
|
c |= (unsigned char)is.Take() << 16;
|
||||||
|
c |= (unsigned char)is.Take() << 24;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(c & 0xFFu);
|
||||||
|
os.Put((c >> 8) & 0xFFu);
|
||||||
|
os.Put((c >> 16) & 0xFFu);
|
||||||
|
os.Put((c >> 24) & 0xFFu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-32 big endian encoding.
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32BE : UTF32<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = (unsigned char)is.Take() << 24;
|
||||||
|
c |= (unsigned char)is.Take() << 16;
|
||||||
|
c |= (unsigned char)is.Take() << 8;
|
||||||
|
c |= (unsigned char)is.Take();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put((c >> 24) & 0xFFu);
|
||||||
|
os.Put((c >> 16) & 0xFFu);
|
||||||
|
os.Put((c >> 8) & 0xFFu);
|
||||||
|
os.Put(c & 0xFFu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ASCII
|
||||||
|
|
||||||
|
//! ASCII encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/ASCII
|
||||||
|
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||||
|
\note implements Encoding concept
|
||||||
|
*/
|
||||||
|
template<typename CharType = char>
|
||||||
|
struct ASCII {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 0 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||||
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
unsigned char c = static_cast<unsigned char>(is.Take());
|
||||||
|
*codepoint = c;
|
||||||
|
return c <= 0X7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned char c = is.Take();
|
||||||
|
os.Put(c);
|
||||||
|
return c <= 0x7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
Ch c = Take(is);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
return is.Take();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
(void)os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AutoUTF
|
||||||
|
|
||||||
|
//! Runtime-specified UTF encoding type of a stream.
|
||||||
|
enum UTFType {
|
||||||
|
kUTF8 = 0, //!< UTF-8.
|
||||||
|
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||||
|
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||||
|
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||||
|
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||||
|
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||||
|
*/
|
||||||
|
template<typename CharType>
|
||||||
|
struct AutoUTF {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||||
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||||
|
(*f[os.GetType()])(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||||
|
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||||
|
return (*f[is.GetType()])(is, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||||
|
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||||
|
return (*f[is.GetType()])(is, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Transcoder
|
||||||
|
|
||||||
|
//! Encoding conversion.
|
||||||
|
template<typename SourceEncoding, typename TargetEncoding>
|
||||||
|
struct Transcoder {
|
||||||
|
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!SourceEncoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
TargetEncoding::Encode(os, codepoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Validate one Unicode codepoint from an encoded stream.
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Specialization of Transcoder with same source and target encoding.
|
||||||
|
template<typename Encoding>
|
||||||
|
struct Transcoder<Encoding, Encoding> {
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||||
|
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_MSV_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ENCODINGS_H_
|
|
@ -0,0 +1,65 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ERROR_EN_H__
|
||||||
|
#define RAPIDJSON_ERROR_EN_H__
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Maps error code of parsing into error message.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\param parseErrorCode Error code obtained in parsing.
|
||||||
|
\return the error message.
|
||||||
|
\note User can make a copy of this function for localization.
|
||||||
|
Using switch-case is safer for future modification of error codes.
|
||||||
|
*/
|
||||||
|
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||||
|
switch (parseErrorCode) {
|
||||||
|
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||||
|
|
||||||
|
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||||
|
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
|
||||||
|
|
||||||
|
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||||
|
|
||||||
|
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||||
|
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||||
|
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||||
|
|
||||||
|
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||||
|
|
||||||
|
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||||
|
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||||
|
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||||
|
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||||
|
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||||
|
|
||||||
|
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||||
|
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||||
|
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||||
|
|
||||||
|
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||||
|
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||||
|
|
||||||
|
default:
|
||||||
|
return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_EN_H__
|
|
@ -0,0 +1,146 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ERROR_ERROR_H__
|
||||||
|
#define RAPIDJSON_ERROR_ERROR_H__
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
/*! \file error.h */
|
||||||
|
|
||||||
|
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
|
||||||
|
//! Character type of error messages.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
The default character type is \c char.
|
||||||
|
On Windows, user can define this macro as \c TCHAR for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_STRING
|
||||||
|
|
||||||
|
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
By default this conversion macro does nothing.
|
||||||
|
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_STRING
|
||||||
|
#define RAPIDJSON_ERROR_STRING(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ParseErrorCode
|
||||||
|
|
||||||
|
//! Error code of parsing.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
\see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||||
|
*/
|
||||||
|
enum ParseErrorCode {
|
||||||
|
kParseErrorNone = 0, //!< No error.
|
||||||
|
|
||||||
|
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||||
|
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||||
|
|
||||||
|
kParseErrorValueInvalid, //!< Invalid value.
|
||||||
|
|
||||||
|
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||||
|
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||||
|
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||||
|
|
||||||
|
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||||
|
|
||||||
|
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||||
|
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||||
|
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||||
|
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||||
|
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||||
|
|
||||||
|
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||||
|
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||||
|
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||||
|
|
||||||
|
kParseErrorTermination, //!< Parsing was terminated.
|
||||||
|
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Result of parsing (wraps ParseErrorCode)
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\code
|
||||||
|
Document doc;
|
||||||
|
ParseResult ok = doc.Parse("[42]");
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||||
|
GetParseError_En(ok.Code()), ok.Offset());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
\see GenericReader::Parse, GenericDocument::Parse
|
||||||
|
*/
|
||||||
|
struct ParseResult {
|
||||||
|
|
||||||
|
//! Default constructor, no error.
|
||||||
|
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||||
|
//! Constructor to set an error.
|
||||||
|
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||||
|
|
||||||
|
//! Get the error code.
|
||||||
|
ParseErrorCode Code() const { return code_; }
|
||||||
|
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||||
|
size_t Offset() const { return offset_; }
|
||||||
|
|
||||||
|
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||||
|
operator bool() const { return !IsError(); }
|
||||||
|
//! Whether the result is an error.
|
||||||
|
bool IsError() const { return code_ != kParseErrorNone; }
|
||||||
|
|
||||||
|
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||||
|
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||||
|
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||||
|
|
||||||
|
//! Reset error code.
|
||||||
|
void Clear() { Set(kParseErrorNone); }
|
||||||
|
//! Update error code and offset.
|
||||||
|
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ParseErrorCode code_;
|
||||||
|
size_t offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Function pointer type of GetParseError().
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
|
||||||
|
This is the prototype for \c GetParseError_X(), where \c X is a locale.
|
||||||
|
User can dynamically change locale in runtime, e.g.:
|
||||||
|
\code
|
||||||
|
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||||
|
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_ERROR_H__
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||||
|
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! File byte stream for input using fread().
|
||||||
|
/*!
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
class FileReadStream {
|
||||||
|
public:
|
||||||
|
typedef char Ch; //!< Character type (byte).
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param fp File pointer opened for read.
|
||||||
|
\param buffer user-supplied buffer.
|
||||||
|
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||||
|
*/
|
||||||
|
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||||
|
RAPIDJSON_ASSERT(fp_ != 0);
|
||||||
|
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||||
|
Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Peek() const { return *current_; }
|
||||||
|
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||||
|
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
return (current_ + 4 <= bufferLast_) ? current_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Read() {
|
||||||
|
if (current_ < bufferLast_)
|
||||||
|
++current_;
|
||||||
|
else if (!eof_) {
|
||||||
|
count_ += readCount_;
|
||||||
|
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
|
||||||
|
bufferLast_ = buffer_ + readCount_ - 1;
|
||||||
|
current_ = buffer_;
|
||||||
|
|
||||||
|
if (readCount_ < bufferSize_) {
|
||||||
|
buffer_[readCount_] = '\0';
|
||||||
|
++bufferLast_;
|
||||||
|
eof_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::FILE* fp_;
|
||||||
|
Ch *buffer_;
|
||||||
|
size_t bufferSize_;
|
||||||
|
Ch *bufferLast_;
|
||||||
|
Ch *current_;
|
||||||
|
size_t readCount_;
|
||||||
|
size_t count_; //!< Number of characters read
|
||||||
|
bool eof_;
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
|
@ -0,0 +1,95 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||||
|
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Wrapper of C file stream for input using fread().
|
||||||
|
/*!
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
class FileWriteStream {
|
||||||
|
public:
|
||||||
|
typedef char Ch; //!< Character type. Only support char.
|
||||||
|
|
||||||
|
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||||
|
RAPIDJSON_ASSERT(fp_ != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(char c) {
|
||||||
|
if (current_ >= bufferEnd_)
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
*current_++ = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutN(char c, size_t n) {
|
||||||
|
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||||
|
while (n > avail) {
|
||||||
|
std::memset(current_, c, avail);
|
||||||
|
current_ += avail;
|
||||||
|
Flush();
|
||||||
|
n -= avail;
|
||||||
|
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
std::memset(current_, c, n);
|
||||||
|
current_ += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush() {
|
||||||
|
if (current_ != buffer_) {
|
||||||
|
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||||
|
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||||
|
// failure deliberately ignored at this time
|
||||||
|
// added to avoid warn_unused_result build errors
|
||||||
|
}
|
||||||
|
current_ = buffer_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
FileWriteStream(const FileWriteStream&);
|
||||||
|
FileWriteStream& operator=(const FileWriteStream&);
|
||||||
|
|
||||||
|
std::FILE* fp_;
|
||||||
|
char *buffer_;
|
||||||
|
char *bufferEnd_;
|
||||||
|
char *current_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||||
|
stream.PutN(c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
|
@ -0,0 +1,290 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_BIGINTEGER_H_
|
||||||
|
#define RAPIDJSON_BIGINTEGER_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#include <intrin.h> // for _umul128
|
||||||
|
#pragma intrinsic(_umul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class BigInteger {
|
||||||
|
public:
|
||||||
|
typedef uint64_t Type;
|
||||||
|
|
||||||
|
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
|
||||||
|
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit BigInteger(uint64_t u) : count_(1) {
|
||||||
|
digits_[0] = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||||
|
RAPIDJSON_ASSERT(length > 0);
|
||||||
|
digits_[0] = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
|
||||||
|
while (length >= kMaxDigitPerIteration) {
|
||||||
|
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
|
||||||
|
length -= kMaxDigitPerIteration;
|
||||||
|
i += kMaxDigitPerIteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 0)
|
||||||
|
AppendDecimal64(decimals + i, decimals + i + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator=(const BigInteger &rhs)
|
||||||
|
{
|
||||||
|
if (this != &rhs) {
|
||||||
|
count_ = rhs.count_;
|
||||||
|
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator=(uint64_t u) {
|
||||||
|
digits_[0] = u;
|
||||||
|
count_ = 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator+=(uint64_t u) {
|
||||||
|
Type backup = digits_[0];
|
||||||
|
digits_[0] += u;
|
||||||
|
for (size_t i = 0; i < count_ - 1; i++) {
|
||||||
|
if (digits_[i] >= backup)
|
||||||
|
return *this; // no carry
|
||||||
|
backup = digits_[i + 1];
|
||||||
|
digits_[i + 1] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last carry
|
||||||
|
if (digits_[count_ - 1] < backup)
|
||||||
|
PushBack(1);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator*=(uint64_t u) {
|
||||||
|
if (u == 0) return *this = 0;
|
||||||
|
if (u == 1) return *this;
|
||||||
|
if (*this == 1) return *this = u;
|
||||||
|
|
||||||
|
uint64_t k = 0;
|
||||||
|
for (size_t i = 0; i < count_; i++) {
|
||||||
|
uint64_t hi;
|
||||||
|
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
|
||||||
|
k = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > 0)
|
||||||
|
PushBack(k);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator*=(uint32_t u) {
|
||||||
|
if (u == 0) return *this = 0;
|
||||||
|
if (u == 1) return *this;
|
||||||
|
if (*this == 1) return *this = u;
|
||||||
|
|
||||||
|
uint64_t k = 0;
|
||||||
|
for (size_t i = 0; i < count_; i++) {
|
||||||
|
const uint64_t c = digits_[i] >> 32;
|
||||||
|
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||||
|
const uint64_t uc = u * c;
|
||||||
|
const uint64_t ud = u * d;
|
||||||
|
const uint64_t p0 = ud + k;
|
||||||
|
const uint64_t p1 = uc + (p0 >> 32);
|
||||||
|
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
|
||||||
|
k = p1 >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > 0)
|
||||||
|
PushBack(k);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator<<=(size_t shift) {
|
||||||
|
if (IsZero() || shift == 0) return *this;
|
||||||
|
|
||||||
|
size_t offset = shift / kTypeBit;
|
||||||
|
size_t interShift = shift % kTypeBit;
|
||||||
|
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||||
|
|
||||||
|
if (interShift == 0) {
|
||||||
|
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
|
||||||
|
count_ += offset;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digits_[count_] = 0;
|
||||||
|
for (size_t i = count_; i > 0; i--)
|
||||||
|
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
|
||||||
|
digits_[offset] = digits_[0] << interShift;
|
||||||
|
count_ += offset;
|
||||||
|
if (digits_[count_])
|
||||||
|
count_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(digits_, 0, offset * sizeof(Type));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const BigInteger& rhs) const {
|
||||||
|
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Type rhs) const {
|
||||||
|
return count_ == 1 && digits_[0] == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& MultiplyPow5(unsigned exp) {
|
||||||
|
static const uint32_t kPow5[12] = {
|
||||||
|
5,
|
||||||
|
5 * 5,
|
||||||
|
5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
|
||||||
|
};
|
||||||
|
if (exp == 0) return *this;
|
||||||
|
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
|
||||||
|
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
|
||||||
|
if (exp > 0) *this *= kPow5[exp - 1];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute absolute difference of this and rhs.
|
||||||
|
// Assume this != rhs
|
||||||
|
bool Difference(const BigInteger& rhs, BigInteger* out) const {
|
||||||
|
int cmp = Compare(rhs);
|
||||||
|
RAPIDJSON_ASSERT(cmp != 0);
|
||||||
|
const BigInteger *a, *b; // Makes a > b
|
||||||
|
bool ret;
|
||||||
|
if (cmp < 0) { a = &rhs; b = this; ret = true; }
|
||||||
|
else { a = this; b = &rhs; ret = false; }
|
||||||
|
|
||||||
|
Type borrow = 0;
|
||||||
|
for (size_t i = 0; i < a->count_; i++) {
|
||||||
|
Type d = a->digits_[i] - borrow;
|
||||||
|
if (i < b->count_)
|
||||||
|
d -= b->digits_[i];
|
||||||
|
borrow = (d > a->digits_[i]) ? 1 : 0;
|
||||||
|
out->digits_[i] = d;
|
||||||
|
if (d != 0)
|
||||||
|
out->count_ = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Compare(const BigInteger& rhs) const {
|
||||||
|
if (count_ != rhs.count_)
|
||||||
|
return count_ < rhs.count_ ? -1 : 1;
|
||||||
|
|
||||||
|
for (size_t i = count_; i-- > 0;)
|
||||||
|
if (digits_[i] != rhs.digits_[i])
|
||||||
|
return digits_[i] < rhs.digits_[i] ? -1 : 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetCount() const { return count_; }
|
||||||
|
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
|
||||||
|
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AppendDecimal64(const char* begin, const char* end) {
|
||||||
|
uint64_t u = ParseUint64(begin, end);
|
||||||
|
if (IsZero())
|
||||||
|
*this = u;
|
||||||
|
else {
|
||||||
|
unsigned exp = static_cast<unsigned>(end - begin);
|
||||||
|
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushBack(Type digit) {
|
||||||
|
RAPIDJSON_ASSERT(count_ < kCapacity);
|
||||||
|
digits_[count_++] = digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||||
|
uint64_t r = 0;
|
||||||
|
for (const char* p = begin; p != end; ++p) {
|
||||||
|
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||||
|
r = r * 10u + (unsigned)(*p - '0');
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume a * b + k < 2^128
|
||||||
|
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t low = _umul128(a, b, outHigh) + k;
|
||||||
|
if (low < k)
|
||||||
|
(*outHigh)++;
|
||||||
|
return low;
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
__extension__ typedef unsigned __int128 uint128;
|
||||||
|
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||||
|
p += k;
|
||||||
|
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||||
|
return static_cast<uint64_t>(p);
|
||||||
|
#else
|
||||||
|
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||||
|
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
|
||||||
|
x1 += (x0 >> 32); // can't give carry
|
||||||
|
x1 += x2;
|
||||||
|
if (x1 < x2)
|
||||||
|
x3 += (static_cast<uint64_t>(1) << 32);
|
||||||
|
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
|
||||||
|
uint64_t hi = x3 + (x1 >> 32);
|
||||||
|
|
||||||
|
lo += k;
|
||||||
|
if (lo < k)
|
||||||
|
hi++;
|
||||||
|
*outHigh = hi;
|
||||||
|
return lo;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
|
||||||
|
static const size_t kCapacity = kBitCount / sizeof(Type);
|
||||||
|
static const size_t kTypeBit = sizeof(Type) * 8;
|
||||||
|
|
||||||
|
Type digits_[kCapacity];
|
||||||
|
size_t count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_BIGINTEGER_H_
|
|
@ -0,0 +1,248 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||||
|
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||||
|
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_DIYFP_H_
|
||||||
|
#define RAPIDJSON_DIYFP_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanReverse64)
|
||||||
|
#pragma intrinsic(_umul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct DiyFp {
|
||||||
|
DiyFp() {}
|
||||||
|
|
||||||
|
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
|
||||||
|
|
||||||
|
explicit DiyFp(double d) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
} u = { d };
|
||||||
|
|
||||||
|
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||||
|
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||||
|
if (biased_e != 0) {
|
||||||
|
f = significand + kDpHiddenBit;
|
||||||
|
e = biased_e - kDpExponentBias;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f = significand;
|
||||||
|
e = kDpMinExponent + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator-(const DiyFp& rhs) const {
|
||||||
|
return DiyFp(f - rhs.f, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator*(const DiyFp& rhs) const {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t h;
|
||||||
|
uint64_t l = _umul128(f, rhs.f, &h);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
__extension__ typedef unsigned __int128 uint128;
|
||||||
|
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||||
|
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||||
|
uint64_t l = static_cast<uint64_t>(p);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#else
|
||||||
|
const uint64_t M32 = 0xFFFFFFFF;
|
||||||
|
const uint64_t a = f >> 32;
|
||||||
|
const uint64_t b = f & M32;
|
||||||
|
const uint64_t c = rhs.f >> 32;
|
||||||
|
const uint64_t d = rhs.f & M32;
|
||||||
|
const uint64_t ac = a * c;
|
||||||
|
const uint64_t bc = b * c;
|
||||||
|
const uint64_t ad = a * d;
|
||||||
|
const uint64_t bd = b * d;
|
||||||
|
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||||
|
tmp += 1U << 31; /// mult_round
|
||||||
|
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp Normalize() const {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
unsigned long index;
|
||||||
|
_BitScanReverse64(&index, f);
|
||||||
|
return DiyFp(f << (63 - index), e - (63 - index));
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
int s = __builtin_clzll(f);
|
||||||
|
return DiyFp(f << s, e - s);
|
||||||
|
#else
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp NormalizeBoundary() const {
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (kDpHiddenBit << 1))) {
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||||
|
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||||
|
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||||
|
mi.f <<= mi.e - pl.e;
|
||||||
|
mi.e = pl.e;
|
||||||
|
*plus = pl;
|
||||||
|
*minus = mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ToDouble() const {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
}u;
|
||||||
|
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||||
|
static_cast<uint64_t>(e + kDpExponentBias);
|
||||||
|
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||||
|
return u.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDiySignificandSize = 64;
|
||||||
|
static const int kDpSignificandSize = 52;
|
||||||
|
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||||
|
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||||
|
static const int kDpMinExponent = -kDpExponentBias;
|
||||||
|
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||||
|
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
uint64_t f;
|
||||||
|
int e;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||||
|
// 10^-348, 10^-340, ..., 10^340
|
||||||
|
static const uint64_t kCachedPowers_F[] = {
|
||||||
|
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||||
|
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||||
|
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||||
|
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||||
|
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||||
|
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||||
|
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||||
|
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||||
|
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||||
|
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||||
|
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||||
|
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||||
|
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||||
|
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||||
|
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||||
|
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||||
|
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||||
|
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||||
|
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||||
|
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||||
|
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||||
|
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||||
|
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||||
|
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||||
|
};
|
||||||
|
static const int16_t kCachedPowers_E[] = {
|
||||||
|
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||||
|
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||||
|
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||||
|
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||||
|
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||||
|
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||||
|
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||||
|
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||||
|
907, 933, 960, 986, 1013, 1039, 1066
|
||||||
|
};
|
||||||
|
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower(int e, int* K) {
|
||||||
|
|
||||||
|
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||||
|
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||||
|
int k = static_cast<int>(dk);
|
||||||
|
if (dk - k > 0.0)
|
||||||
|
k++;
|
||||||
|
|
||||||
|
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||||
|
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||||
|
|
||||||
|
return GetCachedPowerByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||||
|
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
|
||||||
|
*outExp = -348 + static_cast<int>(index) * 8;
|
||||||
|
return GetCachedPowerByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DIYFP_H_
|
|
@ -0,0 +1,217 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||||
|
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||||
|
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_DTOA_
|
||||||
|
#define RAPIDJSON_DTOA_
|
||||||
|
|
||||||
|
#include "itoa.h" // GetDigitsLut()
|
||||||
|
#include "diyfp.h"
|
||||||
|
#include "ieee754.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
||||||
|
while (rest < wp_w && delta - rest >= ten_kappa &&
|
||||||
|
(rest + ten_kappa < wp_w || /// closer
|
||||||
|
wp_w - rest > rest + ten_kappa - wp_w)) {
|
||||||
|
buffer[len - 1]--;
|
||||||
|
rest += ten_kappa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned CountDecimalDigit32(uint32_t n) {
|
||||||
|
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||||
|
if (n < 10) return 1;
|
||||||
|
if (n < 100) return 2;
|
||||||
|
if (n < 1000) return 3;
|
||||||
|
if (n < 10000) return 4;
|
||||||
|
if (n < 100000) return 5;
|
||||||
|
if (n < 1000000) return 6;
|
||||||
|
if (n < 10000000) return 7;
|
||||||
|
if (n < 100000000) return 8;
|
||||||
|
// Will not reach 10 digits in DigitGen()
|
||||||
|
//if (n < 1000000000) return 9;
|
||||||
|
//return 10;
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||||
|
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||||
|
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||||
|
const DiyFp wp_w = Mp - W;
|
||||||
|
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||||
|
uint64_t p2 = Mp.f & (one.f - 1);
|
||||||
|
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
while (kappa > 0) {
|
||||||
|
uint32_t d = 0;
|
||||||
|
switch (kappa) {
|
||||||
|
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
||||||
|
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
||||||
|
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
||||||
|
case 6: d = p1 / 100000; p1 %= 100000; break;
|
||||||
|
case 5: d = p1 / 10000; p1 %= 10000; break;
|
||||||
|
case 4: d = p1 / 1000; p1 %= 1000; break;
|
||||||
|
case 3: d = p1 / 100; p1 %= 100; break;
|
||||||
|
case 2: d = p1 / 10; p1 %= 10; break;
|
||||||
|
case 1: d = p1; p1 = 0; break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
|
||||||
|
kappa--;
|
||||||
|
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||||
|
if (tmp <= delta) {
|
||||||
|
*K += kappa;
|
||||||
|
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kappa = 0
|
||||||
|
for (;;) {
|
||||||
|
p2 *= 10;
|
||||||
|
delta *= 10;
|
||||||
|
char d = static_cast<char>(p2 >> -one.e);
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = static_cast<char>('0' + d);
|
||||||
|
p2 &= one.f - 1;
|
||||||
|
kappa--;
|
||||||
|
if (p2 < delta) {
|
||||||
|
*K += kappa;
|
||||||
|
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-static_cast<int>(kappa)]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
||||||
|
const DiyFp v(value);
|
||||||
|
DiyFp w_m, w_p;
|
||||||
|
v.NormalizedBoundaries(&w_m, &w_p);
|
||||||
|
|
||||||
|
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||||
|
const DiyFp W = v.Normalize() * c_mk;
|
||||||
|
DiyFp Wp = w_p * c_mk;
|
||||||
|
DiyFp Wm = w_m * c_mk;
|
||||||
|
Wm.f++;
|
||||||
|
Wp.f--;
|
||||||
|
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* WriteExponent(int K, char* buffer) {
|
||||||
|
if (K < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
K = -K;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (K >= 100) {
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
|
||||||
|
K %= 100;
|
||||||
|
const char* d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else if (K >= 10) {
|
||||||
|
const char* d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* Prettify(char* buffer, int length, int k) {
|
||||||
|
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
|
||||||
|
if (length <= kk && kk <= 21) {
|
||||||
|
// 1234e7 -> 12340000000
|
||||||
|
for (int i = length; i < kk; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
buffer[kk] = '.';
|
||||||
|
buffer[kk + 1] = '0';
|
||||||
|
return &buffer[kk + 2];
|
||||||
|
}
|
||||||
|
else if (0 < kk && kk <= 21) {
|
||||||
|
// 1234e-2 -> 12.34
|
||||||
|
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||||
|
buffer[kk] = '.';
|
||||||
|
return &buffer[length + 1];
|
||||||
|
}
|
||||||
|
else if (-6 < kk && kk <= 0) {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
const int offset = 2 - kk;
|
||||||
|
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
for (int i = 2; i < offset; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
return &buffer[length + offset];
|
||||||
|
}
|
||||||
|
else if (length == 1) {
|
||||||
|
// 1e30
|
||||||
|
buffer[1] = 'e';
|
||||||
|
return WriteExponent(kk - 1, &buffer[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 1234e30 -> 1.234e33
|
||||||
|
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[length + 1] = 'e';
|
||||||
|
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* dtoa(double value, char* buffer) {
|
||||||
|
Double d(value);
|
||||||
|
if (d.IsZero()) {
|
||||||
|
if (d.Sign())
|
||||||
|
*buffer++ = '-'; // -0.0, Issue #289
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[2] = '0';
|
||||||
|
return &buffer[3];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
int length, K;
|
||||||
|
Grisu2(value, buffer, &length, &K);
|
||||||
|
return Prettify(buffer, length, K);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DTOA_
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_IEEE754_
|
||||||
|
#define RAPIDJSON_IEEE754_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class Double {
|
||||||
|
public:
|
||||||
|
Double() {}
|
||||||
|
Double(double d) : d_(d) {}
|
||||||
|
Double(uint64_t u) : u_(u) {}
|
||||||
|
|
||||||
|
double Value() const { return d_; }
|
||||||
|
uint64_t Uint64Value() const { return u_; }
|
||||||
|
|
||||||
|
double NextPositiveDouble() const {
|
||||||
|
RAPIDJSON_ASSERT(!Sign());
|
||||||
|
return Double(u_ + 1).Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||||
|
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||||
|
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||||
|
|
||||||
|
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
|
||||||
|
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
|
||||||
|
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
|
||||||
|
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||||
|
|
||||||
|
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||||
|
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||||
|
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||||
|
|
||||||
|
static unsigned EffectiveSignificandSize(int order) {
|
||||||
|
if (order >= -1021)
|
||||||
|
return 53;
|
||||||
|
else if (order <= -1074)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return (unsigned)order + 1074;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int kSignificandSize = 52;
|
||||||
|
static const int kExponentBias = 0x3FF;
|
||||||
|
static const int kDenormalExponent = 1 - kExponentBias;
|
||||||
|
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
|
||||||
|
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
union {
|
||||||
|
double d_;
|
||||||
|
uint64_t u_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_IEEE754_
|
|
@ -0,0 +1,304 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ITOA_
|
||||||
|
#define RAPIDJSON_ITOA_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline const char* GetDigitsLut() {
|
||||||
|
static const char cDigitsLut[200] = {
|
||||||
|
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
|
||||||
|
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
|
||||||
|
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
|
||||||
|
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
|
||||||
|
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
|
||||||
|
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
|
||||||
|
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
|
||||||
|
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
|
||||||
|
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
|
||||||
|
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
|
||||||
|
};
|
||||||
|
return cDigitsLut;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* u32toa(uint32_t value, char* buffer) {
|
||||||
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
|
||||||
|
if (value < 10000) {
|
||||||
|
const uint32_t d1 = (value / 100) << 1;
|
||||||
|
const uint32_t d2 = (value % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 1000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 100)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 10)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
}
|
||||||
|
else if (value < 100000000) {
|
||||||
|
// value = bbbbcccc
|
||||||
|
const uint32_t b = value / 10000;
|
||||||
|
const uint32_t c = value % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 10000000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 1000000)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 100000)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// value = aabbbbcccc in decimal
|
||||||
|
|
||||||
|
const uint32_t a = value / 100000000; // 1 to 42
|
||||||
|
value %= 100000000;
|
||||||
|
|
||||||
|
if (a >= 10) {
|
||||||
|
const unsigned i = a << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||||
|
|
||||||
|
const uint32_t b = value / 10000; // 0 to 9999
|
||||||
|
const uint32_t c = value % 10000; // 0 to 9999
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* i32toa(int32_t value, char* buffer) {
|
||||||
|
uint32_t u = static_cast<uint32_t>(value);
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
u = ~u + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u32toa(u, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* u64toa(uint64_t value, char* buffer) {
|
||||||
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
const uint64_t kTen8 = 100000000;
|
||||||
|
const uint64_t kTen9 = kTen8 * 10;
|
||||||
|
const uint64_t kTen10 = kTen8 * 100;
|
||||||
|
const uint64_t kTen11 = kTen8 * 1000;
|
||||||
|
const uint64_t kTen12 = kTen8 * 10000;
|
||||||
|
const uint64_t kTen13 = kTen8 * 100000;
|
||||||
|
const uint64_t kTen14 = kTen8 * 1000000;
|
||||||
|
const uint64_t kTen15 = kTen8 * 10000000;
|
||||||
|
const uint64_t kTen16 = kTen8 * kTen8;
|
||||||
|
|
||||||
|
if (value < kTen8) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(value);
|
||||||
|
if (v < 10000) {
|
||||||
|
const uint32_t d1 = (v / 100) << 1;
|
||||||
|
const uint32_t d2 = (v % 100) << 1;
|
||||||
|
|
||||||
|
if (v >= 1000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (v >= 100)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (v >= 10)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// value = bbbbcccc
|
||||||
|
const uint32_t b = v / 10000;
|
||||||
|
const uint32_t c = v % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 10000000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 1000000)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 100000)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value < kTen16) {
|
||||||
|
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||||
|
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||||
|
|
||||||
|
const uint32_t b0 = v0 / 10000;
|
||||||
|
const uint32_t c0 = v0 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b0 / 100) << 1;
|
||||||
|
const uint32_t d2 = (b0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c0 / 100) << 1;
|
||||||
|
const uint32_t d4 = (c0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t b1 = v1 / 10000;
|
||||||
|
const uint32_t c1 = v1 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d5 = (b1 / 100) << 1;
|
||||||
|
const uint32_t d6 = (b1 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d7 = (c1 / 100) << 1;
|
||||||
|
const uint32_t d8 = (c1 % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= kTen15)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= kTen14)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= kTen13)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
if (value >= kTen12)
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
if (value >= kTen11)
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
if (value >= kTen10)
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
if (value >= kTen9)
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
if (value >= kTen8)
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d5];
|
||||||
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
*buffer++ = cDigitsLut[d6 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d7];
|
||||||
|
*buffer++ = cDigitsLut[d7 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d8];
|
||||||
|
*buffer++ = cDigitsLut[d8 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
|
||||||
|
value %= kTen16;
|
||||||
|
|
||||||
|
if (a < 10)
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||||
|
else if (a < 100) {
|
||||||
|
const uint32_t i = a << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else if (a < 1000) {
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
|
||||||
|
|
||||||
|
const uint32_t i = (a % 100) << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint32_t i = (a / 100) << 1;
|
||||||
|
const uint32_t j = (a % 100) << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
*buffer++ = cDigitsLut[j];
|
||||||
|
*buffer++ = cDigitsLut[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||||
|
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||||
|
|
||||||
|
const uint32_t b0 = v0 / 10000;
|
||||||
|
const uint32_t c0 = v0 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b0 / 100) << 1;
|
||||||
|
const uint32_t d2 = (b0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c0 / 100) << 1;
|
||||||
|
const uint32_t d4 = (c0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t b1 = v1 / 10000;
|
||||||
|
const uint32_t c1 = v1 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d5 = (b1 / 100) << 1;
|
||||||
|
const uint32_t d6 = (b1 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d7 = (c1 / 100) << 1;
|
||||||
|
const uint32_t d8 = (c1 % 100) << 1;
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d5];
|
||||||
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
*buffer++ = cDigitsLut[d6 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d7];
|
||||||
|
*buffer++ = cDigitsLut[d7 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d8];
|
||||||
|
*buffer++ = cDigitsLut[d8 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* i64toa(int64_t value, char* buffer) {
|
||||||
|
uint64_t u = static_cast<uint64_t>(value);
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
u = ~u + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u64toa(u, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ITOA_
|
|
@ -0,0 +1,181 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_META_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(6334)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//@cond RAPIDJSON_INTERNAL
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||||
|
template <typename T> struct Void { typedef void Type; };
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BoolType, TrueType, FalseType
|
||||||
|
//
|
||||||
|
template <bool Cond> struct BoolType {
|
||||||
|
static const bool Value = Cond;
|
||||||
|
typedef BoolType Type;
|
||||||
|
};
|
||||||
|
typedef BoolType<true> TrueType;
|
||||||
|
typedef BoolType<false> FalseType;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||||
|
//
|
||||||
|
|
||||||
|
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||||
|
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||||
|
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||||
|
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||||
|
|
||||||
|
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||||
|
template <> struct AndExprCond<true, true> : TrueType {};
|
||||||
|
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||||
|
template <> struct OrExprCond<false, false> : FalseType {};
|
||||||
|
|
||||||
|
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||||
|
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||||
|
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AddConst, MaybeAddConst, RemoveConst
|
||||||
|
template <typename T> struct AddConst { typedef const T Type; };
|
||||||
|
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
|
template <typename T> struct RemoveConst { typedef T Type; };
|
||||||
|
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||||
|
//
|
||||||
|
template <typename T, typename U> struct IsSame : FalseType {};
|
||||||
|
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename T> struct IsConst : FalseType {};
|
||||||
|
template <typename T> struct IsConst<const T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename CT, typename T>
|
||||||
|
struct IsMoreConst
|
||||||
|
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||||
|
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||||
|
|
||||||
|
template <typename T> struct IsPointer : FalseType {};
|
||||||
|
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsBaseOf
|
||||||
|
//
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||||
|
|
||||||
|
#else // simplified version adopted from Boost
|
||||||
|
|
||||||
|
template<typename B, typename D> struct IsBaseOfImpl {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||||
|
|
||||||
|
typedef char (&Yes)[1];
|
||||||
|
typedef char (&No) [2];
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static Yes Check(const D*, T);
|
||||||
|
static No Check(const B*, int);
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
operator const B*() const;
|
||||||
|
operator const D*();
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// EnableIf / DisableIf
|
||||||
|
//
|
||||||
|
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||||
|
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||||
|
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
// SFINAE helpers
|
||||||
|
struct SfinaeTag {};
|
||||||
|
template <typename T> struct RemoveSfinaeTag;
|
||||||
|
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||||
|
|
||||||
|
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||||
|
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF(cond) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF(cond) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
//@endcond
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_META_H_
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_POW10_
|
||||||
|
#define RAPIDJSON_POW10_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Computes integer powers of 10 in double (10.0^n).
|
||||||
|
/*! This function uses lookup table for fast and accurate results.
|
||||||
|
\param n non-negative exponent. Must <= 308.
|
||||||
|
\return 10.0^n
|
||||||
|
*/
|
||||||
|
inline double Pow10(int n) {
|
||||||
|
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
|
||||||
|
1e+0,
|
||||||
|
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||||
|
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||||
|
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||||
|
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||||
|
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||||
|
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||||
|
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||||
|
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||||
|
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||||
|
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||||
|
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||||
|
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||||
|
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||||
|
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||||
|
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||||
|
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||||
|
};
|
||||||
|
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
|
||||||
|
return e[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_POW10_
|
|
@ -0,0 +1,196 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
#include "swap.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stack
|
||||||
|
|
||||||
|
//! A type-unsafe stack for storing different types of data.
|
||||||
|
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||||
|
*/
|
||||||
|
template <typename Allocator>
|
||||||
|
class Stack {
|
||||||
|
public:
|
||||||
|
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||||
|
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||||
|
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||||
|
RAPIDJSON_ASSERT(stackCapacity > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Stack(Stack&& rhs)
|
||||||
|
: allocator_(rhs.allocator_),
|
||||||
|
ownAllocator_(rhs.ownAllocator_),
|
||||||
|
stack_(rhs.stack_),
|
||||||
|
stackTop_(rhs.stackTop_),
|
||||||
|
stackEnd_(rhs.stackEnd_),
|
||||||
|
initialCapacity_(rhs.initialCapacity_)
|
||||||
|
{
|
||||||
|
rhs.allocator_ = 0;
|
||||||
|
rhs.ownAllocator_ = 0;
|
||||||
|
rhs.stack_ = 0;
|
||||||
|
rhs.stackTop_ = 0;
|
||||||
|
rhs.stackEnd_ = 0;
|
||||||
|
rhs.initialCapacity_ = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
~Stack() {
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Stack& operator=(Stack&& rhs) {
|
||||||
|
if (&rhs != this)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
allocator_ = rhs.allocator_;
|
||||||
|
ownAllocator_ = rhs.ownAllocator_;
|
||||||
|
stack_ = rhs.stack_;
|
||||||
|
stackTop_ = rhs.stackTop_;
|
||||||
|
stackEnd_ = rhs.stackEnd_;
|
||||||
|
initialCapacity_ = rhs.initialCapacity_;
|
||||||
|
|
||||||
|
rhs.allocator_ = 0;
|
||||||
|
rhs.ownAllocator_ = 0;
|
||||||
|
rhs.stack_ = 0;
|
||||||
|
rhs.stackTop_ = 0;
|
||||||
|
rhs.stackEnd_ = 0;
|
||||||
|
rhs.initialCapacity_ = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
|
internal::Swap(allocator_, rhs.allocator_);
|
||||||
|
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||||
|
internal::Swap(stack_, rhs.stack_);
|
||||||
|
internal::Swap(stackTop_, rhs.stackTop_);
|
||||||
|
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||||
|
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() { stackTop_ = stack_; }
|
||||||
|
|
||||||
|
void ShrinkToFit() {
|
||||||
|
if (Empty()) {
|
||||||
|
// If the stack is empty, completely deallocate the memory.
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
stack_ = 0;
|
||||||
|
stackTop_ = 0;
|
||||||
|
stackEnd_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Resize(GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimization note: try to minimize the size of this function for force inline.
|
||||||
|
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||||
|
// Expand the stack if needed
|
||||||
|
if (stackTop_ + sizeof(T) * count >= stackEnd_)
|
||||||
|
Expand<T>(count);
|
||||||
|
|
||||||
|
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||||
|
stackTop_ += sizeof(T) * count;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Pop(size_t count) {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||||
|
stackTop_ -= count * sizeof(T);
|
||||||
|
return reinterpret_cast<T*>(stackTop_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Top() {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Bottom() { return (T*)stack_; }
|
||||||
|
|
||||||
|
bool HasAllocator() const {
|
||||||
|
return allocator_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator& GetAllocator() {
|
||||||
|
RAPIDJSON_ASSERT(allocator_);
|
||||||
|
return *allocator_;
|
||||||
|
}
|
||||||
|
bool Empty() const { return stackTop_ == stack_; }
|
||||||
|
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||||
|
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
void Expand(size_t count) {
|
||||||
|
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||||
|
size_t newCapacity;
|
||||||
|
if (stack_ == 0) {
|
||||||
|
if (!allocator_)
|
||||||
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||||
|
newCapacity = initialCapacity_;
|
||||||
|
} else {
|
||||||
|
newCapacity = GetCapacity();
|
||||||
|
newCapacity += (newCapacity + 1) / 2;
|
||||||
|
}
|
||||||
|
size_t newSize = GetSize() + sizeof(T) * count;
|
||||||
|
if (newCapacity < newSize)
|
||||||
|
newCapacity = newSize;
|
||||||
|
|
||||||
|
Resize(newCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize(size_t newCapacity) {
|
||||||
|
const size_t size = GetSize(); // Backup the current size
|
||||||
|
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
|
||||||
|
stackTop_ = stack_ + size;
|
||||||
|
stackEnd_ = stack_ + newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy() {
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
Stack(const Stack&);
|
||||||
|
Stack& operator=(const Stack&);
|
||||||
|
|
||||||
|
Allocator* allocator_;
|
||||||
|
Allocator* ownAllocator_;
|
||||||
|
char *stack_;
|
||||||
|
char *stackTop_;
|
||||||
|
char *stackEnd_;
|
||||||
|
size_t initialCapacity_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STACK_H_
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Custom strlen() which works on different character types.
|
||||||
|
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||||
|
\param s Null-terminated input string.
|
||||||
|
\return Number of characters in the string.
|
||||||
|
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||||
|
*/
|
||||||
|
template <typename Ch>
|
||||||
|
inline SizeType StrLen(const Ch* s) {
|
||||||
|
const Ch* p = s;
|
||||||
|
while (*p) ++p;
|
||||||
|
return SizeType(p - s);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
|
@ -0,0 +1,270 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_STRTOD_
|
||||||
|
#define RAPIDJSON_STRTOD_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
#include "ieee754.h"
|
||||||
|
#include "biginteger.h"
|
||||||
|
#include "diyfp.h"
|
||||||
|
#include "pow10.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline double FastPath(double significand, int exp) {
|
||||||
|
if (exp < -308)
|
||||||
|
return 0.0;
|
||||||
|
else if (exp >= 0)
|
||||||
|
return significand * internal::Pow10(exp);
|
||||||
|
else
|
||||||
|
return significand / internal::Pow10(-exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodNormalPrecision(double d, int p) {
|
||||||
|
if (p < -308) {
|
||||||
|
// Prevent expSum < -308, making Pow10(p) = 0
|
||||||
|
d = FastPath(d, -308);
|
||||||
|
d = FastPath(d, p + 308);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d = FastPath(d, p);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T Min3(T a, T b, T c) {
|
||||||
|
T m = a;
|
||||||
|
if (m > b) m = b;
|
||||||
|
if (m > c) m = c;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||||
|
const Double db(b);
|
||||||
|
const uint64_t bInt = db.IntegerSignificand();
|
||||||
|
const int bExp = db.IntegerExponent();
|
||||||
|
const int hExp = bExp - 1;
|
||||||
|
|
||||||
|
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
|
||||||
|
|
||||||
|
// Adjust for decimal exponent
|
||||||
|
if (dExp >= 0) {
|
||||||
|
dS_Exp2 += dExp;
|
||||||
|
dS_Exp5 += dExp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bS_Exp2 -= dExp;
|
||||||
|
bS_Exp5 -= dExp;
|
||||||
|
hS_Exp2 -= dExp;
|
||||||
|
hS_Exp5 -= dExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for binary exponent
|
||||||
|
if (bExp >= 0)
|
||||||
|
bS_Exp2 += bExp;
|
||||||
|
else {
|
||||||
|
dS_Exp2 -= bExp;
|
||||||
|
hS_Exp2 -= bExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for half ulp exponent
|
||||||
|
if (hExp >= 0)
|
||||||
|
hS_Exp2 += hExp;
|
||||||
|
else {
|
||||||
|
dS_Exp2 -= hExp;
|
||||||
|
bS_Exp2 -= hExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove common power of two factor from all three scaled values
|
||||||
|
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
|
||||||
|
dS_Exp2 -= common_Exp2;
|
||||||
|
bS_Exp2 -= common_Exp2;
|
||||||
|
hS_Exp2 -= common_Exp2;
|
||||||
|
|
||||||
|
BigInteger dS = d;
|
||||||
|
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||||
|
|
||||||
|
BigInteger bS(bInt);
|
||||||
|
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||||
|
|
||||||
|
BigInteger hS(1);
|
||||||
|
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||||
|
|
||||||
|
BigInteger delta(0);
|
||||||
|
dS.Difference(bS, &delta);
|
||||||
|
|
||||||
|
return delta.Compare(hS);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StrtodFast(double d, int p, double* result) {
|
||||||
|
// Use fast path for string-to-double conversion if possible
|
||||||
|
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||||
|
if (p > 22 && p < 22 + 16) {
|
||||||
|
// Fast Path Cases In Disguise
|
||||||
|
d *= internal::Pow10(p - 22);
|
||||||
|
p = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||||
|
*result = FastPath(d, p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute an approximation and see if it is within 1/2 ULP
|
||||||
|
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
||||||
|
uint64_t significand = 0;
|
||||||
|
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||||
|
for (; i < length; i++) {
|
||||||
|
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||||
|
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||||
|
break;
|
||||||
|
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < length && decimals[i] >= '5') // Rounding
|
||||||
|
significand++;
|
||||||
|
|
||||||
|
size_t remaining = length - i;
|
||||||
|
const unsigned kUlpShift = 3;
|
||||||
|
const unsigned kUlp = 1 << kUlpShift;
|
||||||
|
int error = (remaining == 0) ? 0 : kUlp / 2;
|
||||||
|
|
||||||
|
DiyFp v(significand, 0);
|
||||||
|
v = v.Normalize();
|
||||||
|
error <<= -v.e;
|
||||||
|
|
||||||
|
const int dExp = (int)decimalPosition - (int)i + exp;
|
||||||
|
|
||||||
|
int actualExp;
|
||||||
|
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||||
|
if (actualExp != dExp) {
|
||||||
|
static const DiyFp kPow10[] = {
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
||||||
|
};
|
||||||
|
int adjustment = dExp - actualExp - 1;
|
||||||
|
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
||||||
|
v = v * kPow10[adjustment];
|
||||||
|
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
||||||
|
error += kUlp / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v * cachedPower;
|
||||||
|
|
||||||
|
error += kUlp + (error == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
const int oldExp = v.e;
|
||||||
|
v = v.Normalize();
|
||||||
|
error <<= oldExp - v.e;
|
||||||
|
|
||||||
|
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
|
||||||
|
unsigned precisionSize = 64 - effectiveSignificandSize;
|
||||||
|
if (precisionSize + kUlpShift >= 64) {
|
||||||
|
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
|
||||||
|
v.f >>= scaleExp;
|
||||||
|
v.e += scaleExp;
|
||||||
|
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
|
||||||
|
precisionSize -= scaleExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
|
||||||
|
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||||
|
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||||
|
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||||
|
rounded.f++;
|
||||||
|
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||||
|
rounded.f >>= 1;
|
||||||
|
rounded.e++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = rounded.ToDouble();
|
||||||
|
|
||||||
|
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
|
const BigInteger dInt(decimals, length);
|
||||||
|
const int dExp = (int)decimalPosition - (int)length + exp;
|
||||||
|
Double a(approx);
|
||||||
|
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||||
|
if (cmp < 0)
|
||||||
|
return a.Value(); // within half ULP
|
||||||
|
else if (cmp == 0) {
|
||||||
|
// Round towards even
|
||||||
|
if (a.Significand() & 1)
|
||||||
|
return a.NextPositiveDouble();
|
||||||
|
else
|
||||||
|
return a.Value();
|
||||||
|
}
|
||||||
|
else // adjustment
|
||||||
|
return a.NextPositiveDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
|
RAPIDJSON_ASSERT(d >= 0.0);
|
||||||
|
RAPIDJSON_ASSERT(length >= 1);
|
||||||
|
|
||||||
|
double result;
|
||||||
|
if (StrtodFast(d, p, &result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Trim leading zeros
|
||||||
|
while (*decimals == '0' && length > 1) {
|
||||||
|
length--;
|
||||||
|
decimals++;
|
||||||
|
decimalPosition--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim trailing zeros
|
||||||
|
while (decimals[length - 1] == '0' && length > 1) {
|
||||||
|
length--;
|
||||||
|
decimalPosition--;
|
||||||
|
exp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim right-most digits
|
||||||
|
const int kMaxDecimalDigit = 780;
|
||||||
|
if ((int)length > kMaxDecimalDigit) {
|
||||||
|
int delta = (int(length) - kMaxDecimalDigit);
|
||||||
|
exp += delta;
|
||||||
|
decimalPosition -= static_cast<unsigned>(delta);
|
||||||
|
length = kMaxDecimalDigit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If too small, underflow to zero
|
||||||
|
if (int(length) + exp < -324)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||||
|
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STRTOD_
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||||
|
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||||
|
\note This has the same semantics as std::swap().
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||||
|
T tmp = a;
|
||||||
|
a = b;
|
||||||
|
b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
#define RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
#include "internal/stack.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory output byte stream.
|
||||||
|
/*!
|
||||||
|
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
|
||||||
|
|
||||||
|
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
|
||||||
|
|
||||||
|
Differences between MemoryBuffer and StringBuffer:
|
||||||
|
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
|
||||||
|
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
|
||||||
|
|
||||||
|
\tparam Allocator type for allocating memory buffer.
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
template <typename Allocator = CrtAllocator>
|
||||||
|
struct GenericMemoryBuffer {
|
||||||
|
typedef char Ch; // byte
|
||||||
|
|
||||||
|
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||||
|
|
||||||
|
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||||
|
void Flush() {}
|
||||||
|
|
||||||
|
void Clear() { stack_.Clear(); }
|
||||||
|
void ShrinkToFit() { stack_.ShrinkToFit(); }
|
||||||
|
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||||
|
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||||
|
|
||||||
|
const Ch* GetBuffer() const {
|
||||||
|
return stack_.template Bottom<Ch>();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetSize() const { return stack_.GetSize(); }
|
||||||
|
|
||||||
|
static const size_t kDefaultCapacity = 256;
|
||||||
|
mutable internal::Stack<Allocator> stack_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GenericMemoryBuffer<> MemoryBuffer;
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
|
||||||
|
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MEMORYSTREAM_H_
|
||||||
|
#define RAPIDJSON_MEMORYSTREAM_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory input byte stream.
|
||||||
|
/*!
|
||||||
|
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
|
||||||
|
|
||||||
|
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
|
||||||
|
|
||||||
|
Differences between MemoryStream and StringStream:
|
||||||
|
1. StringStream has encoding but MemoryStream is a byte stream.
|
||||||
|
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
|
||||||
|
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
struct MemoryStream {
|
||||||
|
typedef char Ch; // byte
|
||||||
|
|
||||||
|
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
|
||||||
|
Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
|
||||||
|
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
return Tell() + 4 <= size_ ? src_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ch* src_; //!< Current read position.
|
||||||
|
const Ch* begin_; //!< Original head of the string.
|
||||||
|
const Ch* end_; //!< End of stream.
|
||||||
|
size_t size_; //!< Size of the stream.
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
|
@ -0,0 +1,316 @@
|
||||||
|
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||||
|
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are met:
|
||||||
|
//
|
||||||
|
// 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
// this list of conditions and the following disclaimer.
|
||||||
|
//
|
||||||
|
// 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer in the
|
||||||
|
// documentation and/or other materials provided with the distribution.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the product nor the names of its contributors may
|
||||||
|
// be used to endorse or promote products derived from this software
|
||||||
|
// without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// The above software in this distribution may have been modified by
|
||||||
|
// THL A29 Limited ("Tencent Modifications").
|
||||||
|
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||||
|
|
||||||
|
#ifndef _MSC_VER // [
|
||||||
|
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||||
|
#endif // _MSC_VER ]
|
||||||
|
|
||||||
|
#ifndef _MSC_INTTYPES_H_ // [
|
||||||
|
#define _MSC_INTTYPES_H_
|
||||||
|
|
||||||
|
#if _MSC_VER > 1000
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
// miloyip: VC supports inttypes.h since VC2013
|
||||||
|
#if _MSC_VER >= 1800
|
||||||
|
#include <inttypes.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
// 7.8 Format conversion of integer types
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intmax_t quot;
|
||||||
|
intmax_t rem;
|
||||||
|
} imaxdiv_t;
|
||||||
|
|
||||||
|
// 7.8.1 Macros for format specifiers
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||||
|
|
||||||
|
// The fprintf macros for signed integers are:
|
||||||
|
#define PRId8 "d"
|
||||||
|
#define PRIi8 "i"
|
||||||
|
#define PRIdLEAST8 "d"
|
||||||
|
#define PRIiLEAST8 "i"
|
||||||
|
#define PRIdFAST8 "d"
|
||||||
|
#define PRIiFAST8 "i"
|
||||||
|
|
||||||
|
#define PRId16 "hd"
|
||||||
|
#define PRIi16 "hi"
|
||||||
|
#define PRIdLEAST16 "hd"
|
||||||
|
#define PRIiLEAST16 "hi"
|
||||||
|
#define PRIdFAST16 "hd"
|
||||||
|
#define PRIiFAST16 "hi"
|
||||||
|
|
||||||
|
#define PRId32 "I32d"
|
||||||
|
#define PRIi32 "I32i"
|
||||||
|
#define PRIdLEAST32 "I32d"
|
||||||
|
#define PRIiLEAST32 "I32i"
|
||||||
|
#define PRIdFAST32 "I32d"
|
||||||
|
#define PRIiFAST32 "I32i"
|
||||||
|
|
||||||
|
#define PRId64 "I64d"
|
||||||
|
#define PRIi64 "I64i"
|
||||||
|
#define PRIdLEAST64 "I64d"
|
||||||
|
#define PRIiLEAST64 "I64i"
|
||||||
|
#define PRIdFAST64 "I64d"
|
||||||
|
#define PRIiFAST64 "I64i"
|
||||||
|
|
||||||
|
#define PRIdMAX "I64d"
|
||||||
|
#define PRIiMAX "I64i"
|
||||||
|
|
||||||
|
#define PRIdPTR "Id"
|
||||||
|
#define PRIiPTR "Ii"
|
||||||
|
|
||||||
|
// The fprintf macros for unsigned integers are:
|
||||||
|
#define PRIo8 "o"
|
||||||
|
#define PRIu8 "u"
|
||||||
|
#define PRIx8 "x"
|
||||||
|
#define PRIX8 "X"
|
||||||
|
#define PRIoLEAST8 "o"
|
||||||
|
#define PRIuLEAST8 "u"
|
||||||
|
#define PRIxLEAST8 "x"
|
||||||
|
#define PRIXLEAST8 "X"
|
||||||
|
#define PRIoFAST8 "o"
|
||||||
|
#define PRIuFAST8 "u"
|
||||||
|
#define PRIxFAST8 "x"
|
||||||
|
#define PRIXFAST8 "X"
|
||||||
|
|
||||||
|
#define PRIo16 "ho"
|
||||||
|
#define PRIu16 "hu"
|
||||||
|
#define PRIx16 "hx"
|
||||||
|
#define PRIX16 "hX"
|
||||||
|
#define PRIoLEAST16 "ho"
|
||||||
|
#define PRIuLEAST16 "hu"
|
||||||
|
#define PRIxLEAST16 "hx"
|
||||||
|
#define PRIXLEAST16 "hX"
|
||||||
|
#define PRIoFAST16 "ho"
|
||||||
|
#define PRIuFAST16 "hu"
|
||||||
|
#define PRIxFAST16 "hx"
|
||||||
|
#define PRIXFAST16 "hX"
|
||||||
|
|
||||||
|
#define PRIo32 "I32o"
|
||||||
|
#define PRIu32 "I32u"
|
||||||
|
#define PRIx32 "I32x"
|
||||||
|
#define PRIX32 "I32X"
|
||||||
|
#define PRIoLEAST32 "I32o"
|
||||||
|
#define PRIuLEAST32 "I32u"
|
||||||
|
#define PRIxLEAST32 "I32x"
|
||||||
|
#define PRIXLEAST32 "I32X"
|
||||||
|
#define PRIoFAST32 "I32o"
|
||||||
|
#define PRIuFAST32 "I32u"
|
||||||
|
#define PRIxFAST32 "I32x"
|
||||||
|
#define PRIXFAST32 "I32X"
|
||||||
|
|
||||||
|
#define PRIo64 "I64o"
|
||||||
|
#define PRIu64 "I64u"
|
||||||
|
#define PRIx64 "I64x"
|
||||||
|
#define PRIX64 "I64X"
|
||||||
|
#define PRIoLEAST64 "I64o"
|
||||||
|
#define PRIuLEAST64 "I64u"
|
||||||
|
#define PRIxLEAST64 "I64x"
|
||||||
|
#define PRIXLEAST64 "I64X"
|
||||||
|
#define PRIoFAST64 "I64o"
|
||||||
|
#define PRIuFAST64 "I64u"
|
||||||
|
#define PRIxFAST64 "I64x"
|
||||||
|
#define PRIXFAST64 "I64X"
|
||||||
|
|
||||||
|
#define PRIoMAX "I64o"
|
||||||
|
#define PRIuMAX "I64u"
|
||||||
|
#define PRIxMAX "I64x"
|
||||||
|
#define PRIXMAX "I64X"
|
||||||
|
|
||||||
|
#define PRIoPTR "Io"
|
||||||
|
#define PRIuPTR "Iu"
|
||||||
|
#define PRIxPTR "Ix"
|
||||||
|
#define PRIXPTR "IX"
|
||||||
|
|
||||||
|
// The fscanf macros for signed integers are:
|
||||||
|
#define SCNd8 "d"
|
||||||
|
#define SCNi8 "i"
|
||||||
|
#define SCNdLEAST8 "d"
|
||||||
|
#define SCNiLEAST8 "i"
|
||||||
|
#define SCNdFAST8 "d"
|
||||||
|
#define SCNiFAST8 "i"
|
||||||
|
|
||||||
|
#define SCNd16 "hd"
|
||||||
|
#define SCNi16 "hi"
|
||||||
|
#define SCNdLEAST16 "hd"
|
||||||
|
#define SCNiLEAST16 "hi"
|
||||||
|
#define SCNdFAST16 "hd"
|
||||||
|
#define SCNiFAST16 "hi"
|
||||||
|
|
||||||
|
#define SCNd32 "ld"
|
||||||
|
#define SCNi32 "li"
|
||||||
|
#define SCNdLEAST32 "ld"
|
||||||
|
#define SCNiLEAST32 "li"
|
||||||
|
#define SCNdFAST32 "ld"
|
||||||
|
#define SCNiFAST32 "li"
|
||||||
|
|
||||||
|
#define SCNd64 "I64d"
|
||||||
|
#define SCNi64 "I64i"
|
||||||
|
#define SCNdLEAST64 "I64d"
|
||||||
|
#define SCNiLEAST64 "I64i"
|
||||||
|
#define SCNdFAST64 "I64d"
|
||||||
|
#define SCNiFAST64 "I64i"
|
||||||
|
|
||||||
|
#define SCNdMAX "I64d"
|
||||||
|
#define SCNiMAX "I64i"
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define SCNdPTR "I64d"
|
||||||
|
# define SCNiPTR "I64i"
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define SCNdPTR "ld"
|
||||||
|
# define SCNiPTR "li"
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// The fscanf macros for unsigned integers are:
|
||||||
|
#define SCNo8 "o"
|
||||||
|
#define SCNu8 "u"
|
||||||
|
#define SCNx8 "x"
|
||||||
|
#define SCNX8 "X"
|
||||||
|
#define SCNoLEAST8 "o"
|
||||||
|
#define SCNuLEAST8 "u"
|
||||||
|
#define SCNxLEAST8 "x"
|
||||||
|
#define SCNXLEAST8 "X"
|
||||||
|
#define SCNoFAST8 "o"
|
||||||
|
#define SCNuFAST8 "u"
|
||||||
|
#define SCNxFAST8 "x"
|
||||||
|
#define SCNXFAST8 "X"
|
||||||
|
|
||||||
|
#define SCNo16 "ho"
|
||||||
|
#define SCNu16 "hu"
|
||||||
|
#define SCNx16 "hx"
|
||||||
|
#define SCNX16 "hX"
|
||||||
|
#define SCNoLEAST16 "ho"
|
||||||
|
#define SCNuLEAST16 "hu"
|
||||||
|
#define SCNxLEAST16 "hx"
|
||||||
|
#define SCNXLEAST16 "hX"
|
||||||
|
#define SCNoFAST16 "ho"
|
||||||
|
#define SCNuFAST16 "hu"
|
||||||
|
#define SCNxFAST16 "hx"
|
||||||
|
#define SCNXFAST16 "hX"
|
||||||
|
|
||||||
|
#define SCNo32 "lo"
|
||||||
|
#define SCNu32 "lu"
|
||||||
|
#define SCNx32 "lx"
|
||||||
|
#define SCNX32 "lX"
|
||||||
|
#define SCNoLEAST32 "lo"
|
||||||
|
#define SCNuLEAST32 "lu"
|
||||||
|
#define SCNxLEAST32 "lx"
|
||||||
|
#define SCNXLEAST32 "lX"
|
||||||
|
#define SCNoFAST32 "lo"
|
||||||
|
#define SCNuFAST32 "lu"
|
||||||
|
#define SCNxFAST32 "lx"
|
||||||
|
#define SCNXFAST32 "lX"
|
||||||
|
|
||||||
|
#define SCNo64 "I64o"
|
||||||
|
#define SCNu64 "I64u"
|
||||||
|
#define SCNx64 "I64x"
|
||||||
|
#define SCNX64 "I64X"
|
||||||
|
#define SCNoLEAST64 "I64o"
|
||||||
|
#define SCNuLEAST64 "I64u"
|
||||||
|
#define SCNxLEAST64 "I64x"
|
||||||
|
#define SCNXLEAST64 "I64X"
|
||||||
|
#define SCNoFAST64 "I64o"
|
||||||
|
#define SCNuFAST64 "I64u"
|
||||||
|
#define SCNxFAST64 "I64x"
|
||||||
|
#define SCNXFAST64 "I64X"
|
||||||
|
|
||||||
|
#define SCNoMAX "I64o"
|
||||||
|
#define SCNuMAX "I64u"
|
||||||
|
#define SCNxMAX "I64x"
|
||||||
|
#define SCNXMAX "I64X"
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define SCNoPTR "I64o"
|
||||||
|
# define SCNuPTR "I64u"
|
||||||
|
# define SCNxPTR "I64x"
|
||||||
|
# define SCNXPTR "I64X"
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define SCNoPTR "lo"
|
||||||
|
# define SCNuPTR "lu"
|
||||||
|
# define SCNxPTR "lx"
|
||||||
|
# define SCNXPTR "lX"
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
#endif // __STDC_FORMAT_MACROS ]
|
||||||
|
|
||||||
|
// 7.8.2 Functions for greatest-width integer types
|
||||||
|
|
||||||
|
// 7.8.2.1 The imaxabs function
|
||||||
|
#define imaxabs _abs64
|
||||||
|
|
||||||
|
// 7.8.2.2 The imaxdiv function
|
||||||
|
|
||||||
|
// This is modified version of div() function from Microsoft's div.c found
|
||||||
|
// in %MSVC.NET%\crt\src\div.c
|
||||||
|
#ifdef STATIC_IMAXDIV // [
|
||||||
|
static
|
||||||
|
#else // STATIC_IMAXDIV ][
|
||||||
|
_inline
|
||||||
|
#endif // STATIC_IMAXDIV ]
|
||||||
|
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||||
|
{
|
||||||
|
imaxdiv_t result;
|
||||||
|
|
||||||
|
result.quot = numer / denom;
|
||||||
|
result.rem = numer % denom;
|
||||||
|
|
||||||
|
if (numer < 0 && result.rem > 0) {
|
||||||
|
// did division wrong; must fix up
|
||||||
|
++result.quot;
|
||||||
|
result.rem -= denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||||
|
#define strtoimax _strtoi64
|
||||||
|
#define strtoumax _strtoui64
|
||||||
|
|
||||||
|
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||||
|
#define wcstoimax _wcstoi64
|
||||||
|
#define wcstoumax _wcstoui64
|
||||||
|
|
||||||
|
#endif // _MSC_VER >= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_INTTYPES_H_ ]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue