mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-25 17:56:37 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			159 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OPENMW_ESM_COMMON_H
 | |
| #define OPENMW_ESM_COMMON_H
 | |
| 
 | |
| #include <string>
 | |
| #include <cstring>
 | |
| #include <vector>
 | |
| 
 | |
| #include <stdint.h>
 | |
| 
 | |
| namespace ESM
 | |
| {
 | |
| enum Version
 | |
|   {
 | |
|     VER_12 = 0x3f99999a,
 | |
|     VER_13 = 0x3fa66666
 | |
|   };
 | |
| 
 | |
| 
 | |
| // CRTP for FIXED_STRING class, a structure used for holding fixed-length strings
 | |
| template< template<size_t> class DERIVED, size_t SIZE>
 | |
| class FIXED_STRING_BASE
 | |
| {
 | |
|     /* The following methods must be implemented in derived classes:
 | |
|      *   char const* ro_data() const; // return pointer to ro buffer
 | |
|      *   char*       rw_data();       // return pointer to rw buffer
 | |
|      */
 | |
| public:
 | |
|     enum { size = SIZE };
 | |
| 
 | |
|     template<size_t OTHER_SIZE>
 | |
|     bool operator==(char const (&str)[OTHER_SIZE]) const
 | |
|     {
 | |
|         size_t other_len = strnlen(str, OTHER_SIZE);
 | |
|         if (other_len != this->length())
 | |
|             return false;
 | |
|         return std::strncmp(self()->ro_data(), str, size) == 0;
 | |
|     }
 | |
| 
 | |
|     //this operator will not be used for char[N], only for char*
 | |
|     template<typename T, typename = typename std::enable_if<std::is_same<T, char>::value>::type>
 | |
|     bool operator==(const T* const& str) const
 | |
|     {
 | |
|         char const* const data = self()->ro_data();
 | |
|         for(size_t i = 0; i < size; ++i)
 | |
|         {
 | |
|             if(data[i] != str[i]) return false;
 | |
|             else if(data[i] == '\0') return true;
 | |
|         }
 | |
|         return str[size] == '\0';
 | |
|     }
 | |
|     bool operator!=(const char* const str) const { return !( (*this) == str ); }
 | |
| 
 | |
|     bool operator==(const std::string& str) const
 | |
|     {
 | |
|         return (*this) == str.c_str();
 | |
|     }
 | |
|     bool operator!=(const std::string& str) const { return !( (*this) == str ); }
 | |
| 
 | |
|     static size_t data_size() { return size; }
 | |
|     size_t length() const { return strnlen(self()->ro_data(), size); }
 | |
|     std::string toString() const { return std::string(self()->ro_data(), this->length()); }
 | |
| 
 | |
|     void assign(const std::string& value)
 | |
|     {
 | |
|         std::strncpy(self()->rw_data(), value.c_str(), size-1);
 | |
|         self()->rw_data()[size-1] = '\0';
 | |
|     }
 | |
| 
 | |
|     void clear() { this->assign(""); }
 | |
| private:
 | |
|     DERIVED<size> const* self() const
 | |
|     {
 | |
|         return static_cast<DERIVED<size> const*>(this);
 | |
|     }
 | |
| 
 | |
|     // write the non-const version in terms of the const version
 | |
|     // Effective C++ 3rd ed., Item 3 (p. 24-25)
 | |
|     DERIVED<size>* self()
 | |
|     {
 | |
|         return const_cast<DERIVED<size>*>(static_cast<FIXED_STRING_BASE const*>(this)->self());
 | |
|     }
 | |
| };
 | |
| 
 | |
| // Generic implementation
 | |
| template <size_t SIZE>
 | |
| struct FIXED_STRING : public FIXED_STRING_BASE<FIXED_STRING, SIZE>
 | |
| {
 | |
|     char data[SIZE];
 | |
| 
 | |
|     char const* ro_data() const { return data; }
 | |
|     char*       rw_data() { return data; }
 | |
| };
 | |
| 
 | |
| // In the case of SIZE=4, it can be more efficient to match the string
 | |
| // as a 32 bit number, therefore the struct is implemented as a union with an int.
 | |
| template <>
 | |
| struct FIXED_STRING<4> : public FIXED_STRING_BASE<FIXED_STRING, 4>
 | |
| {
 | |
|     union {
 | |
|         char data[4];
 | |
|         uint32_t intval;
 | |
|     };
 | |
| 
 | |
|     using FIXED_STRING_BASE::operator==;
 | |
|     using FIXED_STRING_BASE::operator!=;
 | |
| 
 | |
|     bool operator==(uint32_t v) const { return v == intval; }
 | |
|     bool operator!=(uint32_t v) const { return v != intval; }
 | |
| 
 | |
|     void assign(const std::string& value)
 | |
|     {
 | |
|         intval = 0;
 | |
|         size_t length = value.size();
 | |
|         if (length == 0) return;
 | |
|         data[0] = value[0];
 | |
|         if (length == 1) return;
 | |
|         data[1] = value[1];
 | |
|         if (length == 2) return;
 | |
|         data[2] = value[2];
 | |
|         if (length == 3) return;
 | |
|         data[3] = value[3];
 | |
|     }
 | |
| 
 | |
|     char const* ro_data() const { return data; }
 | |
|     char*       rw_data() { return data; }
 | |
| };
 | |
| 
 | |
| typedef FIXED_STRING<4> NAME;
 | |
| typedef FIXED_STRING<32> NAME32;
 | |
| typedef FIXED_STRING<64> NAME64;
 | |
| 
 | |
| /* This struct defines a file 'context' which can be saved and later
 | |
|    restored by an ESMReader instance. It will save the position within
 | |
|    a file, and when restored will let you read from that position as
 | |
|    if you never left it.
 | |
|  */
 | |
| struct ESM_Context
 | |
| {
 | |
|   std::string filename;
 | |
|   uint32_t leftRec, leftSub;
 | |
|   size_t leftFile;
 | |
|   NAME recName, subName;
 | |
|   // When working with multiple esX files, we will generate lists of all files that
 | |
|   //  actually contribute to a specific cell. Therefore, we need to store the index
 | |
|   //  of the file belonging to this contest. See CellStore::(list/load)refs for details.
 | |
|   int index;
 | |
|   std::vector<int> parentFileIndices;
 | |
| 
 | |
|   // True if subName has been read but not used.
 | |
|   bool subCached;
 | |
| 
 | |
|   // File position. Only used for stored contexts, not regularly
 | |
|   // updated within the reader itself.
 | |
|   size_t filePos;
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif
 |