summaryrefslogtreecommitdiff
path: root/src/win95/mishchnk.cpp
diff options
context:
space:
mode:
authorSteven Fuller <relnev@icculus.org>2001-07-01 00:55:22 +0000
committerPatryk Obara <dreamer.tan@gmail.com>2019-08-20 02:09:04 +0200
commit2186d5f3f95cd74a070a490d899291648d58667a (patch)
tree55241a1afa3e1a22e0b6593a8dead0b703800f44 /src/win95/mishchnk.cpp
parent218ca90543758a20ac326e444ca0643174ca7384 (diff)
Initial revision
Diffstat (limited to 'src/win95/mishchnk.cpp')
-rw-r--r--src/win95/mishchnk.cpp1999
1 files changed, 1999 insertions, 0 deletions
diff --git a/src/win95/mishchnk.cpp b/src/win95/mishchnk.cpp
new file mode 100644
index 0000000..5f4dde3
--- /dev/null
+++ b/src/win95/mishchnk.cpp
@@ -0,0 +1,1999 @@
+#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);
+ }
+}