Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
554 lines
13 KiB
C++
554 lines
13 KiB
C++
#include "StuffHeaders.hpp"
|
|
#include <mbstring.h>
|
|
#define __mbschr(s,c) (char*)_mbschr((const unsigned char*)(s),(c))
|
|
|
|
#if !defined(TOOLOS_HPP)
|
|
#include <GameOS\ToolOS.hpp>
|
|
#endif
|
|
|
|
//#############################################################################
|
|
//############################# Directory ###############################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Directory::Directory(
|
|
const char *find_files,
|
|
bool directories
|
|
):
|
|
fileEntries(NULL,NULL),
|
|
folderEntries(NULL,NULL)
|
|
{
|
|
Check_Pointer(find_files);
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// Isolate the search path that we are looking for
|
|
//------------------------------------------------
|
|
//
|
|
MString new_directory_string = find_files;
|
|
currentDirectoryString = find_files;
|
|
currentDirectoryString.IsolateDirectory();
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Now look for the files and add each entry into the chain
|
|
//---------------------------------------------------------
|
|
//
|
|
const char* file_name = gos_FindFiles(new_directory_string);
|
|
while (file_name)
|
|
{
|
|
MString file_name_string = file_name;
|
|
DirectoryEntry *entry = new(g_Heap) DirectoryEntry(file_name_string);
|
|
Check_Object(entry);
|
|
fileEntries.AddValue(entry,file_name_string);
|
|
file_name = gos_FindFilesNext();
|
|
}
|
|
gos_FindFilesClose();
|
|
fileWalker = new(g_Heap) SortedChainIteratorOf<DirectoryEntry*,MString>(&fileEntries);
|
|
Check_Object(fileWalker);
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Look through the directories if we are supposed to
|
|
//---------------------------------------------------
|
|
//
|
|
folderWalker = NULL;
|
|
if (directories)
|
|
{
|
|
file_name = gos_FindDirectories(new_directory_string);
|
|
while (file_name)
|
|
{
|
|
MString file_name_string = file_name;
|
|
DirectoryFolder *entry = new(g_Heap) DirectoryFolder(file_name_string);
|
|
Check_Object(entry);
|
|
folderEntries.AddValue(entry,file_name_string);
|
|
file_name = gos_FindDirectoriesNext();
|
|
}
|
|
gos_FindDirectoriesClose();
|
|
folderWalker = new(g_Heap) SortedChainIteratorOf<DirectoryFolder*,MString>(&folderEntries);
|
|
Check_Object(folderWalker);
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Directory::~Directory(void)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(fileWalker);
|
|
fileWalker->DeletePlugs();
|
|
Check_Object(fileWalker);
|
|
delete fileWalker;
|
|
if (folderWalker != NULL)
|
|
{
|
|
Check_Object(folderWalker);
|
|
folderWalker->DeletePlugs();
|
|
Check_Object(folderWalker);
|
|
delete folderWalker;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char* Directory::GetCurrentFileName(void)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(fileWalker);
|
|
|
|
DirectoryEntry *entry;
|
|
|
|
if ((entry = fileWalker->GetCurrent()) != NULL)
|
|
{
|
|
Check_Object(entry);
|
|
return entry->GetItem();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Directory::AdvanceCurrentFile(void)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(fileWalker);
|
|
fileWalker->Next();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char * Directory::GetCurrentFolderName( void )
|
|
{
|
|
Check_Object(this);
|
|
if (folderWalker == NULL)
|
|
STOP(("Directory class was instantiated without directory support:\n Set the <directories> parameter to true to enable."));
|
|
Check_Object(folderWalker);
|
|
|
|
DirectoryFolder *entry;
|
|
|
|
if ((entry = folderWalker->GetCurrent()) != NULL)
|
|
{
|
|
Check_Object(entry);
|
|
return entry->GetItem();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Directory::AdvanceCurrentFolder( void )
|
|
{
|
|
Check_Object(this);
|
|
if (folderWalker == NULL)
|
|
STOP(("Directory class was instantiated without directory support:\n Set the <directories> parameter to true to enable."));
|
|
Check_Object(folderWalker);
|
|
folderWalker->Next();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const char* Directory::GetNewestFile(void)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(fileWalker);
|
|
|
|
SortedChainIteratorOf<DirectoryEntry*, MString> file_walker(&fileEntries);
|
|
DirectoryEntry *entry;
|
|
DirectoryEntry *newest_entry;
|
|
__int64 new_file_time;
|
|
|
|
newest_entry = file_walker.GetCurrent();
|
|
|
|
if(newest_entry)
|
|
{
|
|
MString file_name = currentDirectoryString;
|
|
file_name += newest_entry->GetItem();
|
|
new_file_time = gos_FileTimeStamp((const char *)file_name);
|
|
while((entry = file_walker.ReadAndNext()) != NULL)
|
|
{
|
|
Check_Object(entry);
|
|
file_name = currentDirectoryString;
|
|
file_name += entry->GetItem();
|
|
__int64 current_file_time = gos_FileTimeStamp((const char *)file_name);
|
|
if(current_file_time > new_file_time)
|
|
{
|
|
newest_entry = entry;
|
|
new_file_time = current_file_time;
|
|
}
|
|
}
|
|
|
|
return newest_entry->GetItem();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################### FileStream ################################
|
|
//#############################################################################
|
|
|
|
FileStream::ClassData* FileStream::DefaultData = NULL;
|
|
|
|
HGOSHEAP FileStream::s_Heap = NULL;
|
|
|
|
const char * FileStream::WhiteSpace = " \t\n";
|
|
|
|
char FileStream::RedirectedName[256];
|
|
bool
|
|
FileStream::IsRedirected=false,
|
|
FileStream::IgnoreReadOnlyFlag=false;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FileStream::InitializeClass()
|
|
{
|
|
Verify(!s_Heap);
|
|
s_Heap = gos_CreateMemoryHeap("File Buffers", 0, Stuff::g_LibraryHeap);
|
|
Check_Pointer(s_Heap);
|
|
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
FileStreamClassID,
|
|
"Stuff::FileStream",
|
|
MemoryStream::DefaultData
|
|
);
|
|
Check_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FileStream::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
Check_Pointer(s_Heap);
|
|
gos_DestroyMemoryHeap(s_Heap);
|
|
s_Heap = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FileStream::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FileStream::FileStream():
|
|
MemoryStream(DefaultData, NULL, 0)
|
|
{
|
|
fileName = NULL;
|
|
isOpen = false;
|
|
fileHandle = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FileStream::FileStream(
|
|
const char* file_name,
|
|
WriteStatus writable
|
|
):
|
|
MemoryStream(DefaultData, NULL, 0)
|
|
{
|
|
fileName = NULL;
|
|
isOpen = false;
|
|
Open(file_name, writable);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FileStream::~FileStream()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FileStream::Open(
|
|
const char* file_name,
|
|
WriteStatus writable
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Check_Pointer(file_name);
|
|
|
|
writeEnabled = writable;
|
|
currentPosition = streamStart = highWaterByte = NULL;
|
|
streamSize = 0;
|
|
fileHandle = NULL;
|
|
|
|
//
|
|
//------------------------------------------------
|
|
// If this is a readonly file, have gos read it in
|
|
//------------------------------------------------
|
|
//
|
|
if (writeEnabled == ReadOnly)
|
|
{
|
|
if (IsRedirected)
|
|
{
|
|
void (__stdcall *old_hook)(const char*, BYTE**, DWORD*) = Environment.HookGetFile;
|
|
Environment.HookGetFile = NULL;
|
|
gos_PushCurrentHeap(s_Heap);
|
|
gos_GetFile(RedirectedName, &streamStart, &streamSize);
|
|
gos_PopCurrentHeap();
|
|
Environment.HookGetFile = old_hook;
|
|
fileName = _strdup(RedirectedName);
|
|
}
|
|
else
|
|
{
|
|
gos_PushCurrentHeap(s_Heap);
|
|
gos_GetFile(file_name, &streamStart, &streamSize);
|
|
gos_PopCurrentHeap();
|
|
if (IsRedirected)
|
|
fileName = _strdup(RedirectedName);
|
|
else
|
|
fileName = _strdup(file_name);
|
|
}
|
|
isOpen = true;
|
|
currentPosition = streamStart;
|
|
highWaterByte = currentPosition;
|
|
}
|
|
|
|
//
|
|
//-----------------------------------------------
|
|
// Write only flags go through standard file open
|
|
//-----------------------------------------------
|
|
//
|
|
else
|
|
{
|
|
writeEnabled = writable;
|
|
if (IgnoreReadOnlyFlag)
|
|
{
|
|
bool (__stdcall *old_hook)(const char*) = Environment.HookDoesFileExist;
|
|
Environment.HookDoesFileExist = NULL;
|
|
if (gos_DoesFileExist(file_name))
|
|
gos_FileSetReadWrite(file_name);
|
|
Environment.HookDoesFileExist = old_hook;
|
|
}
|
|
gos_OpenFile(
|
|
&fileHandle,
|
|
file_name,
|
|
READWRITE
|
|
);
|
|
isOpen = true;
|
|
streamSize = 0xFFFFFFFFU;
|
|
fileName = _strdup(file_name);
|
|
}
|
|
|
|
//
|
|
//--------------------------
|
|
// Try and open the filename
|
|
//--------------------------
|
|
//
|
|
IsRedirected = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FileStream::Close()
|
|
{
|
|
Check_Object(this);
|
|
|
|
//
|
|
//---------------------------------
|
|
// If the file was opened, close it
|
|
//---------------------------------
|
|
//
|
|
if (fileHandle)
|
|
{
|
|
gos_CloseFile(fileHandle);
|
|
fileHandle = NULL;
|
|
}
|
|
else if (streamStart != NULL)
|
|
gos_Free(streamStart);
|
|
|
|
//
|
|
//----------------
|
|
// Delete the name
|
|
//----------------
|
|
//
|
|
isOpen = false;
|
|
if (fileName)
|
|
{
|
|
Check_Pointer(fileName);
|
|
free(fileName);
|
|
fileName = NULL;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FileStream::SetPointer(DWORD index)
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsFileOpened());
|
|
MemoryStream::SetPointer(index);
|
|
if (writeEnabled == WriteOnly)
|
|
gos_SeekFile(fileHandle, FROMSTART, reinterpret_cast<DWORD>(currentPosition));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream& FileStream::AdvancePointer(DWORD index)
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsFileOpened());
|
|
MemoryStream::AdvancePointer(index);
|
|
if (writeEnabled == WriteOnly)
|
|
gos_SeekFile(fileHandle, FROMSTART, reinterpret_cast<DWORD>(currentPosition));
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream& FileStream::RewindPointer(DWORD index)
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsFileOpened());
|
|
MemoryStream::RewindPointer(index);
|
|
if (writeEnabled == WriteOnly)
|
|
gos_SeekFile(fileHandle, FROMSTART, reinterpret_cast<DWORD>(currentPosition));
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream& FileStream::ReadBytes(
|
|
void *ptr,
|
|
DWORD number_of_bytes
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsFileOpened());
|
|
Verify(writeEnabled == ReadOnly);
|
|
return MemoryStream::ReadBytes(ptr, number_of_bytes);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
MemoryStream& FileStream::WriteBytes(
|
|
const void *ptr,
|
|
DWORD number_of_bytes
|
|
)
|
|
{
|
|
Check_Object(this);
|
|
Verify(IsFileOpened());
|
|
Verify(writeEnabled == WriteOnly);
|
|
DWORD written =
|
|
gos_WriteFile(
|
|
fileHandle,
|
|
Cast_Pointer(BYTE*, const_cast<void*>(ptr)),
|
|
number_of_bytes
|
|
);
|
|
Verify(written == number_of_bytes);
|
|
currentPosition += written;
|
|
return *this;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool FileStream::IsFileOpened()
|
|
{
|
|
Check_Object(this);
|
|
return isOpen;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool Stuff::CreateDirectories(const char *directory_path)
|
|
{
|
|
|
|
if (directory_path == NULL)
|
|
return false;
|
|
|
|
Check_Pointer(directory_path);
|
|
|
|
|
|
const char *start_position = directory_path;
|
|
const char *current_position = directory_path;
|
|
|
|
if (*current_position != '\\')
|
|
{
|
|
|
|
if ((current_position + 1) != NULL)
|
|
{
|
|
if((current_position + 2) != NULL)
|
|
{
|
|
if ( *(current_position + 1) == ':' && *(current_position + 2) == '\\')
|
|
{
|
|
current_position += 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*current_position != '\\')
|
|
return false;
|
|
|
|
|
|
while((current_position != NULL))
|
|
{
|
|
//make a substring with the path...
|
|
const char *next_slash;
|
|
next_slash = __mbschr( current_position + 1, '\\' );
|
|
|
|
char *new_string = NULL;
|
|
|
|
if (next_slash == NULL)
|
|
{
|
|
//copy the whole string
|
|
int length = strlen(start_position)+1;
|
|
new_string = new(g_Heap) char[length];
|
|
Check_Pointer(new_string);
|
|
|
|
Str_Copy(new_string, start_position, length);
|
|
}
|
|
else
|
|
{
|
|
|
|
if (next_slash - current_position == 0)
|
|
{
|
|
return false;
|
|
}
|
|
if (next_slash - current_position == 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//copy the sub string
|
|
int length = next_slash - start_position;
|
|
new_string = new(g_Heap) char[length+1];
|
|
Check_Pointer(new_string);
|
|
|
|
strncpy(new_string, start_position, length);
|
|
|
|
new_string[length] = NULL;
|
|
|
|
}
|
|
|
|
Verify(new_string != NULL);
|
|
|
|
|
|
if (!gos_DoesFileExist(new_string))
|
|
{
|
|
gos_CreateDirectory(new_string);
|
|
}
|
|
|
|
|
|
|
|
Check_Pointer(new_string);
|
|
delete new_string;
|
|
|
|
current_position = next_slash;
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} |