⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 database.cpp

📁 机甲指挥官2源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "StuffHeaders.hpp"
#include "Database.hpp"
#include <ToolOS.hpp>

//===========================================================================//
// File:	Database.cpp                                                     //
// Contents: Database functionality											 //												 
//---------------------------------------------------------------------------//
// Copyright (C) Microsoft Corporation. All rights reserved.                 //
//===========================================================================//



//
// A pointer to this structure is the handle to the database
//
class Stuff::Database
{
public:
	enum {
		e_DataBlockSize=1021,
		e_Tag = 'DBV#',
		e_Version = 2
	};

	Database();

	DWORD
		m_tag,							// Magic number to identity file
		m_version;						// Version number
	DWORD
		m_numberOfRecords,				// Number of used records in database
		m_nextRecordID;					// Sequential index assigned in ADD
	DWORD
		m_idOffsets[e_DataBlockSize],	// Offsets to DatabaseRecords ( sorted by index )
		m_nameOffsets[e_DataBlockSize];	// Offsets to DatabaseRecords ( sorted by HASH )

	void
		TestInstance() const
			{Verify(m_tag == e_Tag && m_version <= e_Version);}

	static int
		FilesOpened;
};

//
// Each database record has this header
//
class Stuff::Record
{
public:
	Record::Record(
		const RecordHandle *handle,
		DWORD record_hash,
		DWORD name_length
	);
	void
		Unhook(const RecordHandle *handle);

	__int64
		m_lastModified;				// Time record was last modifyed

	DWORD
		m_nextIDRecord,				// offset to chain of records that share the same hash
		m_nextNameRecord,			// offset to chain of records that share the same hash
		m_ID,						// ID
		m_hash,						// Hash value
		m_nameLength,
		m_length;					// If this is zero, the record has been deleted (used to signify gaps before compressing)

	bool
		m_mustFree;					// When 1 gos_Free must be called on the block
	char
		m_name[1];
	BYTE
		m_data[1];

	void
		TestInstance() const
			{}
};

