
Source code release, imported from: https://www.gamefront.com/games/aliens-vs-predator-3/file/avp-gold-complete-source-code All text files were converted to Unix format.
1999 lines
44 KiB
C++
1999 lines
44 KiB
C++
#include "chunk.hpp"
|
|
#include "chnktype.hpp"
|
|
#include "mishchnk.hpp"
|
|
|
|
#include "shpchunk.hpp"
|
|
#include "obchunk.hpp"
|
|
|
|
|
|
|
|
#include "huffman.hpp"
|
|
|
|
|
|
#include <mbstring.h>
|
|
|
|
#ifdef cencon
|
|
#define new my_new
|
|
#endif
|
|
|
|
|
|
// Class Lockable_Chunk_With_Children functions
|
|
|
|
#if cencon
|
|
#else
|
|
extern char * users_name;
|
|
#endif
|
|
|
|
//macro for helping to force inclusion of chunks when using libraries
|
|
FORCE_CHUNK_INCLUDE_IMPLEMENT(mishchnk)
|
|
|
|
BOOL Lockable_Chunk_With_Children::lock_chunk(File_Chunk & fchunk)
|
|
{
|
|
if (!fchunk.filename) return FALSE;
|
|
|
|
if (local_lock) return FALSE; // you can't lock a chunk twice
|
|
|
|
#if DisableLock
|
|
if(external_lock) return FALSE;
|
|
local_lock = TRUE;
|
|
set_lock_user (users_name);
|
|
return TRUE;
|
|
#else
|
|
if (!fchunk.check_file()) return FALSE;
|
|
if (updated_outside || external_lock) return FALSE;
|
|
|
|
HANDLE rif_file;
|
|
unsigned long bytes_read;
|
|
|
|
int tries = 0;
|
|
|
|
rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
while(rif_file == INVALID_HANDLE_VALUE && tries<10)
|
|
{
|
|
rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
tries ++;
|
|
clock_t ctime = clock();
|
|
double secs = (double)ctime / (double)CLOCKS_PER_SEC;
|
|
double secsgone;
|
|
do
|
|
{
|
|
ctime = clock();
|
|
secsgone = (double)ctime / (double)CLOCKS_PER_SEC;
|
|
}
|
|
while( (secsgone-secs)<1);
|
|
}
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> chfptrs;
|
|
list_chunks_in_file(& chfptrs, rif_file, identifier);
|
|
|
|
LIF<int> cfpl(&chfptrs);
|
|
|
|
if (chfptrs.size()) {
|
|
for (; !cfpl.done(); cfpl.next()) {
|
|
|
|
SetFilePointer (rif_file, cfpl(),0,FILE_BEGIN);
|
|
|
|
if (file_equals(rif_file)) break;
|
|
}
|
|
}
|
|
|
|
if (!cfpl.done()) {
|
|
|
|
// go to start of chunk
|
|
SetFilePointer (rif_file,cfpl(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
if (get_head_id())
|
|
{
|
|
List<int> obhead;
|
|
list_chunks_in_file(& obhead, rif_file, get_head_id());
|
|
|
|
assert (obhead.size() == 1);
|
|
|
|
int flags;
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
SetFilePointer(rif_file,-4,0,FILE_CURRENT);
|
|
flags |= GENERAL_FLAG_LOCKED;
|
|
WriteFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
WriteFile (rif_file, (long *) &users_name[0], 16, &bytes_read, 0);
|
|
}
|
|
|
|
}
|
|
|
|
local_lock = TRUE;
|
|
|
|
set_lock_user (users_name);
|
|
|
|
CloseHandle (rif_file);
|
|
return TRUE;
|
|
#endif
|
|
|
|
}
|
|
|
|
BOOL Lockable_Chunk_With_Children::unlock_chunk (File_Chunk & fchunk, BOOL updateyn)
|
|
{
|
|
if (updateyn) {
|
|
updated = TRUE;
|
|
}
|
|
#if DisableLock
|
|
local_lock = FALSE;
|
|
(void)fchunk;
|
|
#else
|
|
else
|
|
{
|
|
fchunk.check_file();
|
|
if (updated_outside || external_lock) return FALSE;
|
|
|
|
HANDLE rif_file;
|
|
unsigned long bytes_read;
|
|
|
|
rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> chfptrs;
|
|
list_chunks_in_file(& chfptrs, rif_file, identifier);
|
|
|
|
List<obinfile> obs;
|
|
|
|
char name[50];
|
|
|
|
LIF<int> ofpl(&chfptrs);
|
|
|
|
if (chfptrs.size()) {
|
|
for (; !ofpl.done(); ofpl.next()) {
|
|
|
|
SetFilePointer (rif_file, ofpl(),0,FILE_BEGIN);
|
|
|
|
if (file_equals(rif_file)) break;
|
|
}
|
|
}
|
|
|
|
if (!ofpl.done()) {
|
|
|
|
// go to start of chunk
|
|
SetFilePointer (rif_file,ofpl(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
if (get_head_id())
|
|
{
|
|
List<int> obhead;
|
|
list_chunks_in_file(& obhead, rif_file, get_head_id());
|
|
|
|
assert (obhead.size() == 1);
|
|
|
|
int flags;
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
SetFilePointer(rif_file,-4,0,FILE_CURRENT);
|
|
flags &= ~GENERAL_FLAG_LOCKED;
|
|
WriteFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
WriteFile (rif_file, (long *) &users_name[0], 16, &bytes_read, 0);
|
|
}
|
|
|
|
}
|
|
|
|
local_lock = FALSE;
|
|
|
|
CloseHandle (rif_file);
|
|
}
|
|
#endif
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
BOOL Lockable_Chunk_With_Children::update_chunk_in_file(HANDLE &rif_file)
|
|
{
|
|
|
|
unsigned long bytes_read;
|
|
int length = 0;
|
|
|
|
const char * hd_id = get_head_id();
|
|
|
|
if (!hd_id) return FALSE;
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
//twprintf("\nLooking for chunks in file\n");
|
|
|
|
List<int> shpfptrs;
|
|
list_chunks_in_file(& shpfptrs, rif_file, identifier);
|
|
|
|
// look through chunks for the save of our current chunk
|
|
|
|
//twprintf("Checking each chunk\n");
|
|
|
|
LIF<int> sfpl(&shpfptrs);
|
|
|
|
if (shpfptrs.size()) {
|
|
for (; !sfpl.done(); sfpl.next()) {
|
|
|
|
SetFilePointer (rif_file, sfpl()+8,0,FILE_BEGIN);
|
|
|
|
ReadFile (rif_file, (long *) &(length), 4, &bytes_read, 0);
|
|
|
|
SetFilePointer (rif_file, sfpl(),0,FILE_BEGIN);
|
|
if (file_equals(rif_file)) break;
|
|
}
|
|
}
|
|
|
|
// then load the file after that chunk into a buffer,
|
|
// output the chunk and write the buffer
|
|
// unless the chunk is the last one in the file
|
|
|
|
//twprintf("Updating file\n");
|
|
|
|
if (!sfpl.done())
|
|
{
|
|
|
|
int file_length = GetFileSize(rif_file,0);
|
|
|
|
if (file_length > (sfpl() + length)) {
|
|
|
|
SetFilePointer (rif_file, sfpl() + length,0,FILE_BEGIN);
|
|
|
|
char * tempbuffer;
|
|
tempbuffer = new char [file_length - (sfpl() + length)];
|
|
|
|
ReadFile (rif_file, (long *) tempbuffer, (file_length - (sfpl() + length)), &bytes_read, 0);
|
|
|
|
SetFilePointer (rif_file, sfpl() ,0,FILE_BEGIN);
|
|
|
|
if (!deleted)
|
|
{
|
|
size_chunk();
|
|
output_chunk(rif_file);
|
|
}
|
|
|
|
WriteFile (rif_file, (long *) tempbuffer, (file_length - (sfpl() + length)), &bytes_read, 0);
|
|
|
|
delete [] tempbuffer;
|
|
|
|
SetEndOfFile (rif_file);
|
|
}
|
|
else{
|
|
|
|
SetFilePointer (rif_file, sfpl() ,0,FILE_BEGIN);
|
|
if (!deleted)
|
|
{
|
|
size_chunk();
|
|
output_chunk(rif_file);
|
|
}
|
|
SetEndOfFile (rif_file);
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
SetFilePointer (rif_file,0 ,0,FILE_END);
|
|
if (!deleted)
|
|
{
|
|
size_chunk();
|
|
output_chunk(rif_file);
|
|
}
|
|
SetEndOfFile (rif_file);
|
|
}
|
|
|
|
local_lock = FALSE;
|
|
|
|
updated = FALSE;
|
|
|
|
int file_length = GetFileSize(rif_file,0);
|
|
SetFilePointer (rif_file,8,0,FILE_BEGIN);
|
|
|
|
WriteFile (rif_file, (long *) &file_length, 4, &bytes_read, 0);
|
|
|
|
|
|
// DO NOT PUT ANY CODE AFTER THIS
|
|
|
|
if (deleted) delete this;
|
|
|
|
// OR ELSE !!!
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
size_t Lockable_Chunk_With_Children::size_chunk_for_process()
|
|
{
|
|
if (output_chunk_for_process)
|
|
return size_chunk();
|
|
return(chunk_size = 0);
|
|
}
|
|
|
|
|
|
void Lockable_Chunk_With_Children::fill_data_block_for_process(char * data_start)
|
|
{
|
|
if (output_chunk_for_process)
|
|
{
|
|
fill_data_block(data_start);
|
|
output_chunk_for_process = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
// Class File_Chunk functions
|
|
|
|
/*
|
|
Children for File_Chunk :
|
|
"REBSHAPE" Shape_Chunk
|
|
"RSPRITES" AllSprites_Chunk
|
|
"RBOBJECT" Object_Chunk
|
|
"RIFVERIN" RIF_Version_Num_Chunk
|
|
"REBENVDT" Environment_Data_Chunk
|
|
"REBENUMS" Enum_Chunk
|
|
"OBJCHIER" Object_Hierarchy_Chunk
|
|
"OBHALTSH" Object_Hierarchy_Alternate_Shape_Set_Chunk
|
|
"HIDEGDIS" Hierarchy_Degradation_Distance_Chunk
|
|
"INDSOUND" Indexed_Sound_Chunk
|
|
"HSETCOLL" Hierarchy_Shape_Set_Collection_Chunk
|
|
"DUMMYOBJ" Dummy_Object_Chunk
|
|
|
|
*/
|
|
|
|
File_Chunk::File_Chunk(const char * file_name)
|
|
: Chunk_With_Children (NULL, "REBINFF2")
|
|
{
|
|
// Load in whole chunk and traverse
|
|
char rifIsCompressed = FALSE;
|
|
char *uncompressedData = NULL;
|
|
HANDLE rif_file;
|
|
DWORD file_size;
|
|
DWORD file_size_from_file;
|
|
unsigned long bytes_read;
|
|
char * buffer;
|
|
char * buffer_ptr;
|
|
char id_buffer[9];
|
|
|
|
Parent_File = this;
|
|
|
|
error_code = 0;
|
|
object_array_size=0;
|
|
object_array=0;
|
|
|
|
filename = new char [strlen(file_name) + 1];
|
|
|
|
strcpy (filename, file_name);
|
|
|
|
rif_file = CreateFileA (file_name, GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
return;
|
|
}
|
|
|
|
file_size = GetFileSize (rif_file, NULL);
|
|
|
|
|
|
if (!ReadFile(rif_file, id_buffer, 8, &bytes_read, 0)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
|
|
#if UseOldChunkLoader
|
|
if (strncmp (id_buffer, "REBINFLF", 8)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
#else
|
|
/* KJL 16:46:14 19/09/98 - check for a compressed rif */
|
|
if (!strncmp (id_buffer, COMPRESSED_RIF_IDENTIFIER, 8))
|
|
{
|
|
rifIsCompressed = TRUE;
|
|
}
|
|
else if (strncmp (id_buffer, "REBINFF2", 8))
|
|
{
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
#endif
|
|
buffer = new char [file_size];
|
|
|
|
/* KJL 17:57:44 19/09/98 - if the rif is compressed, we must load the whole
|
|
file in and then pass it to the decompression routine, which will return a
|
|
pointer to the original data. */
|
|
if (rifIsCompressed)
|
|
{
|
|
if (!ReadFile(rif_file, buffer+8, (file_size-8), &bytes_read, 0))
|
|
{
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
uncompressedData = HuffmanDecompress((HuffmanPackage*)buffer);
|
|
file_size = ((HuffmanPackage*)buffer)->UncompressedDataSize;
|
|
|
|
delete [] buffer; // kill the buffer the compressed file was loaded into
|
|
|
|
buffer_ptr = buffer = uncompressedData+12; // skip header data
|
|
}
|
|
else // the normal uncompressed approach:
|
|
{
|
|
if (!ReadFile(rif_file, &file_size_from_file, 4, &bytes_read, 0)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
|
|
if (file_size != file_size_from_file) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
|
|
if (!ReadFile(rif_file, buffer, (file_size-12), &bytes_read, 0))
|
|
{
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
return;
|
|
}
|
|
buffer_ptr = buffer;
|
|
}
|
|
|
|
// Process the RIF
|
|
// The start of the first chunk
|
|
|
|
while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) {
|
|
|
|
if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)file_size-12)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
break;
|
|
}
|
|
|
|
DynCreate(buffer_ptr);
|
|
buffer_ptr += *(int *)(buffer_ptr + 8);
|
|
|
|
}
|
|
|
|
/* KJL 17:59:42 19/09/98 - release the memory holding the rif */
|
|
if (rifIsCompressed)
|
|
{
|
|
free(uncompressedData);
|
|
}
|
|
else
|
|
{
|
|
delete [] buffer;
|
|
}
|
|
|
|
CloseHandle (rif_file);
|
|
|
|
post_input_processing();
|
|
|
|
}
|
|
|
|
File_Chunk::File_Chunk()
|
|
: Chunk_With_Children (NULL, "REBINFF2")
|
|
{
|
|
// Empty File chunk
|
|
new RIF_Version_Num_Chunk (this);
|
|
filename = 0;
|
|
|
|
object_array_size=0;
|
|
object_array=0;
|
|
}
|
|
|
|
|
|
File_Chunk::~File_Chunk()
|
|
{
|
|
if (filename)
|
|
delete [] filename;
|
|
|
|
if(object_array)
|
|
free(object_array);
|
|
}
|
|
|
|
#define SAVE_USING_COMPRESSION 1
|
|
|
|
BOOL File_Chunk::write_file (const char * fname)
|
|
{
|
|
if(!fname) return FALSE;
|
|
//if a read_only file exists with this filename , then abort attempt to save
|
|
DWORD attributes = GetFileAttributesA(fname);
|
|
if (0xffffffff!=attributes)
|
|
{
|
|
if (attributes & FILE_ATTRIBUTE_READONLY)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HANDLE rif_file;
|
|
|
|
if (filename) delete [] filename;
|
|
|
|
filename = new char [strlen(fname) + 1];
|
|
strcpy (filename, fname);
|
|
|
|
//save under a temporary name in case a crash occurs during save;
|
|
int filename_start_pos=0;
|
|
int pos=0;
|
|
while(fname[pos])
|
|
{
|
|
if(fname[pos]=='\\' || fname[pos]==':')
|
|
{
|
|
filename_start_pos=pos+1;
|
|
}
|
|
//go to next MBCS character in string
|
|
pos+=_mbclen((unsigned const char*)&fname[pos]);
|
|
}
|
|
if(!fname[filename_start_pos]) return FALSE;
|
|
|
|
char* temp_name=new char[strlen(fname)+7];
|
|
strcpy(temp_name,fname);
|
|
strcpy(&temp_name[filename_start_pos],"~temp~");
|
|
strcpy(&temp_name[filename_start_pos+6],&fname[filename_start_pos]);
|
|
|
|
prepare_for_output();
|
|
|
|
|
|
#if SAVE_USING_COMPRESSION
|
|
//create a block containing the uncompressed rif file
|
|
unsigned char* uncompressedData = (unsigned char*) make_data_block_from_chunk();
|
|
if(!uncompressedData) return FALSE;
|
|
|
|
//do the compression thing
|
|
HuffmanPackage *outPackage = HuffmanCompression(uncompressedData,chunk_size);
|
|
delete [] uncompressedData;
|
|
if(!outPackage) return FALSE;
|
|
|
|
//and now try to write the file
|
|
rif_file = CreateFileA (temp_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
delete [] temp_name;
|
|
free (outPackage);
|
|
return FALSE;
|
|
}
|
|
|
|
unsigned long junk;
|
|
BOOL ok;
|
|
|
|
ok = WriteFile (rif_file, (long *) outPackage,outPackage->CompressedDataSize+sizeof(HuffmanPackage), &junk, 0);
|
|
|
|
CloseHandle (rif_file);
|
|
|
|
free (outPackage);
|
|
|
|
if(!ok) return FALSE;
|
|
|
|
|
|
#else
|
|
size_chunk();
|
|
|
|
rif_file = CreateFileA (temp_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
delete [] temp_name;
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(this->output_chunk(rif_file)))
|
|
{
|
|
CloseHandle (rif_file);
|
|
delete [] temp_name;
|
|
return FALSE;
|
|
}
|
|
|
|
CloseHandle (rif_file);
|
|
#endif
|
|
|
|
//Delete the old file with this name (if it exists) , and rename the temprary file
|
|
DeleteFileA(fname);
|
|
MoveFileA(temp_name,fname);
|
|
|
|
delete [] temp_name;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// the file_chunk must link all of its shapes & objects together
|
|
|
|
void File_Chunk::post_input_processing()
|
|
{
|
|
List<Shape_Chunk *> shplist;
|
|
List<Object_Chunk *> objlist;
|
|
|
|
List<Chunk *> child_lists;
|
|
|
|
lookup_child("REBSHAPE",child_lists);
|
|
|
|
while (child_lists.size()) {
|
|
shplist.add_entry((Shape_Chunk *)child_lists.first_entry());
|
|
child_lists.delete_first_entry();
|
|
}
|
|
|
|
lookup_child("RBOBJECT",child_lists);
|
|
|
|
while (child_lists.size()) {
|
|
objlist.add_entry((Object_Chunk *)child_lists.first_entry());
|
|
child_lists.delete_first_entry();
|
|
}
|
|
|
|
for (LIF<Shape_Chunk *> sli(&shplist); !sli.done(); sli.next())
|
|
{
|
|
Shape_Chunk::max_id = max (Shape_Chunk::max_id,sli()->get_header()->file_id_num);
|
|
}
|
|
Shape_Chunk** shape_array=new Shape_Chunk*[Shape_Chunk::max_id+1];
|
|
|
|
for(sli.restart();!sli.done();sli.next())
|
|
{
|
|
shape_array[sli()->get_header()->file_id_num]=sli();
|
|
}
|
|
|
|
for (LIF<Object_Chunk *> ol(&objlist); !ol.done(); ol.next())
|
|
{
|
|
ol()->assoc_with_shape(shape_array[ol()->get_header()->shape_id_no]);
|
|
}
|
|
|
|
delete shape_array;
|
|
|
|
|
|
Chunk_With_Children::post_input_processing();
|
|
}
|
|
|
|
|
|
|
|
BOOL File_Chunk::check_file()
|
|
{
|
|
if (!filename) return TRUE;
|
|
|
|
#if DisableLock
|
|
return(TRUE);
|
|
#else
|
|
|
|
int flags;
|
|
int v_no;
|
|
char locker[17];
|
|
|
|
|
|
HANDLE rif_file;
|
|
unsigned long bytes_read;
|
|
|
|
int tries = 0;
|
|
|
|
rif_file = CreateFileA (filename, GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
while(rif_file == INVALID_HANDLE_VALUE && tries<10)
|
|
{
|
|
rif_file = CreateFileA (filename, GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
tries ++;
|
|
clock_t ctime = clock();
|
|
double secs = (double)ctime / (double)CLOCKS_PER_SEC;
|
|
double secsgone;
|
|
do
|
|
{
|
|
ctime = clock();
|
|
secsgone = (double)ctime / (double)CLOCKS_PER_SEC;
|
|
}
|
|
while( (secsgone-secs)<1);
|
|
}
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
error_code = CHECK_FAILED_NOT_OPEN;
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
error_code = CHECK_FAILED_NOT_OPEN;
|
|
return FALSE;
|
|
}
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> obfptrs;
|
|
list_chunks_in_file(& obfptrs, rif_file, "RBOBJECT");
|
|
|
|
// ok, go through the objects, first locate the header and find
|
|
// the associated object.
|
|
|
|
if (obfptrs.size()) {
|
|
|
|
for (LIF<int> obflst(&obfptrs); !obflst.done(); obflst.next()) {
|
|
|
|
// go to start of chunk
|
|
SetFilePointer (rif_file,obflst(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
List<int> obhead;
|
|
list_chunks_in_file(& obhead, rif_file, "OBJHEAD1");
|
|
|
|
assert (obhead.size() == 1);
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
|
|
|
|
// go to version number
|
|
SetFilePointer(rif_file,obhead.first_entry() + 88,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
|
|
|
|
char name[50];
|
|
|
|
// get object identifier
|
|
SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN);
|
|
int i = 0;
|
|
do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0);
|
|
while (name[i++] != 0);
|
|
|
|
Object_Chunk * tmpob;
|
|
Object_Header_Chunk * tmpobh;
|
|
List<Chunk *> obchs;
|
|
lookup_child ("RBOBJECT",obchs);
|
|
|
|
if (obchs.size()){
|
|
for (LIF<Chunk *> obchls(&obchs); !obchls.done(); obchls.next()){
|
|
tmpob = (Object_Chunk *)obchls();
|
|
// if this is the same object
|
|
if (!strcmp (name, tmpob->object_data.o_name)) break;
|
|
}
|
|
if (!obchls.done()) {
|
|
tmpobh = tmpob->get_header();
|
|
if (tmpobh) {
|
|
if (tmpobh->version_no < v_no)
|
|
tmpob->updated_outside = TRUE;
|
|
if (flags & GENERAL_FLAG_LOCKED) {
|
|
// do the lock check
|
|
if (!tmpob->local_lock) {
|
|
tmpob->external_lock = TRUE;
|
|
strncpy(tmpobh->lock_user, locker,16);
|
|
tmpobh->lock_user[16] = '\0';
|
|
}
|
|
else if (strncmp(tmpobh->lock_user, locker,16)) {
|
|
tmpob->external_lock = TRUE;
|
|
strncpy(tmpobh->lock_user, locker,16);
|
|
tmpobh->lock_user[16] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// shapes
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> shpfptrs;
|
|
list_chunks_in_file(& shpfptrs, rif_file, "REBSHAPE");
|
|
|
|
if (shpfptrs.size()) {
|
|
|
|
for (LIF<int> shpflst(&shpfptrs); !shpflst.done(); shpflst.next()) {
|
|
|
|
// go to start of chunk
|
|
SetFilePointer (rif_file,shpflst(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
List<int> shphead;
|
|
list_chunks_in_file(& shphead, rif_file, "SHPHEAD1");
|
|
|
|
assert (shphead.size() == 1);
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,shphead.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
|
|
|
|
int id;
|
|
// get shape identifier
|
|
ReadFile (rif_file, (long *) &id, 4, &bytes_read, 0);
|
|
|
|
|
|
// Here we update max_id
|
|
Shape_Chunk::max_id = max (Shape_Chunk::max_id,id);
|
|
|
|
// go to version number
|
|
SetFilePointer(rif_file,shphead.first_entry() + 100,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
|
|
|
|
Shape_Chunk * tmpshp;
|
|
Shape_Header_Chunk * tmpshph;
|
|
List<Chunk *> shpchs;
|
|
lookup_child ("REBSHAPE",shpchs);
|
|
|
|
if (shpchs.size()){
|
|
for (LIF<Chunk *> shpchls(&shpchs); !shpchls.done(); shpchls.next()){
|
|
tmpshp = (Shape_Chunk *)shpchls();
|
|
tmpshph = tmpshp->get_header();
|
|
// if this is the same object
|
|
if (tmpshph)
|
|
if (id == tmpshph->file_id_num) break;
|
|
}
|
|
if (!shpchls.done()) {
|
|
if (tmpshph->version_no < v_no)
|
|
tmpshp->updated_outside = TRUE;
|
|
if (flags & GENERAL_FLAG_LOCKED) {
|
|
// do the lock check
|
|
if (!tmpshp->local_lock) {
|
|
tmpshp->external_lock = TRUE;
|
|
strncpy(tmpshph->lock_user, locker,16);
|
|
tmpshph->lock_user[16] = '\0';
|
|
}
|
|
else if (strncmp(tmpshph->lock_user, locker,16)) {
|
|
tmpshp->external_lock = TRUE;
|
|
strncpy(tmpshph->lock_user, locker,16);
|
|
tmpshph->lock_user[16] = '\0';
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// sprites
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> sprfptrs;
|
|
list_chunks_in_file(& sprfptrs, rif_file, "RSPRITES");
|
|
List<Chunk *> sprchlst;
|
|
lookup_child("RSPRITES",sprchlst);
|
|
|
|
AllSprites_Chunk * sprch;
|
|
AllSprites_Header_Chunk * sprhead = 0;
|
|
|
|
if (sprchlst.size())
|
|
{
|
|
sprch = (AllSprites_Chunk *)sprchlst.first_entry();
|
|
sprhead = sprch->get_header();
|
|
}
|
|
|
|
if (sprhead)
|
|
{
|
|
if (sprfptrs.size())
|
|
{
|
|
SetFilePointer (rif_file,sprfptrs.first_entry(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
List<int> sprchhl;
|
|
list_chunks_in_file(& sprchhl, rif_file, "ASPRHEAD");
|
|
|
|
assert (sprchhl.size() == 1);
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,sprchhl.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
|
|
|
|
// go to version number
|
|
SetFilePointer(rif_file,sprchhl.first_entry() + 32,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
|
|
|
|
if (sprhead->version_no < v_no)
|
|
{
|
|
sprch->updated_outside = TRUE;
|
|
}
|
|
if (flags & GENERAL_FLAG_LOCKED)
|
|
{
|
|
if (!sprch->local_lock) {
|
|
sprch->external_lock = TRUE;
|
|
strncpy(sprhead->lock_user, locker,16);
|
|
sprhead->lock_user[16] = '\0';
|
|
}
|
|
else if (strncmp(sprhead->lock_user, locker,16)) {
|
|
sprch->external_lock = TRUE;
|
|
strncpy(sprhead->lock_user, locker,16);
|
|
sprhead->lock_user[16] = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// environment data
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> edfptrs;
|
|
list_chunks_in_file(& edfptrs, rif_file, "REBENVDT");
|
|
|
|
Environment_Data_Chunk * ed;
|
|
Environment_Data_Header_Chunk * edhead = 0;
|
|
|
|
|
|
ed = (Environment_Data_Chunk *)lookup_single_child("REBENVDT");
|
|
if (ed)
|
|
{
|
|
edhead = ed->get_header();
|
|
}
|
|
|
|
if (edhead)
|
|
{
|
|
if (edfptrs.size())
|
|
{
|
|
SetFilePointer (rif_file,edfptrs.first_entry(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
List<int> edhl; list_chunks_in_file(& edhl, rif_file, "ENDTHEAD");
|
|
|
|
assert (edhl.size() == 1);
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,edhl.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
|
|
|
|
// go to version number
|
|
SetFilePointer(rif_file,edhl.first_entry() + 32,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
|
|
|
|
if (edhead->version_no < v_no)
|
|
{
|
|
ed->updated_outside = TRUE;
|
|
}
|
|
if (flags & GENERAL_FLAG_LOCKED)
|
|
{
|
|
if (!ed->local_lock) {
|
|
ed->external_lock = TRUE;
|
|
strncpy(edhead->lock_user, locker,16);
|
|
edhead->lock_user[16] = '\0';
|
|
}
|
|
else if (strncmp(edhead->lock_user, locker,16)) {
|
|
ed->external_lock = TRUE;
|
|
strncpy(edhead->lock_user, locker,16);
|
|
edhead->lock_user[16] = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check file for REBENUMS chunk
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> enumfptrs; list_chunks_in_file(& enumfptrs, rif_file, "REBENUMS");
|
|
|
|
Enum_Chunk * enumch;
|
|
Enum_Header_Chunk * enumhead = 0;
|
|
|
|
enumch = (Enum_Chunk *)lookup_single_child("REBENUMS");
|
|
if (enumch)
|
|
{
|
|
enumhead = enumch->get_header();
|
|
}
|
|
|
|
if (enumhead)
|
|
{
|
|
if (enumfptrs.size())
|
|
{
|
|
SetFilePointer (rif_file,enumfptrs.first_entry(),0,FILE_BEGIN);
|
|
|
|
// get header list
|
|
List<int> enumchhl; list_chunks_in_file(& enumchhl, rif_file, "ENUMHEAD");
|
|
|
|
assert (enumchhl.size() == 1);
|
|
|
|
// go to lock status in header
|
|
SetFilePointer(rif_file,enumchhl.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
|
|
ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
|
|
|
|
// go to version number
|
|
SetFilePointer(rif_file,enumchhl.first_entry() + 32,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
|
|
|
|
if (enumhead->version_no < v_no)
|
|
{
|
|
enumch->updated_outside = TRUE;
|
|
}
|
|
if (flags & GENERAL_FLAG_LOCKED)
|
|
{
|
|
if (!enumch->local_lock) {
|
|
enumch->external_lock = TRUE;
|
|
strncpy(enumhead->lock_user, locker,16);
|
|
enumhead->lock_user[16] = '\0';
|
|
}
|
|
else if (strncmp(enumhead->lock_user, locker,16)) {
|
|
enumch->external_lock = TRUE;
|
|
strncpy(enumhead->lock_user, locker,16);
|
|
enumhead->lock_user[16] = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CloseHandle (rif_file);
|
|
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
|
|
#if InterfaceEngine
|
|
|
|
extern File_Chunk * Env_Chunk;
|
|
|
|
#endif
|
|
|
|
BOOL File_Chunk::update_file()
|
|
{
|
|
|
|
#if DisableLock
|
|
if (!filename) return FALSE;
|
|
|
|
char tempname [256];
|
|
strcpy (tempname, filename);
|
|
|
|
List<Shape_Chunk *> slist;
|
|
list_shapes(&slist);
|
|
List<Object_Chunk *> olist;
|
|
list_objects(&olist);
|
|
|
|
for (LIF<Shape_Chunk *> sli(&slist); !sli.done(); sli.next())
|
|
{
|
|
if (sli()->deleted)
|
|
{
|
|
delete sli();
|
|
}
|
|
}
|
|
|
|
for (LIF<Object_Chunk *> oli(&olist); !oli.done(); oli.next())
|
|
{
|
|
if (oli()->deleted)
|
|
{
|
|
delete oli();
|
|
}
|
|
}
|
|
|
|
|
|
return(write_file(tempname));
|
|
|
|
#else
|
|
|
|
#if InterfaceEngine
|
|
|
|
// log, to track error
|
|
char fname [256];
|
|
char * dotpos;
|
|
|
|
strcpy (fname, filename);
|
|
|
|
dotpos = strrchr (fname, '.');
|
|
|
|
sprintf (dotpos, ".log");
|
|
|
|
FILE * log = fopen (fname, "a");
|
|
|
|
#endif
|
|
|
|
if (!filename) return FALSE;
|
|
|
|
twprintf("Updating %s\n",filename);
|
|
|
|
check_file();
|
|
|
|
HANDLE rif_file;
|
|
unsigned long bytes_read;
|
|
|
|
int tries = 0;
|
|
|
|
//twprintf("Opening file\n");
|
|
|
|
rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE)
|
|
{
|
|
DWORD error_num = GetLastError();
|
|
switch (error_num)
|
|
{
|
|
case ERROR_SHARING_VIOLATION:
|
|
twprintf("Sharing violation - retrying\n");
|
|
break;
|
|
case ERROR_ACCESS_DENIED:
|
|
twprintf("File is Read Only\n");
|
|
return FALSE;
|
|
default:
|
|
twprintf("Unknown error updating file, Error code %#08x\n",error_num);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
while(rif_file == INVALID_HANDLE_VALUE && tries<10)
|
|
{
|
|
twprintf("Again...\n");
|
|
rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
tries ++;
|
|
clock_t ctime = clock();
|
|
double secs = (double)ctime / (double)CLOCKS_PER_SEC;
|
|
double secsgone;
|
|
do
|
|
{
|
|
ctime = clock();
|
|
secsgone = (double)ctime / (double)CLOCKS_PER_SEC;
|
|
}
|
|
while( (secsgone-secs)<1);
|
|
}
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
error_code = CHECK_FAILED_NOT_OPEN;
|
|
twprintf("ERROR - SHARING VIOLATION UNRESOLVED\n\n");
|
|
return FALSE;
|
|
}
|
|
|
|
//twprintf("Opened\n\n");
|
|
|
|
prepare_for_output();
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
//twprintf("Version info\n");
|
|
|
|
List<int> verinf; list_chunks_in_file(& verinf, rif_file, "RIFVERIN");
|
|
|
|
// taking first entry of this list, if there are more - tough ha ha
|
|
// there shouldn't be
|
|
|
|
// Just increment it by one and reoutput
|
|
// check_file sets the internal copy of the chunk to the current file
|
|
// setting, so we need to increment that as well
|
|
|
|
if (verinf.size()) {
|
|
|
|
int f_version_num;
|
|
SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0);
|
|
|
|
SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
|
|
|
|
RIF_Version_Num_Chunk* rvnc=(RIF_Version_Num_Chunk*)lookup_single_child ("RIFVERIN");
|
|
|
|
if (rvnc)
|
|
rvnc->file_version_no++;
|
|
|
|
f_version_num++;
|
|
|
|
WriteFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0);
|
|
|
|
}
|
|
|
|
// go through the list of shape chunks looking for shape chunks to output
|
|
//twprintf("\nShapes\n");
|
|
|
|
List<Chunk *> shplst;
|
|
lookup_child ("REBSHAPE",shplst);
|
|
|
|
if (shplst.size())
|
|
for (LIF<Chunk *> sli(&shplst); !sli.done(); sli.next()) {
|
|
|
|
Shape_Chunk * tmpshpptr = ((Shape_Chunk *)sli());
|
|
|
|
if (tmpshpptr->updated &&
|
|
!(tmpshpptr->updated_outside || tmpshpptr->external_lock))
|
|
tmpshpptr->update_chunk_in_file(rif_file);
|
|
}
|
|
|
|
|
|
// go through the list of object chunks looking for chunks to output
|
|
//twprintf("\nObjects\n");
|
|
|
|
List<Chunk *> oblst;
|
|
lookup_child ("RBOBJECT",oblst);
|
|
|
|
if (oblst.size())
|
|
for (LIF<Chunk *> oli(&oblst); !oli.done(); oli.next()) {
|
|
|
|
Object_Chunk * tmpobptr = ((Object_Chunk *)oli());
|
|
|
|
if (tmpobptr->updated && !(tmpobptr->updated_outside || tmpobptr->external_lock))
|
|
tmpobptr->update_chunk_in_file(rif_file);
|
|
|
|
}
|
|
|
|
|
|
//twprintf("\nSprites\n");
|
|
|
|
List<Chunk *> sprfptrs;
|
|
lookup_child ("RSPRITES",sprfptrs);
|
|
AllSprites_Chunk * sprch;
|
|
|
|
if (sprfptrs.size())
|
|
{
|
|
sprch = (AllSprites_Chunk *)sprfptrs.first_entry();
|
|
if (sprch->updated &&
|
|
!(sprch->updated_outside || sprch->external_lock))
|
|
sprch->update_chunk_in_file(rif_file);
|
|
}
|
|
|
|
//twprintf("\nEnvironment data\n");
|
|
|
|
Environment_Data_Chunk * ed;
|
|
|
|
ed = (Environment_Data_Chunk *)lookup_single_child ("REBENVDT");
|
|
if (ed)
|
|
{
|
|
|
|
#if InterfaceEngine
|
|
|
|
fprintf (log, "Env_Data %d %d %d %d", ed->updated, ed->local_lock, ed->updated_outside, ed->external_lock);
|
|
|
|
#endif
|
|
|
|
if (ed->updated &&
|
|
!(ed->updated_outside || ed->external_lock))
|
|
ed->update_chunk_in_file(rif_file);
|
|
}
|
|
|
|
//twprintf("\nEnum data\n");
|
|
|
|
List<Chunk *> enumfptrs;
|
|
lookup_child ("REBENUMS",enumfptrs);
|
|
Enum_Chunk * enumch;
|
|
|
|
if (enumfptrs.size())
|
|
{
|
|
enumch = (Enum_Chunk *)enumfptrs.first_entry();
|
|
if (enumch->updated &&
|
|
!(enumch->updated_outside || enumch->external_lock))
|
|
enumch->update_chunk_in_file(rif_file);
|
|
}
|
|
|
|
//
|
|
|
|
int file_length = GetFileSize(rif_file,0);
|
|
SetFilePointer (rif_file,8,0,FILE_BEGIN);
|
|
|
|
WriteFile (rif_file, (long *) &file_length, 4, &bytes_read, 0);
|
|
|
|
CloseHandle (rif_file);
|
|
|
|
#if InterfaceEngine
|
|
|
|
fclose (log);
|
|
|
|
#endif
|
|
return TRUE;
|
|
|
|
#endif //DisableLock
|
|
}
|
|
|
|
BOOL File_Chunk::update_chunks_from_file()
|
|
{
|
|
#if DisableLock
|
|
return(TRUE);
|
|
#endif
|
|
|
|
if (!filename) return FALSE;
|
|
check_file();
|
|
|
|
HANDLE rif_file;
|
|
unsigned long bytes_read;
|
|
|
|
rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
error_code = CHECK_FAILED_NOT_OPEN;
|
|
return FALSE;
|
|
}
|
|
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> verinf; list_chunks_in_file(& verinf, rif_file, "RIFVERIN");
|
|
|
|
if (verinf.size()) {
|
|
|
|
int f_version_num;
|
|
SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
|
|
ReadFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0);
|
|
|
|
SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
|
|
|
|
List<Chunk *> lverinf;
|
|
lookup_child ("RIFVERIN",lverinf);
|
|
|
|
if (lverinf.size())
|
|
if (f_version_num == ((RIF_Version_Num_Chunk *)(lverinf.first_entry()))->file_version_no){
|
|
CloseHandle (rif_file);
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
// go through the list of object chunks looking for chunks to input
|
|
|
|
List<Chunk *> oblst;
|
|
lookup_child ("RBOBJECT",oblst);
|
|
|
|
if (oblst.size())
|
|
for (LIF<Chunk *> oli(&oblst); !oli.done(); oli.next()) {
|
|
|
|
Object_Chunk * tmpobptr = ((Object_Chunk *)oli());
|
|
|
|
if (tmpobptr->updated_outside) {
|
|
// find the chunk, then input it to a buffer and create a new object
|
|
// from the buffer
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> obfptrs; list_chunks_in_file(& obfptrs, rif_file, "RBOBJECT");
|
|
|
|
char name[50];
|
|
|
|
LIF<int> ofpl(&obfptrs);
|
|
|
|
if (obfptrs.size()) {
|
|
for (; !ofpl.done(); ofpl.next()) {
|
|
|
|
SetFilePointer (rif_file, ofpl(),0,FILE_BEGIN);
|
|
// get header list
|
|
List<int> obhead; list_chunks_in_file(& obhead, rif_file, "OBJHEAD1");
|
|
|
|
assert (obhead.size() == 1);
|
|
|
|
// get object identifier
|
|
SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN);
|
|
int i = 0;
|
|
do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0);
|
|
while (name[i++] != 0);
|
|
|
|
if (!strcmp(name, tmpobptr->object_data.o_name)) break;
|
|
}
|
|
}
|
|
|
|
if (!ofpl.done()) {
|
|
|
|
char * buffer;
|
|
|
|
SetFilePointer (rif_file,ofpl()+8,0,FILE_BEGIN);
|
|
int length;
|
|
ReadFile(rif_file, (long *) &length, 4, &bytes_read, 0);
|
|
buffer = new char [length];
|
|
ReadFile(rif_file, (long *) buffer, length-12, &bytes_read, 0);
|
|
new Object_Chunk (this, buffer, length-12);
|
|
delete [] buffer;
|
|
if (tmpobptr->get_header())
|
|
if (tmpobptr->get_header()->associated_shape)
|
|
tmpobptr->deassoc_with_shape(tmpobptr->get_header()->associated_shape);
|
|
delete tmpobptr;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// go through the list of shape chunks looking for shape chunks to input
|
|
|
|
List<Chunk *> shplst;
|
|
lookup_child ("REBSHAPE",shplst);
|
|
|
|
if (shplst.size())
|
|
for (LIF<Chunk *> sli(&shplst); !sli.done(); sli.next()) {
|
|
|
|
Shape_Chunk * tmpshpptr = ((Shape_Chunk *)sli());
|
|
|
|
Shape_Header_Chunk * shhead = tmpshpptr->get_header();
|
|
|
|
if (!shhead) continue;
|
|
|
|
if (tmpshpptr->updated_outside) {
|
|
// find the chunk, then input it to a buffer and create a new object
|
|
// from the buffer
|
|
SetFilePointer (rif_file,0,0,FILE_BEGIN);
|
|
|
|
List<int> shfptrs; list_chunks_in_file(& shfptrs, rif_file, "REBSHAPE");
|
|
|
|
LIF<int> sfpl(&shfptrs);
|
|
|
|
if (shfptrs.size()) {
|
|
for (sfpl.restart(); !sfpl.done(); sfpl.next()) {
|
|
|
|
SetFilePointer (rif_file, sfpl(),0,FILE_BEGIN);
|
|
// get header list
|
|
List<int> shphead; list_chunks_in_file(& shphead, rif_file, "SHPHEAD1");
|
|
|
|
assert (shphead.size() == 1);
|
|
|
|
// get object identifier
|
|
SetFilePointer(rif_file,shphead.first_entry() + 32,0,FILE_BEGIN);
|
|
int sh_number;
|
|
ReadFile (rif_file, (long *) &sh_number, 4, &bytes_read, 0);
|
|
|
|
if (sh_number == shhead->file_id_num) break;
|
|
}
|
|
}
|
|
|
|
if (!sfpl.done()) {
|
|
|
|
char * buffer;
|
|
|
|
SetFilePointer (rif_file,sfpl()+8,0,FILE_BEGIN);
|
|
int length;
|
|
ReadFile(rif_file, (long *) &length, 4, &bytes_read, 0);
|
|
buffer = new char [length];
|
|
ReadFile(rif_file, (long *) buffer, length-12, &bytes_read, 0);
|
|
new Shape_Chunk (this, buffer, length-12);
|
|
delete [] buffer;
|
|
// Associate with the new objects
|
|
if ((shhead->associated_objects_store).size())
|
|
{
|
|
for (LIF<Object_Chunk *> aol(&(shhead->associated_objects_store)); !aol.done(); aol.next())
|
|
{
|
|
tmpshpptr->deassoc_with_object(aol());
|
|
}
|
|
}
|
|
delete tmpshpptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
post_input_processing();
|
|
|
|
CloseHandle(rif_file);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
void File_Chunk::list_objects(List<Object_Chunk *> * pList)
|
|
{
|
|
Chunk * child_ptr = children;
|
|
|
|
while (pList->size())
|
|
pList->delete_first_entry();
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("RBOBJECT", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
pList->add_entry((Object_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
|
|
}
|
|
|
|
void File_Chunk::list_shapes(List<Shape_Chunk *> * pList)
|
|
{
|
|
Chunk * child_ptr = children;
|
|
|
|
while (pList->size())
|
|
pList->delete_first_entry();
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("REBSHAPE", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
pList->add_entry((Shape_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
|
|
}
|
|
|
|
void File_Chunk::list_dummy_objects(List<Dummy_Object_Chunk *> * pList){
|
|
Chunk * child_ptr = children;
|
|
|
|
while (pList->size())
|
|
pList->delete_first_entry();
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("DUMMYOBJ", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
pList->add_entry((Dummy_Object_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
|
|
}
|
|
|
|
Environment_Data_Chunk * File_Chunk::get_env_data()
|
|
{
|
|
List<Environment_Data_Chunk *> e_list;
|
|
Chunk * child_ptr = children;
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("REBENVDT", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
e_list.add_entry((Environment_Data_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
|
|
// There can be only ONE.
|
|
assert (e_list.size() < 2);
|
|
|
|
if (e_list.size())
|
|
return e_list.first_entry();
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
void File_Chunk::build_object_array()
|
|
{
|
|
List<Object_Chunk*> oblist;
|
|
list_objects(&oblist);
|
|
|
|
if(object_array)
|
|
{
|
|
free(object_array);
|
|
object_array=0;
|
|
}
|
|
object_array_size=0;
|
|
|
|
LIF<Object_Chunk*> oblif(&oblist);
|
|
|
|
//find the highest object index
|
|
for(oblif.restart();!oblif.done();oblif.next())
|
|
{
|
|
object_array_size=max(object_array_size,oblif()->object_data.index_num+1);
|
|
}
|
|
|
|
if(object_array_size<=0) return;
|
|
|
|
object_array = (Object_Chunk**) malloc(sizeof(Object_Chunk*)*object_array_size);
|
|
for(int i=0;i<object_array_size;i++)
|
|
{
|
|
object_array[i]=0;
|
|
}
|
|
|
|
//now fill in object array
|
|
|
|
for(oblif.restart();!oblif.done();oblif.next())
|
|
{
|
|
int index=oblif()->object_data.index_num;
|
|
if(index>=0)
|
|
{
|
|
object_array[index]=oblif();
|
|
}
|
|
}
|
|
}
|
|
|
|
Object_Chunk* File_Chunk::get_object_by_index(int index)
|
|
{
|
|
if(!object_array) build_object_array();
|
|
if(index<0 || index>=object_array_size)return 0;
|
|
return object_array[index];
|
|
}
|
|
|
|
void File_Chunk::assign_index_to_object(Object_Chunk* object)
|
|
{
|
|
assert(object);
|
|
|
|
if(!object_array) build_object_array();
|
|
//see if there is a free index
|
|
|
|
for(int i=0;i<object_array_size;i++)
|
|
{
|
|
if(!object_array[i])
|
|
{
|
|
object->object_data_store->index_num=i;
|
|
object_array[i]=object;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//add a new entry on the end of the array
|
|
object_array_size++;
|
|
|
|
object_array=(Object_Chunk**) realloc(object_array,sizeof(Object_Chunk*)*object_array_size);
|
|
|
|
|
|
object->object_data_store->index_num=object_array_size-1;;
|
|
object_array[object_array_size-1]=object;
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
|
|
// Class GodFather_Chunk functions
|
|
|
|
/*
|
|
Children for GodFather_Chunk :
|
|
"REBSHAPE" Shape_Chunk
|
|
"RSPRITES" AllSprites_Chunk
|
|
"RBOBJECT" Object_Chunk
|
|
"RIFVERIN" RIF_Version_Num_Chunk
|
|
"REBENVDT" Environment_Data_Chunk
|
|
"REBENUMS" Enum_Chunk
|
|
"OBJCHIER" Object_Hierarchy_Chunk
|
|
"OBHALTSH" Object_Hierarchy_Alternate_Shape_Set_Chunk
|
|
|
|
*/
|
|
|
|
GodFather_Chunk::GodFather_Chunk(char * buffer, size_t size)
|
|
: Chunk_With_Children (NULL, "REBINFF2")
|
|
{
|
|
Parent_File = this;
|
|
|
|
char * buffer_ptr = buffer;
|
|
|
|
// The start of the first chunk
|
|
|
|
while ((buffer_ptr-buffer)< ((signed)size-12) && !error_code) {
|
|
|
|
if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)size-12)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
break;
|
|
}
|
|
|
|
DynCreate(buffer_ptr);
|
|
buffer_ptr += *(int *)(buffer_ptr + 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/////////////////////////////////////////
|
|
|
|
// Class RIF_Version_Num_Chunk functions
|
|
|
|
RIF_IMPLEMENT_DYNCREATE("RIFVERIN",RIF_Version_Num_Chunk)
|
|
|
|
void RIF_Version_Num_Chunk::fill_data_block(char * data_start)
|
|
{
|
|
strncpy (data_start, identifier, 8);
|
|
|
|
data_start += 8;
|
|
|
|
*((int *) data_start) = chunk_size;
|
|
|
|
data_start += 4;
|
|
|
|
*((int *) data_start) = file_version_no;
|
|
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////
|
|
|
|
// Class RIF_Name_Chunk functions
|
|
RIF_IMPLEMENT_DYNCREATE("RIFFNAME",RIF_Name_Chunk)
|
|
|
|
RIF_Name_Chunk::RIF_Name_Chunk (Chunk_With_Children * parent, const char * rname)
|
|
: Chunk (parent, "RIFFNAME")
|
|
{
|
|
rif_name = new char [strlen(rname)+1];
|
|
strcpy (rif_name, rname);
|
|
}
|
|
|
|
RIF_Name_Chunk::RIF_Name_Chunk (Chunk_With_Children * parent, const char * rdata, size_t /*rsize*/)
|
|
: Chunk (parent, "RIFFNAME")
|
|
{
|
|
rif_name = new char [strlen(rdata)+1];
|
|
strcpy (rif_name, rdata);
|
|
}
|
|
|
|
RIF_Name_Chunk::~RIF_Name_Chunk ()
|
|
{
|
|
if (rif_name)
|
|
delete [] rif_name;
|
|
}
|
|
|
|
|
|
void RIF_Name_Chunk::fill_data_block (char * data_start)
|
|
{
|
|
strncpy (data_start, identifier, 8);
|
|
|
|
data_start += 8;
|
|
|
|
*((int *) data_start) = chunk_size;
|
|
|
|
data_start += 4;
|
|
|
|
strcpy (data_start, rif_name);
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
/*
|
|
Children for RIF_File_Chunk :
|
|
"REBSHAPE" Shape_Chunk
|
|
"RSPRITES" AllSprites_Chunk
|
|
"RBOBJECT" Object_Chunk
|
|
"RIFVERIN" RIF_Version_Num_Chunk
|
|
"REBENVDT" Environment_Data_Chunk
|
|
"OBJCHIER" Object_Hierarchy_Chunk
|
|
"OBHALTSH" Object_Hierarchy_Alternate_Shape_Set_Chunk
|
|
|
|
*/
|
|
|
|
|
|
RIF_File_Chunk::RIF_File_Chunk (Chunk_With_Children * parent, const char * file_name)
|
|
: Chunk_With_Children (parent, "SUBRIFFL")
|
|
{
|
|
char rifIsCompressed = FALSE;
|
|
char *uncompressedData = NULL;
|
|
HANDLE rif_file;
|
|
DWORD file_size;
|
|
DWORD file_size_from_file;
|
|
unsigned long bytes_read;
|
|
char * buffer;
|
|
char * buffer_ptr;
|
|
char id_buffer[9];
|
|
|
|
|
|
Chunk * ParentFileStore = Parent_File;
|
|
|
|
Parent_File = this;
|
|
|
|
error_code = 0;
|
|
|
|
rif_file = CreateFileA (file_name, GENERIC_READ, 0, 0, OPEN_EXISTING,
|
|
FILE_FLAG_RANDOM_ACCESS, 0);
|
|
|
|
|
|
if (rif_file == INVALID_HANDLE_VALUE) {
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
Parent_File = ParentFileStore;
|
|
return;
|
|
}
|
|
|
|
file_size = GetFileSize (rif_file, NULL);
|
|
|
|
if (!ReadFile(rif_file, id_buffer, 8, &bytes_read, 0)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
Parent_File = ParentFileStore;
|
|
return;
|
|
}
|
|
|
|
//check for compressed rif
|
|
if (!strncmp (id_buffer, COMPRESSED_RIF_IDENTIFIER, 8))
|
|
{
|
|
rifIsCompressed = TRUE;
|
|
}
|
|
else if (strncmp (id_buffer, "REBINFF2", 8)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
CloseHandle (rif_file);
|
|
Parent_File = ParentFileStore;
|
|
return;
|
|
}
|
|
|
|
buffer = new char [file_size];
|
|
|
|
/* KJL 17:57:44 19/09/98 - if the rif is compressed, we must load the whole
|
|
file in and then pass it to the decompression routine, which will return a
|
|
pointer to the original data. */
|
|
if (rifIsCompressed)
|
|
{
|
|
if (!ReadFile(rif_file, buffer+8, (file_size-8), &bytes_read, 0))
|
|
{
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
Parent_File = ParentFileStore;
|
|
delete [] buffer;
|
|
return;
|
|
}
|
|
uncompressedData = HuffmanDecompress((HuffmanPackage*)buffer);
|
|
file_size = ((HuffmanPackage*)buffer)->UncompressedDataSize;
|
|
|
|
delete [] buffer; // kill the buffer the compressed file was loaded into
|
|
|
|
buffer_ptr = buffer = uncompressedData+12; // skip header data
|
|
}
|
|
else // the normal uncompressed approach:
|
|
{
|
|
//get the file size stored in the rif file
|
|
if (!ReadFile(rif_file, &file_size_from_file, 4, &bytes_read, 0)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
Parent_File = ParentFileStore;
|
|
delete [] buffer;
|
|
return;
|
|
}
|
|
|
|
//and compare with the actual file size
|
|
if (file_size != file_size_from_file) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
CloseHandle (rif_file);
|
|
Parent_File = ParentFileStore;
|
|
delete [] buffer;
|
|
return;
|
|
}
|
|
|
|
//read the rest of the file into the buffer
|
|
if (!ReadFile(rif_file, buffer, (file_size-12), &bytes_read, 0))
|
|
{
|
|
error_code = CHUNK_FAILED_ON_LOAD;
|
|
CloseHandle (rif_file);
|
|
Parent_File = ParentFileStore;
|
|
delete [] buffer;
|
|
return;
|
|
}
|
|
buffer_ptr = buffer;
|
|
}
|
|
|
|
|
|
|
|
|
|
// Process the RIF
|
|
|
|
// The start of the first chunk
|
|
|
|
while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) {
|
|
|
|
if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)file_size-12)) {
|
|
error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
|
|
break;
|
|
}
|
|
|
|
DynCreate(buffer_ptr);
|
|
buffer_ptr += *(int *)(buffer_ptr + 8);
|
|
}
|
|
|
|
/* KJL 17:59:42 19/09/98 - release the memory holding the rif */
|
|
if (rifIsCompressed)
|
|
{
|
|
free(uncompressedData);
|
|
}
|
|
else
|
|
{
|
|
delete [] buffer;
|
|
}
|
|
|
|
CloseHandle (rif_file);
|
|
|
|
post_input_processing();
|
|
|
|
Parent_File = ParentFileStore;
|
|
|
|
}
|
|
|
|
void RIF_File_Chunk::post_input_processing()
|
|
{
|
|
List<Shape_Chunk *> shplist;
|
|
List<Object_Chunk *> objlist;
|
|
|
|
List<Chunk *> child_lists;
|
|
|
|
lookup_child("REBSHAPE",child_lists);
|
|
|
|
while (child_lists.size()) {
|
|
shplist.add_entry((Shape_Chunk *)child_lists.first_entry());
|
|
child_lists.delete_first_entry();
|
|
}
|
|
|
|
lookup_child("RBOBJECT",child_lists);
|
|
|
|
|
|
while (child_lists.size()) {
|
|
objlist.add_entry((Object_Chunk *)child_lists.first_entry());
|
|
child_lists.delete_first_entry();
|
|
}
|
|
|
|
for (LIF<Object_Chunk *> ol(&objlist); !ol.done(); ol.next()) {
|
|
|
|
if (ol()->get_header()) {
|
|
|
|
for (LIF<Shape_Chunk *> sl(&shplist);
|
|
!sl.done(); sl.next()) {
|
|
if (sl()->get_header())
|
|
if (sl()->get_header()->file_id_num == ol()->get_header()->shape_id_no){
|
|
ol()->assoc_with_shape(sl());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
for (LIF<Shape_Chunk *> sli(&shplist); !sli.done(); sli.next())
|
|
{
|
|
Shape_Chunk::max_id = max (Shape_Chunk::max_id,sli()->get_header()->file_id_num);
|
|
}
|
|
|
|
Chunk_With_Children::post_input_processing();
|
|
}
|
|
|
|
|
|
void RIF_File_Chunk::list_objects(List<Object_Chunk *> * pList)
|
|
{
|
|
Chunk * child_ptr = children;
|
|
|
|
while (pList->size())
|
|
pList->delete_first_entry();
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("RBOBJECT", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
pList->add_entry((Object_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
}
|
|
|
|
void RIF_File_Chunk::list_shapes(List<Shape_Chunk *> * pList)
|
|
{
|
|
Chunk * child_ptr = children;
|
|
|
|
while (pList->size())
|
|
pList->delete_first_entry();
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("REBSHAPE", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
pList->add_entry((Shape_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
|
|
}
|
|
|
|
Environment_Data_Chunk * RIF_File_Chunk::get_env_data()
|
|
{
|
|
List<Environment_Data_Chunk *> e_list;
|
|
Chunk * child_ptr = children;
|
|
|
|
if (children)
|
|
while (child_ptr != NULL) {
|
|
if (strncmp ("REBENVDT", child_ptr->identifier, 8) == NULL)
|
|
{
|
|
assert (!child_ptr->r_u_miscellaneous());
|
|
e_list.add_entry((Environment_Data_Chunk *)child_ptr);
|
|
}
|
|
child_ptr = child_ptr->next;
|
|
}
|
|
|
|
// There can be only ONE.
|
|
assert (e_list.size() < 2);
|
|
|
|
if (e_list.size())
|
|
return e_list.first_entry();
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|