jediacademy/codemp/win32/win_filecode.cpp

346 lines
7.2 KiB
C++

/*
* UNPUBLISHED -- Rights reserved under the copyright laws of the
* United States. Use of a copyright notice is precautionary only and
* does not imply publication or disclosure.
*
* THIS DOCUMENTATION CONTAINS CONFIDENTIAL AND PROPRIETARY INFORMATION
* OF VICARIOUS VISIONS, INC. ANY DUPLICATION, MODIFICATION,
* DISTRIBUTION, OR DISCLOSURE IS STRICTLY PROHIBITED WITHOUT THE PRIOR
* EXPRESS WRITTEN PERMISSION OF VICARIOUS VISIONS, INC.
*/
#include "../server/exe_headers.h"
#include "../client/client.h"
#include "../win32/win_local.h"
#include "../qcommon/qcommon.h"
#include "../qcommon/fixedmap.h"
#include "../zlib/zlib.h"
#include "../qcommon/files.h"
/***********************************************
*
* WINDOWS/XBOX VERSION
*
* Build a translation table, CRC -> file name. We have the memory.
*
************************************************/
#if defined(_WINDOWS)
#include <windows.h>
#elif defined(_XBOX)
#include <xtl.h>
#endif
struct FileInfo
{
char* name;
int size;
};
static VVFixedMap< FileInfo, unsigned int >* s_Files = NULL;
static byte* buffer;
HANDLE s_Mutex = INVALID_HANDLE_VALUE;
int _buildFileList(const char* path, bool insert, bool buildList)
{
WIN32_FIND_DATA data;
char spec[MAX_OSPATH];
int count = 0;
// Look for all files
Com_sprintf(spec, sizeof(spec), "%s\\*.*", path);
HANDLE h = FindFirstFile(spec, &data);
while (h != INVALID_HANDLE_VALUE)
{
char full[MAX_OSPATH];
Com_sprintf(full, sizeof(full), "%s\\%s", path, data.cFileName);
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// Directory -- lets go recursive
if (data.cFileName[0] != '.') {
count += _buildFileList(full, insert, buildList);
}
}
else
{
if(insert || buildList)
{
// Regular file -- add it to the table
strlwr(full);
unsigned int code = crc32(0, (const byte *)full, strlen(full));
FileInfo info;
info.name = CopyString(full);
info.size = data.nFileSizeLow;
if(insert)
{
s_Files->Insert(info, code);
}
if(buildList)
{
// get the length of the filename
int len;
len = strlen(info.name) + 1;
// save the file code
*(int*)buffer = code;
buffer += sizeof(code);
// save the name of the file
strcpy((char*)buffer,info.name);
buffer += len;
// save the size of the file
*(int*)buffer = info.size;
buffer += sizeof(info.size);
}
}
count++;
}
// Continue the loop
if (!FindNextFile(h, &data))
{
FindClose(h);
return count;
}
}
return count;
}
bool _buildFileListFromSavedList(void)
{
// open the file up for reading
FILE* in;
in = fopen("d:\\xbx_filelist","rb");
if(!in)
{
return false;
}
// read in the number of files
int count;
if(!(fread(&count,sizeof(count),1,in)))
{
fclose(in);
return false;
}
// allocate memory for a temp buffer
byte* baseAddr;
int bufferSize;
bufferSize = count * ( 2 * sizeof(int) + MAX_OSPATH );
buffer = (byte*)Z_Malloc(bufferSize,TAG_TEMP_WORKSPACE,qtrue,32);
baseAddr = buffer;
// read the rest of the file into a big buffer
if(!(fread(buffer,bufferSize,1,in)))
{
fclose(in);
Z_Free(baseAddr);
return false;
}
// allocate some memory for s_Files
s_Files = new VVFixedMap<FileInfo, unsigned int>(count);
// loop through all the files write out the codes
int i;
for(i = 0; i < count; i++)
{
FileInfo info;
unsigned int code;
// read the code for the file
code = *(int*)buffer;
buffer += sizeof(code);
// read the filename
info.name = CopyString((char*)buffer);
buffer += (strlen(info.name) + 1);
// read the size of the file
info.size = *(int*)buffer;
buffer += sizeof(info.size);
// save the data
s_Files->Insert(info, code);
}
fclose(in);
Z_Free(baseAddr);
return true;
}
bool Sys_SaveFileCodes(void)
{
bool ret;
int res;
// get the number of files
int count;
count = _buildFileList(Sys_Cwd(), false, false);
// open a file for writing
FILE* out;
out = fopen("d:\\xbx_filelist","wb");
if(!out)
{
return false;
}
// allocate a buffer for writing
byte* baseAddr;
int bufferSize;
bufferSize = sizeof(int) + ( count * ( 2 * sizeof(int) + MAX_OSPATH ) );
baseAddr = (byte*)Z_Malloc(bufferSize,TAG_TEMP_WORKSPACE,qtrue,32);
buffer = baseAddr;
// write the number of files to the buffer
*(int*)buffer = count;
buffer += sizeof(count);
// fill up the rest of the buffer
ret = _buildFileList(Sys_Cwd(), false, true);
if(!ret)
{
// there was a problem
fclose(out);
Z_Free(baseAddr);
return false;
}
// attempt to write out the data
if(!(fwrite(baseAddr,bufferSize,1,out)))
{
// there was a problem
fclose(out);
Z_Free(baseAddr);
return false;
}
// everything went ok
fclose(out);
Z_Free(baseAddr);
return true;
}
void Sys_InitFileCodes(void)
{
bool ret;
int count = 0;
// First: try to load an existing filecode cache
ret = _buildFileListFromSavedList();
// if we had trouble building the list that way
// we need to do it by searching the files
if( !ret )
{
// There was no filelist cache, make one
if( !Sys_SaveFileCodes() )
Com_Error( ERR_DROP, "ERROR: Couldn't create filecode cache\n" );
// Now re-read it
if( !_buildFileListFromSavedList() )
Com_Error( ERR_DROP, "ERROR: Couldn't re-read filecode cache\n" );
}
s_Files->Sort();
// make it thread safe
s_Mutex = CreateMutex(NULL, FALSE, NULL);
}
void Sys_ShutdownFileCodes(void)
{
FileInfo* info = NULL;
info = s_Files->Pop();
while(info)
{
Z_Free(info->name);
info->name = NULL;
info = s_Files->Pop();
}
delete s_Files;
s_Files = NULL;
CloseHandle(s_Mutex);
}
int Sys_GetFileCode(const char* name)
{
WaitForSingleObject(s_Mutex, INFINITE);
// Get system level path
char* osname = FS_BuildOSPath(name);
// Generate hash for file name
strlwr(osname);
unsigned int code = crc32(0, (const byte *)osname, strlen(osname));
// Check if the file exists
if (!s_Files->Find(code))
{
ReleaseMutex(s_Mutex);
return -1;
}
ReleaseMutex(s_Mutex);
return code;
}
const char* Sys_GetFileCodeName(int code)
{
WaitForSingleObject(s_Mutex, INFINITE);
FileInfo *entry = s_Files->Find(code);
if (entry)
{
ReleaseMutex(s_Mutex);
return entry->name;
}
ReleaseMutex(s_Mutex);
return NULL;
}
int Sys_GetFileCodeSize(int code)
{
WaitForSingleObject(s_Mutex, INFINITE);
FileInfo *entry = s_Files->Find(code);
if (entry)
{
ReleaseMutex(s_Mutex);
return entry->size;
}
ReleaseMutex(s_Mutex);
return -1;
}
// Quick function to re-scan for new files, update the filecode
// table, and dump the new one to disk
void Sys_FilecodeScan_f( void )
{
// Make an updated filecode cache
if( !Sys_SaveFileCodes() )
Com_Error( ERR_DROP, "ERROR: Couldn't create filecode cache\n" );
// Throw out our current list
Sys_ShutdownFileCodes();
// Re-init, which should use the new list we just made
Sys_InitFileCodes();
}