static HGOSHEAP
	Database_Heap = NULL;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static DWORD
	GenerateHash(const char* name)
{
	DWORD hash=0;

	while (*name)
	{
		hash=(hash<<4) + (*name&15);
		if (hash&0xf0000000)
			hash=hash^(hash>>28);
		name++;
	}
	return hash|0x80000000;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Record::Record(
	const RecordHandle *handle,
	DWORD record_hash,
	DWORD name_length
)
{
	Check_Pointer(this);
	Check_Object(handle);
	DatabaseHandle *db_handle = handle->m_databaseHandle;
	Check_Object(db_handle);
	Database *db = db_handle->m_dataBase;
	Check_Object(db);

	//
	//------------------
	// Set up the record
	//------------------
	//
	m_mustFree = true;
	m_ID = handle->m_ID;
	m_hash = record_hash;
	m_nameLength = name_length;
	m_length = handle->m_length;
	m_lastModified = gos_GetTimeDate();
	memcpy(&m_name[name_length+1], handle->m_data, m_length);

	//
	//------------------
	// Store in database
	//------------------
	//
	DWORD index=m_ID % Database::e_DataBlockSize;
	DWORD offset = (DWORD)this - db_handle->m_baseAddress;
	m_nextIDRecord = db->m_idOffsets[index];
	db->m_idOffsets[index] = offset;
	Check_Pointer(handle->m_name);
	memcpy(m_name, handle->m_name, name_length+1);
	index = record_hash % Database::e_DataBlockSize;
	m_nextNameRecord = db->m_nameOffsets[index];
	db->m_nameOffsets[index] = offset;

	//
	//----------------------------
	// Increase the database count
	//----------------------------
	//
	db->m_numberOfRecords++;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Record::Unhook(const RecordHandle *handle)
{
	Check_Pointer(this);
	Check_Object(handle);
	DatabaseHandle *db_handle = handle->m_databaseHandle;
	Check_Object(db_handle);
	Database *db = db_handle->m_dataBase;
	Check_Object(db);

	//
	//--------------------------------------------
	// Make sure that we can find the record by ID
	//--------------------------------------------
	//
	Record* record;
	DWORD index = m_ID % Database::e_DataBlockSize;
	#ifdef _ARMOR
		record = reinterpret_cast<Record*>(db->m_idOffsets[index]);
		while (record)
		{
			record = reinterpret_cast<Record*>((DWORD)record + db_handle->m_baseAddress);
			Check_Object(record);
			if (record->m_ID == m_ID)
				break;
			record =
				reinterpret_cast<Record*>(record->m_nextIDRecord);
		}	
		Verify(this == record);
	#endif

	//
	//-------------------------------------------
	// Now remove the record from the index database
	//-------------------------------------------
	//
	record = reinterpret_cast<Record*>(db->m_idOffsets[index] + db_handle->m_baseAddress);
	if (record == this)
		db->m_idOffsets[index] = m_nextIDRecord;
	else
	{
		record = reinterpret_cast<Record*>(db->m_idOffsets[index]);
		while (record)
		{
			record = reinterpret_cast<Record*>((DWORD)record + db_handle->m_baseAddress);
			Check_Object(record);
			if ((DWORD)record->m_nextIDRecord+db_handle->m_baseAddress == (DWORD)this)
			{
				record->m_nextIDRecord = m_nextIDRecord;
				break;
			}
			record = reinterpret_cast<Record*>(record->m_nextIDRecord);
		}	
	}

	//
	//---------------------------------
	// Now remove from hash index database
	//---------------------------------
	//
	index = m_hash % Database::e_DataBlockSize;
	record = reinterpret_cast<Record*>(db->m_nameOffsets[index] + db_handle->m_baseAddress);
	if (record == this)
		db->m_nameOffsets[index] = m_nextNameRecord;
	else
	{
		record = reinterpret_cast<Record*>(db->m_nameOffsets[index]);
		while (record)
		{
			record = reinterpret_cast<Record*>((DWORD)record + db_handle->m_baseAddress);
			Check_Object(record);
			if ((DWORD)record->m_nextNameRecord+db_handle->m_baseAddress == (DWORD)this)
			{
				record->m_nextNameRecord = m_nextNameRecord;
				break;
			}
			record = reinterpret_cast<Record*>(record->m_nextNameRecord);
		}	
	}
	db->m_numberOfRecords--;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RecordHandle::Add()
{
	Check_Object(this);
	gos_PushCurrentHeap(Database_Heap);

	//
	//------------------
	// Find our database
	//------------------
	//
	Check_Object(m_databaseHandle);
	Verify(!m_databaseHandle->m_readOnly);
	m_databaseHandle->m_dirtyFlag = true;
	Database* db = m_databaseHandle->m_dataBase;
	Check_Object(db);

	//
	//-------------------------------------------
	// Make sure the record doesn't already exist
	//-------------------------------------------
	//
	Verify(!m_record);
	#ifdef _ARMOR
		if (m_name)
		{
			RecordHandle dup_check = *this;
			if (dup_check.FindName())
				STOP(( "Duplicate Record" ));
		}
	#endif
	
	//
	//------------------
	// Set the record index
	//------------------
	//
	m_ID=db->m_nextRecordID++;

	//
	//---------------------------------------------------
	// Figure out how long the name is and its hash value
	//---------------------------------------------------
	//
	DWORD record_hash, name_length;
	if (m_name)
	{
		record_hash = GenerateHash(m_name);
		name_length = strlen(m_name);
		Verify(name_length > 0);
	}
	else
	{
		record_hash = 0;
		name_length = 0;
	}

	//
	//------------------
	// Set up the record
	//------------------
	//
	Verify(!m_record);
	Record *data =
		new(new BYTE[sizeof(*m_record) + m_length + name_length])
			Record(this, record_hash, name_length);
	Check_Object(data);
	m_data = &data->m_name[name_length+1];
	if (m_name)
		m_name = data->m_name;
	m_timeStamp = data->m_lastModified;

	//
	//------------------
	// Update statistics
	//------------------
	//
	m_record = data;
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RecordHandle::Replace()
{
	Check_Object(this);
	gos_PushCurrentHeap(Database_Heap);

	//
	//------------------
	// Find our database
	//------------------
	//
	Check_Object(m_databaseHandle);
	Verify(!m_databaseHandle->m_readOnly);
	m_databaseHandle->m_dirtyFlag = true;
	
	//
	//----------------------
	// Unhook the old record
	//----------------------
	//
	Check_Object(m_record);
	const_cast<Record*>(m_record)->Unhook(this);

	//
	//---------------------------------------------------
	// Figure out how long the name is and its hash value
	//---------------------------------------------------
	//
	DWORD record_hash, name_length;
	if (m_name)
	{
		record_hash = GenerateHash(m_name);
		name_length = strlen(m_name);
		Verify(name_length > 0);
	}
	else
	{
		record_hash = 0;
		name_length = 0;
	}

	//
	//------------------
	// Set up the record
	//------------------
	//
	Record *data =
		new(new BYTE[sizeof(*m_record) + m_length + name_length])
			Record(this, record_hash, name_length);
	Check_Object(data);
	m_data = &data->m_name[name_length+1];
	if (m_name)
		m_name = data->m_name;
	m_timeStamp = data->m_lastModified;

	//
	//------------------
	// Update statistics
	//------------------
	//
	if (m_record->m_mustFree)
		delete const_cast<Record*>(m_record);
	m_record = data;
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	RecordHandle::Delete()
{
	Check_Object(this);

	//
	//------------------
	// Find our database
	//------------------
	//
	Check_Object(m_databaseHandle);
	Verify(!m_databaseHandle->m_readOnly);
	m_databaseHandle->m_dirtyFlag = true;
	
	//
	//----------------------
	// Delete the old record
	//----------------------
	//
	Check_Object(m_record);
	const_cast<Record*>(m_record)->Unhook(this);
	if (m_record->m_mustFree)
		delete const_cast<Record*>(m_record);
	m_record = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	RecordHandle::FindID()
{
	Check_Object(this);
	Check_Object(m_databaseHandle);
	Database* db = m_databaseHandle->m_dataBase;
	Check_Object(db);

	DWORD index=m_ID % Database::e_DataBlockSize;
	Record* record = reinterpret_cast<Record*>(db->m_idOffsets[index]);
	while (record)
	{
		record =
			reinterpret_cast<Record*>(
				(DWORD)record + m_databaseHandle->m_baseAddress
			);
		Check_Object(record);
		if (record->m_ID==m_ID)
		{
			m_length = record->m_length;
			m_data = &record->m_data[record->m_nameLength];
			m_name = record->m_name;
			m_record = record;
			m_timeStamp = record->m_lastModified;
			return true;
		}
		record = reinterpret_cast<Record*>(record->m_nextIDRecord);
	}	

	m_record = NULL;
	return false;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
	RecordHandle::FindName()
{
	Check_Object(this);
	Check_Object(m_databaseHandle);
	Database* db = m_databaseHandle->m_dataBase;
	Check_Object(db);

	Check_Pointer(m_name);
	DWORD hash = GenerateHash(m_name);
	DWORD index = hash % Database::e_DataBlockSize;

	Record* record = reinterpret_cast<Record*>(db->m_nameOffsets[index]);
	while (record)
	{
		record = reinterpret_cast<Record*>(
			(DWORD)record + m_databaseHandle->m_baseAddress
		);
		Check_Object(record);
		if (record->m_hash == hash && !_stricmp(m_name,record->m_name))
		{
			m_length = record->m_length;
			m_data = &record->m_data[record->m_nameLength];
			m_ID = record->m_ID;
			m_name = record->m_name;
			m_record = record;
			m_timeStamp = record->m_lastModified;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -