Initial commit
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// 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. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef OZZ_OZZ_BASE_IO_ARCHIVE_H_
|
||||
#define OZZ_OZZ_BASE_IO_ARCHIVE_H_
|
||||
|
||||
// Provides input (IArchive) and output (OArchive) serialization containers.
|
||||
// Archive are similar to c++ iostream. Data can be saved to a OArchive with
|
||||
// the << operator, or loaded from a IArchive with the >> operator.
|
||||
// Primitive data types are simply saved/loaded to/from archives, while struct
|
||||
// and class are saved/loaded through Save/Load intrusive or non-intrusive
|
||||
// functions:
|
||||
// - The intrusive function prototypes are "void Save(ozz::io::OArchive*) const"
|
||||
// and "void Load(ozz::io::IArchive*)".
|
||||
// - The non-intrusive functions allow to work on arrays of objects. They must
|
||||
// be implemented in ozz::io namespace, by specializing the following template
|
||||
// struct:
|
||||
// template <typename _Ty>
|
||||
// struct Extern {
|
||||
// static void Save(OArchive& _archive, const _Ty* _ty, size_t _count);
|
||||
// static void Load(IArchive& _archive, _Ty* _ty, size_t _count,
|
||||
// uint32_t _version);
|
||||
// };
|
||||
//
|
||||
// Arrays of struct/class or primitive types can be saved/loaded with the
|
||||
// helper function ozz::io::MakeArray() that is then streamed in or out using
|
||||
// << and >> archive operators: archive << ozz::io::MakeArray(my_array, count);
|
||||
//
|
||||
// Versioning can be done using OZZ_IO_TYPE_VERSION macros. Type version
|
||||
// is saved in the OArchive, and is given back to Load functions to allow to
|
||||
// manually handle version modifications. Versioning can be disabled using
|
||||
// OZZ_IO_TYPE_NOT_VERSIONABLE like macros. It can not be re-enabled afterward.
|
||||
//
|
||||
// Objects can be assigned a tag using OZZ_IO_TYPE_TAG macros. A tag allows to
|
||||
// check the type of the next object to read from an archive. An automatic
|
||||
// assertion check is performed for each object that has a tag. It can also be
|
||||
// done manually to ensure an archive has the expected content.
|
||||
//
|
||||
// Endianness (big-endian or little-endian) can be specified while constructing
|
||||
// an output archive (ozz::io::OArchive). Input archives automatically handle
|
||||
// endianness conversion if the native platform endian mode differs from the
|
||||
// archive one.
|
||||
//
|
||||
// IArchive and OArchive expect valid streams as argument, respectively opened
|
||||
// for reading and writing. Archives do NOT perform error detection while
|
||||
// reading or writing. All errors are considered programming errors. This leads
|
||||
// to the following assertions on the user side:
|
||||
// - When writing: the stream must be big (or grow-able) enough to support the
|
||||
// data being written.
|
||||
// - When reading: Stream's tell (position in the stream) must match the object
|
||||
// being read. To help with this requirement, archives provide a tag mechanism
|
||||
// that allows to check the tag (ie the type) of the next object to read. Stream
|
||||
// integrity, like data corruption or file truncation, must also be validated on
|
||||
// the user side.
|
||||
|
||||
#include "ozz/base/endianness.h"
|
||||
#include "ozz/base/io/stream.h"
|
||||
#include "ozz/base/platform.h"
|
||||
#include "ozz/base/span.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cassert>
|
||||
|
||||
#include "ozz/base/io/archive_traits.h"
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
namespace internal {
|
||||
// Defines Tagger helper object struct.
|
||||
// The boolean template argument is used to automatically select a template
|
||||
// specialization, whether _Ty has a tag or not.
|
||||
template <typename _Ty,
|
||||
bool _HasTag = internal::Tag<const _Ty>::kTagLength != 0>
|
||||
struct Tagger;
|
||||
} // namespace internal
|
||||
|
||||
// Implements output archive concept used to save/serialize data from a Stream.
|
||||
// The output endianness mode is set at construction time. It is written to the
|
||||
// stream to allow the IArchive to perform the required conversion to the native
|
||||
// endianness mode while reading.
|
||||
class OArchive {
|
||||
public:
|
||||
// Constructs an output archive from the Stream _stream that must be valid
|
||||
// and opened for writing.
|
||||
explicit OArchive(Stream* _stream,
|
||||
Endianness _endianness = GetNativeEndianness());
|
||||
|
||||
// Returns true if an endian swap is required while writing.
|
||||
bool endian_swap() const { return endian_swap_; }
|
||||
|
||||
// Saves _size bytes of binary data from _data.
|
||||
size_t SaveBinary(const void* _data, size_t _size) {
|
||||
return stream_->Write(_data, _size);
|
||||
}
|
||||
|
||||
// Class type saving.
|
||||
template <typename _Ty>
|
||||
void operator<<(const _Ty& _ty) {
|
||||
internal::Tagger<const _Ty>::Write(*this);
|
||||
SaveVersion<_Ty>();
|
||||
Extern<_Ty>::Save(*this, &_ty, 1);
|
||||
}
|
||||
|
||||
// Primitive type saving.
|
||||
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
|
||||
void operator<<(_type _v) { \
|
||||
_type v = endian_swap_ ? EndianSwapper<_type>::Swap(_v) : _v; \
|
||||
OZZ_IF_DEBUG(size_t size =) stream_->Write(&v, sizeof(v)); \
|
||||
assert(size == sizeof(v)); \
|
||||
}
|
||||
|
||||
OZZ_IO_PRIMITIVE_TYPE(char)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int8_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int16_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int32_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int64_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(bool)
|
||||
OZZ_IO_PRIMITIVE_TYPE(float)
|
||||
#undef OZZ_IO_PRIMITIVE_TYPE
|
||||
|
||||
// Returns output stream.
|
||||
Stream* stream() const { return stream_; }
|
||||
|
||||
private:
|
||||
template <typename _Ty>
|
||||
void SaveVersion() {
|
||||
// Compilation could fail here if the version is not defined for _Ty, or if
|
||||
// the .h file containing its definition is not included by the caller of
|
||||
// this function.
|
||||
if (void(0), internal::Version<const _Ty>::kValue != 0) {
|
||||
uint32_t version = internal::Version<const _Ty>::kValue;
|
||||
*this << version;
|
||||
}
|
||||
}
|
||||
|
||||
// The output stream.
|
||||
Stream* stream_;
|
||||
|
||||
// Endian swap state, true if a conversion is required while writing.
|
||||
bool endian_swap_;
|
||||
};
|
||||
|
||||
// Implements input archive concept used to load/de-serialize data to a Stream.
|
||||
// Endianness conversions are automatically performed according to the Archive
|
||||
// and the native formats.
|
||||
class IArchive {
|
||||
public:
|
||||
// Constructs an input archive from the Stream _stream that must be opened for
|
||||
// reading, at the same tell (position in the stream) as when it was passed to
|
||||
// the OArchive.
|
||||
explicit IArchive(Stream* _stream);
|
||||
|
||||
// Returns true if an endian swap is required while reading.
|
||||
bool endian_swap() const { return endian_swap_; }
|
||||
|
||||
// Loads _size bytes of binary data to _data.
|
||||
size_t LoadBinary(void* _data, size_t _size) {
|
||||
return stream_->Read(_data, _size);
|
||||
}
|
||||
|
||||
// Class type loading.
|
||||
template <typename _Ty>
|
||||
void operator>>(_Ty& _ty) {
|
||||
// Only uses tag validation for assertions, as reading cannot fail.
|
||||
OZZ_IF_DEBUG(bool valid =) internal::Tagger<const _Ty>::Validate(*this);
|
||||
assert(valid && "Type tag does not match archive content.");
|
||||
|
||||
// Loads instance.
|
||||
uint32_t version = LoadVersion<_Ty>();
|
||||
Extern<_Ty>::Load(*this, &_ty, 1, version);
|
||||
}
|
||||
|
||||
// Primitive type loading.
|
||||
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
|
||||
void operator>>(_type& _v) { \
|
||||
_type v; \
|
||||
OZZ_IF_DEBUG(size_t size =) stream_->Read(&v, sizeof(v)); \
|
||||
assert(size == sizeof(v)); \
|
||||
_v = endian_swap_ ? EndianSwapper<_type>::Swap(v) : v; \
|
||||
}
|
||||
|
||||
OZZ_IO_PRIMITIVE_TYPE(char)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int8_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int16_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int32_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int64_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(bool)
|
||||
OZZ_IO_PRIMITIVE_TYPE(float)
|
||||
#undef OZZ_IO_PRIMITIVE_TYPE
|
||||
|
||||
template <typename _Ty>
|
||||
bool TestTag() {
|
||||
// Only tagged types can be tested. If compilations fails here, it can
|
||||
// mean the file containing tag declaration is not included.
|
||||
static_assert(internal::Tag<const _Ty>::kTagLength != 0,
|
||||
"Tag unknown for type.");
|
||||
|
||||
const int tell = stream_->Tell();
|
||||
bool valid = internal::Tagger<const _Ty>::Validate(*this);
|
||||
stream_->Seek(tell, Stream::kSet); // Rewinds before the tag test.
|
||||
return valid;
|
||||
}
|
||||
|
||||
// Returns input stream.
|
||||
Stream* stream() const { return stream_; }
|
||||
|
||||
private:
|
||||
template <typename _Ty>
|
||||
uint32_t LoadVersion() {
|
||||
uint32_t version = 0;
|
||||
if (void(0), internal::Version<const _Ty>::kValue != 0) {
|
||||
*this >> version;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
// The input stream.
|
||||
Stream* stream_;
|
||||
|
||||
// Endian swap state, true if a conversion is required while reading.
|
||||
bool endian_swap_;
|
||||
};
|
||||
|
||||
// Primitive type are not versionable.
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(char)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(int8_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(uint8_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(int16_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(uint16_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(int32_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(uint32_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(int64_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(uint64_t)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(bool)
|
||||
OZZ_IO_TYPE_NOT_VERSIONABLE(float)
|
||||
|
||||
// Default loading and saving external implementation.
|
||||
template <typename _Ty>
|
||||
struct Extern {
|
||||
inline static void Save(OArchive& _archive, const _Ty* _ty, size_t _count) {
|
||||
for (size_t i = 0; i < _count; ++i) {
|
||||
_ty[i].Save(_archive);
|
||||
}
|
||||
}
|
||||
inline static void Load(IArchive& _archive, _Ty* _ty, size_t _count,
|
||||
uint32_t _version) {
|
||||
for (size_t i = 0; i < _count; ++i) {
|
||||
_ty[i].Load(_archive, _version);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Wrapper for dynamic array serialization.
|
||||
// Must be used through ozz::io::MakeArray.
|
||||
namespace internal {
|
||||
template <typename _Ty>
|
||||
struct Array {
|
||||
OZZ_INLINE void Save(OArchive& _archive) const {
|
||||
ozz::io::Extern<_Ty>::Save(_archive, array, count);
|
||||
}
|
||||
OZZ_INLINE void Load(IArchive& _archive, uint32_t _version) const {
|
||||
ozz::io::Extern<_Ty>::Load(_archive, array, count, _version);
|
||||
}
|
||||
_Ty* array;
|
||||
size_t count;
|
||||
};
|
||||
// Specialize for const _Ty which can only be saved.
|
||||
template <typename _Ty>
|
||||
struct Array<const _Ty> {
|
||||
OZZ_INLINE void Save(OArchive& _archive) const {
|
||||
ozz::io::Extern<_Ty>::Save(_archive, array, count);
|
||||
}
|
||||
const _Ty* array;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
// Array copies version from the type it contains.
|
||||
// Definition of Array of _Ty version: _Ty version.
|
||||
template <typename _Ty>
|
||||
struct Version<const Array<_Ty>> {
|
||||
enum { kValue = Version<const _Ty>::kValue };
|
||||
};
|
||||
|
||||
// Specializes Array Save/Load for primitive types.
|
||||
#define OZZ_IO_PRIMITIVE_TYPE(_type) \
|
||||
template <> \
|
||||
inline void Array<const _type>::Save(OArchive& _archive) const { \
|
||||
if (_archive.endian_swap()) { \
|
||||
/* Save element by element as swapping in place the whole buffer is*/ \
|
||||
/* not possible.*/ \
|
||||
for (size_t i = 0; i < count; ++i) { \
|
||||
_archive << array[i]; \
|
||||
} \
|
||||
} else { \
|
||||
OZZ_IF_DEBUG(size_t size =) \
|
||||
_archive.SaveBinary(array, count * sizeof(_type)); \
|
||||
assert(size == count * sizeof(_type)); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template <> \
|
||||
inline void Array<_type>::Save(OArchive& _archive) const { \
|
||||
if (_archive.endian_swap()) { \
|
||||
/* Save element by element as swapping in place the whole buffer is*/ \
|
||||
/* not possible.*/ \
|
||||
for (size_t i = 0; i < count; ++i) { \
|
||||
_archive << array[i]; \
|
||||
} \
|
||||
} else { \
|
||||
OZZ_IF_DEBUG(size_t size =) \
|
||||
_archive.SaveBinary(array, count * sizeof(_type)); \
|
||||
assert(size == count * sizeof(_type)); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template <> \
|
||||
inline void Array<_type>::Load(IArchive& _archive, uint32_t /*_version*/) \
|
||||
const { \
|
||||
OZZ_IF_DEBUG(size_t size =) \
|
||||
_archive.LoadBinary(array, count * sizeof(_type)); \
|
||||
assert(size == count * sizeof(_type)); \
|
||||
if (_archive.endian_swap()) { /*Can swap in-place.*/ \
|
||||
EndianSwapper<_type>::Swap(array, count); \
|
||||
} \
|
||||
}
|
||||
|
||||
OZZ_IO_PRIMITIVE_TYPE(char)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int8_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint8_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int16_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint16_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int32_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint32_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(int64_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(uint64_t)
|
||||
OZZ_IO_PRIMITIVE_TYPE(bool)
|
||||
OZZ_IO_PRIMITIVE_TYPE(float)
|
||||
#undef OZZ_IO_PRIMITIVE_TYPE
|
||||
} // namespace internal
|
||||
|
||||
// Utility function that instantiates Array wrapper.
|
||||
template <typename _Ty>
|
||||
OZZ_INLINE const internal::Array<_Ty> MakeArray(_Ty* _array, size_t _count) {
|
||||
const internal::Array<_Ty> array = {_array, _count};
|
||||
return array;
|
||||
}
|
||||
template <typename _Ty>
|
||||
OZZ_INLINE const internal::Array<const _Ty> MakeArray(const _Ty* _array,
|
||||
size_t _count) {
|
||||
const internal::Array<const _Ty> array = {_array, _count};
|
||||
return array;
|
||||
}
|
||||
template <typename _Ty>
|
||||
OZZ_INLINE const internal::Array<_Ty> MakeArray(span<_Ty> _array) {
|
||||
const internal::Array<_Ty> array = {_array.data(), _array.size()};
|
||||
return array;
|
||||
}
|
||||
template <typename _Ty>
|
||||
OZZ_INLINE const internal::Array<const _Ty> MakeArray(span<const _Ty> _array) {
|
||||
const internal::Array<const _Ty> array = {_array.data(), _array.size()};
|
||||
return array;
|
||||
}
|
||||
template <typename _Ty, size_t _count>
|
||||
OZZ_INLINE const internal::Array<_Ty> MakeArray(_Ty (&_array)[_count]) {
|
||||
const internal::Array<_Ty> array = {_array, _count};
|
||||
return array;
|
||||
}
|
||||
template <typename _Ty, size_t _count>
|
||||
OZZ_INLINE const internal::Array<const _Ty> MakeArray(
|
||||
const _Ty (&_array)[_count]) {
|
||||
const internal::Array<const _Ty> array = {_array, _count};
|
||||
return array;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
// Specialization of the Tagger helper for tagged types.
|
||||
template <typename _Ty>
|
||||
struct Tagger<_Ty, true> {
|
||||
static void Write(OArchive& _archive) {
|
||||
typedef internal::Tag<const _Ty> Tag;
|
||||
OZZ_IF_DEBUG(size_t size =)
|
||||
_archive.SaveBinary(Tag::Get(), Tag::kTagLength);
|
||||
assert(size == Tag::kTagLength);
|
||||
}
|
||||
static bool Validate(IArchive& _archive) {
|
||||
typedef internal::Tag<const _Ty> Tag;
|
||||
char buf[Tag::kTagLength];
|
||||
if (Tag::kTagLength != _archive.LoadBinary(buf, Tag::kTagLength)) {
|
||||
return false;
|
||||
}
|
||||
const char* tag = Tag::Get();
|
||||
size_t i = 0;
|
||||
for (; i < Tag::kTagLength && buf[i] == tag[i]; ++i) {
|
||||
}
|
||||
return i == Tag::kTagLength;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization of the Tagger helper for types with no tag.
|
||||
template <typename _Ty>
|
||||
struct Tagger<_Ty, false> {
|
||||
static void Write(OArchive& /*_archive*/) {}
|
||||
static bool Validate(IArchive& /*_archive*/) { return true; }
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
#endif // OZZ_OZZ_BASE_IO_ARCHIVE_H_
|
||||
@@ -0,0 +1,220 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// 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. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
|
||||
#define OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
|
||||
|
||||
// Provides traits for customizing archive serialization properties: version,
|
||||
// tag... See archive.h for more details.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstddef>
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
|
||||
// Forward declaration of archive types.
|
||||
class OArchive;
|
||||
class IArchive;
|
||||
|
||||
// Default loading and saving external declaration.
|
||||
// Those template implementations aim to be specialized at compilation time by
|
||||
// non-member Load and save functions. For example the specialization of the
|
||||
// Save() function for a type Type is:
|
||||
// void Save(OArchive& _archive, const Extrusive* _test, size_t _count) {
|
||||
// }
|
||||
// The Load() function receives the version _version of type _Ty at the time the
|
||||
// archive was saved.
|
||||
// This uses polymorphism rather than template specialization to avoid
|
||||
// including the file that contains the template definition.
|
||||
//
|
||||
// This default function call member _Ty::Load/Save function.
|
||||
template <typename _Ty>
|
||||
struct Extern;
|
||||
|
||||
// Declares the current (compile time) version of _type.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// Syntax is: OZZ_IO_TYPE_VERSION(46, Foo).
|
||||
#define OZZ_IO_TYPE_VERSION(_version, _type) \
|
||||
static_assert(_version > 0, "Version number must be > 0"); \
|
||||
namespace internal { \
|
||||
template <> \
|
||||
struct Version<const _type> { \
|
||||
enum { kValue = _version }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Declares the current (compile time) version of a template _type.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// OZZ_IO_TYPE_VERSION_T1(46, typename _T1, Foo<_T1>).
|
||||
#define OZZ_IO_TYPE_VERSION_T1(_version, _arg0, ...) \
|
||||
static_assert(_version > 0, "Version number must be > 0"); \
|
||||
namespace internal { \
|
||||
template <_arg0> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = _version }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Declares the current (compile time) version of a template _type.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// OZZ_IO_TYPE_VERSION_T2(46, typename _T1, typename _T2, Foo<_T1, _T2>).
|
||||
#define OZZ_IO_TYPE_VERSION_T2(_version, _arg0, _arg1, ...) \
|
||||
static_assert(_version > 0, "Version number must be > 0"); \
|
||||
namespace internal { \
|
||||
template <_arg0, _arg1> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = _version }; \
|
||||
}; \
|
||||
\
|
||||
} // internal
|
||||
|
||||
// Declares the current (compile time) version of a template _type.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// OZZ_IO_TYPE_VERSION_T3(
|
||||
// 46, typename _T1, typename _T2, typename _T3, Foo<_T1, _T2, _T3>).
|
||||
#define OZZ_IO_TYPE_VERSION_T3(_version, _arg0, _arg1, _arg2, ...) \
|
||||
static_assert(_version > 0, "Version number must be > 0"); \
|
||||
namespace internal { \
|
||||
template <_arg0, _arg1, _arg2> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = _version }; \
|
||||
}; \
|
||||
\
|
||||
} // internal
|
||||
|
||||
// Declares the current (compile time) version of a template _type.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// OZZ_IO_TYPE_VERSION_T4(
|
||||
// 46, typename _T1, typename _T2, typename _T3, typename _T4,
|
||||
// Foo<_T1, _T2, _T3, _T4>).
|
||||
#define OZZ_IO_TYPE_VERSION_T4(_version, _arg0, _arg1, _arg2, _arg3, ...) \
|
||||
static_assert(_version > 0, "Version number must be > 0"); \
|
||||
namespace internal { \
|
||||
template <_arg0, _arg1, _arg2, _arg3> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = _version }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Declares that _type is not versionable. Its version number is 0.
|
||||
// Once a type has been declared not versionable, it cannot be changed without
|
||||
// braking versioning.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// Syntax is: OZZ_IO_TYPE_NOT_VERSIONABLE(Foo).
|
||||
#define OZZ_IO_TYPE_NOT_VERSIONABLE(_type) \
|
||||
namespace internal { \
|
||||
template <> \
|
||||
struct Version<const _type> { \
|
||||
enum { kValue = 0 }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Declares that a template _type is not versionable. Its version number is 0.
|
||||
// Once a type has been declared not versionable, it cannot be changed without
|
||||
// braking versioning.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// Syntax is:
|
||||
// OZZ_IO_TYPE_NOT_VERSIONABLE_T1(typename _T1, Foo<_T1>).
|
||||
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T1(_arg0, ...) \
|
||||
namespace internal { \
|
||||
template <_arg0> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = 0 }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Decline non-versionable template declaration to 2 template arguments.
|
||||
// Syntax is:
|
||||
// OZZ_IO_TYPE_NOT_VERSIONABLE_T2(typename _T1, typename _T2, Foo<_T1, _T2>).
|
||||
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T2(_arg0, _arg1, ...) \
|
||||
namespace internal { \
|
||||
template <_arg0, _arg1> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = 0 }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Decline non-versionable template declaration to 3 template arguments.
|
||||
// Syntax is:
|
||||
// OZZ_IO_TYPE_NOT_VERSIONABLE_T3(
|
||||
// typename _T1, typename _T2, typename _T3, Foo<_T1, _T2, _T3>).
|
||||
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T3(_arg0, _arg1, _arg2, ...) \
|
||||
namespace internal { \
|
||||
template <_arg0, _arg1, _arg2> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = 0 }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Decline non-versionable template declaration to 4 template arguments.
|
||||
// Syntax is:
|
||||
// OZZ_IO_TYPE_NOT_VERSIONABLE_T4(
|
||||
// typename _T1, typename _T2, typename _T3, typename _T4,
|
||||
// Foo<_T1, _T2, _T3, _T4>).
|
||||
#define OZZ_IO_TYPE_NOT_VERSIONABLE_T4(_arg0, _arg1, _arg2, _arg3, ...) \
|
||||
namespace internal { \
|
||||
template <_arg0, _arg1, _arg2, _arg3> \
|
||||
struct Version<const __VA_ARGS__> { \
|
||||
enum { kValue = 0 }; \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
// Declares the tag of a template _type.
|
||||
// A tag is a c-string that can be used to check the type (through its tag) of
|
||||
// the next object to be read from an archive. If no tag is defined, then no
|
||||
// check is performed.
|
||||
// This macro must be used inside namespace ozz::io.
|
||||
// OZZ_IO_TYPE_TAG("Foo", Foo).
|
||||
#define OZZ_IO_TYPE_TAG(_tag, _type) \
|
||||
namespace internal { \
|
||||
template <> \
|
||||
struct Tag<const _type> { \
|
||||
/* Length includes null terminated character to detect partial */ \
|
||||
/* tag mapping.*/ \
|
||||
enum { kTagLength = OZZ_ARRAY_SIZE(_tag) }; \
|
||||
static const char* Get() { return _tag; } \
|
||||
}; \
|
||||
} // internal
|
||||
|
||||
namespace internal {
|
||||
// Definition of version specializable template struct.
|
||||
// There's no default implementation in order to force user to define it, which
|
||||
// in turn forces those who want to serialize an object to include the file that
|
||||
// defines it's version. This helps with detecting issues at compile time.
|
||||
template <typename _Ty>
|
||||
struct Version;
|
||||
|
||||
// Defines default tag value, which is disabled.
|
||||
template <typename _Ty>
|
||||
struct Tag {
|
||||
enum { kTagLength = 0 };
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
#endif // OZZ_OZZ_BASE_IO_ARCHIVE_TRAITS_H_
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
//----------------------------------------------------------------------------//
|
||||
// //
|
||||
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
|
||||
// and distributed under the MIT License (MIT). //
|
||||
// //
|
||||
// Copyright (c) Guillaume Blanc //
|
||||
// //
|
||||
// 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. //
|
||||
// //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef OZZ_OZZ_BASE_IO_STREAM_H_
|
||||
#define OZZ_OZZ_BASE_IO_STREAM_H_
|
||||
|
||||
// Provides Stream interface used to read/write a memory buffer or a file with
|
||||
// Crt fread/fwrite/fseek/ftell like functions.
|
||||
|
||||
#include "ozz/base/platform.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace ozz {
|
||||
namespace io {
|
||||
|
||||
// Declares a stream access interface that conforms with CRT FILE API.
|
||||
// This interface should be used to remap io operations.
|
||||
class Stream {
|
||||
public:
|
||||
// Tests whether a file is opened.
|
||||
virtual bool opened() const = 0;
|
||||
|
||||
// Reads _size bytes of data to _buffer from the stream. _buffer must be big
|
||||
// enough to store _size bytes. The position indicator of the stream is
|
||||
// advanced by the total amount of bytes read.
|
||||
// Returns the number of bytes actually read, which may be less than _size.
|
||||
virtual size_t Read(void* _buffer, size_t _size) = 0;
|
||||
|
||||
// Writes _size bytes of data from _buffer to the stream. The position
|
||||
// indicator of the stream is advanced by the total number of bytes written.
|
||||
// Returns the number of bytes actually written, which may be less than _size.
|
||||
virtual size_t Write(const void* _buffer, size_t _size) = 0;
|
||||
|
||||
// Declares seeking origin enumeration.
|
||||
enum Origin {
|
||||
kCurrent, // Current position of the stream pointer.
|
||||
kEnd, // End of stream.
|
||||
kSet, // Beginning of stream.
|
||||
};
|
||||
// Sets the position indicator associated with the stream to a new position
|
||||
// defined by adding _offset to a reference position specified by _origin.
|
||||
// Returns a zero value if successful, otherwise returns a non-zero value.
|
||||
virtual int Seek(int _offset, Origin _origin) = 0;
|
||||
|
||||
// Returns the current value of the position indicator of the stream.
|
||||
// Returns -1 if an error occurs.
|
||||
virtual int Tell() const = 0;
|
||||
|
||||
// Returns the current size of the stream.
|
||||
virtual size_t Size() const = 0;
|
||||
|
||||
protected:
|
||||
Stream() {}
|
||||
|
||||
// Required virtual destructor.
|
||||
virtual ~Stream() {}
|
||||
|
||||
private:
|
||||
Stream(const Stream&);
|
||||
void operator=(const Stream&);
|
||||
};
|
||||
|
||||
// Implements Stream of type File.
|
||||
class File : public Stream {
|
||||
public:
|
||||
// Test if a file at path _filename exists.
|
||||
// Note that this function is costly. If you aim to open the file right after,
|
||||
// then open it and use File::opened() to test if it's actually existing.
|
||||
static bool Exist(const char* _filename);
|
||||
|
||||
// Open a file at path _filename with mode * _mode, in conformance with fopen
|
||||
// specifications.
|
||||
// Use opened() function to test opening result.
|
||||
File(const char* _filename, const char* _mode);
|
||||
|
||||
// Gives _file ownership to the FileStream, which will be in charge of closing
|
||||
// it. _file must be nullptr or a valid std::FILE pointer.
|
||||
explicit File(void* _file);
|
||||
|
||||
// Close the file if it is opened.
|
||||
virtual ~File();
|
||||
|
||||
// Close the file if it is opened.
|
||||
void Close();
|
||||
|
||||
// See Stream::opened for details.
|
||||
virtual bool opened() const;
|
||||
|
||||
// See Stream::Read for details.
|
||||
virtual size_t Read(void* _buffer, size_t _size);
|
||||
|
||||
// See Stream::Write for details.
|
||||
virtual size_t Write(const void* _buffer, size_t _size);
|
||||
|
||||
// See Stream::Seek for details.
|
||||
virtual int Seek(int _offset, Origin _origin);
|
||||
|
||||
// See Stream::Tell for details.
|
||||
virtual int Tell() const;
|
||||
|
||||
// See Stream::Tell for details.
|
||||
virtual size_t Size() const;
|
||||
|
||||
private:
|
||||
// The CRT file pointer.
|
||||
void* file_;
|
||||
};
|
||||
|
||||
// Implements an in-memory Stream. Allows to use a memory buffer as a Stream.
|
||||
// The opening mode is equivalent to fopen w+b (binary read/write).
|
||||
class MemoryStream : public Stream {
|
||||
public:
|
||||
// Construct an empty memory stream opened in w+b mode.
|
||||
MemoryStream();
|
||||
|
||||
// Closes the stream and deallocates memory buffer.
|
||||
virtual ~MemoryStream();
|
||||
|
||||
// See Stream::opened for details.
|
||||
virtual bool opened() const;
|
||||
|
||||
// See Stream::Read for details.
|
||||
virtual size_t Read(void* _buffer, size_t _size);
|
||||
|
||||
// See Stream::Write for details.
|
||||
virtual size_t Write(const void* _buffer, size_t _size);
|
||||
|
||||
// See Stream::Seek for details.
|
||||
virtual int Seek(int _offset, Origin _origin);
|
||||
|
||||
// See Stream::Tell for details.
|
||||
virtual int Tell() const;
|
||||
|
||||
// See Stream::Tell for details.
|
||||
virtual size_t Size() const;
|
||||
|
||||
private:
|
||||
// Resizes buffers size to _size bytes. If _size is less than the actual
|
||||
// buffer size, then it remains unchanged.
|
||||
// Returns true if the buffer can contains _size bytes.
|
||||
bool Resize(size_t _size);
|
||||
|
||||
// Size of the buffer increment.
|
||||
static const size_t kBufferSizeIncrement;
|
||||
|
||||
// Maximum stream size.
|
||||
static const size_t kMaxSize;
|
||||
|
||||
// Buffer of data.
|
||||
char* buffer_;
|
||||
|
||||
// The size of the buffer, which is greater or equal to the size of the data
|
||||
// it contains (end_).
|
||||
size_t alloc_size_;
|
||||
|
||||
// The effective size of the data in the buffer.
|
||||
int end_;
|
||||
|
||||
// The cursor position in the buffer of data.
|
||||
int tell_;
|
||||
};
|
||||
} // namespace io
|
||||
} // namespace ozz
|
||||
#endif // OZZ_OZZ_BASE_IO_STREAM_H_
|
||||
Reference in New Issue
Block a user