#ifndef OPENMW_ESM_COMMON_H #define OPENMW_ESM_COMMON_H #include #include #include #include #include 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 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 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::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 const* self() const { return static_cast const*>(this); } // write the non-const version in terms of the const version // Effective C++ 3rd ed., Item 3 (p. 24-25) DERIVED* self() { return const_cast*>(static_cast(this)->self()); } }; // Generic implementation template struct FIXED_STRING : public FIXED_STRING_BASE { 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 { 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; std::memcpy(data, value.data(), std::min(value.size(), sizeof(data))); } 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 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