#ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #include namespace Nif { class NIFFile; class NIFStream { /// Input stream Ogre::DataStreamPtr inp; template value_t read_le () { uint8_t buffer [sizeof (value_t)]; if (inp->read (buffer, sizeof (buffer)) != sizeof (buffer)) throw std::runtime_error ("unexpected"); value_t Value = 0; value_t Shift = 0; for (size_t i = 0; i < sizeof (value_t); ++i) { Value |= value_t (buffer[i]) << Shift; Shift += 8; } return Value; } public: /* * This should be true for any processor/platform whose endianess, alignment * and packing rules would be compatible with x86 and not fault or degrade * with misaligned reads. This enables some pretty big savings when reading in * animations and meshes. */ #if defined (__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) static const bool FileCompatiblePlatform = true; #else static const bool FileCompatiblePlatform = false; #endif template struct handler; template struct le_handler; template friend struct le_handler; template struct conversion_handler; NIFFile * const file; NIFStream (NIFFile * file, Ogre::DataStreamPtr inp) : file (file), inp (inp) {} /************************************************* Parser functions ****************************************************/ void skip(size_t size) { return inp->skip (size); } size_t read (void * data, size_t size) { return inp->read (data, size); } template void uncheckedRead (T & Value) { typedef handler handler_t; handler_t::extract (*this, Value); } template T getValue () { T Value; getValue (Value); return Value; } template void getValue (T & Value) { typedef handler handler_t; if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) { BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (T), "unexpected structure size"); inp->read (&Value, handler_t::EncodedLength); } else { handler_t::extract (*this, Value); } } template void getArray (element_type * Array, size_t Size) { typedef handler handler_t; if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) { BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (element_type), "unexpected structure size"); inp->read (Array, handler_t::EncodedLength * Size); } else { for(size_t i = 0; i < Size; i++) handler_t::extract (*this, Array[i]); } } template void getStdVector (std::vector & Vector, size_t Size) { Vector.resize(Size); getArray (&Vector.front (), Vector.size ()); } template void getStdVector (std::vector & Vector) { length_type Length; getValue (Length); getStdVector (Vector, Length); } char getChar() { return getValue (); } signed int getInt() { return getValue (); } unsigned int getUInt() { return getValue (); } signed short getShort() { return getValue (); } unsigned short getUShort() { return getValue (); } //signed long getLong() { return getValue (); } //unsigned long getULong() { return getValue (); } float getFloat() { return getValue (); } Ogre::Vector2 getVector2() { return getValue (); } Ogre::Vector3 getVector3() { return getValue (); } Ogre::Vector4 getVector4() { return getValue (); } Ogre::Matrix3 getMatrix3() { return getValue (); } Ogre::Quaternion getQuaternion() { return getValue (); } Transformation getTrafo() { return getValue (); } void getShorts(std::vector &vec, size_t size) { return getStdVector (vec, size); } void getFloats(std::vector &vec, size_t size) { return getStdVector (vec, size); } void getVector2s(std::vector &vec, size_t size) { return getStdVector (vec, size); } void getVector3s(std::vector &vec, size_t size) { return getStdVector (vec, size); } void getVector4s(std::vector &vec, size_t size) { return getStdVector (vec, size); } void getQuaternions(std::vector &vec, size_t size) { return getStdVector (vec, size); } std::string getString(size_t length) { std::vector str (length+1, 0); if(read(&str[0], length) != length) throw std::runtime_error ("string length in NIF file does not match"); return &str[0]; } std::string getString() { size_t size = getValue (); return getString(size); } }; /* * generic type handlers */ template struct NIFStream::handler < type [Size] > { typedef handler inner_handler; static const bool FixedLength = inner_handler::FixedLength; static const size_t EncodedLength = inner_handler::EncodedLength * Size; static const bool FileCompatibleLayout = inner_handler::FileCompatibleLayout; static void extract (NIFStream & Stream, type (&Value) [Size]) { for (size_t i = 0; i < Size; ++i) inner_handler::extract (Stream, Value [i]); } }; template struct NIFStream::le_handler { static const bool FixedLength = true; static const size_t EncodedLength = sizeof (backing_type); static const bool FileCompatibleLayout = true; static void extract (NIFStream & Stream, presentation_type & Value) { BOOST_STATIC_ASSERT_MSG(sizeof (presentation_type) == sizeof (backing_type), "Invalid use of NIFile::le_handler template"); union { backing_type Backing; presentation_type Presentation; } u; u.Backing = Stream.read_le (); Value = u.Presentation; } }; template struct NIFStream::conversion_handler { typedef handler store_handler; static const bool FixedLength = store_handler::FixedLength; static const size_t EncodedLength = store_handler::EncodedLength; static const bool FileCompatibleLayout = false; static void extract (NIFStream & Stream, final_type & Value) { store_type StoreValue; store_handler::extract (Stream, StoreValue); Value = final_type (StoreValue); } }; template struct NIFStream::conversion_handler { typedef handler store_handler; static const bool FixedLength = store_handler::FixedLength; static const size_t EncodedLength = store_handler::EncodedLength; static const bool FileCompatibleLayout = store_handler::FileCompatibleLayout; static void extract (NIFStream & Stream, final_type & FinalValue) { store_handler::extract (Stream, reinterpret_cast (FinalValue)); } }; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::le_handler {}; template <> struct NIFStream::handler : NIFStream::conversion_handler {}; template <> struct NIFStream::handler : NIFStream::conversion_handler {}; template <> struct NIFStream::handler : NIFStream::conversion_handler {}; template <> struct NIFStream::handler : NIFStream::conversion_handler {}; template <> struct NIFStream::handler : NIFStream::conversion_handler {}; template <> struct NIFStream::handler { static const bool FixedLength = true; static const size_t EncodedLength = handler ::EncodedLength + handler ::EncodedLength + handler ::EncodedLength; static const bool FileCompatibleLayout = true; static void extract (NIFStream & stream, Transformation & value) { stream.uncheckedRead (value.pos); stream.uncheckedRead (value.rotation); stream.uncheckedRead (value.scale); } }; } #endif