mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-23 05:07:46 +00:00
155 lines
4.3 KiB
C++
155 lines
4.3 KiB
C++
#include "Index.h"
|
|
|
|
#include "bparse.h"
|
|
|
|
namespace xiv::dat
|
|
{
|
|
struct IndexBlockRecord
|
|
{
|
|
uint32_t offset;
|
|
uint32_t size;
|
|
SqPackBlockHash blockHash;
|
|
};
|
|
|
|
struct IndexHashTableEntry
|
|
{
|
|
uint32_t filenameHash;
|
|
uint32_t dirHash;
|
|
uint32_t datOffset;
|
|
uint32_t padding;
|
|
};
|
|
}
|
|
|
|
namespace xiv::utils::bparse
|
|
{
|
|
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 >( 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::dat
|
|
{
|
|
|
|
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< IndexBlockRecord >( m_handle );
|
|
isIndexBlockValid( hashTableBlockRecord );
|
|
|
|
// 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 );
|
|
|
|
// 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 ];
|
|
// 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 );
|
|
|
|
// Dat Count
|
|
m_datCount = extract< uint32_t >( m_handle, "dat_count" );
|
|
|
|
// Free List
|
|
isIndexBlockValid( extract< IndexBlockRecord >( m_handle ) );
|
|
|
|
// Dir Hash Table
|
|
isIndexBlockValid( extract< IndexBlockRecord >( m_handle ) );
|
|
}
|
|
|
|
Index::~Index()
|
|
{
|
|
}
|
|
|
|
uint32_t Index::getDatCount() const
|
|
{
|
|
return m_datCount;
|
|
}
|
|
|
|
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() )
|
|
{
|
|
return ( dir_it->second.find( filename_hash ) != dir_it->second.end() );
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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() )
|
|
{
|
|
throw std::runtime_error( "dirHash not found" );
|
|
}
|
|
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() )
|
|
{
|
|
throw std::runtime_error( "filenameHash not found" );
|
|
}
|
|
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 );
|
|
}
|
|
|
|
}
|