From 5f18c43dd6f134fae0e1b835761c287f86630792 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Mon, 10 Feb 2020 14:05:04 +1100 Subject: [PATCH] loads of datreader cleanup/consistency fixes --- deps/datReader/Dat.cpp | 509 +++++++++++++------------ deps/datReader/Dat.h | 45 +-- deps/datReader/DatCat.cpp | 6 +- deps/datReader/DatCat.h | 86 +++-- deps/datReader/Exd.cpp | 737 ++++++++++++++++++------------------ deps/datReader/Exd.h | 56 +-- deps/datReader/ExdCat.cpp | 113 +++--- deps/datReader/ExdData.cpp | 126 +++--- deps/datReader/Exh.cpp | 74 ++-- deps/datReader/Exh.h | 190 ++++++---- deps/datReader/File.cpp | 59 ++- deps/datReader/File.h | 62 ++- deps/datReader/GameData.cpp | 453 +++++++++++----------- deps/datReader/GameData.h | 114 +++--- deps/datReader/Index.cpp | 228 ++++++----- deps/datReader/Index.h | 72 ++-- deps/datReader/SqPack.cpp | 12 +- deps/datReader/SqPack.h | 78 ++-- deps/datReader/bparse.h | 152 ++++---- deps/datReader/conv.cpp | 8 +- deps/datReader/conv.h | 8 +- deps/datReader/crc32.cpp | 169 ++++----- deps/datReader/crc32.h | 11 +- deps/datReader/stream.cpp | 8 +- deps/datReader/stream.h | 24 +- deps/datReader/zlib.cpp | 48 +-- deps/datReader/zlib.h | 13 +- 27 files changed, 1727 insertions(+), 1734 deletions(-) diff --git a/deps/datReader/Dat.cpp b/deps/datReader/Dat.cpp index 5e12d5d1..943e12fd 100644 --- a/deps/datReader/Dat.cpp +++ b/deps/datReader/Dat.cpp @@ -4,308 +4,319 @@ #include "File.h" -namespace -{ - const uint32_t model_section_count = 0xB; +namespace { + const uint32_t model_section_count = 0xB; } -namespace xiv +namespace xiv::dat { -namespace dat -{ - struct DatFileHeader - { - uint32_t size; - FileType entry_type; - uint32_t total_uncompressed_size; - uint32_t unknown[0x2]; - }; + struct DatFileHeader + { + uint32_t size; + FileType entry_type; + uint32_t total_uncompressed_size; + uint32_t unknown[0x2]; + }; - struct DatBlockRecord - { - uint32_t offset; - uint32_t size; - uint32_t unknown[0x4]; - SqPackBlockHash block_hash; - }; + struct DatBlockRecord + { + uint32_t offset; + uint32_t size; + uint32_t unknown[0x4]; + SqPackBlockHash block_hash; + }; - struct DatBlockHeader - { - uint32_t size; - uint32_t unknown1; - uint32_t compressed_size; - uint32_t uncompressed_size; - }; + struct DatBlockHeader + { + uint32_t size; + uint32_t unknown1; + uint32_t compressed_size; + uint32_t uncompressed_size; + }; - struct DatStdFileBlockInfos - { - uint32_t offset; - uint16_t size; - uint16_t uncompressed_size; - }; + struct DatStdFileBlockInfos + { + uint32_t offset; + uint16_t size; + uint16_t uncompressed_size; + }; - struct DatMdlFileBlockInfos - { - uint32_t unknown1; - uint32_t uncompressed_sizes[::model_section_count]; - uint32_t compressed_sizes[::model_section_count]; - uint32_t offsets[::model_section_count]; - uint16_t block_ids[::model_section_count]; - uint16_t block_counts[::model_section_count]; - uint32_t unknown2[0x2]; - }; + struct DatMdlFileBlockInfos + { + uint32_t unknown1; + uint32_t uncompressed_sizes[::model_section_count]; + uint32_t compressed_sizes[::model_section_count]; + uint32_t offsets[::model_section_count]; + uint16_t block_ids[::model_section_count]; + uint16_t block_counts[::model_section_count]; + uint32_t unknown2[0x2]; + }; - struct DatTexFileBlockInfos - { - uint32_t offset; - uint32_t size; - uint32_t uncompressed_size; - uint32_t block_id; - uint32_t block_count; - }; - + struct DatTexFileBlockInfos + { + uint32_t offset; + uint32_t size; + uint32_t uncompressed_size; + uint32_t block_id; + uint32_t block_count; + }; } -} -namespace xiv +namespace xiv::utils::bparse { -namespace utils -{ -namespace bparse -{ - template <> - inline void reorder(xiv::dat::DatFileHeader& i_struct) - { - xiv::utils::bparse::reorder(i_struct.size); - xiv::utils::bparse::reorder(i_struct.entry_type); - xiv::utils::bparse::reorder(i_struct.total_uncompressed_size); - for (int32_t i = 0; i < 0x2; ++i) { xiv::utils::bparse::reorder(i_struct.unknown[i]); } - } + template<> + inline void reorder< xiv::dat::DatFileHeader >( xiv::dat::DatFileHeader& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.size ); + xiv::utils::bparse::reorder( i_struct.entry_type ); + xiv::utils::bparse::reorder( i_struct.total_uncompressed_size ); + for( int32_t i = 0; i < 0x2; ++i ) + { + xiv::utils::bparse::reorder( i_struct.unknown[ i ] ); + } + } - template <> - inline void reorder(xiv::dat::DatBlockRecord& i_struct) - { - xiv::utils::bparse::reorder(i_struct.offset); - xiv::utils::bparse::reorder(i_struct.size); - for (int32_t i = 0; i < 0x4; ++i) { xiv::utils::bparse::reorder(i_struct.unknown[i]); } - xiv::utils::bparse::reorder(i_struct.block_hash); - } + template<> + inline void reorder< xiv::dat::DatBlockRecord >( xiv::dat::DatBlockRecord& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.size ); + for( int32_t i = 0; i < 0x4; ++i ) + { + xiv::utils::bparse::reorder( i_struct.unknown[ i ] ); + } + xiv::utils::bparse::reorder( i_struct.block_hash ); + } - template <> - inline void reorder(xiv::dat::DatBlockHeader& i_struct) - { - xiv::utils::bparse::reorder(i_struct.size); - xiv::utils::bparse::reorder(i_struct.unknown1); - xiv::utils::bparse::reorder(i_struct.compressed_size); - xiv::utils::bparse::reorder(i_struct.uncompressed_size); - } + template<> + inline void reorder< xiv::dat::DatBlockHeader >( xiv::dat::DatBlockHeader& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.size ); + xiv::utils::bparse::reorder( i_struct.unknown1 ); + xiv::utils::bparse::reorder( i_struct.compressed_size ); + xiv::utils::bparse::reorder( i_struct.uncompressed_size ); + } - template <> - inline void reorder(xiv::dat::DatStdFileBlockInfos& i_struct) - { - xiv::utils::bparse::reorder(i_struct.offset); - xiv::utils::bparse::reorder(i_struct.size); - xiv::utils::bparse::reorder(i_struct.uncompressed_size); - } + template<> + inline void reorder< xiv::dat::DatStdFileBlockInfos >( xiv::dat::DatStdFileBlockInfos& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.size ); + xiv::utils::bparse::reorder( i_struct.uncompressed_size ); + } - template <> - inline void reorder(xiv::dat::DatMdlFileBlockInfos& i_struct) - { - xiv::utils::bparse::reorder(i_struct.unknown1); - for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.uncompressed_sizes[i]); } - for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.compressed_sizes[i]); } - for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.offsets[i]); } - for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.block_ids[i]); } - for (auto i = 0; i < ::model_section_count; ++i) { xiv::utils::bparse::reorder(i_struct.block_counts[i]); } - for (auto i = 0; i < 0x2; ++i) { xiv::utils::bparse::reorder(i_struct.unknown2[i]); } - } + template<> + inline void reorder< xiv::dat::DatMdlFileBlockInfos >( xiv::dat::DatMdlFileBlockInfos& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.unknown1 ); + for( auto i = 0; i < ::model_section_count; ++i ) + { + xiv::utils::bparse::reorder( i_struct.uncompressed_sizes[ i ] ); + } + for( auto i = 0; i < ::model_section_count; ++i ) + { + xiv::utils::bparse::reorder( i_struct.compressed_sizes[ i ] ); + } + for( auto i = 0; i < ::model_section_count; ++i ) + { + xiv::utils::bparse::reorder( i_struct.offsets[ i ] ); + } + for( auto i = 0; i < ::model_section_count; ++i ) + { + xiv::utils::bparse::reorder( i_struct.block_ids[ i ] ); + } + for( auto i = 0; i < ::model_section_count; ++i ) + { + xiv::utils::bparse::reorder( i_struct.block_counts[ i ] ); + } + for( auto i = 0; i < 0x2; ++i ) + { + xiv::utils::bparse::reorder( i_struct.unknown2[ i ] ); + } + } - template <> - inline void reorder(xiv::dat::DatTexFileBlockInfos& i_struct) - { - xiv::utils::bparse::reorder(i_struct.offset); - xiv::utils::bparse::reorder(i_struct.size); - xiv::utils::bparse::reorder(i_struct.uncompressed_size); - xiv::utils::bparse::reorder(i_struct.block_id); - xiv::utils::bparse::reorder(i_struct.block_count); - } + template<> + inline void reorder< xiv::dat::DatTexFileBlockInfos >( xiv::dat::DatTexFileBlockInfos& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.size ); + xiv::utils::bparse::reorder( i_struct.uncompressed_size ); + xiv::utils::bparse::reorder( i_struct.block_id ); + xiv::utils::bparse::reorder( i_struct.block_count ); + } } -} -}; using xiv::utils::bparse::extract; -namespace xiv -{ -namespace dat +namespace xiv::dat { -Dat::Dat( const std::filesystem::path& i_path, uint32_t i_nb ) : - SqPack( i_path ), - m_num( i_nb ) -{ - auto block_record = extract(m_handle); - block_record.offset *= 0x80; - isBlockValid(block_record.offset, block_record.size, block_record.block_hash); -} + Dat::Dat( const std::filesystem::path& i_path, uint32_t i_nb ) : + SqPack( i_path ), + m_num( i_nb ) + { + auto block_record = extract< DatBlockRecord >( m_handle ); + block_record.offset *= 0x80; + isBlockValid( block_record.offset, block_record.size, block_record.block_hash ); + } -Dat::~Dat() -{ -} + Dat::~Dat() + { + } -std::unique_ptr Dat::getFile( uint32_t i_offset ) -{ - std::unique_ptr outputFile(new File()); - { + std::unique_ptr< File > Dat::getFile( uint32_t i_offset ) + { + std::unique_ptr< File > outputFile( new File() ); + { // Lock in this scope - std::lock_guard lock(m_fileMutex); + std::lock_guard< std::mutex > lock( m_fileMutex ); // Seek to the start of the header of the file record and extract it - m_handle.seekg(i_offset); - auto file_header = extract(m_handle); + m_handle.seekg( i_offset ); + auto file_header = extract< DatFileHeader >( m_handle ); - switch (file_header.entry_type) + switch( file_header.entry_type ) { - case FileType::empty: - throw std::runtime_error("File is empty"); + case FileType::empty: + throw std::runtime_error( "File is empty" ); - case FileType::standard: - { - outputFile->_type = FileType::standard; + case FileType::standard: + { + outputFile->_type = FileType::standard; - uint32_t number_of_blocks = extract(m_handle, "number_of_blocks"); + uint32_t number_of_blocks = extract< uint32_t >( m_handle, "number_of_blocks" ); - // Just extract offset infos for the blocks to extract - std::vector std_file_block_infos; - extract( m_handle, number_of_blocks, std_file_block_infos ); + // Just extract offset infos for the blocks to extract + std::vector< DatStdFileBlockInfos > std_file_block_infos; + extract< DatStdFileBlockInfos >( m_handle, number_of_blocks, std_file_block_infos ); - // Pre allocate data vector for the whole file - outputFile->_data_sections.resize(1); - auto& data_section = outputFile->_data_sections.front(); + // Pre allocate data vector for the whole file + outputFile->_data_sections.resize( 1 ); + auto& data_section = outputFile->_data_sections.front(); - data_section.reserve(file_header.total_uncompressed_size); - // Extract each block - for (auto& file_block_info : std_file_block_infos) + data_section.reserve( file_header.total_uncompressed_size ); + // Extract each block + for( auto& file_block_info : std_file_block_infos ) + { + extractBlock( i_offset + file_header.size + file_block_info.offset, data_section ); + } + } + break; + + case FileType::model: + { + outputFile->_type = FileType::model; + + DatMdlFileBlockInfos mdlBlockInfo = extract< DatMdlFileBlockInfos >( m_handle ); + + // Getting the block number and read their sizes + const uint32_t block_count = mdlBlockInfo.block_ids[ ::model_section_count - 1 ] + + mdlBlockInfo.block_counts[ ::model_section_count - 1 ]; + std::vector< uint16_t > block_sizes; + extract< uint16_t >( m_handle, "block_size", block_count, block_sizes ); + + // Preallocate sufficient space + outputFile->_data_sections.resize( ::model_section_count ); + + for( uint32_t i = 0; i < ::model_section_count; ++i ) + { + // Preallocating for section + auto& data_section = outputFile->_data_sections[ i ]; + data_section.reserve( mdlBlockInfo.uncompressed_sizes[ i ] ); + + uint32_t current_offset = i_offset + file_header.size + mdlBlockInfo.offsets[ i ]; + for( uint32_t j = 0; j < mdlBlockInfo.block_counts[ i ]; ++j ) { - extractBlock(i_offset + file_header.size + file_block_info.offset, data_section); + extractBlock( current_offset, data_section ); + current_offset += block_sizes[ mdlBlockInfo.block_ids[ i ] + j ]; } - } - break; + } + } + break; - case FileType::model: - { - outputFile->_type = FileType::model; + case FileType::texture: + { + outputFile->_type = FileType::texture; - DatMdlFileBlockInfos mdlBlockInfo = extract(m_handle); + // Extracts mipmap entries and the block sizes + uint32_t sectionCount = extract< uint32_t >( m_handle, "sections_count" ); - // Getting the block number and read their sizes - const uint32_t block_count = mdlBlockInfo.block_ids[::model_section_count - 1] + - mdlBlockInfo.block_counts[::model_section_count - 1]; - std::vector block_sizes; - extract(m_handle, "block_size", block_count, block_sizes); + std::vector< DatTexFileBlockInfos > texBlockInfo; + extract< DatTexFileBlockInfos >( m_handle, sectionCount, texBlockInfo ); - // Preallocate sufficient space - outputFile->_data_sections.resize(::model_section_count); + // Extracting block sizes + uint32_t block_count = texBlockInfo.back().block_id + texBlockInfo.back().block_count; + std::vector< uint16_t > block_sizes; + extract< uint16_t >( m_handle, "block_size", block_count, block_sizes ); - for (uint32_t i = 0; i < ::model_section_count; ++i) + outputFile->_data_sections.resize( sectionCount + 1 ); + + // Extracting header in section 0 + const uint32_t header_size = texBlockInfo.front().offset; + auto& header_section = outputFile->_data_sections[ 0 ]; + header_section.resize( header_size ); + + m_handle.seekg( i_offset + file_header.size ); + m_handle.read( header_section.data(), header_size ); + + // Extracting other sections + for( uint32_t i = 0; i < sectionCount; ++i ) + { + auto& data_section = outputFile->_data_sections[ i + 1 ]; + auto& section_infos = texBlockInfo[ i ]; + data_section.reserve( section_infos.uncompressed_size ); + + uint32_t current_offset = i_offset + file_header.size + section_infos.offset; + for( uint32_t j = 0; j < section_infos.block_count; ++j ) { - // Preallocating for section - auto& data_section = outputFile->_data_sections[i]; - data_section.reserve(mdlBlockInfo.uncompressed_sizes[i]); - - uint32_t current_offset = i_offset + file_header.size + mdlBlockInfo.offsets[i]; - for (uint32_t j = 0; j < mdlBlockInfo.block_counts[i]; ++j) - { - extractBlock(current_offset, data_section); - current_offset += block_sizes[mdlBlockInfo.block_ids[i] + j]; - } + extractBlock( current_offset, data_section ); + current_offset += block_sizes[ section_infos.block_id + j ]; } - } - break; + } + } + break; - case FileType::texture: - { - outputFile->_type = FileType::texture; - - // Extracts mipmap entries and the block sizes - uint32_t sectionCount = extract(m_handle, "sections_count"); - - std::vector texBlockInfo; - extract(m_handle, sectionCount, texBlockInfo); - - // Extracting block sizes - uint32_t block_count = texBlockInfo.back().block_id + texBlockInfo.back().block_count; - std::vector block_sizes; - extract(m_handle, "block_size", block_count, block_sizes); - - outputFile->_data_sections.resize(sectionCount + 1); - - // Extracting header in section 0 - const uint32_t header_size = texBlockInfo.front().offset; - auto& header_section = outputFile->_data_sections[0]; - header_section.resize(header_size); - - m_handle.seekg(i_offset + file_header.size); - m_handle.read(header_section.data(), header_size); - - // Extracting other sections - for (uint32_t i = 0; i < sectionCount; ++i) - { - auto& data_section = outputFile->_data_sections[i + 1]; - auto& section_infos = texBlockInfo[i]; - data_section.reserve(section_infos.uncompressed_size); - - uint32_t current_offset = i_offset + file_header.size + section_infos.offset; - for (uint32_t j = 0; j < section_infos.block_count; ++j) - { - extractBlock(current_offset, data_section); - current_offset += block_sizes[section_infos.block_id + j]; - } - } - } - break; - - default: - throw std::runtime_error("Invalid entry_type: " + std::to_string(static_cast(file_header.entry_type))); + default: + throw std::runtime_error( + "Invalid entry_type: " + std::to_string( static_cast(file_header.entry_type) ) ); } - } + } - return outputFile; -} + return outputFile; + } -void Dat::extractBlock( uint32_t i_offset, std::vector& o_data ) -{ - m_handle.seekg(i_offset); + void Dat::extractBlock( uint32_t i_offset, std::vector< char >& o_data ) + { + m_handle.seekg( i_offset ); - DatBlockHeader block_header = extract(m_handle); + DatBlockHeader block_header = extract< DatBlockHeader >( m_handle ); - // Resizing the vector to write directly into it - const uint32_t data_size = o_data.size(); - o_data.resize(data_size + block_header.uncompressed_size); + // Resizing the vector to write directly into it + const uint32_t data_size = o_data.size(); + o_data.resize( data_size + block_header.uncompressed_size ); - // 32000 in compressed_size means it is not compressed so take uncompressed_size - if (block_header.compressed_size == 32000) - { - m_handle.read(o_data.data() + data_size, block_header.uncompressed_size); - } - else - { + // 32000 in compressed_size means it is not compressed so take uncompressed_size + if( block_header.compressed_size == 32000 ) + { + m_handle.read( o_data.data() + data_size, block_header.uncompressed_size ); + } + else + { // If it is compressed use zlib // Read the data to be decompressed - std::vector temp_buffer(block_header.compressed_size); - m_handle.read(temp_buffer.data(), block_header.compressed_size); + std::vector< char > temp_buffer( block_header.compressed_size ); + m_handle.read( temp_buffer.data(), block_header.compressed_size ); - utils::zlib::no_header_decompress(reinterpret_cast(temp_buffer.data()), - temp_buffer.size(), - reinterpret_cast(o_data.data() + data_size), - block_header.uncompressed_size); - } -} + utils::zlib::no_header_decompress( reinterpret_cast(temp_buffer.data()), + temp_buffer.size(), + reinterpret_cast(o_data.data() + data_size), + block_header.uncompressed_size ); + } + } -uint32_t Dat::getNum() const -{ - return m_num; -} + uint32_t Dat::getNum() const + { + return m_num; + } } -} diff --git a/deps/datReader/Dat.h b/deps/datReader/Dat.h index 10693b3c..f1827782 100644 --- a/deps/datReader/Dat.h +++ b/deps/datReader/Dat.h @@ -7,39 +7,36 @@ #include -namespace xiv -{ -namespace dat +namespace xiv::dat { -class File; + class File; -class Dat : public SqPack -{ -public: - // Full path to the dat file - Dat( const std::filesystem::path& i_path, uint32_t i_nb ); - virtual ~Dat(); + class Dat : public SqPack + { + public: + // Full path to the dat file + Dat( const std::filesystem::path& i_path, uint32_t i_nb ); + virtual ~Dat(); - // Retrieves a file given the offset in the dat file - std::unique_ptr getFile( uint32_t i_offset ); + // Retrieves a file given the offset in the dat file + std::unique_ptr getFile( uint32_t i_offset ); - // Appends to the vector the data of this block, it is assumed to be preallocated - // Is it also assumed that the m_fileMutex is currently locked by this thread before the call - void extractBlock( uint32_t i_offset, std::vector& o_data ); + // Appends to the vector the data of this block, it is assumed to be preallocated + // Is it also assumed that the m_fileMutex is currently locked by this thread before the call + void extractBlock( uint32_t i_offset, std::vector& o_data ); - // Returns the dat number - uint32_t getNum() const; + // Returns the dat number + uint32_t getNum() const; -protected: - // File reading mutex to have only one thread reading the file at a time - std::mutex m_fileMutex; + protected: + // File reading mutex to have only one thread reading the file at a time + std::mutex m_fileMutex; - // Dat nb - uint32_t m_num; -}; + // Dat nb + uint32_t m_num; + }; -} } #endif // XIV_DAT_DAT_H diff --git a/deps/datReader/DatCat.cpp b/deps/datReader/DatCat.cpp index 8bd8e79e..ccf3d6a0 100644 --- a/deps/datReader/DatCat.cpp +++ b/deps/datReader/DatCat.cpp @@ -26,7 +26,7 @@ Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::str // For all dat files linked to this index, create it: XX0000.win32.datX for( uint32_t i = 0; i < getIndex().getDatCount(); ++i ) { - m_dats.emplace_back( std::unique_ptr( new Dat( basePath / "ffxiv" / ( prefix + ".dat" + std::to_string( i ) ), i ) ) ); + m_dats.emplace_back( std::make_unique< Dat >(basePath / "ffxiv" / ( prefix + ".dat" + std::to_string( i ) ), i ) ); } } @@ -36,12 +36,12 @@ Cat::Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::str m_chunk( chunk ) { // Creates the index: XX0000.win32.index - m_index = std::unique_ptr( new Index( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "index" ) ) ); + m_index = std::make_unique< Index >( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "index" ) ); // For all dat files linked to this index, create it: XX0000.win32.datX for( uint32_t i = 0; i < getIndex().getDatCount(); ++i ) { - m_dats.emplace_back( std::unique_ptr( new Dat( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "dat" + std::to_string( i ) ), i ) ) ); + m_dats.emplace_back( std::make_unique< Dat >( basePath / GameData::buildDatStr( "ex" + std::to_string( exNum ), catNum, exNum, chunk, "win32", "dat" + std::to_string( i ) ), i ) ); } } diff --git a/deps/datReader/DatCat.h b/deps/datReader/DatCat.h index 07878589..43d842a1 100644 --- a/deps/datReader/DatCat.h +++ b/deps/datReader/DatCat.h @@ -5,60 +5,64 @@ #include #include -namespace xiv { -namespace dat { - -class Index; -class Dat; -class File; - -// A category represents an .index and its associated .datX -class Cat +namespace xiv::dat { -public: - // basePath: Path to the folder containingthe datfiles - // catNum: The number of the category - // name: The name of the category, empty if not known - Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name ); - // basePath: Path to the folder containingthe datfiles - // catNum: The number of the category - // name: The name of the category, empty if not known - // exNum: The number of the expansion to load from - // chunk: The chunk to load from - Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, uint32_t chunk ); - ~Cat(); + class Index; - // Returns .index of the category - const Index& getIndex() const; + class Dat; - // Retrieve a file from the category given its hashes - std::unique_ptr getFile( uint32_t dir_hash, uint32_t filename_hash ) const; + class File; + + // A category represents an .index and its associated .datX + class Cat + { + public: + // basePath: Path to the folder containingthe datfiles + // catNum: The number of the category + // name: The name of the category, empty if not known + Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name ); + + // basePath: Path to the folder containingthe datfiles + // catNum: The number of the category + // name: The name of the category, empty if not known + // exNum: The number of the expansion to load from + // chunk: The chunk to load from + Cat( const std::filesystem::path& basePath, uint32_t catNum, const std::string& name, uint32_t exNum, + uint32_t chunk ); + + ~Cat(); + + // Returns .index of the category + const Index& getIndex() const; + + // Retrieve a file from the category given its hashes + std::unique_ptr< File > getFile( uint32_t dir_hash, uint32_t filename_hash ) const; - bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const; - bool doesDirExist( uint32_t dir_hash ) const; + bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const; + + bool doesDirExist( uint32_t dir_hash ) const; - // Returns thename of the category - const std::string& getName() const; + // Returns thename of the category + const std::string& getName() const; - // Returns the number of the category - uint32_t getCatNum() const; + // Returns the number of the category + uint32_t getCatNum() const; -protected: - const std::string m_name; - const uint32_t m_catNum; - const uint32_t m_chunk; + protected: + const std::string m_name; + const uint32_t m_catNum; + const uint32_t m_chunk; - // The .index - std::unique_ptr m_index; + // The .index + std::unique_ptr< Index > m_index; - // The .datXs such as dat nb X => m_dats[X] - std::vector> m_dats; -}; + // The .datXs such as dat nb X => m_dats[X] + std::vector< std::unique_ptr< Dat>> m_dats; + }; -} } #endif // XIV_DAT_CAT_H diff --git a/deps/datReader/Exd.cpp b/deps/datReader/Exd.cpp index e82fcc96..79de150b 100644 --- a/deps/datReader/Exd.cpp +++ b/deps/datReader/Exd.cpp @@ -8,373 +8,378 @@ using xiv::utils::bparse::extract; -namespace xiv +namespace xiv::exd { - namespace exd - { + struct ExdHeader + { + char magic[0x4]; + uint16_t unknown; + uint16_t unknown2; + uint32_t index_size; + }; + + struct ExdRecordIndex + { + uint32_t id; + uint32_t offset; + }; +} + +namespace xiv::utils::bparse { +template<> + inline void reorder< xiv::exd::ExdHeader >( xiv::exd::ExdHeader& i_struct ) + { + for( int32_t i = 0; i < 0x4; ++i ) + { + xiv::utils::bparse::reorder( i_struct.magic[ i ] ); + } + i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); + xiv::utils::bparse::reorder( i_struct.unknown ); + i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 ); + xiv::utils::bparse::reorder( i_struct.unknown2 ); + i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size ); + xiv::utils::bparse::reorder( i_struct.index_size ); + } + + template<> + inline void reorder< xiv::exd::ExdRecordIndex >( xiv::exd::ExdRecordIndex& i_struct ) + { + i_struct.id = xiv::utils::bparse::byteswap( i_struct.id ); + xiv::utils::bparse::reorder( i_struct.id ); + i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.offset ); + } +}; + +namespace xiv::exd +{ + Exd::Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files ) + { + _exh = i_exh; + _files = i_files; + + + // Iterates over all the files + const uint32_t member_count = _exh->get_members().size(); + for( auto& file_ptr : _files ) + { + // Get a stream + std::vector< char > dataCpy = file_ptr->get_data_sections().front(); + std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); + + // Extract the header and skip to the record indices + auto exd_header = extract< ExdHeader >( iss ); + iss.seekg( 0x20 ); + + // Preallocate and extract the record_indices + const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex ); + std::vector< ExdRecordIndex > record_indices; + record_indices.reserve( record_count ); + for( uint32_t i = 0; i < record_count; ++i ) + { + auto recordIndex = extract< ExdRecordIndex >( iss ); + _idCache[ recordIndex.id ] = ExdCacheEntry{ file_ptr, recordIndex.offset }; + } + } + } + + Exd::~Exd() + { + } + + const std::vector< Field > Exd::get_row( uint32_t id, uint32_t subRow ) + { + + auto cacheEntryIt = _idCache.find( id ); + if( cacheEntryIt == _idCache.end() ) + throw std::runtime_error( "Id not found: " + std::to_string( id ) ); + + // Iterates over all the files + const uint32_t member_count = _exh->get_members().size(); + auto& file_ptr = cacheEntryIt->second.file; + + std::vector< char > dataCpy = file_ptr->get_data_sections().front(); + std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); + + // Get the vector fields for the given record and preallocate it + auto fields = _data[ id ]; + fields.reserve( member_count ); + iss.seekg( cacheEntryIt->second.offset + 6 ); + + uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] ); + + if( subRow >= subRows ) + throw std::runtime_error( "Out of bounds sub-row!" ); + + int offset = cacheEntryIt->second.offset + 6 + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) ); + + for( auto& member_entry : _exh->get_exh_members() ) + { + // Seek to the position of the member to extract. + // 6 is because we have uint32_t/uint16_t at the start of each record + iss.seekg( offset + member_entry.offset ); + + // Switch depending on the type to extract + switch( member_entry.type ) + { + case DataType::string: + // Extract the offset to the actual string + // Seek to it then extract the actual string + { + throw std::runtime_error( "String not implemented for variant 2!" ); + //auto string_offset = extract( iss, "string_offset", false ); + //iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset ); + //fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) ); + } + break; + + case DataType::boolean: + fields.emplace_back( extract< bool >( iss, "bool" ) ); + break; + + case DataType::int8: + fields.emplace_back( extract< int8_t >( iss, "int8_t" ) ); + break; + + case DataType::uint8: + fields.emplace_back( extract< uint8_t >( iss, "uint8_t" ) ); + break; + + case DataType::int16: + fields.emplace_back( extract< int16_t >( iss, "int16_t", false ) ); + break; + + case DataType::uint16: + fields.emplace_back( extract< uint16_t >( iss, "uint16_t", false ) ); + break; + + case DataType::int32: + fields.emplace_back( extract< int32_t >( iss, "int32_t", false ) ); + break; + + case DataType::uint32: + fields.emplace_back( extract< uint32_t >( iss, "uint32_t", false ) ); + break; + + case DataType::float32: + fields.emplace_back( extract< float >( iss, "float", false ) ); + break; + + case DataType::uint64: + fields.emplace_back( extract< uint64_t >( iss, "uint64_t", false ) ); + break; + + default: + auto type = static_cast< uint16_t >( member_entry.type ); + if( type < 0x19 || type > 0x20 ) + throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) ); + uint64_t val = extract< uint64_t >( iss, "bool" ); + int32_t shift = type - 0x19; + int32_t i = 1 << shift; + val &= i; + fields.emplace_back( ( val & i ) == i ); + break; + } + } + return fields; + + } + + + const std::vector< Field > Exd::get_row( uint32_t id ) + { + + auto cacheEntryIt = _idCache.find( id ); + if( cacheEntryIt == _idCache.end() ) + throw std::runtime_error( "Id not found: " + std::to_string( id ) ); + + // Iterates over all the files + const uint32_t member_count = _exh->get_members().size(); + auto& file_ptr = cacheEntryIt->second.file; + + std::vector< char > dataCpy = file_ptr->get_data_sections().front(); + std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); + + // Get the vector fields for the given record and preallocate it + auto fields = _data[ id ]; + fields.reserve( member_count ); + iss.seekg( cacheEntryIt->second.offset + 6 ); + + uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] ); + + for( auto& member_entry : _exh->get_exh_members() ) + { + // Seek to the position of the member to extract. + // 6 is because we have uint32_t/uint16_t at the start of each record + iss.seekg( cacheEntryIt->second.offset + 6 + member_entry.offset ); + + // Switch depending on the type to extract + switch( member_entry.type ) + { + case DataType::string: + // Extract the offset to the actual string + // Seek to it then extract the actual string + { + auto string_offset = extract< uint32_t >( iss, "string_offset", false ); + iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset ); + fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) ); + } + break; + + case DataType::boolean: + fields.emplace_back( extract< bool >( iss, "bool" ) ); + break; + + case DataType::int8: + fields.emplace_back( extract< int8_t >( iss, "int8_t" ) ); + break; + + case DataType::uint8: + fields.emplace_back( extract< uint8_t >( iss, "uint8_t" ) ); + break; + + case DataType::int16: + fields.emplace_back( extract< int16_t >( iss, "int16_t", false ) ); + break; + + case DataType::uint16: + fields.emplace_back( extract< uint16_t >( iss, "uint16_t", false ) ); + break; + + case DataType::int32: + fields.emplace_back( extract< int32_t >( iss, "int32_t", false ) ); + break; + + case DataType::uint32: + fields.emplace_back( extract< uint32_t >( iss, "uint32_t", false ) ); + break; + + case DataType::float32: + fields.emplace_back( extract< float >( iss, "float", false ) ); + break; + + case DataType::uint64: + fields.emplace_back( extract< uint64_t >( iss, "uint64_t", false ) ); + break; + + default: + auto type = static_cast< uint16_t >( member_entry.type ); + if( type < 0x19 || type > 0x20 ) + throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) ); + uint64_t val = extract< uint64_t >( iss, "bool" ); + int32_t shift = type - 0x19; + int32_t i = 1 << shift; + val &= i; + fields.emplace_back( ( val & i ) == i ); + break; + } + } + return fields; + + } + + // Get all rows + const std::map< uint32_t, std::vector< Field>>& Exd::get_rows() + { + // Iterates over all the files + const uint32_t member_count = _exh->get_members().size(); + for( auto& file_ptr : _files ) + { + // Get a stream + std::vector< char > dataCpy = file_ptr->get_data_sections().front(); + std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); + + // Extract the header and skip to the record indices + auto exd_header = extract< ExdHeader >( iss ); + iss.seekg( 0x20 ); + + // Preallocate and extract the record_indices + const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex ); + std::vector< ExdRecordIndex > record_indices; + record_indices.reserve( record_count ); + for( uint32_t i = 0; i < record_count; ++i ) + { + record_indices.emplace_back( extract< ExdRecordIndex >( iss ) ); + } + + for( auto& record_index : record_indices ) + { + // Get the vector fields for the given record and preallocate it + auto& fields = _data[ record_index.id ]; + fields.reserve( member_count ); + + for( auto& member_entry : _exh->get_exh_members() ) + //for( auto& member_entry : _exh->get_members() ) + { + // Seek to the position of the member to extract. + // 6 is because we have uint32_t/uint16_t at the start of each record + iss.seekg( record_index.offset + 6 + member_entry.offset ); + + // Switch depending on the type to extract + switch( member_entry.type ) + { + case DataType::string: + // Extract the offset to the actual string + // Seek to it then extract the actual string + { + auto string_offset = extract< uint32_t >( iss, "string_offset", false ); + iss.seekg( record_index.offset + 6 + _exh->get_header().data_offset + string_offset ); + fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) ); + } + break; + + case DataType::boolean: + fields.emplace_back( extract< bool >( iss, "bool" ) ); + break; + + case DataType::int8: + fields.emplace_back( extract< int8_t >( iss, "int8_t" ) ); + break; + + case DataType::uint8: + fields.emplace_back( extract< uint8_t >( iss, "uint8_t" ) ); + break; + + case DataType::int16: + fields.emplace_back( extract< int16_t >( iss, "int16_t", false ) ); + break; + + case DataType::uint16: + fields.emplace_back( extract< uint16_t >( iss, "uint16_t", false ) ); + break; + + case DataType::int32: + fields.emplace_back( extract< int32_t >( iss, "int32_t", false ) ); + break; + + case DataType::uint32: + fields.emplace_back( extract< uint32_t >( iss, "uint32_t", false ) ); + break; + + case DataType::float32: + fields.emplace_back( extract< float >( iss, "float", false ) ); + break; + + case DataType::uint64: + fields.emplace_back( extract< uint64_t >( iss, "uint64_t", false ) ); + break; + + default: + auto type = static_cast< uint16_t >( member_entry.type ); + if( type < 0x19 || type > 0x20 ) + throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) ); + uint64_t val = extract< uint64_t >( iss, "bool" ); + int32_t shift = type - 0x19; + int32_t i = 1 << shift; + val &= i; + fields.emplace_back( ( val & i ) == i ); + break; + } + } + } + } + return _data; + } - struct ExdHeader - { - char magic[0x4]; - uint16_t unknown; - uint16_t unknown2; - uint32_t index_size; - }; - - struct ExdRecordIndex - { - uint32_t id; - uint32_t offset; - }; - - } -} - -namespace xiv -{ - namespace utils - { - namespace bparse - { - template <> inline void reorder( xiv::exd::ExdHeader& i_struct ) { for( int32_t i = 0; i < 0x4; ++i ) { xiv::utils::bparse::reorder( i_struct.magic[i] ); } i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); xiv::utils::bparse::reorder( i_struct.unknown ); i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 ); xiv::utils::bparse::reorder( i_struct.unknown2 ); i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size ); xiv::utils::bparse::reorder( i_struct.index_size ); } - template <> inline void reorder( xiv::exd::ExdRecordIndex& i_struct ) { i_struct.id = xiv::utils::bparse::byteswap( i_struct.id ); xiv::utils::bparse::reorder( i_struct.id ); i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); xiv::utils::bparse::reorder( i_struct.offset ); } - } - } -}; - -namespace xiv -{ - namespace exd - { - - Exd::Exd( std::shared_ptr i_exh, const std::vector>& i_files ) - { - _exh = i_exh; - _files = i_files; - - - // Iterates over all the files - const uint32_t member_count = _exh->get_members().size(); - for ( auto &file_ptr : _files ) - { - // Get a stream - std::vector< char > dataCpy = file_ptr->get_data_sections().front(); - std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); - - // Extract the header and skip to the record indices - auto exd_header = extract< ExdHeader >( iss ); - iss.seekg( 0x20 ); - - // Preallocate and extract the record_indices - const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex ); - std::vector< ExdRecordIndex > record_indices; - record_indices.reserve( record_count ); - for ( uint32_t i = 0; i < record_count; ++i ) - { - auto recordIndex = extract< ExdRecordIndex >( iss ); - _idCache[recordIndex.id] = ExdCacheEntry{file_ptr, recordIndex.offset}; - } - } - } - - Exd::~Exd() - { - } - - const std::vector Exd::get_row( uint32_t id, uint32_t subRow ) - { - - auto cacheEntryIt = _idCache.find( id ); - if( cacheEntryIt == _idCache.end() ) - throw std::runtime_error( "Id not found: " + std::to_string( id ) ); - - // Iterates over all the files - const uint32_t member_count = _exh->get_members().size(); - auto& file_ptr = cacheEntryIt->second.file; - - std::vector< char > dataCpy = file_ptr->get_data_sections().front(); - std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); - - // Get the vector fields for the given record and preallocate it - auto fields = _data[id]; - fields.reserve( member_count ); - iss.seekg( cacheEntryIt->second.offset + 6 ); - - uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] ); - - if( subRow >= subRows ) - throw std::runtime_error( "Out of bounds sub-row!" ); - - int offset = cacheEntryIt->second.offset + 6 + ( subRow * _exh->get_header().data_offset + 2 * ( subRow + 1 ) ); - - for( auto& member_entry : _exh->get_exh_members() ) - { - // Seek to the position of the member to extract. - // 6 is because we have uint32_t/uint16_t at the start of each record - iss.seekg( offset + member_entry.offset ); - - // Switch depending on the type to extract - switch( member_entry.type ) - { - case DataType::string: - // Extract the offset to the actual string - // Seek to it then extract the actual string - { - throw std::runtime_error( "String not implemented for variant 2!" ); - //auto string_offset = extract( iss, "string_offset", false ); - //iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset ); - //fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) ); - } - break; - - case DataType::boolean: - fields.emplace_back( extract( iss, "bool" ) ); - break; - - case DataType::int8: - fields.emplace_back( extract( iss, "int8_t" ) ); - break; - - case DataType::uint8: - fields.emplace_back( extract( iss, "uint8_t" ) ); - break; - - case DataType::int16: - fields.emplace_back( extract( iss, "int16_t", false ) ); - break; - - case DataType::uint16: - fields.emplace_back( extract( iss, "uint16_t", false ) ); - break; - - case DataType::int32: - fields.emplace_back( extract( iss, "int32_t", false ) ); - break; - - case DataType::uint32: - fields.emplace_back( extract( iss, "uint32_t", false ) ); - break; - - case DataType::float32: - fields.emplace_back( extract( iss, "float", false ) ); - break; - - case DataType::uint64: - fields.emplace_back( extract( iss, "uint64_t", false ) ); - break; - - default: - auto type = static_cast< uint16_t >( member_entry.type ); - if( type < 0x19 || type > 0x20 ) - throw std::runtime_error("Unknown DataType: " + std::to_string( type )); - uint64_t val = extract< uint64_t >( iss, "bool" ); - int32_t shift = type - 0x19; - int32_t i = 1 << shift; - val &= i; - fields.emplace_back( ( val & i ) == i ); - break; - } - } - return fields; - - } - - - const std::vector Exd::get_row( uint32_t id ) - { - - auto cacheEntryIt = _idCache.find( id ); - if( cacheEntryIt == _idCache.end() ) - throw std::runtime_error( "Id not found: " + std::to_string( id ) ); - - // Iterates over all the files - const uint32_t member_count = _exh->get_members().size(); - auto& file_ptr = cacheEntryIt->second.file; - - std::vector< char > dataCpy = file_ptr->get_data_sections().front(); - std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); - - // Get the vector fields for the given record and preallocate it - auto fields = _data[id]; - fields.reserve( member_count ); - iss.seekg( cacheEntryIt->second.offset + 6 ); - - uint8_t subRows = *reinterpret_cast< uint8_t* >( &dataCpy[ cacheEntryIt->second.offset + 5 ] ); - - for( auto& member_entry : _exh->get_exh_members() ) - { - // Seek to the position of the member to extract. - // 6 is because we have uint32_t/uint16_t at the start of each record - iss.seekg( cacheEntryIt->second.offset + 6 + member_entry.offset ); - - // Switch depending on the type to extract - switch( member_entry.type ) - { - case DataType::string: - // Extract the offset to the actual string - // Seek to it then extract the actual string - { - auto string_offset = extract( iss, "string_offset", false ); - iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset ); - fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) ); - } - break; - - case DataType::boolean: - fields.emplace_back( extract( iss, "bool" ) ); - break; - - case DataType::int8: - fields.emplace_back( extract( iss, "int8_t" ) ); - break; - - case DataType::uint8: - fields.emplace_back( extract( iss, "uint8_t" ) ); - break; - - case DataType::int16: - fields.emplace_back( extract( iss, "int16_t", false ) ); - break; - - case DataType::uint16: - fields.emplace_back( extract( iss, "uint16_t", false ) ); - break; - - case DataType::int32: - fields.emplace_back( extract( iss, "int32_t", false ) ); - break; - - case DataType::uint32: - fields.emplace_back( extract( iss, "uint32_t", false ) ); - break; - - case DataType::float32: - fields.emplace_back( extract( iss, "float", false ) ); - break; - - case DataType::uint64: - fields.emplace_back( extract( iss, "uint64_t", false ) ); - break; - - default: - auto type = static_cast< uint16_t >( member_entry.type ); - if( type < 0x19 || type > 0x20 ) - throw std::runtime_error("Unknown DataType: " + std::to_string( type )); - uint64_t val = extract< uint64_t >( iss, "bool" ); - int32_t shift = type - 0x19; - int32_t i = 1 << shift; - val &= i; - fields.emplace_back( ( val & i ) == i ); - break; - } - } - return fields; - - } - - // Get all rows - const std::map>& Exd::get_rows() - { - // Iterates over all the files - const uint32_t member_count = _exh->get_members().size(); - for( auto& file_ptr : _files ) - { - // Get a stream - std::vector< char > dataCpy = file_ptr->get_data_sections().front(); - std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); - - // Extract the header and skip to the record indices - auto exd_header = extract( iss ); - iss.seekg( 0x20 ); - - // Preallocate and extract the record_indices - const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex ); - std::vector record_indices; - record_indices.reserve( record_count ); - for( uint32_t i = 0; i < record_count; ++i ) - { - record_indices.emplace_back( extract( iss ) ); - } - - for( auto& record_index : record_indices ) - { - // Get the vector fields for the given record and preallocate it - auto& fields = _data[record_index.id]; - fields.reserve( member_count ); - - for( auto& member_entry : _exh->get_exh_members() ) - //for( auto& member_entry : _exh->get_members() ) - { - // Seek to the position of the member to extract. - // 6 is because we have uint32_t/uint16_t at the start of each record - iss.seekg( record_index.offset + 6 + member_entry.offset ); - - // Switch depending on the type to extract - switch( member_entry.type ) - { - case DataType::string: - // Extract the offset to the actual string - // Seek to it then extract the actual string - { - auto string_offset = extract( iss, "string_offset", false ); - iss.seekg( record_index.offset + 6 + _exh->get_header().data_offset + string_offset ); - fields.emplace_back( utils::bparse::extract_cstring( iss, "string" ) ); - } - break; - - case DataType::boolean: - fields.emplace_back( extract( iss, "bool" ) ); - break; - - case DataType::int8: - fields.emplace_back( extract( iss, "int8_t" ) ); - break; - - case DataType::uint8: - fields.emplace_back( extract( iss, "uint8_t" ) ); - break; - - case DataType::int16: - fields.emplace_back( extract( iss, "int16_t", false ) ); - break; - - case DataType::uint16: - fields.emplace_back( extract( iss, "uint16_t", false ) ); - break; - - case DataType::int32: - fields.emplace_back( extract( iss, "int32_t", false ) ); - break; - - case DataType::uint32: - fields.emplace_back( extract( iss, "uint32_t", false ) ); - break; - - case DataType::float32: - fields.emplace_back( extract( iss, "float", false ) ); - break; - - case DataType::uint64: - fields.emplace_back( extract( iss, "uint64_t", false ) ); - break; - - default: - auto type = static_cast< uint16_t >( member_entry.type ); - if( type < 0x19 || type > 0x20 ) - throw std::runtime_error("Unknown DataType: " + std::to_string( type )); - uint64_t val = extract< uint64_t >( iss, "bool" ); - int32_t shift = type - 0x19; - int32_t i = 1 << shift; - val &= i; - fields.emplace_back( ( val & i ) == i ); - break; - } - } - } - } - return _data; - } - - } } diff --git a/deps/datReader/Exd.h b/deps/datReader/Exd.h index c504176b..a16c135b 100644 --- a/deps/datReader/Exd.h +++ b/deps/datReader/Exd.h @@ -8,15 +8,13 @@ #include "File.h" -namespace xiv -{ -namespace exd +namespace xiv::exd { -class Exh; + class Exh; -// Field type containing all the possible types in the data files -using Field = std::variant< + // Field type containing all the possible types in the data files + using Field = std::variant< std::string, bool, int8_t, @@ -27,40 +25,44 @@ using Field = std::variant< uint32_t, float, uint64_t >; - -struct ExdCacheEntry -{ - std::shared_ptr file; - uint32_t offset; -}; -// Data for a given language -class Exd -{ -public: + struct ExdCacheEntry + { + std::shared_ptr< dat::File > file; + uint32_t offset; + }; + + // Data for a given language + class Exd + { + public: // i_exh: the header // i_files: the multiple exd files - Exd() {} - Exd(std::shared_ptr i_exh, const std::vector>& i_files); + Exd() + { + } + + Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files ); + ~Exd(); // Get a row by its id - const std::vector get_row(uint32_t id); + const std::vector< Field > get_row( uint32_t id ); // Get a row by its id and sub-row - const std::vector get_row(uint32_t id, uint32_t subRow); + const std::vector< Field > get_row( uint32_t id, uint32_t subRow ); + // Get all rows - const std::map>& get_rows(); + const std::map< uint32_t, std::vector< Field>>& get_rows(); -protected: + protected: // Data indexed by the ID of the row, the vector is field with the same order as exh.members - std::map> _data; - std::vector> _files; - std::shared_ptr _exh; + std::map< uint32_t, std::vector< Field>> _data; + std::vector< std::shared_ptr< dat::File>> _files; + std::shared_ptr< Exh > _exh; std::map< uint32_t, ExdCacheEntry > _idCache; -}; + }; -} } #endif // XIV_EXD_EXD_H diff --git a/deps/datReader/ExdCat.cpp b/deps/datReader/ExdCat.cpp index ddab260e..ebf75ec7 100644 --- a/deps/datReader/ExdCat.cpp +++ b/deps/datReader/ExdCat.cpp @@ -9,74 +9,73 @@ namespace { - // Suffix of the filenames given a language - std::map language_map = - {{xiv::exd::Language::none, ""}, - {xiv::exd::Language::ja, "_ja"}, - {xiv::exd::Language::en, "_en"}, - {xiv::exd::Language::de, "_de"}, - {xiv::exd::Language::fr, "_fr"}, - {xiv::exd::Language::chs, "_chs"}}; + // Suffix of the filenames given a language + std::map language_map = + { + {xiv::exd::Language::none, ""}, + {xiv::exd::Language::ja, "_ja"}, + {xiv::exd::Language::en, "_en"}, + {xiv::exd::Language::de, "_de"}, + {xiv::exd::Language::fr, "_fr"}, + {xiv::exd::Language::chs, "_chs"} + }; } -namespace xiv +namespace xiv::exd { - namespace exd - { + Cat::Cat( dat::GameData& i_game_data, const std::string& i_name ) : + _name( i_name ) + { + //XIV_INFO(xiv_exd_logger, "Initializing Cat with name: " << i_name); + // creates the header .exh + { + auto header_file = i_game_data.getFile( "exd/" + i_name + ".exh" ); + _header = std::shared_ptr< Exh >( new Exh( *header_file ) ); - Cat::Cat(dat::GameData& i_game_data, const std::string& i_name) : - _name(i_name) + } + + for( auto language: _header->get_languages() ) + { + // chs not yet in data files + if( language == Language::en || language == Language::none ) { - //XIV_INFO(xiv_exd_logger, "Initializing Cat with name: " << i_name); - // creates the header .exh - { - auto header_file = i_game_data.getFile("exd/" + i_name + ".exh"); - _header = std::shared_ptr< Exh >( new Exh( *header_file ) ); - - } - - for(auto language: _header->get_languages()) - { - // chs not yet in data files - if (language == Language::en || language == Language::none) - { - // Get all the files for a given category/language, in case of multiple range of IDs in separate files (like Quest) - std::vector> files; - for(auto& exd_def: _header->get_exd_defs()) - { - files.emplace_back( i_game_data.getFile("exd/" + i_name + "_" + std::to_string(exd_def.start_id) + language_map.at(language) + ".exd") ); - } - // Instantiate the data for this language - _data[language] = std::unique_ptr(new Exd(_header, files)); - } - } + // Get all the files for a given category/language, in case of multiple range of IDs in separate files (like Quest) + std::vector< std::shared_ptr< dat::File>> files; + for( auto& exd_def: _header->get_exd_defs() ) + { + files.emplace_back( i_game_data.getFile( + "exd/" + i_name + "_" + std::to_string( exd_def.start_id ) + language_map.at( language ) + ".exd" ) ); + } + // Instantiate the data for this language + _data[ language ] = std::make_unique< Exd >( _header, files ); } + } + } - Cat::~Cat() - { + Cat::~Cat() + { - } + } - const std::string& Cat::get_name() const - { - return _name; - } + const std::string& Cat::get_name() const + { + return _name; + } - const Exh& Cat::get_header() const - { - return *_header; - } + const Exh& Cat::get_header() const + { + return *_header; + } - const Exd& Cat::get_data_ln(Language i_language) const - { - auto ln_it = _data.find(i_language); - if (ln_it == _data.end()) - { - throw std::runtime_error("No data for language: " + std::to_string(uint16_t(i_language))); - } + const Exd& Cat::get_data_ln( Language i_language ) const + { + auto ln_it = _data.find( i_language ); + if( ln_it == _data.end() ) + { + throw std::runtime_error( "No data for language: " + std::to_string( uint16_t( i_language ) ) ); + } - return *(ln_it->second); - } + return *( ln_it->second ); + } - } } diff --git a/deps/datReader/ExdData.cpp b/deps/datReader/ExdData.cpp index 3c4af47a..5307f5de 100644 --- a/deps/datReader/ExdData.cpp +++ b/deps/datReader/ExdData.cpp @@ -7,50 +7,47 @@ #include "ExdCat.h" -namespace xiv -{ -namespace exd +namespace xiv::exd { + +ExdData::ExdData( dat::GameData& i_game_data ) try : + _game_data( i_game_data ) { + //XIV_INFO(xiv_exd_logger, "Initializing ExdData"); -ExdData::ExdData(dat::GameData& i_game_data) try : - _game_data(i_game_data) -{ - //XIV_INFO(xiv_exd_logger, "Initializing ExdData"); + // Fetch the root.exl and get a stream from it + auto root_exl = i_game_data.getFile( "exd/root.exl" ); + std::vector< char > dataCpy = root_exl->get_data_sections().front(); + xiv::utils::stream::vectorwrapbuf< char > databuf( dataCpy ); + std::istream stream( &databuf ); - // Fetch the root.exl and get a stream from it - auto root_exl = i_game_data.getFile("exd/root.exl"); - std::vector< char > dataCpy = root_exl->get_data_sections().front(); - xiv::utils::stream::vectorwrapbuf databuf(dataCpy); - std::istream stream(&databuf); + // Iterates over the lines while skipping the first one + std::string line; + std::getline( stream, line ); // extract first line EXLT,2 + std::getline( stream, line ); - // Iterates over the lines while skipping the first one - std::string line; - std::getline(stream, line); // extract first line EXLT,2 - std::getline(stream, line); + // Until the EOF + while( !line.empty() ) + { + // Format is cat_name,XX + // XX being an internal identifier + // Get only the cat_name + auto sep = line.find( ',' ); + auto category = line.substr( 0, sep ); - // Until the EOF - while (!line.empty()) - { - // Format is cat_name,XX - // XX being an internal identifier - // Get only the cat_name - auto sep = line.find(','); - auto category = line.substr(0, sep); + // Add to the list of category name + // creates the empty category in the cats map + // instantiate the creation mutex for this category + _cat_names.push_back( category ); + _cats[ category ] = std::unique_ptr< Cat >(); + _cat_creation_mutexes[ category ] = std::make_unique< std::mutex >(); - // Add to the list of category name - // creates the empty category in the cats map - // instantiate the creation mutex for this category - _cat_names.push_back(category); - _cats[category] = std::unique_ptr(); - _cat_creation_mutexes[category] = std::unique_ptr(new std::mutex()); - - std::getline(stream, line); - } + std::getline( stream, line ); + } } -catch(std::exception& e) +catch( std::exception& e ) { - // In case of failure here, client is supposed to catch the exception because it is not recoverable on our side - throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) ); + // In case of failure here, client is supposed to catch the exception because it is not recoverable on our side + throw std::runtime_error( "ExdData initialization failed: " + std::string( e.what() ) ); } ExdData::~ExdData() @@ -58,43 +55,42 @@ ExdData::~ExdData() } -const std::vector& ExdData::get_cat_names() const +const std::vector< std::string >& ExdData::get_cat_names() const { - return _cat_names; + return _cat_names; } -const Cat& ExdData::get_category(const std::string& i_cat_name) +const Cat& ExdData::get_category( const std::string& i_cat_name ) { - // Get the category from its name - auto cat_it = _cats.find(i_cat_name); - if (cat_it == _cats.end()) - { - throw std::runtime_error("Category not found: " + i_cat_name); - } + // Get the category from its name + auto cat_it = _cats.find( i_cat_name ); + if( cat_it == _cats.end() ) + { + throw std::runtime_error( "Category not found: " + i_cat_name ); + } - if (cat_it->second) - { - // If valid return it - return *(cat_it->second); - } - else - { - // If not, create it and return it - create_category(i_cat_name); - return *(_cats[i_cat_name]); - } + if( cat_it->second ) + { + // If valid return it + return *( cat_it->second ); + } + else + { + // If not, create it and return it + create_category( i_cat_name ); + return *( _cats[ i_cat_name ] ); + } } -void ExdData::create_category(const std::string& i_cat_name) +void ExdData::create_category( const std::string& i_cat_name ) { - // Lock mutex in this scope - std::lock_guard lock(*(_cat_creation_mutexes[i_cat_name])); - // Maybe after unlocking it has already been created, so check (most likely if it blocked) - if (!_cats[i_cat_name]) - { - _cats[i_cat_name] = std::unique_ptr(new Cat(_game_data, i_cat_name)); - } + // Lock mutex in this scope + std::lock_guard< std::mutex > lock( *( _cat_creation_mutexes[ i_cat_name ] ) ); + // Maybe after unlocking it has already been created, so check (most likely if it blocked) + if( !_cats[ i_cat_name ] ) + { + _cats[ i_cat_name ] = std::make_unique< Cat >( _game_data, i_cat_name ); + } } } -} diff --git a/deps/datReader/Exh.cpp b/deps/datReader/Exh.cpp index 0a829bec..a8c300b8 100644 --- a/deps/datReader/Exh.cpp +++ b/deps/datReader/Exh.cpp @@ -7,71 +7,69 @@ using xiv::utils::bparse::extract; -namespace xiv -{ -namespace exd -{ -Exh::Exh(const dat::File& i_file) +namespace xiv::exd { + + Exh::Exh( const dat::File& i_file ) + { // Get a stream from the file std::vector< char > dataCpy = i_file.get_data_sections().front(); std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); // Extract header and skip to member definitions - _header = extract(iss); - iss.seekg(0x20); + _header = extract< ExhHeader >( iss ); + iss.seekg( 0x20 ); // Extract all the members and feed the _members map - for (auto i = 0; i < _header.field_count; ++i) + for( auto i = 0; i < _header.field_count; ++i ) { - auto member = extract(iss); - _members[member.offset] = member; - _exh_defs.push_back( member ); + auto member = extract< ExhMember >( iss ); + _members[ member.offset ] = member; + _exh_defs.push_back( member ); } // Extract all the exd_defs - _exd_defs.reserve(_header.exd_count); - for (auto i = 0; i < _header.exd_count; ++i) + _exd_defs.reserve( _header.exd_count ); + for( auto i = 0; i < _header.exd_count; ++i ) { - _exd_defs.emplace_back(extract(iss)); + _exd_defs.emplace_back( extract< ExhExdDef >( iss ) ); } // Extract all the languages - _languages.reserve(_header.language_count); - for (auto i = 0; i < _header.language_count; ++i) + _languages.reserve( _header.language_count ); + for( auto i = 0; i < _header.language_count; ++i ) { - _languages.emplace_back(Language(extract(iss, "language"))); + _languages.emplace_back( Language( extract< uint16_t >( iss, "language" ) ) ); } -} + } -Exh::~Exh() -{ -} + Exh::~Exh() + { + } -const ExhHeader& Exh::get_header() const -{ + const ExhHeader& Exh::get_header() const + { return _header; -} + } -const std::vector& Exh::get_exd_defs() const -{ + const std::vector< ExhExdDef >& Exh::get_exd_defs() const + { return _exd_defs; -} + } -const std::vector& Exh::get_languages() const -{ + const std::vector< Language >& Exh::get_languages() const + { return _languages; -} + } -const std::map& Exh::get_members() const -{ + const std::map< uint32_t, ExhMember >& Exh::get_members() const + { return _members; -} + } -const std::vector& Exh::get_exh_members() const -{ - return _exh_defs; -} + const std::vector< ExhMember >& Exh::get_exh_members() const + { + return _exh_defs; + } } -} diff --git a/deps/datReader/Exh.h b/deps/datReader/Exh.h index be273185..37301d0b 100644 --- a/deps/datReader/Exh.h +++ b/deps/datReader/Exh.h @@ -5,99 +5,131 @@ #include "bparse.h" -namespace xiv +namespace xiv::exd { - namespace exd - { - enum class DataType : uint16_t - { - string = 0, - boolean = 1, - int8 = 2, - uint8 = 3, - int16 = 4, - uint16 = 5, - int32 = 6, - uint32 = 7, - float32 = 9, - uint64 = 11, - }; + enum class DataType : + uint16_t + { + string = 0, + boolean = 1, + int8 = 2, + uint8 = 3, + int16 = 4, + uint16 = 5, + int32 = 6, + uint32 = 7, + float32 = 9, + uint64 = 11, + }; - struct ExhHeader - { - char magic[0x4]; - uint16_t unknown; - uint16_t data_offset; - uint16_t field_count; - uint16_t exd_count; - uint16_t language_count; - uint16_t unknown1; - uint8_t u2; - uint8_t variant; - }; + struct ExhHeader + { + char magic[0x4]; + uint16_t unknown; + uint16_t data_offset; + uint16_t field_count; + uint16_t exd_count; + uint16_t language_count; + uint16_t unknown1; + uint8_t u2; + uint8_t variant; + }; - struct ExhMember - { - DataType type; - uint16_t offset; - }; + struct ExhMember + { + DataType type; + uint16_t offset; + }; - struct ExhExdDef - { - uint32_t start_id; - uint32_t count_id; - }; - } + struct ExhExdDef + { + uint32_t start_id; + uint32_t count_id; + }; +}; + +namespace xiv::utils::bparse { +template<> +inline void reorder< xiv::exd::ExhHeader >( xiv::exd::ExhHeader& i_struct ) +{ + for( int32_t i = 0; i < 0x4; ++i ) + { + xiv::utils::bparse::reorder( i_struct.magic[ i ] ); + } + i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); + xiv::utils::bparse::reorder( i_struct.unknown ); + i_struct.data_offset = xiv::utils::bparse::byteswap( i_struct.data_offset ); + xiv::utils::bparse::reorder( i_struct.data_offset ); + i_struct.field_count = xiv::utils::bparse::byteswap( i_struct.field_count ); + xiv::utils::bparse::reorder( i_struct.field_count ); + i_struct.exd_count = xiv::utils::bparse::byteswap( i_struct.exd_count ); + xiv::utils::bparse::reorder( i_struct.exd_count ); + i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count ); + xiv::utils::bparse::reorder( i_struct.language_count ); +} + +template<> +inline void reorder< xiv::exd::ExhMember >( xiv::exd::ExhMember& i_struct ) +{ + i_struct.type = xiv::utils::bparse::byteswap( i_struct.type ); + xiv::utils::bparse::reorder( i_struct.type ); + i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.offset ); +} + +template<> +inline void reorder< xiv::exd::ExhExdDef >( xiv::exd::ExhExdDef& i_struct ) +{ + i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id ); + xiv::utils::bparse::reorder( i_struct.start_id ); + i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id ); + xiv::utils::bparse::reorder( i_struct.count_id ); +} }; namespace xiv { - namespace utils - { - namespace bparse - { - template <> inline void reorder( xiv::exd::ExhHeader& i_struct ) { for( int32_t i = 0; i < 0x4; ++i ) { xiv::utils::bparse::reorder( i_struct.magic[i] ); } i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); xiv::utils::bparse::reorder( i_struct.unknown ); i_struct.data_offset = xiv::utils::bparse::byteswap( i_struct.data_offset ); xiv::utils::bparse::reorder( i_struct.data_offset ); i_struct.field_count = xiv::utils::bparse::byteswap( i_struct.field_count ); xiv::utils::bparse::reorder( i_struct.field_count ); i_struct.exd_count = xiv::utils::bparse::byteswap( i_struct.exd_count ); xiv::utils::bparse::reorder( i_struct.exd_count ); i_struct.language_count = xiv::utils::bparse::byteswap( i_struct.language_count ); xiv::utils::bparse::reorder( i_struct.language_count ); } - template <> inline void reorder( xiv::exd::ExhMember& i_struct ) { i_struct.type = xiv::utils::bparse::byteswap( i_struct.type ); xiv::utils::bparse::reorder( i_struct.type ); i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); xiv::utils::bparse::reorder( i_struct.offset ); } - template <> inline void reorder( xiv::exd::ExhExdDef& i_struct ) { i_struct.start_id = xiv::utils::bparse::byteswap( i_struct.start_id ); xiv::utils::bparse::reorder( i_struct.start_id ); i_struct.count_id = xiv::utils::bparse::byteswap( i_struct.count_id ); xiv::utils::bparse::reorder( i_struct.count_id ); } - } - } -}; -namespace xiv -{ - namespace dat - { - class File; - } - namespace exd - { + namespace dat + { + class File; + } - enum Language : uint16_t; + namespace exd + { - // Header file for exd data - class Exh - { - public: - // The header file - Exh( const dat::File& i_file ); - ~Exh(); + enum Language : + uint16_t; - const ExhHeader& get_header() const; - const std::vector& get_exd_defs() const; - const std::vector& get_languages() const; - const std::map& get_members() const; - const std::vector& get_exh_members() const; + // Header file for exd data + class Exh + { + public: + // The header file + Exh( const dat::File& i_file ); - protected: - ExhHeader _header; - // Members of the datastruct ordered(indexed) by offset - std::map _members; - std::vector _exh_defs; - std::vector _exd_defs; - std::vector _languages; - }; + ~Exh(); - } + const ExhHeader& get_header() const; + + const std::vector< ExhExdDef >& get_exd_defs() const; + + const std::vector< Language >& get_languages() const; + + const std::map< uint32_t, ExhMember >& get_members() const; + + const std::vector< ExhMember >& get_exh_members() const; + + protected: + ExhHeader _header; + // Members of the datastruct ordered(indexed) by offset + std::map< uint32_t, ExhMember > _members; + std::vector< ExhMember > _exh_defs; + std::vector< ExhExdDef > _exd_defs; + std::vector< Language > _languages; + }; + + } } #endif // XIV_EXD_EXH_H diff --git a/deps/datReader/File.cpp b/deps/datReader/File.cpp index c3413d5a..e83659c1 100644 --- a/deps/datReader/File.cpp +++ b/deps/datReader/File.cpp @@ -2,44 +2,41 @@ #include -namespace xiv -{ -namespace dat +namespace xiv::dat { -File::File() : - _type(FileType::empty) -{ -} + File::File() : + _type( FileType::empty ) + { + } -File::~File() -{ -} + File::~File() + { + } -FileType File::get_type() const -{ - return _type; -} + FileType File::get_type() const + { + return _type; + } -const std::vector>& File::get_data_sections() const -{ - return _data_sections; -} + const std::vector< std::vector< char>>& File::get_data_sections() const + { + return _data_sections; + } -std::vector>& File::access_data_sections() -{ - return _data_sections; -} + std::vector< std::vector< char>>& File::access_data_sections() + { + return _data_sections; + } -void File::exportToFile(const std::filesystem::path& i_path) const -{ - std::ofstream ofs( i_path.string(), std::ios_base::binary | std::ios_base::out ); - for( auto& data_section : _data_sections ) - { + void File::exportToFile( const std::filesystem::path& i_path ) const + { + std::ofstream ofs( i_path.string(), std::ios_base::binary | std::ios_base::out ); + for( auto& data_section : _data_sections ) + { ofs.write( data_section.data(), data_section.size() ); - } - ofs.close(); -} + } + ofs.close(); + } } -} diff --git a/deps/datReader/File.h b/deps/datReader/File.h index 3ce77b4f..31c12fbe 100644 --- a/deps/datReader/File.h +++ b/deps/datReader/File.h @@ -7,50 +7,42 @@ #include #include "bparse.h" - -namespace xiv +namespace xiv::dat { - namespace dat - { - enum class FileType : uint32_t - { - empty = 1, - standard = 2, - model = 3, - texture = 4, - }; - } -}; + enum class FileType : + uint32_t + { + empty = 1, + standard = 2, + model = 3, + texture = 4, + }; -namespace xiv -{ - namespace dat - { + class Dat; - class Dat; + // Basic file from the dats + class File + { + friend class Dat; - // Basic file from the dats - class File - { - friend class Dat; - public: - File(); - ~File(); + public: + File(); - FileType get_type() const; + ~File(); - // Getters functions for the data in the file - const std::vector>& get_data_sections() const; - std::vector>& access_data_sections(); + FileType get_type() const; - void exportToFile( const std::filesystem::path& i_path ) const; + // Getters functions for the data in the file + const std::vector< std::vector< char>>& get_data_sections() const; - protected: - FileType _type; - std::vector> _data_sections; - }; + std::vector< std::vector< char>>& access_data_sections(); - } + void exportToFile( const std::filesystem::path& i_path ) const; + + protected: + FileType _type; + std::vector< std::vector< char>> _data_sections; + }; } #endif // XIV_DAT_FILE_H diff --git a/deps/datReader/GameData.cpp b/deps/datReader/GameData.cpp index e3f36b6b..f3e56537 100644 --- a/deps/datReader/GameData.cpp +++ b/deps/datReader/GameData.cpp @@ -11,312 +11,315 @@ #include "DatCat.h" #include "File.h" -namespace -{ - // Relation between category number and category name - // These names are taken straight from the exe, it helps resolve dispatching when getting files by path +namespace { +// Relation between category number and category name +// These names are taken straight from the exe, it helps resolve dispatching when getting files by path - std::unordered_map< std::string, uint32_t > categoryNameToIdMap = - {{"common", 0x00}, - {"bgcommon", 0x01}, - {"bg", 0x02}, - {"cut", 0x03}, - {"chara", 0x04}, - {"shader", 0x05}, - {"ui", 0x06}, - {"sound", 0x07}, - {"vfx", 0x08}, - {"ui_script", 0x09}, - {"exd", 0x0A}, - {"game_script", 0x0B}, - {"music", 0x0C} - }; +std::unordered_map< std::string, uint32_t > categoryNameToIdMap = + { { "common", 0x00 }, + { "bgcommon", 0x01 }, + { "bg", 0x02 }, + { "cut", 0x03 }, + { "chara", 0x04 }, + { "shader", 0x05 }, + { "ui", 0x06 }, + { "sound", 0x07 }, + { "vfx", 0x08 }, + { "ui_script", 0x09 }, + { "exd", 0x0A }, + { "game_script", 0x0B }, + { "music", 0x0C } + }; - std::unordered_map< uint32_t, std::string > categoryIdToNameMap = - {{0x00, "common"}, - {0x01, "bgcommon"}, - {0x02, "bg"}, - {0x03, "cut"}, - {0x04, "chara"}, - {0x05, "shader"}, - {0x06, "ui"}, - {0x07, "sound"}, - {0x08, "vfx"}, - {0x09, "ui_script"}, - {0x0A, "exd"}, - {0x0B, "game_script"}, - {0x0C, "music"}}; +std::unordered_map< uint32_t, std::string > categoryIdToNameMap = + { { 0x00, "common" }, + { 0x01, "bgcommon" }, + { 0x02, "bg" }, + { 0x03, "cut" }, + { 0x04, "chara" }, + { 0x05, "shader" }, + { 0x06, "ui" }, + { 0x07, "sound" }, + { 0x08, "vfx" }, + { 0x09, "ui_script" }, + { 0x0A, "exd" }, + { 0x0B, "game_script" }, + { 0x0C, "music" } }; } -namespace xiv -{ -namespace dat +namespace xiv::dat { + GameData::GameData( const std::filesystem::path& path ) try : + m_path( path ) + { + int maxExLevel = 0; -GameData::GameData(const std::filesystem::path& path) try : - m_path(path) -{ - int maxExLevel = 0; + // msvc has retarded stdlib implementation + #ifdef _WIN32 + static constexpr auto sep = "\\"; + #else + static constexpr auto sep = std::filesystem::path::preferred_separator; + #endif - // msvc has retarded stdlib implementation -#ifdef _WIN32 - static constexpr auto sep = "\\"; -#else - static constexpr auto sep = std::filesystem::path::preferred_separator; -#endif - - // Determine which expansions are available - while( std::filesystem::exists( std::filesystem::path( m_path.string() + sep + "ex" + std::to_string( maxExLevel + 1 ) + sep + "ex" + std::to_string( maxExLevel + 1 ) + ".ver" ) ) ) - { + // Determine which expansions are available + while( std::filesystem::exists( std::filesystem::path( + m_path.string() + sep + "ex" + std::to_string( maxExLevel + 1 ) + sep + "ex" + std::to_string( maxExLevel + 1 ) + + ".ver" ) ) ) + { maxExLevel++; - } - + } - // Iterate over the files in path - for( auto it = std::filesystem::directory_iterator( m_path.string() + "//ffxiv" ); it != std::filesystem::directory_iterator(); ++it ) - { + + // Iterate over the files in path + for( auto it = std::filesystem::directory_iterator( m_path.string() + "//ffxiv" ); + it != std::filesystem::directory_iterator(); ++it ) + { // Get the filename of the current element auto filename = it->path().filename().string(); // If it contains ".win32.index" this is most likely a hit for a category - if( filename.find( ".win32.index" ) != std::string::npos && filename.find( ".win32.index2" ) == std::string::npos ) + if( filename.find( ".win32.index" ) != std::string::npos && filename.find( ".win32.index2" ) == std::string::npos ) { - // Format of indexes is XX0000.win32.index, so fetch the hex number for category number - std::istringstream iss( filename.substr( 0, 2 ) ); - uint32_t cat_nb; - iss >> std::hex >> cat_nb; + // Format of indexes is XX0000.win32.index, so fetch the hex number for category number + std::istringstream iss( filename.substr( 0, 2 ) ); + uint32_t cat_nb; + iss >> std::hex >> cat_nb; - // Add to the list of category number - // creates the empty category in the cats map - // instantiate the creation mutex for this category - m_catNums.push_back( cat_nb ); - m_cats[cat_nb] = std::unique_ptr(); - m_catCreationMutexes[cat_nb] = std::unique_ptr( new std::mutex() ); + // Add to the list of category number + // creates the empty category in the cats map + // instantiate the creation mutex for this category + m_catNums.push_back( cat_nb ); + m_cats[ cat_nb ] = std::unique_ptr< Cat >(); + m_catCreationMutexes[ cat_nb ] = std::make_unique< std::mutex >(); - // Check for expansion - for( int exNum = 1; exNum <= maxExLevel; exNum++ ) - { - const std::string path = m_path.string() + sep + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, 0, "win32", "index" ); + // Check for expansion + for( int exNum = 1; exNum <= maxExLevel; exNum++ ) + { + const std::string path = + m_path.string() + sep + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, 0, "win32", "index" ); - if( std::filesystem::exists( std::filesystem::path( path ) ) ) + if( std::filesystem::exists( std::filesystem::path( path ) ) ) + { + + int chunkCount = 0; + + for( int chunkTest = 0; chunkTest < 256; chunkTest++ ) { - - int chunkCount = 0; - - for(int chunkTest = 0; chunkTest < 256; chunkTest++ ) - { - if( std::filesystem::exists( m_path.string() + sep + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, chunkTest, "win32", "index" ) ) ) - { - m_exCats[cat_nb].exNumToChunkMap[exNum].chunkToCatMap[chunkTest] = std::unique_ptr(); - chunkCount++; - } - } - + if( std::filesystem::exists( m_path.string() + sep + + buildDatStr( "ex" + std::to_string( exNum ), cat_nb, exNum, chunkTest, "win32", + "index" ) ) ) + { + m_exCats[ cat_nb ].exNumToChunkMap[ exNum ].chunkToCatMap[ chunkTest ] = std::unique_ptr< Cat >(); + chunkCount++; + } } - } + + } + } } - } + } -} -catch( std::exception& e ) -{ - // In case of failure here, client is supposed to catch the exception because it is not recoverable on our side - throw std::runtime_error( "GameData initialization failed: " + std::string( e.what() ) ); -} + } + catch( std::exception& e ) + { + // In case of failure here, client is supposed to catch the exception because it is not recoverable on our side + throw std::runtime_error( "GameData initialization failed: " + std::string( e.what() ) ); + } -GameData::~GameData() -{ + GameData::~GameData() + { -} + } -const std::string GameData::buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, const std::string platform, const std::string type ) -{ - char dat[1024]; - sprintf( dat, "%s/%02x%02x%02x.%s.%s", folder.c_str(), cat, exNum, chunk, platform.c_str(), type.c_str() ); - return std::string( dat ); -} + const std::string GameData::buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, + const std::string platform, const std::string type ) + { + char dat[1024]; + sprintf( dat, "%s/%02x%02x%02x.%s.%s", folder.c_str(), cat, exNum, chunk, platform.c_str(), type.c_str() ); + return std::string( dat ); + } -const std::vector& GameData::getCatNumbers() const -{ + const std::vector< uint32_t >& GameData::getCatNumbers() const + { return m_catNums; -} + } -std::unique_ptr GameData::getFile(const std::string& path) -{ - // Get the hashes, the category from the path then call the getFile of the category - uint32_t dirHash; - uint32_t filenameHash; - getHashes( path, dirHash, filenameHash ); + std::unique_ptr< File > GameData::getFile( const std::string& path ) + { + // Get the hashes, the category from the path then call the getFile of the category + uint32_t dirHash; + uint32_t filenameHash; + getHashes( path, dirHash, filenameHash ); - return getCategoryFromPath( path ).getFile( dirHash, filenameHash ); -} + return getCategoryFromPath( path ).getFile( dirHash, filenameHash ); + } -bool GameData::doesFileExist(const std::string& path) -{ - uint32_t dirHash; - uint32_t filenameHash; - getHashes( path, dirHash, filenameHash ); + bool GameData::doesFileExist( const std::string& path ) + { + uint32_t dirHash; + uint32_t filenameHash; + getHashes( path, dirHash, filenameHash ); - return getCategoryFromPath( path ).doesFileExist( dirHash, filenameHash ); -} + return getCategoryFromPath( path ).doesFileExist( dirHash, filenameHash ); + } -bool GameData::doesDirExist(const std::string& i_path) -{ - uint32_t dirHash; - uint32_t filenameHash; - getHashes( i_path, dirHash, filenameHash ); + bool GameData::doesDirExist( const std::string& i_path ) + { + uint32_t dirHash; + uint32_t filenameHash; + getHashes( i_path, dirHash, filenameHash ); - return getCategoryFromPath( i_path ).doesDirExist( dirHash ); -} + return getCategoryFromPath( i_path ).doesDirExist( dirHash ); + } -const Cat& GameData::getCategory(uint32_t catNum) -{ - // Check that the category number exists - auto catIt = m_cats.find( catNum ); - if( catIt == m_cats.end() ) - { + const Cat& GameData::getCategory( uint32_t catNum ) + { + // Check that the category number exists + auto catIt = m_cats.find( catNum ); + if( catIt == m_cats.end() ) + { throw std::runtime_error( "Category not found: " + std::to_string( catNum ) ); - } + } - // If it exists and already instantiated return it - if( catIt->second ) - { + // If it exists and already instantiated return it + if( catIt->second ) + { return *( catIt->second ); - } - else - { + } + else + { // Else create it and return it createCategory( catNum ); - return *( m_cats[catNum] ); - } -} + return *( m_cats[ catNum ] ); + } + } -const Cat& GameData::getCategory(const std::string& catName) -{ - // Find the category number from the name - auto categoryNameToIdMapIt = ::categoryNameToIdMap.find( catName ); - if( categoryNameToIdMapIt == ::categoryNameToIdMap.end() ) - { + const Cat& GameData::getCategory( const std::string& catName ) + { + // Find the category number from the name + auto categoryNameToIdMapIt = ::categoryNameToIdMap.find( catName ); + if( categoryNameToIdMapIt == ::categoryNameToIdMap.end() ) + { throw std::runtime_error( "Category not found: " + catName ); - } + } - // From the category number return the category - return getCategory( categoryNameToIdMapIt->second ); -} + // From the category number return the category + return getCategory( categoryNameToIdMapIt->second ); + } -const Cat& GameData::getExCategory( const std::string& catName, uint32_t exNum, const std::string& path ) -{ - // Find the category number from the name - auto categoryMapIt = ::categoryNameToIdMap.find( catName ); - if( categoryMapIt == ::categoryNameToIdMap.end() ) - { + const Cat& GameData::getExCategory( const std::string& catName, uint32_t exNum, const std::string& path ) + { + // Find the category number from the name + auto categoryMapIt = ::categoryNameToIdMap.find( catName ); + if( categoryMapIt == ::categoryNameToIdMap.end() ) + { throw std::runtime_error( "Category not found: " + catName ); - } + } - uint32_t dirHash; - uint32_t filenameHash; - getHashes( path, dirHash, filenameHash ); + uint32_t dirHash; + uint32_t filenameHash; + getHashes( path, dirHash, filenameHash ); - for( auto const& chunk : m_exCats[categoryMapIt->second].exNumToChunkMap[exNum].chunkToCatMap ) - { + for( auto const& chunk : m_exCats[ categoryMapIt->second ].exNumToChunkMap[ exNum ].chunkToCatMap ) + { if( !chunk.second ) - createExCategory( categoryMapIt->second ); + createExCategory( categoryMapIt->second ); if( chunk.second->doesFileExist( dirHash, filenameHash ) ) { - return *( chunk.second ); + return *( chunk.second ); } - } + } - throw std::runtime_error( "Chunk not found for path: " + path ); -} + throw std::runtime_error( "Chunk not found for path: " + path ); + } -const Cat& GameData::getCategoryFromPath(const std::string& path) -{ - // Find the first / in the string, paths are in the format CAT_NAME/..../.../../.... - auto firstSlashPos = path.find( '/' ); - if( firstSlashPos == std::string::npos ) - { + const Cat& GameData::getCategoryFromPath( const std::string& path ) + { + // Find the first / in the string, paths are in the format CAT_NAME/..../.../../.... + auto firstSlashPos = path.find( '/' ); + if( firstSlashPos == std::string::npos ) + { throw std::runtime_error( "Path does not have a / char: " + path ); - } + } - if( path.substr( firstSlashPos + 1, 2) == "ex" ) - { + if( path.substr( firstSlashPos + 1, 2 ) == "ex" ) + { return getExCategory( path.substr( 0, firstSlashPos ), std::stoi( path.substr( firstSlashPos + 3, 1 ) ), path ); - } - else - { + } + else + { // From the sub string found beforethe first / get the category return getCategory( path.substr( 0, firstSlashPos ) ); - } -} + } + } -void GameData::getHashes(const std::string& path, uint32_t& dirHash, uint32_t& filenameHash) const -{ - // Convert the path to lowercase before getting the hashes - std::string pathLower; - pathLower.resize( path.size() ); - std::transform( path.begin(), path.end(), pathLower.begin(), ::tolower ); + void GameData::getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const + { + // Convert the path to lowercase before getting the hashes + std::string pathLower; + pathLower.resize( path.size() ); + std::transform( path.begin(), path.end(), pathLower.begin(), ::tolower ); - // Find last / to separate dir from filename - auto lastSlashPos = pathLower.rfind( '/' ); - if( lastSlashPos == std::string::npos ) - { + // Find last / to separate dir from filename + auto lastSlashPos = pathLower.rfind( '/' ); + if( lastSlashPos == std::string::npos ) + { throw std::runtime_error( "Path does not have a / char: " + path ); - } + } - std::string dirPart = pathLower.substr( 0, lastSlashPos ); - std::string filenamePart = pathLower.substr( lastSlashPos + 1 ); + std::string dirPart = pathLower.substr( 0, lastSlashPos ); + std::string filenamePart = pathLower.substr( lastSlashPos + 1 ); - // Get the crc32 values from zlib, to compensate the final XOR 0xFFFFFFFF that isnot done in the exe we just reXOR - dirHash = crc32( 0, reinterpret_cast( dirPart.data() ), dirPart.size() ) ^ 0xFFFFFFFF; - filenameHash = crc32( 0, reinterpret_cast( filenamePart.data() ), filenamePart.size() ) ^ 0xFFFFFFFF; -} + // Get the crc32 values from zlib, to compensate the final XOR 0xFFFFFFFF that isnot done in the exe we just reXOR + dirHash = crc32( 0, reinterpret_cast( dirPart.data() ), dirPart.size() ) ^ 0xFFFFFFFF; + filenameHash = crc32( 0, reinterpret_cast( filenamePart.data() ), filenamePart.size() ) ^ 0xFFFFFFFF; + } -void GameData::createCategory(uint32_t catNum) -{ - // Lock mutex in this scope - std::lock_guard lock( *( m_catCreationMutexes[catNum] ) ); - // Maybe after unlocking it has already been created, so check (most likely if it blocked) - if( !m_cats[catNum] ) - { + void GameData::createCategory( uint32_t catNum ) + { + // Lock mutex in this scope + std::lock_guard< std::mutex > lock( *( m_catCreationMutexes[ catNum ] ) ); + // Maybe after unlocking it has already been created, so check (most likely if it blocked) + if( !m_cats[ catNum ] ) + { // Get the category name if we have it std::string catName; auto categoryMapIt = ::categoryIdToNameMap.find( catNum ); if( categoryMapIt != ::categoryIdToNameMap.end() ) { - catName = categoryMapIt->second; + catName = categoryMapIt->second; } // Actually creates the category - m_cats[catNum] = std::unique_ptr( new Cat( m_path, catNum, catName ) ); - } -} + m_cats[ catNum ] = std::make_unique< Cat >( m_path, catNum, catName ); + } + } -void GameData::createExCategory( uint32_t catNum ) -{ - // Maybe after unlocking it has already been created, so check (most likely if it blocked) - if( !m_exCats[catNum].exNumToChunkMap[1].chunkToCatMap[0] ) - { + void GameData::createExCategory( uint32_t catNum ) + { + // Maybe after unlocking it has already been created, so check (most likely if it blocked) + if( !m_exCats[ catNum ].exNumToChunkMap[ 1 ].chunkToCatMap[ 0 ] ) + { // Get the category name if we have it std::string catName; auto categoryMapIt = ::categoryIdToNameMap.find( catNum ); if( categoryMapIt != ::categoryIdToNameMap.end() ) { - catName = categoryMapIt->second; + catName = categoryMapIt->second; } - for( auto const& ex : m_exCats[catNum].exNumToChunkMap ) + for( auto const& ex : m_exCats[ catNum ].exNumToChunkMap ) { - for( auto const& chunk : m_exCats[catNum].exNumToChunkMap[ex.first].chunkToCatMap ) - { - // Actually creates the category - m_exCats[catNum].exNumToChunkMap[ex.first].chunkToCatMap[chunk.first] = std::unique_ptr( new Cat( m_path, catNum, catName, ex.first, chunk.first ) ); - } + for( auto const& chunk : m_exCats[ catNum ].exNumToChunkMap[ ex.first ].chunkToCatMap ) + { + // Actually creates the category + m_exCats[ catNum ].exNumToChunkMap[ ex.first ].chunkToCatMap[ chunk.first ] = std::unique_ptr< Cat >( + new Cat( m_path, catNum, catName, ex.first, chunk.first ) ); + } } - } -} + } + } } -} diff --git a/deps/datReader/GameData.h b/deps/datReader/GameData.h index d44c9ac8..53b7f021 100644 --- a/deps/datReader/GameData.h +++ b/deps/datReader/GameData.h @@ -7,78 +7,86 @@ #include -namespace xiv -{ -namespace dat +namespace xiv::dat { -class Cat; -class File; + class Cat; -// Interface to all the datfiles - Main entry point -// All the paths to files/dirs inside the dats are case-insensitive -class GameData -{ -public: - // This should be the path in which the .index/.datX files are located - GameData( const std::filesystem::path& path ); - ~GameData(); + class File; - static const std::string buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, const std::string platform, const std::string type ); + // Interface to all the datfiles - Main entry point + // All the paths to files/dirs inside the dats are case-insensitive + class GameData + { + public: + // This should be the path in which the .index/.datX files are located + GameData( const std::filesystem::path& path ); - // Returns all the scanned category number available in the path - const std::vector& getCatNumbers() const; + ~GameData(); - // Return a specific category by its number (see getCatNumbers() for loops) - const Cat& getCategory( uint32_t catNum ); - // Return a specific category by it's name (e.g.: "exd"/"game_script"/ etc...) - const Cat& getCategory( const std::string& catName ); + static const std::string + buildDatStr( const std::string folder, const int cat, const int exNum, const int chunk, const std::string platform, + const std::string type ); - const Cat& getExCategory( const std::string& catName, uint32_t exNum, const std::string& path ); + // Returns all the scanned category number available in the path + const std::vector< uint32_t >& getCatNumbers() const; - // Retrieve a file from the dats given its filename - std::unique_ptr getFile( const std::string& path ); + // Return a specific category by its number (see getCatNumbers() for loops) + const Cat& getCategory( uint32_t catNum ); - // Checks that a file exists - bool doesFileExist( const std::string& path ); + // Return a specific category by it's name (e.g.: "exd"/"game_script"/ etc...) + const Cat& getCategory( const std::string& catName ); - // Checks that a dir exists, there must be a trailing / in the path - // Note that it won't work for dirs that don't contain any file - // e.g.: - "ui/icon/" will return False - // - "ui/icon/000000/" will return True - bool doesDirExist( const std::string& path ); + const Cat& getExCategory( const std::string& catName, uint32_t exNum, const std::string& path ); -protected: - // Return a specific category given a path (calls const Cat& getCategory(const std::string& catName)) - const Cat& getCategoryFromPath( const std::string& path ); + // Retrieve a file from the dats given its filename + std::unique_ptr< File > getFile( const std::string& path ); - // From a full path, returns the dirHash and the filenameHash - void getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const; + // Checks that a file exists + bool doesFileExist( const std::string& path ); - // Lazy instantiation of category - void createCategory( uint32_t catNum ); + // Checks that a dir exists, there must be a trailing / in the path + // Note that it won't work for dirs that don't contain any file + // e.g.: - "ui/icon/" will return False + // - "ui/icon/000000/" will return True + bool doesDirExist( const std::string& path ); - void createExCategory( uint32_t catNum ); + protected: + // Return a specific category given a path (calls const Cat& getCategory(const std::string& catName)) + const Cat& getCategoryFromPath( const std::string& path ); - // Path given to constructor, pointing to the folder with the .index/.datX files - const std::filesystem::path m_path; + // From a full path, returns the dirHash and the filenameHash + void getHashes( const std::string& path, uint32_t& dirHash, uint32_t& filenameHash ) const; - // Stored categories, indexed by their number, categories are instantiated and parsed individually when they are needed - std::unordered_map> m_cats; + // Lazy instantiation of category + void createCategory( uint32_t catNum ); - // List of all the categories numbers, is equal to m_cats.keys() - std::vector m_catNums; + void createExCategory( uint32_t catNum ); - // Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))" - // Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))" - using ChunkToCatMap = struct { std::unordered_map< uint32_t, std::unique_ptr< Cat > > chunkToCatMap; }; - using ExNumToChunkMap = struct { std::unordered_map< uint32_t, ChunkToCatMap > exNumToChunkMap; }; - using CatNumToExNumMap = std::unordered_map< uint32_t, ExNumToChunkMap >; - CatNumToExNumMap m_exCats; - std::unordered_map> m_catCreationMutexes; -}; + // Path given to constructor, pointing to the folder with the .index/.datX files + const std::filesystem::path m_path; + + // Stored categories, indexed by their number, categories are instantiated and parsed individually when they are needed + std::unordered_map< uint32_t, std::unique_ptr< Cat>> m_cats; + + // List of all the categories numbers, is equal to m_cats.keys() + std::vector< uint32_t > m_catNums; + + // Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))" + // Map of all EX categories and their chunks, "CatNum - (ExNum - (ChunkNum - Cat))" + using ChunkToCatMap = struct + { + std::unordered_map< uint32_t, std::unique_ptr< Cat > > chunkToCatMap; + }; + using ExNumToChunkMap = struct + { + std::unordered_map< uint32_t, ChunkToCatMap > exNumToChunkMap; + }; + using CatNumToExNumMap = std::unordered_map< uint32_t, ExNumToChunkMap >; + CatNumToExNumMap m_exCats; + std::unordered_map< uint32_t, std::unique_ptr< std::mutex>> m_catCreationMutexes; + }; -} } #endif // XIV_DAT_GAMEDATA_H diff --git a/deps/datReader/Index.cpp b/deps/datReader/Index.cpp index 3ff7d365..d46b20c6 100644 --- a/deps/datReader/Index.cpp +++ b/deps/datReader/Index.cpp @@ -2,166 +2,154 @@ #include "bparse.h" -namespace xiv +namespace xiv::dat { -namespace dat -{ - struct IndexBlockRecord - { - uint32_t offset; - uint32_t size; - SqPackBlockHash blockHash; - }; + struct IndexBlockRecord + { + uint32_t offset; + uint32_t size; + SqPackBlockHash blockHash; + }; - struct IndexHashTableEntry - { - uint32_t filenameHash; - uint32_t dirHash; - uint32_t datOffset; - uint32_t padding; - }; -} + struct IndexHashTableEntry + { + uint32_t filenameHash; + uint32_t dirHash; + uint32_t datOffset; + uint32_t padding; + }; } -namespace xiv +namespace xiv::utils::bparse { -namespace utils -{ -namespace bparse -{ - template <> - inline void reorder(xiv::dat::IndexBlockRecord& i_struct) - { - xiv::utils::bparse::reorder(i_struct.offset); - xiv::utils::bparse::reorder(i_struct.size); - xiv::utils::bparse::reorder(i_struct.blockHash); - } + template<> + inline void reorder< xiv::dat::IndexBlockRecord >( xiv::dat::IndexBlockRecord& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.size ); + xiv::utils::bparse::reorder( i_struct.blockHash ); + } - template <> - inline void reorder(xiv::dat::IndexHashTableEntry& i_struct) - { - xiv::utils::bparse::reorder(i_struct.filenameHash); - xiv::utils::bparse::reorder(i_struct.dirHash); - xiv::utils::bparse::reorder(i_struct.datOffset); - xiv::utils::bparse::reorder(i_struct.padding); - } + template<> + inline void reorder< xiv::dat::IndexHashTableEntry >( xiv::dat::IndexHashTableEntry& i_struct ) + { + xiv::utils::bparse::reorder( i_struct.filenameHash ); + xiv::utils::bparse::reorder( i_struct.dirHash ); + xiv::utils::bparse::reorder( i_struct.datOffset ); + xiv::utils::bparse::reorder( i_struct.padding ); + } } -} -}; using xiv::utils::bparse::extract; -namespace xiv -{ -namespace dat +namespace xiv::dat { -Index::Index(const std::filesystem::path& path) : - SqPack( path ) -{ - if( !m_handle ) + Index::Index( const std::filesystem::path& path ) : + SqPack( path ) + { + if( !m_handle ) throw new std::runtime_error( "Failed to load Index at " + path.string() ); - // Hash Table record - auto hashTableBlockRecord = extract( m_handle ); - isIndexBlockValid( hashTableBlockRecord ); + // Hash Table record + auto hashTableBlockRecord = extract< IndexBlockRecord >( m_handle ); + isIndexBlockValid( hashTableBlockRecord ); - // Save the posin the stream to go back to it later on - auto pos = m_handle.tellg(); + // Save the posin the stream to go back to it later on + auto pos = m_handle.tellg(); - // Seek to the pos of the hash table in the file - m_handle.seekg( hashTableBlockRecord.offset ); + // Seek to the pos of the hash table in the file + m_handle.seekg( hashTableBlockRecord.offset ); - // Preallocate and extract the index_hash_table_entries - std::vector indexHashTableEntries; - extract( m_handle, hashTableBlockRecord.size / sizeof( IndexHashTableEntry ), - indexHashTableEntries ); + // Preallocate and extract the index_hash_table_entries + std::vector< IndexHashTableEntry > indexHashTableEntries; + extract< IndexHashTableEntry >( m_handle, hashTableBlockRecord.size / sizeof( IndexHashTableEntry ), + indexHashTableEntries ); - // Feed the correct entry in the HashTable for each index_hash_table_entry - for( auto& indexHashTableEntry : indexHashTableEntries ) - { - auto& hashTableEntry = m_hashTable[indexHashTableEntry.dirHash][indexHashTableEntry.filenameHash]; + // Feed the correct entry in the HashTable for each index_hash_table_entry + for( auto& indexHashTableEntry : indexHashTableEntries ) + { + auto& hashTableEntry = m_hashTable[ indexHashTableEntry.dirHash ][ indexHashTableEntry.filenameHash ]; // The dat number is found in the offset, last four bits hashTableEntry.datNum = ( indexHashTableEntry.datOffset & 0xF ) / 0x2; // The offset in the dat file, needs to strip the dat number indicator hashTableEntry.datOffset = ( indexHashTableEntry.datOffset - ( indexHashTableEntry.datOffset & 0x000F ) ) * 0x08; hashTableEntry.dirHash = indexHashTableEntry.dirHash; hashTableEntry.filenameHash = indexHashTableEntry.filenameHash; - } + } - // Come back to where we were before reading the HashTable - m_handle.seekg( pos ); + // Come back to where we were before reading the HashTable + m_handle.seekg( pos ); - // Dat Count - m_datCount = extract( m_handle, "dat_count" ); + // Dat Count + m_datCount = extract< uint32_t >( m_handle, "dat_count" ); - // Free List - isIndexBlockValid( extract( m_handle ) ); + // Free List + isIndexBlockValid( extract< IndexBlockRecord >( m_handle ) ); - // Dir Hash Table - isIndexBlockValid( extract( m_handle ) ); -} + // Dir Hash Table + isIndexBlockValid( extract< IndexBlockRecord >( m_handle ) ); + } -Index::~Index() -{ -} + Index::~Index() + { + } -uint32_t Index::getDatCount() const -{ - return m_datCount; -} + uint32_t Index::getDatCount() const + { + return m_datCount; + } -const Index::HashTable& Index::getHashTable() const -{ - return m_hashTable; -} + const Index::HashTable& Index::getHashTable() const + { + return m_hashTable; + } -bool Index::doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const -{ - auto dir_it = getHashTable().find( dir_hash ); - if( dir_it != getHashTable().end() ) - { + bool Index::doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const + { + auto dir_it = getHashTable().find( dir_hash ); + if( dir_it != getHashTable().end() ) + { return ( dir_it->second.find( filename_hash ) != dir_it->second.end() ); - } - return false; -} + } + return false; + } -bool Index::doesDirExist( uint32_t dir_hash ) const -{ - return ( getHashTable().find( dir_hash ) != getHashTable().end() ); -} + bool Index::doesDirExist( uint32_t dir_hash ) const + { + return ( getHashTable().find( dir_hash ) != getHashTable().end() ); + } -const Index::DirHashTable& Index::getDirHashTable( uint32_t dir_hash ) const -{ - auto dir_it = getHashTable().find( dir_hash ); - if( dir_it == getHashTable().end() ) - { + const Index::DirHashTable& Index::getDirHashTable( uint32_t dir_hash ) const + { + auto dir_it = getHashTable().find( dir_hash ); + if( dir_it == getHashTable().end() ) + { throw std::runtime_error( "dirHash not found" ); - } - else - { + } + else + { return dir_it->second; - } -} + } + } -const Index::HashTableEntry& Index::getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const -{ - auto& dirHashTable = getDirHashTable( dir_hash ); - auto file_it = dirHashTable.find( filename_hash ); - if( file_it == dirHashTable.end() ) - { + const Index::HashTableEntry& Index::getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const + { + auto& dirHashTable = getDirHashTable( dir_hash ); + auto file_it = dirHashTable.find( filename_hash ); + if( file_it == dirHashTable.end() ) + { throw std::runtime_error( "filenameHash not found" ); - } - else - { + } + else + { return file_it->second; - } -} + } + } -void Index::isIndexBlockValid( const IndexBlockRecord& i_index_block_record ) -{ - isBlockValid( i_index_block_record.offset, i_index_block_record.size, i_index_block_record.blockHash ); -} + void Index::isIndexBlockValid( const IndexBlockRecord& i_index_block_record ) + { + isBlockValid( i_index_block_record.offset, i_index_block_record.size, i_index_block_record.blockHash ); + } } -} diff --git a/deps/datReader/Index.h b/deps/datReader/Index.h index b7999ad5..d98b96a6 100644 --- a/deps/datReader/Index.h +++ b/deps/datReader/Index.h @@ -7,53 +7,57 @@ #include -namespace xiv { -namespace dat { - -struct IndexBlockRecord; - -class Index : public SqPack +namespace xiv::dat { -public: - // Full path to the index file - Index( const std::filesystem::path& i_path ); - virtual ~Index(); - // An entry in the hash table, representing a file in a given dat - struct HashTableEntry - { + struct IndexBlockRecord; + + class Index : + public SqPack + { + public: + // Full path to the index file + Index( const std::filesystem::path& i_path ); + + virtual ~Index(); + + // An entry in the hash table, representing a file in a given dat + struct HashTableEntry + { uint32_t datNum; uint32_t dirHash; uint32_t filenameHash; uint32_t datOffset; - }; + }; - // HashTable has dir hashes -> filename hashes -> HashTableEntry - using DirHashTable = std::unordered_map< uint32_t, HashTableEntry >; - using HashTable = std::unordered_map< uint32_t, DirHashTable >; + // HashTable has dir hashes -> filename hashes -> HashTableEntry + using DirHashTable = std::unordered_map< uint32_t, HashTableEntry >; + using HashTable = std::unordered_map< uint32_t, DirHashTable >; - // Get the number of dat files the index is linked to - uint32_t getDatCount() const; + // Get the number of dat files the index is linked to + uint32_t getDatCount() const; - bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const; - bool doesDirExist( uint32_t dir_hash ) const; + bool doesFileExist( uint32_t dir_hash, uint32_t filename_hash ) const; - // Returns the whole HashTable - const HashTable& getHashTable() const; - // Returns the hash table for a specific dir - const DirHashTable& getDirHashTable( uint32_t dir_hash ) const; - // Returns the HashTableEntry for a given file given its hashes - const HashTableEntry& getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const; + bool doesDirExist( uint32_t dir_hash ) const; -protected: - // Checks that the block is valid with regards to its hash - void isIndexBlockValid( const IndexBlockRecord& i_index_block_record ); + // Returns the whole HashTable + const HashTable& getHashTable() const; - uint32_t m_datCount; - HashTable m_hashTable; -}; + // Returns the hash table for a specific dir + const DirHashTable& getDirHashTable( uint32_t dir_hash ) const; + + // Returns the HashTableEntry for a given file given its hashes + const HashTableEntry& getHashTableEntry( uint32_t dir_hash, uint32_t filename_hash ) const; + + protected: + // Checks that the block is valid with regards to its hash + void isIndexBlockValid( const IndexBlockRecord& i_index_block_record ); + + uint32_t m_datCount; + HashTable m_hashTable; + }; -} } #endif // XIV_DAT_INDEX_H diff --git a/deps/datReader/SqPack.cpp b/deps/datReader/SqPack.cpp index 4885cdf1..fb8c244a 100644 --- a/deps/datReader/SqPack.cpp +++ b/deps/datReader/SqPack.cpp @@ -54,12 +54,12 @@ using xiv::utils::bparse::extract; namespace xiv::dat { - // Open the file - SqPack::SqPack( const std::filesystem::path& path ) : - m_handle( path.string(), std::ios_base::in | std::ios_base::binary ) - { - // Extract the header - extract( m_handle ); + // Open the file + SqPack::SqPack( const std::filesystem::path& path ) : + m_handle( path.string(), std::ios_base::in | std::ios_base::binary ) + { + // Extract the header + extract< SqPackHeader >( m_handle ); // Skip until the IndexHeader the extract it m_handle.seekg( 0x400 ); diff --git a/deps/datReader/SqPack.h b/deps/datReader/SqPack.h index 5fcb1c36..4c6e34c4 100644 --- a/deps/datReader/SqPack.h +++ b/deps/datReader/SqPack.h @@ -8,59 +8,51 @@ #include "bparse.h" -namespace xiv +namespace xiv::dat { - namespace dat - { - - struct SqPackBlockHash - { - uint8_t hash[0x14]; - uint32_t padding[0xB]; - }; - - } + struct SqPackBlockHash + { + uint8_t hash[0x14]; + uint32_t padding[0xB]; + }; } -namespace xiv { - namespace utils { - namespace bparse { - template <> inline void reorder( xiv::dat::SqPackBlockHash& i_struct ) - { - for( auto i = 0; i < 0x14; ++i ) - { - xiv::utils::bparse::reorder( i_struct.hash[i] ); - } - for( auto i = 0; i < 0xB; ++i ) - { - xiv::utils::bparse::reorder( i_struct.padding[i] ); - } - } - } - } + +namespace xiv::utils::bparse +{ + template<> + inline void reorder< xiv::dat::SqPackBlockHash >( xiv::dat::SqPackBlockHash& i_struct ) + { + for( auto i = 0; i < 0x14; ++i ) + { + xiv::utils::bparse::reorder( i_struct.hash[ i ] ); + } + for( auto i = 0; i < 0xB; ++i ) + { + xiv::utils::bparse::reorder( i_struct.padding[ i ] ); + } + } }; -namespace xiv -{ -namespace dat +namespace xiv::dat { -class SqPack -{ + class SqPack + { -public: - // Full path to the sqpack file - SqPack( const std::filesystem::path& i_path ); - virtual ~SqPack(); + public: + // Full path to the sqpack file + SqPack( const std::filesystem::path& i_path ); -protected: - // Checks that a given block is valid iven its hash - void isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash ); + virtual ~SqPack(); - // File handle - std::ifstream m_handle; - }; + protected: + // Checks that a given block is valid iven its hash + void isBlockValid( uint32_t i_offset, uint32_t i_size, const SqPackBlockHash& i_block_hash ); + + // File handle + std::ifstream m_handle; + }; -} } #endif // XIV_DAT_SQPACK_H diff --git a/deps/datReader/bparse.h b/deps/datReader/bparse.h index f26d2faa..e3fd13f6 100644 --- a/deps/datReader/bparse.h +++ b/deps/datReader/bparse.h @@ -6,98 +6,96 @@ #include #include -namespace xiv -{ -namespace utils -{ -namespace bparse +namespace xiv::utils::bparse { -// Internal macro for byteswapping -template -void byteswap_impl(char (&bytes)[N]) -{ - for( auto p = std::begin( bytes ), end = std::end( bytes ) - 1; p < end; ++p, --end ) - { + // Internal macro for byteswapping + template< int N > + void byteswap_impl( char (& bytes)[N] ) + { + for( auto p = std::begin( bytes ), end = std::end( bytes ) - 1; p < end; ++p, --end ) + { std::swap( *p, *end ); - } -} + } + } -// byteswapping any type (no pointers to array) -template -T byteswap(T value) -{ - byteswap_impl(*reinterpret_cast(&value)); + // byteswapping any type (no pointers to array) + template< typename T > + T byteswap( T value ) + { + byteswap_impl( *reinterpret_cast(&value) ); return value; -} + } -// Read a struct from a stream -template -void read(std::istream& i_stream, StructType& i_struct) -{ - static_assert( std::is_pod::value, "StructType must be a POD to be able to use read." ); - i_stream.read( reinterpret_cast( &i_struct ), sizeof( StructType ) ); -} + // Read a struct from a stream + template< typename StructType > + void read( std::istream& i_stream, StructType& i_struct ) + { + static_assert( std::is_pod< StructType >::value, "StructType must be a POD to be able to use read." ); + i_stream.read( reinterpret_cast( &i_struct ), sizeof( StructType ) ); + } -// By default a type does not need reordering -template void reorder(StructType& i_struct) {} + // By default a type does not need reordering + template< typename StructType > + void reorder( StructType& i_struct ) + { + } -// "Overload" for passed struct as arg -template -void extract(std::istream& i_stream, StructType& o_struct) -{ - read( i_stream, o_struct ); - reorder( o_struct ); -} + // "Overload" for passed struct as arg + template< typename StructType > + void extract( std::istream& i_stream, StructType& o_struct ) + { + read( i_stream, o_struct ); + reorder( o_struct ); + } -// This should not copy because of RVO -// Extract a struct from a stream and log it -template -StructType extract( std::istream& i_stream ) -{ - StructType temp_struct; - extract( i_stream, temp_struct ); - return temp_struct; -} + // This should not copy because of RVO + // Extract a struct from a stream and log it + template< typename StructType > + StructType extract( std::istream& i_stream ) + { + StructType temp_struct; + extract< StructType >( i_stream, temp_struct ); + return temp_struct; + } -template -void extract(std::istream& i_stream, uint32_t i_size, std::vector& o_structs ) -{ - o_structs.reserve( i_size ); - for( uint32_t i = 0; i < i_size; ++i ) - { - o_structs.emplace_back( extract( i_stream ) ); - } -} + template< typename StructType > + void extract( std::istream& i_stream, uint32_t i_size, std::vector< StructType >& o_structs ) + { + o_structs.reserve( i_size ); + for( uint32_t i = 0; i < i_size; ++i ) + { + o_structs.emplace_back( extract< StructType >( i_stream ) ); + } + } -// For simple (integral) types just provide name and endianness directly -template -StructType extract(std::istream& i_stream, const std::string& i_name, bool i_is_le = true) -{ - StructType temp_struct; - read( i_stream, temp_struct ); - if( !i_is_le ) - { + // For simple (integral) types just provide name and endianness directly + template< typename StructType > + StructType extract( std::istream& i_stream, const std::string& i_name, bool i_is_le = true ) + { + StructType temp_struct; + read( i_stream, temp_struct ); + if( !i_is_le ) + { temp_struct = byteswap( temp_struct ); - } - return temp_struct; -} + } + return temp_struct; + } -template -void extract(std::istream& i_stream, const std::string& i_name, uint32_t i_size, std::vector& o_structs, bool i_is_le = true) -{ - o_structs.reserve( i_size ); - for( uint32_t i = 0; i < i_size; ++i ) - { - o_structs.emplace_back( extract( i_stream, i_name ) ); - } -} + template< typename StructType > + void extract( std::istream& i_stream, const std::string& i_name, uint32_t i_size, std::vector< StructType >& o_structs, + bool i_is_le = true ) + { + o_structs.reserve( i_size ); + for( uint32_t i = 0; i < i_size; ++i ) + { + o_structs.emplace_back( extract< StructType >( i_stream, i_name ) ); + } + } -// For cstrings -std::string extract_cstring( std::istream& i_stream, const std::string& i_name ); + // For cstrings + std::string extract_cstring( std::istream& i_stream, const std::string& i_name ); -} -} } #endif // XIV_UTILS_BPARSE_H diff --git a/deps/datReader/conv.cpp b/deps/datReader/conv.cpp index 40b94080..b591045b 100644 --- a/deps/datReader/conv.cpp +++ b/deps/datReader/conv.cpp @@ -1,8 +1,8 @@ #include "conv.h" -namespace xiv { -namespace utils { -namespace conv { +namespace xiv::utils::conv +{ + float half2float( const uint16_t i_value ) { uint32_t t1; @@ -30,6 +30,4 @@ namespace conv { } } -} -} diff --git a/deps/datReader/conv.h b/deps/datReader/conv.h index c0a4529b..b8f3326f 100644 --- a/deps/datReader/conv.h +++ b/deps/datReader/conv.h @@ -5,13 +5,11 @@ #include #include -namespace xiv { -namespace utils { -namespace conv { +namespace xiv::utils::conv +{ float half2float( const uint16_t i_value ); + float ubyte2float( const uint8_t i_value ); } -} -} #endif // XIV_UTILS_CONV_H diff --git a/deps/datReader/crc32.cpp b/deps/datReader/crc32.cpp index 7b9490d9..c861cebc 100644 --- a/deps/datReader/crc32.cpp +++ b/deps/datReader/crc32.cpp @@ -65,116 +65,111 @@ namespace internal } } -namespace xiv -{ -namespace utils -{ -namespace crc32 +namespace xiv::utils::crc32 { -uint32_t compute(const std::string& i_input, uint32_t init_crc) -{ + uint32_t compute( const std::string& i_input, uint32_t init_crc ) + { // Classical crc stuff - auto& crc_table = internal::get_crc_table(); + auto& crc_table = internal::get_crc_table(); auto crc = init_crc; - for(std::size_t i = 0; i < i_input.size(); ++i) + for( std::size_t i = 0; i < i_input.size(); ++i ) { - crc = crc_table[(crc ^ i_input[i]) & 0xFF] ^ (crc >> 8); + crc = crc_table[ ( crc ^ i_input[ i ] ) & 0xFF ] ^ ( crc >> 8 ); } return crc; -} + } -uint32_t rev_compute(const std::string& i_input, uint32_t init_crc) -{ - auto& rev_crc_table = internal::get_rev_crc_table(); + uint32_t rev_compute( const std::string& i_input, uint32_t init_crc ) + { + auto& rev_crc_table = internal::get_rev_crc_table(); auto crc = init_crc; const auto input_size = i_input.size(); // Reverse crc - for(auto i = input_size; i > 0; --i) + for( auto i = input_size; i > 0; --i ) { - crc = rev_crc_table[crc >> 24] ^ ((crc << 8) & 0xFFFFFF00) ^ i_input[input_size - i - 1]; + crc = rev_crc_table[ crc >> 24 ] ^ ( ( crc << 8 ) & 0xFFFFFF00 ) ^ i_input[ input_size - i - 1 ]; } // Compute the 4 bytes needed for this init_crc - for (auto i = 0; i < 4; ++i) + for( auto i = 0; i < 4; ++i ) { - crc = rev_crc_table[crc >> 24] ^ ((crc << 8) & 0xFFFFFF00); + crc = rev_crc_table[ crc >> 24 ] ^ ( ( crc << 8 ) & 0xFFFFFF00 ); } return crc; -} + } -void generate_hashes_1(std::string& i_format, const uint32_t i_first_index, std::vector& o_hashes) -{ - char* str = const_cast(i_format.data()); - const uint32_t str_size = i_format.size(); + void generate_hashes_1( std::string& i_format, const uint32_t i_first_index, std::vector< uint32_t >& o_hashes ) + { + char* str = const_cast(i_format.data()); + const uint32_t str_size = i_format.size(); - o_hashes.resize(10000); + o_hashes.resize( 10000 ); - uint32_t i = 0; - for (char a = '0'; a <= '9'; ++a) - { - str[i_first_index] = a; - for (char b = '0'; b <= '9'; ++b) - { - str[i_first_index + 1] = b; - for (char c = '0'; c <= '9'; ++c) - { - str[i_first_index + 2] = c; - for (char d = '0'; d <= '9'; ++d) - { - str[i_first_index + 3] = d; - o_hashes[i] = ::crc32(0, reinterpret_cast(&(str[0])), str_size) ^ 0xFFFFFFFF; - ++i; - } - } - } - } -} + uint32_t i = 0; + for( char a = '0'; a <= '9'; ++a ) + { + str[ i_first_index ] = a; + for( char b = '0'; b <= '9'; ++b ) + { + str[ i_first_index + 1 ] = b; + for( char c = '0'; c <= '9'; ++c ) + { + str[ i_first_index + 2 ] = c; + for( char d = '0'; d <= '9'; ++d ) + { + str[ i_first_index + 3 ] = d; + o_hashes[ i ] = ::crc32( 0, reinterpret_cast(&( str[ 0 ] )), str_size ) ^ 0xFFFFFFFF; + ++i; + } + } + } + } + } -void generate_hashes_2(std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index, std::vector& o_hashes) -{ - char* str = const_cast(i_format.data()); - const uint32_t str_size = i_format.size(); + void generate_hashes_2( std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index, + std::vector< uint32_t >& o_hashes ) + { + char* str = const_cast(i_format.data()); + const uint32_t str_size = i_format.size(); - o_hashes.resize(100000000); + o_hashes.resize( 100000000 ); - uint32_t i = 0; - for (char a = '0'; a <= '9'; ++a) - { - str[i_first_index] = a; - for (char b = '0'; b <= '9'; ++b) - { - str[i_first_index + 1] = b; - for (char c = '0'; c <= '9'; ++c) - { - str[i_first_index + 2] = c; - for (char d = '0'; d <= '9'; ++d) - { - str[i_first_index + 3] = d; - for (char e = '0'; e <= '9'; ++e) - { - str[i_second_index] = e; - for (char f = '0'; f <= '9'; ++f) - { - str[i_second_index + 1] = f; - for (char g = '0'; g <= '9'; ++g) - { - str[i_second_index + 2] = g; - for (char h = '0'; h <= '9'; ++h) - { - str[i_second_index + 3] = h; - o_hashes[i] = ::crc32(0, reinterpret_cast(&(str[0])), str_size) ^ 0xFFFFFFFF; - ++i; - } - } - } - } - } - } - } - } -} + uint32_t i = 0; + for( char a = '0'; a <= '9'; ++a ) + { + str[ i_first_index ] = a; + for( char b = '0'; b <= '9'; ++b ) + { + str[ i_first_index + 1 ] = b; + for( char c = '0'; c <= '9'; ++c ) + { + str[ i_first_index + 2 ] = c; + for( char d = '0'; d <= '9'; ++d ) + { + str[ i_first_index + 3 ] = d; + for( char e = '0'; e <= '9'; ++e ) + { + str[ i_second_index ] = e; + for( char f = '0'; f <= '9'; ++f ) + { + str[ i_second_index + 1 ] = f; + for( char g = '0'; g <= '9'; ++g ) + { + str[ i_second_index + 2 ] = g; + for( char h = '0'; h <= '9'; ++h ) + { + str[ i_second_index + 3 ] = h; + o_hashes[ i ] = ::crc32( 0, reinterpret_cast(&( str[ 0 ] )), str_size ) ^ 0xFFFFFFFF; + ++i; + } + } + } + } + } + } + } + } + } } -} -} diff --git a/deps/datReader/crc32.h b/deps/datReader/crc32.h index e8c59286..7d4894b7 100644 --- a/deps/datReader/crc32.h +++ b/deps/datReader/crc32.h @@ -5,9 +5,8 @@ #include #include -namespace xiv { -namespace utils { -namespace crc32 { +namespace xiv::utils::crc32 +{ // Normal crc32 computation from a given intial crc value, use zlib.crc32 instead, the final XOR 0xFFFFFFFF is not done uint32_t compute( const std::string& i_input, uint32_t init_crc = 0xFFFFFFFF ); @@ -17,10 +16,10 @@ namespace crc32 { uint32_t rev_compute( const std::string& i_input, uint32_t init_crc = 0 ); void generate_hashes_1( std::string& i_format, const uint32_t i_first_index, std::vector< uint32_t >& o_hashes ); - void generate_hashes_2( std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index, std::vector< uint32_t >& o_hashes ); -} -} + void generate_hashes_2( std::string& i_format, const uint32_t i_first_index, const uint32_t i_second_index, + std::vector< uint32_t >& o_hashes ); + } #endif // XIV_UTILS_CRC32_H diff --git a/deps/datReader/stream.cpp b/deps/datReader/stream.cpp index 0a38fbfc..b9019a6a 100644 --- a/deps/datReader/stream.cpp +++ b/deps/datReader/stream.cpp @@ -4,13 +4,7 @@ #include #include -namespace xiv -{ -namespace utils -{ -namespace stream +namespace xiv::utils::stream { } -} -} diff --git a/deps/datReader/stream.h b/deps/datReader/stream.h index c0b98074..37b9f28e 100644 --- a/deps/datReader/stream.h +++ b/deps/datReader/stream.h @@ -5,23 +5,17 @@ #include #include -namespace xiv +namespace xiv::utils::stream { -namespace utils -{ -namespace stream -{ -template > -class vectorwrapbuf : public std::basic_streambuf -{ -public: - vectorwrapbuf(std::vector &vec) + template< typename CharT, typename TraitsT = std::char_traits< CharT > > + class vectorwrapbuf : + public std::basic_streambuf< CharT, TraitsT > + { + public: + vectorwrapbuf( std::vector< CharT >& vec ) { - this->setg(vec.data(), vec.data(), vec.data() + vec.size()); + this->setg( vec.data(), vec.data(), vec.data() + vec.size() ); } -}; + }; } -} -} - #endif // XIV_UTILS_STREAM_H diff --git a/deps/datReader/zlib.cpp b/deps/datReader/zlib.cpp index 9f75d929..29396b99 100644 --- a/deps/datReader/zlib.cpp +++ b/deps/datReader/zlib.cpp @@ -4,32 +4,28 @@ #include #include -namespace xiv -{ -namespace utils -{ -namespace zlib +namespace xiv::utils::zlib { -void compress(const std::vector& in, std::vector& out) -{ + void compress( const std::vector< char >& in, std::vector< char >& out ) + { // Fetching upper bound for out size - auto out_size = compressBound(in.size()); - out.resize(out_size); + auto out_size = compressBound( in.size() ); + out.resize( out_size ); - auto ret = compress2(reinterpret_cast(out.data()), &out_size, - reinterpret_cast(in.data()), in.size(), Z_BEST_COMPRESSION); + auto ret = compress2( reinterpret_cast(out.data()), &out_size, + reinterpret_cast(in.data()), in.size(), Z_BEST_COMPRESSION ); - if (ret != Z_OK) + if( ret != Z_OK ) { - throw std::runtime_error("Error at zlib uncompress: " + std::to_string(ret)); + throw std::runtime_error( "Error at zlib uncompress: " + std::to_string( ret ) ); } - out.resize(out_size); -} + out.resize( out_size ); + } -void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size) -{ + void no_header_decompress( uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size ) + { z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; @@ -38,10 +34,10 @@ void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t strm.next_in = Z_NULL; // Init with -15 because we do not have header in this compressed data - auto ret = inflateInit2(&strm, -15); - if (ret != Z_OK) + auto ret = inflateInit2( &strm, -15 ); + if( ret != Z_OK ) { - throw std::runtime_error("Error at zlib init: " + std::to_string(ret)); + throw std::runtime_error( "Error at zlib init: " + std::to_string( ret ) ); } // Set pointers to the right addresses @@ -50,16 +46,14 @@ void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t strm.next_out = out; // Effectively decompress data - ret = inflate(&strm, Z_NO_FLUSH); - if (ret != Z_STREAM_END) + ret = inflate( &strm, Z_NO_FLUSH ); + if( ret != Z_STREAM_END ) { - throw std::runtime_error("Error at zlib inflate: " + std::to_string(ret)); + throw std::runtime_error( "Error at zlib inflate: " + std::to_string( ret ) ); } // Clean up - inflateEnd(&strm); -} + inflateEnd( &strm ); + } } -} -} diff --git a/deps/datReader/zlib.h b/deps/datReader/zlib.h index 942efaf9..7c93a5a3 100644 --- a/deps/datReader/zlib.h +++ b/deps/datReader/zlib.h @@ -4,18 +4,13 @@ #include #include -namespace xiv -{ -namespace utils -{ -namespace zlib +namespace xiv::utils::zlib { -void compress(const std::vector& in, std::vector& out); -void no_header_decompress(uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size); + void compress( const std::vector< char >& in, std::vector< char >& out ); + + void no_header_decompress( uint8_t* in, uint32_t in_size, uint8_t* out, uint32_t out_size ); -} -} } #endif // XIV_UTILS_ZLIB_H