1 #include "chunk.hpp"
2 #include "chnktype.hpp"
3 #include "mishchnk.hpp"
4 
5 #include "shpchunk.hpp"
6 #include "obchunk.hpp"
7 
8 
9 
10 #include "huffman.hpp"
11 
12 
13 // Class Lockable_Chunk_With_Children functions
14 
15 extern char * users_name;
16 
17 //macro for helping to force inclusion of chunks when using libraries
FORCE_CHUNK_INCLUDE_IMPLEMENT(mishchnk)18 FORCE_CHUNK_INCLUDE_IMPLEMENT(mishchnk)
19 
20 BOOL Lockable_Chunk_With_Children::lock_chunk(File_Chunk & fchunk)
21 {
22 	if (!fchunk.filename) return FALSE;
23 
24 	if (local_lock) return FALSE; // you can't lock a chunk twice
25 
26 	#if DisableLock
27 	if(external_lock) return FALSE;
28 	local_lock = TRUE;
29 	set_lock_user (users_name);
30 	return TRUE;
31 	#else
32 	if (!fchunk.check_file()) return FALSE;
33 	if (updated_outside || external_lock) return FALSE;
34 
35 	HANDLE rif_file;
36 	unsigned long bytes_read;
37 
38 	int tries = 0;
39 
40  	rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
41  					FILE_FLAG_RANDOM_ACCESS, 0);
42 
43 	while(rif_file == INVALID_HANDLE_VALUE && tries<10)
44 	{
45 	 	rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
46 	 					FILE_FLAG_RANDOM_ACCESS, 0);
47 	 	tries ++;
48 		clock_t ctime = clock();
49 		double secs	= (double)ctime / (double)CLOCKS_PER_SEC;
50 		double secsgone;
51 		do
52 		{
53 			ctime = clock();
54 			secsgone = (double)ctime / (double)CLOCKS_PER_SEC;
55 		}
56 		while( (secsgone-secs)<1);
57 	}
58 
59 	if (rif_file == INVALID_HANDLE_VALUE) {
60 		return FALSE;
61 	}
62 
63 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
64 
65 	List<int> chfptrs;
66 	list_chunks_in_file(& chfptrs, rif_file, identifier);
67 
68 	LIF<int> cfpl(&chfptrs);
69 
70 	if (chfptrs.size()) {
71 		for (; !cfpl.done(); cfpl.next()) {
72 
73 			SetFilePointer (rif_file, cfpl(),0,FILE_BEGIN);
74 
75 			if (file_equals(rif_file)) break;
76 		}
77 	}
78 
79 	if (!cfpl.done()) {
80 
81 		// go to start of chunk
82 		SetFilePointer (rif_file,cfpl(),0,FILE_BEGIN);
83 
84 		// get header list
85 		if (get_head_id())
86 		{
87 			List<int> obhead;
88 			list_chunks_in_file(& obhead, rif_file, get_head_id());
89 
90 			assert (obhead.size() == 1);
91 
92 			int flags;
93 
94 			// go to lock status in header
95 			SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN);
96 			ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
97 			SetFilePointer(rif_file,-4,0,FILE_CURRENT);
98 			flags |= GENERAL_FLAG_LOCKED;
99 			WriteFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
100 			WriteFile (rif_file, (long *) &users_name[0], 16, &bytes_read, 0);
101 		}
102 
103 	}
104 
105 	local_lock = TRUE;
106 
107 	set_lock_user (users_name);
108 
109 	CloseHandle (rif_file);
110 	return TRUE;
111 	#endif
112 }
113 
unlock_chunk(File_Chunk & fchunk,BOOL updateyn)114 BOOL Lockable_Chunk_With_Children::unlock_chunk (File_Chunk & fchunk, BOOL updateyn)
115 {
116 	if (updateyn)	{
117 		updated = TRUE;
118 	}
119 	#if DisableLock
120 	local_lock = FALSE;
121 	(void)fchunk;
122 	#else
123 	else
124 	{
125 		fchunk.check_file();
126 		if (updated_outside || external_lock) return FALSE;
127 
128 		HANDLE rif_file;
129 		unsigned long bytes_read;
130 
131 		rif_file = CreateFile (fchunk.filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
132 							FILE_FLAG_RANDOM_ACCESS, 0);
133 
134 		if (rif_file == INVALID_HANDLE_VALUE) {
135 			return FALSE;
136 		}
137 
138 		SetFilePointer (rif_file,0,0,FILE_BEGIN);
139 
140 		List<int> chfptrs;
141 		list_chunks_in_file(& chfptrs, rif_file, identifier);
142 
143 		List<obinfile> obs;
144 
145 		char name[50];
146 
147 		LIF<int> ofpl(&chfptrs);
148 
149 		if (chfptrs.size()) {
150 			for (; !ofpl.done(); ofpl.next()) {
151 
152 				SetFilePointer (rif_file, ofpl(),0,FILE_BEGIN);
153 
154 				if (file_equals(rif_file)) break;
155 			}
156 		}
157 
158 		if (!ofpl.done()) {
159 
160 			// go to start of chunk
161 			SetFilePointer (rif_file,ofpl(),0,FILE_BEGIN);
162 
163 			// get header list
164 			if (get_head_id())
165 			{
166 				List<int> obhead;
167 				list_chunks_in_file(& obhead, rif_file, get_head_id());
168 
169 				assert (obhead.size() == 1);
170 
171 				int flags;
172 
173 				// go to lock status in header
174 				SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN);
175 				ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
176 				SetFilePointer(rif_file,-4,0,FILE_CURRENT);
177 				flags &= ~GENERAL_FLAG_LOCKED;
178 				WriteFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
179 				WriteFile (rif_file, (long *) &users_name[0], 16, &bytes_read, 0);
180 			}
181 
182 		}
183 
184 		local_lock = FALSE;
185 
186 		CloseHandle (rif_file);
187 	}
188 	#endif
189 
190 
191 	return TRUE;
192 
193 }
194 
195 
update_chunk_in_file(HANDLE & rif_file)196 BOOL Lockable_Chunk_With_Children::update_chunk_in_file(HANDLE &rif_file)
197 {
198 
199 	unsigned long bytes_read;
200 	int length = 0;
201 
202 	const char * hd_id = get_head_id();
203 
204 	if (!hd_id) return FALSE;
205 
206 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
207 
208 	//twprintf("\nLooking for chunks in file\n");
209 
210 	List<int> shpfptrs;
211 	list_chunks_in_file(& shpfptrs, rif_file, identifier);
212 
213 	// look through chunks for the save of our current chunk
214 
215 	//twprintf("Checking each chunk\n");
216 
217 	LIF<int> sfpl(&shpfptrs);
218 
219 	if (shpfptrs.size()) {
220 		for (; !sfpl.done(); sfpl.next()) {
221 
222 			SetFilePointer (rif_file, sfpl()+8,0,FILE_BEGIN);
223 
224 			ReadFile (rif_file, (long *) &(length), 4, &bytes_read, 0);
225 
226 			SetFilePointer (rif_file, sfpl(),0,FILE_BEGIN);
227 			if (file_equals(rif_file)) break;
228 		}
229 	}
230 
231 	// then load the file after that chunk into a buffer,
232 	// output the chunk and write the buffer
233 	// unless the chunk is the last one in the file
234 
235 	//twprintf("Updating file\n");
236 
237 	if (!sfpl.done())
238 	{
239 
240 		int file_length = GetFileSize(rif_file,0);
241 
242 		if (file_length > (sfpl() + length)) {
243 
244 			SetFilePointer (rif_file, sfpl() + length,0,FILE_BEGIN);
245 
246 			char * tempbuffer;
247 			tempbuffer = new char [file_length - (sfpl() + length)];
248 
249 			ReadFile (rif_file, (long *) tempbuffer, (file_length - (sfpl() + length)), &bytes_read, 0);
250 
251 			SetFilePointer (rif_file, sfpl() ,0,FILE_BEGIN);
252 
253 			if (!deleted)
254 			{
255 				size_chunk();
256 				output_chunk(rif_file);
257 			}
258 
259 			WriteFile (rif_file, (long *) tempbuffer, (file_length - (sfpl() + length)), &bytes_read, 0);
260 
261 			delete [] tempbuffer;
262 
263 			SetEndOfFile (rif_file);
264 		}
265 		else{
266 
267 			SetFilePointer (rif_file, sfpl() ,0,FILE_BEGIN);
268 			if (!deleted)
269 			{
270 				size_chunk();
271 				output_chunk(rif_file);
272 			}
273 			SetEndOfFile (rif_file);
274 		}
275 
276 	}
277 	else {
278 
279 		SetFilePointer (rif_file,0 ,0,FILE_END);
280 		if (!deleted)
281 		{
282 			size_chunk();
283 			output_chunk(rif_file);
284 		}
285 		SetEndOfFile (rif_file);
286 	}
287 
288 	local_lock = FALSE;
289 
290 	updated = FALSE;
291 
292 	int file_length = GetFileSize(rif_file,0);
293 	SetFilePointer (rif_file,8,0,FILE_BEGIN);
294 
295 	WriteFile (rif_file, (long *) &file_length, 4, &bytes_read, 0);
296 
297 
298 	// DO NOT PUT ANY CODE AFTER THIS
299 
300 	if (deleted) delete this;
301 
302 	// OR ELSE !!!
303 
304 	return TRUE;
305 
306 }
307 
308 
size_chunk_for_process()309 size_t Lockable_Chunk_With_Children::size_chunk_for_process()
310 {
311 	if (output_chunk_for_process)
312 		return size_chunk();
313 	return(chunk_size = 0);
314 }
315 
316 
fill_data_block_for_process(char * data_start)317 void Lockable_Chunk_With_Children::fill_data_block_for_process(char * data_start)
318 {
319 	if (output_chunk_for_process)
320 	{
321 		fill_data_block(data_start);
322 		output_chunk_for_process = FALSE;
323 	}
324 }
325 
326 
327 
328 
329 ///////////////////////////////////////
330 
331 // Class File_Chunk functions
332 
333 /*
334 Children for File_Chunk :
335 "REBSHAPE"		Shape_Chunk
336 "RSPRITES"		AllSprites_Chunk
337 "RBOBJECT"		Object_Chunk
338 "RIFVERIN"		RIF_Version_Num_Chunk
339 "REBENVDT"		Environment_Data_Chunk
340 "REBENUMS"		Enum_Chunk
341 "OBJCHIER"		Object_Hierarchy_Chunk
342 "OBHALTSH"		Object_Hierarchy_Alternate_Shape_Set_Chunk
343 "HIDEGDIS"		Hierarchy_Degradation_Distance_Chunk
344 "INDSOUND"		Indexed_Sound_Chunk
345 "HSETCOLL"		Hierarchy_Shape_Set_Collection_Chunk
346 "DUMMYOBJ"		Dummy_Object_Chunk
347 
348 */
349 
File_Chunk(const char * file_name)350 File_Chunk::File_Chunk(const char * file_name)
351 : Chunk_With_Children (NULL, "REBINFF2")
352 {
353 // Load in whole chunk and traverse
354 	char rifIsCompressed = FALSE;
355 	char *uncompressedData = NULL;
356 	FILE *rif_file;
357 	DWORD file_size;
358 	DWORD file_size_from_file;
359 	char * buffer;
360 	char * buffer_ptr;
361 	char id_buffer[9];
362 
363 	Parent_File = this;
364 
365 	error_code = 0;
366 	object_array_size=0;
367 	object_array=0;
368 
369 	filename = new char [strlen(file_name) + 1];
370 
371 	strcpy (filename, file_name);
372 
373 	rif_file = OpenGameFile(file_name, FILEMODE_READONLY, FILETYPE_PERM);
374 
375 	if (rif_file == NULL) {
376 		error_code = CHUNK_FAILED_ON_LOAD;
377 		return;
378 	}
379 
380 	fseek(rif_file, 0, SEEK_END);
381 	file_size = ftell(rif_file);
382 	rewind(rif_file);
383 
384 
385 	if (fread(id_buffer, 1, 8, rif_file) != 8) {
386 		error_code = CHUNK_FAILED_ON_LOAD;
387 		fclose(rif_file);
388 		return;
389 	}
390 
391 	/* KJL 16:46:14 19/09/98 - check for a compressed rif */
392 	if (!strncmp (id_buffer, COMPRESSED_RIF_IDENTIFIER, 8))
393 	{
394 		rifIsCompressed = TRUE;
395 	}
396 	else if (strncmp (id_buffer, "REBINFF2", 8))
397 	{
398 		error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
399 		fclose(rif_file);
400 		return;
401 	}
402 
403 	buffer = new char [file_size];
404 
405 	/* KJL 17:57:44 19/09/98 - if the rif is compressed, we must load the whole
406 	file in and then pass it to the decompression routine, which will return a
407 	pointer to the original data. */
408 	if (rifIsCompressed)
409 	{
410 		if (fread(buffer+8, 1, (file_size-8), rif_file) != (file_size-8)) {
411 			error_code = CHUNK_FAILED_ON_LOAD;
412 			fclose(rif_file);
413 			return;
414 		}
415 		uncompressedData = HuffmanDecompress((HuffmanPackage*)buffer);
416 		file_size = ((HuffmanPackage*)buffer)->UncompressedDataSize;
417 
418 		delete [] buffer; // kill the buffer the compressed file was loaded into
419 
420 		buffer_ptr = buffer = uncompressedData+12; // skip header data
421 	}
422 	else // the normal uncompressed approach:
423 	{
424 		if (fread(&file_size_from_file, 1, 4, rif_file) != 4) {
425 			error_code = CHUNK_FAILED_ON_LOAD;
426 			fclose(rif_file);
427 			return;
428 		}
429 
430 		if (file_size != file_size_from_file) {
431 			error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
432 			fclose(rif_file);
433 			return;
434 		}
435 
436 		if (fread(buffer, 1, (file_size-12), rif_file) != (file_size-12)) {
437 			error_code = CHUNK_FAILED_ON_LOAD;
438 			fclose(rif_file);
439 			return;
440 		}
441 		buffer_ptr = buffer;
442 	}
443 
444 	fclose(rif_file);
445 
446 	// Process the RIF
447 	// The start of the first chunk
448 
449 	while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) {
450 
451 		if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)file_size-12)) {
452 			error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
453 			break;
454 		}
455 
456 		DynCreate(buffer_ptr);
457 		buffer_ptr += *(int *)(buffer_ptr + 8);
458 	}
459 
460 	/* KJL 17:59:42 19/09/98 - release the memory holding the rif */
461 	if (rifIsCompressed)
462 	{
463 		free(uncompressedData);
464 	}
465 	else
466 	{
467 		delete [] buffer;
468 	}
469 
470 	post_input_processing();
471 }
472 
File_Chunk()473 File_Chunk::File_Chunk()
474 : Chunk_With_Children (NULL, "REBINFF2")
475 {
476 // Empty File chunk
477 	new RIF_Version_Num_Chunk (this);
478 	filename = 0;
479 
480 	object_array_size=0;
481 	object_array=0;
482 }
483 
484 
~File_Chunk()485 File_Chunk::~File_Chunk()
486 {
487 	if (filename)
488 		delete [] filename;
489 
490 	if(object_array)
491 		free(object_array);
492 }
493 
494 #define SAVE_USING_COMPRESSION 1
495 
write_file(const char * fname)496 BOOL File_Chunk::write_file (const char * fname)
497 {
498 	if(!fname) return FALSE;
499 	//if a read_only file exists with this filename , then abort attempt to save
500 	DWORD attributes = GetFileAttributesA(fname);
501 	if (0xffffffff!=attributes)
502 	{
503 		if (attributes & FILE_ATTRIBUTE_READONLY)
504 		{
505 			return FALSE;
506 		}
507 	}
508 
509 
510 
511 	HANDLE rif_file;
512 
513 	if (filename) delete [] filename;
514 
515 	filename = new char [strlen(fname) + 1];
516 	strcpy (filename, fname);
517 
518 	//save under a temporary name in case a crash occurs during save;
519 	int filename_start_pos=0;
520 	int pos=0;
521 	while(fname[pos])
522 	{
523 		if(fname[pos]=='\\' || fname[pos]==':')
524 		{
525 			filename_start_pos=pos+1;
526 		}
527 		//go to next MBCS character in string
528 		pos+=_mbclen((unsigned const char*)&fname[pos]);
529 	}
530 	if(!fname[filename_start_pos]) return FALSE;
531 
532 	char* temp_name=new char[strlen(fname)+7];
533 	strcpy(temp_name,fname);
534 	strcpy(&temp_name[filename_start_pos],"~temp~");
535 	strcpy(&temp_name[filename_start_pos+6],&fname[filename_start_pos]);
536 
537 	prepare_for_output();
538 
539 
540 	#if SAVE_USING_COMPRESSION
541 	//create a block containing the uncompressed rif file
542 	unsigned char* uncompressedData = (unsigned char*) make_data_block_from_chunk();
543 	if(!uncompressedData) return FALSE;
544 
545 	//do the compression thing
546 	HuffmanPackage *outPackage = HuffmanCompression(uncompressedData,chunk_size);
547 	delete [] uncompressedData;
548 	if(!outPackage) return FALSE;
549 
550 	//and now try to write the file
551 	rif_file = CreateFileA (temp_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
552 					FILE_FLAG_RANDOM_ACCESS, 0);
553 
554 	if (rif_file == INVALID_HANDLE_VALUE) {
555 		delete [] temp_name;
556 		free (outPackage);
557 		return FALSE;
558 	}
559 
560 	unsigned long junk;
561 	BOOL ok;
562 
563 	ok = WriteFile (rif_file, (long *) outPackage,outPackage->CompressedDataSize+sizeof(HuffmanPackage), &junk, 0);
564 
565 	CloseHandle (rif_file);
566 
567 	free (outPackage);
568 
569 	if(!ok) return FALSE;
570 
571 
572 	#else
573 	size_chunk();
574 
575 	rif_file = CreateFileA (temp_name, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
576 					FILE_FLAG_RANDOM_ACCESS, 0);
577 
578 	if (rif_file == INVALID_HANDLE_VALUE) {
579 		delete [] temp_name;
580 		return FALSE;
581 	}
582 
583 	if (!(this->output_chunk(rif_file)))
584 	{
585 		CloseHandle (rif_file);
586 		delete [] temp_name;
587 		return FALSE;
588 	}
589 
590 	CloseHandle (rif_file);
591 	#endif
592 
593 	//Delete the old file with this name (if it exists) , and rename the temprary file
594 	DeleteFileA(fname);
595 	MoveFileA(temp_name,fname);
596 
597 	delete [] temp_name;
598 
599 	return TRUE;
600 }
601 
602 // the file_chunk must link all of its shapes & objects together
603 
post_input_processing()604 void File_Chunk::post_input_processing()
605 {
606 	List<Shape_Chunk *> shplist;
607 	List<Object_Chunk *> objlist;
608 
609 	List<Chunk *> child_lists;
610 
611 	lookup_child("REBSHAPE",child_lists);
612 
613 	while (child_lists.size()) {
614 		shplist.add_entry((Shape_Chunk *)child_lists.first_entry());
615 		child_lists.delete_first_entry();
616 	}
617 
618 	lookup_child("RBOBJECT",child_lists);
619 
620 	while (child_lists.size()) {
621 		objlist.add_entry((Object_Chunk *)child_lists.first_entry());
622 		child_lists.delete_first_entry();
623 	}
624 
625 	LIF<Shape_Chunk *> sli(&shplist);
626 	for (; !sli.done(); sli.next())
627 	{
628 		Shape_Chunk::max_id = max (Shape_Chunk::max_id,sli()->get_header()->file_id_num);
629 	}
630 	Shape_Chunk** shape_array=new Shape_Chunk*[Shape_Chunk::max_id+1];
631 
632 	for(sli.restart();!sli.done();sli.next())
633 	{
634 		shape_array[sli()->get_header()->file_id_num]=sli();
635 	}
636 
637 	for (LIF<Object_Chunk *> ol(&objlist); !ol.done(); ol.next())
638 	{
639 		ol()->assoc_with_shape(shape_array[ol()->get_header()->shape_id_no]);
640 	}
641 
642 	delete [] shape_array;
643 
644 
645 	Chunk_With_Children::post_input_processing();
646 }
647 
648 
649 
check_file()650 BOOL File_Chunk::check_file()
651 {
652 	if (!filename) return TRUE;
653 
654 	#if DisableLock
655 	return(TRUE);
656 	#else
657 
658 	int flags;
659 	int v_no;
660 	char locker[17];
661 
662 
663 	HANDLE rif_file;
664 	unsigned long bytes_read;
665 
666 	int tries = 0;
667 
668 	rif_file = CreateFileA (filename, GENERIC_READ, 0, 0, OPEN_EXISTING,
669 						FILE_FLAG_RANDOM_ACCESS, 0);
670 
671 	while(rif_file == INVALID_HANDLE_VALUE && tries<10)
672 	{
673 		rif_file = CreateFileA (filename, GENERIC_READ, 0, 0, OPEN_EXISTING,
674 						FILE_FLAG_RANDOM_ACCESS, 0);
675 	 	tries ++;
676 		clock_t ctime = clock();
677 		double secs	= (double)ctime / (double)CLOCKS_PER_SEC;
678 		double secsgone;
679 		do
680 		{
681 			ctime = clock();
682 			secsgone = (double)ctime / (double)CLOCKS_PER_SEC;
683 		}
684 		while( (secsgone-secs)<1);
685 	}
686 
687 	if (rif_file == INVALID_HANDLE_VALUE) {
688 		error_code = CHECK_FAILED_NOT_OPEN;
689 		return FALSE;
690 	}
691 
692 
693 	if (rif_file == INVALID_HANDLE_VALUE) {
694 		error_code = CHECK_FAILED_NOT_OPEN;
695 		return FALSE;
696 	}
697 
698 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
699 
700 	List<int> obfptrs;
701 	list_chunks_in_file(& obfptrs, rif_file, "RBOBJECT");
702 
703 // ok, go through the objects, first locate the header and find
704 // the associated object.
705 
706 	if (obfptrs.size()) {
707 
708 		for (LIF<int> obflst(&obfptrs); !obflst.done(); obflst.next()) {
709 
710 			// go to start of chunk
711 			SetFilePointer (rif_file,obflst(),0,FILE_BEGIN);
712 
713 			// get header list
714 			List<int> obhead;
715 			list_chunks_in_file(& obhead, rif_file, "OBJHEAD1");
716 
717 			assert (obhead.size() == 1);
718 
719 			// go to lock status in header
720 			SetFilePointer(rif_file,obhead.first_entry() + 12,0,FILE_BEGIN);
721 			ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
722 			ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
723 
724 			// go to version number
725 			SetFilePointer(rif_file,obhead.first_entry() + 88,0,FILE_BEGIN);
726 			ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
727 
728 			char name[50];
729 
730 			// get object identifier
731 			SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN);
732 			int i = 0;
733 			do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0);
734 			while (name[i++] != 0);
735 
736 			Object_Chunk * tmpob;
737 			Object_Header_Chunk * tmpobh;
738 			List<Chunk *> obchs;
739 			lookup_child ("RBOBJECT",obchs);
740 
741 			if (obchs.size()){
742 				for (LIF<Chunk *> obchls(&obchs); !obchls.done(); obchls.next()){
743 					tmpob = (Object_Chunk *)obchls();
744 					// if this is the same object
745 					if (!strcmp (name, tmpob->object_data.o_name)) break;
746 				}
747 				if (!obchls.done()) {
748 					tmpobh = tmpob->get_header();
749 					if (tmpobh) {
750 						if (tmpobh->version_no < v_no)
751 							tmpob->updated_outside = TRUE;
752 						if (flags & GENERAL_FLAG_LOCKED) {
753 							// do the lock check
754 							if (!tmpob->local_lock) {
755 								tmpob->external_lock = TRUE;
756 								strncpy(tmpobh->lock_user, locker,16);
757 								tmpobh->lock_user[16] = '\0';
758 							}
759 							else if (strncmp(tmpobh->lock_user, locker,16)) {
760 								tmpob->external_lock = TRUE;
761 								strncpy(tmpobh->lock_user, locker,16);
762 								tmpobh->lock_user[16] = '\0';
763 							}
764 						}
765 					}
766 
767 				}
768 
769 			}
770 
771 		}
772 
773 	}
774 
775 	// shapes
776 
777 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
778 
779 	List<int> shpfptrs;
780 	list_chunks_in_file(& shpfptrs, rif_file, "REBSHAPE");
781 
782 	if (shpfptrs.size()) {
783 
784 		for (LIF<int> shpflst(&shpfptrs); !shpflst.done(); shpflst.next()) {
785 
786 			// go to start of chunk
787 			SetFilePointer (rif_file,shpflst(),0,FILE_BEGIN);
788 
789 			// get header list
790 			List<int> shphead;
791 			list_chunks_in_file(& shphead, rif_file, "SHPHEAD1");
792 
793 			assert (shphead.size() == 1);
794 
795 			// go to lock status in header
796 			SetFilePointer(rif_file,shphead.first_entry() + 12,0,FILE_BEGIN);
797 			ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
798 			ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
799 
800 			int id;
801 			// get shape identifier
802 			ReadFile (rif_file, (long *) &id, 4, &bytes_read, 0);
803 
804 
805 			// Here we update max_id
806 			Shape_Chunk::max_id = max (Shape_Chunk::max_id,id);
807 
808 			// go to version number
809 			SetFilePointer(rif_file,shphead.first_entry() + 100,0,FILE_BEGIN);
810 			ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
811 
812 			Shape_Chunk * tmpshp;
813 			Shape_Header_Chunk * tmpshph;
814 			List<Chunk *> shpchs;
815 			lookup_child ("REBSHAPE",shpchs);
816 
817 			if (shpchs.size()){
818 				for (LIF<Chunk *> shpchls(&shpchs); !shpchls.done(); shpchls.next()){
819 					tmpshp = (Shape_Chunk *)shpchls();
820 					tmpshph = tmpshp->get_header();
821 					// if this is the same object
822 					if (tmpshph)
823 						if (id == tmpshph->file_id_num) break;
824 				}
825 				if (!shpchls.done()) {
826 					if (tmpshph->version_no < v_no)
827 						tmpshp->updated_outside = TRUE;
828 					if (flags & GENERAL_FLAG_LOCKED) {
829 						// do the lock check
830 						if (!tmpshp->local_lock) {
831 							tmpshp->external_lock = TRUE;
832 							strncpy(tmpshph->lock_user, locker,16);
833 							tmpshph->lock_user[16] = '\0';
834 						}
835 						else if (strncmp(tmpshph->lock_user, locker,16)) {
836 							tmpshp->external_lock = TRUE;
837 							strncpy(tmpshph->lock_user, locker,16);
838 							tmpshph->lock_user[16] = '\0';
839 						}
840 					}
841 
842 				}
843 
844 			}
845 
846 		}
847 
848 	}
849 
850 	// sprites
851 
852 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
853 
854 	List<int> sprfptrs;
855 	list_chunks_in_file(& sprfptrs, rif_file, "RSPRITES");
856 	List<Chunk *> sprchlst;
857 	lookup_child("RSPRITES",sprchlst);
858 
859 	AllSprites_Chunk * sprch;
860 	AllSprites_Header_Chunk * sprhead = 0;
861 
862 	if (sprchlst.size())
863 	{
864 		sprch = (AllSprites_Chunk *)sprchlst.first_entry();
865 		sprhead = sprch->get_header();
866 	}
867 
868 	if (sprhead)
869 	{
870 		if (sprfptrs.size())
871 		{
872 			SetFilePointer (rif_file,sprfptrs.first_entry(),0,FILE_BEGIN);
873 
874 			// get header list
875 			List<int> sprchhl;
876 			list_chunks_in_file(& sprchhl, rif_file, "ASPRHEAD");
877 
878 			assert (sprchhl.size() == 1);
879 
880 			// go to lock status in header
881 			SetFilePointer(rif_file,sprchhl.first_entry() + 12,0,FILE_BEGIN);
882 			ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
883 			ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
884 
885 			// go to version number
886 			SetFilePointer(rif_file,sprchhl.first_entry() + 32,0,FILE_BEGIN);
887 			ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
888 
889 			if (sprhead->version_no < v_no)
890 			{
891 				sprch->updated_outside = TRUE;
892 			}
893 			if (flags & GENERAL_FLAG_LOCKED)
894 			{
895 				if (!sprch->local_lock) {
896 					sprch->external_lock = TRUE;
897 					strncpy(sprhead->lock_user, locker,16);
898 					sprhead->lock_user[16] = '\0';
899 				}
900 				else if (strncmp(sprhead->lock_user, locker,16)) {
901 					sprch->external_lock = TRUE;
902 					strncpy(sprhead->lock_user, locker,16);
903 					sprhead->lock_user[16] = '\0';
904 				}
905 			}
906 		}
907 	}
908 
909 	// environment data
910 
911 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
912 
913 	List<int> edfptrs;
914 	list_chunks_in_file(& edfptrs, rif_file, "REBENVDT");
915 
916 	Environment_Data_Chunk * ed;
917 	Environment_Data_Header_Chunk * edhead = 0;
918 
919 
920 	ed = (Environment_Data_Chunk *)lookup_single_child("REBENVDT");
921 	if (ed)
922 	{
923 		edhead = ed->get_header();
924 	}
925 
926 	if (edhead)
927 	{
928 		if (edfptrs.size())
929 		{
930 			SetFilePointer (rif_file,edfptrs.first_entry(),0,FILE_BEGIN);
931 
932 			// get header list
933 			List<int> edhl; list_chunks_in_file(& edhl, rif_file, "ENDTHEAD");
934 
935 			assert (edhl.size() == 1);
936 
937 			// go to lock status in header
938 			SetFilePointer(rif_file,edhl.first_entry() + 12,0,FILE_BEGIN);
939 			ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
940 			ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
941 
942 			// go to version number
943 			SetFilePointer(rif_file,edhl.first_entry() + 32,0,FILE_BEGIN);
944 			ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
945 
946 			if (edhead->version_no < v_no)
947 			{
948 				ed->updated_outside = TRUE;
949 			}
950 			if (flags & GENERAL_FLAG_LOCKED)
951 			{
952 				if (!ed->local_lock) {
953 					ed->external_lock = TRUE;
954 					strncpy(edhead->lock_user, locker,16);
955 					edhead->lock_user[16] = '\0';
956 				}
957 				else if (strncmp(edhead->lock_user, locker,16)) {
958 					ed->external_lock = TRUE;
959 					strncpy(edhead->lock_user, locker,16);
960 					edhead->lock_user[16] = '\0';
961 				}
962 			}
963 		}
964 	}
965 
966 	// check file for REBENUMS chunk
967 
968 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
969 
970 	List<int> enumfptrs; list_chunks_in_file(& enumfptrs, rif_file, "REBENUMS");
971 
972 	Enum_Chunk * enumch;
973 	Enum_Header_Chunk * enumhead = 0;
974 
975 	enumch = (Enum_Chunk *)lookup_single_child("REBENUMS");
976 	if (enumch)
977 	{
978 		enumhead = enumch->get_header();
979 	}
980 
981 	if (enumhead)
982 	{
983 		if (enumfptrs.size())
984 		{
985 			SetFilePointer (rif_file,enumfptrs.first_entry(),0,FILE_BEGIN);
986 
987 			// get header list
988 			List<int> enumchhl; list_chunks_in_file(& enumchhl, rif_file, "ENUMHEAD");
989 
990 			assert (enumchhl.size() == 1);
991 
992 			// go to lock status in header
993 			SetFilePointer(rif_file,enumchhl.first_entry() + 12,0,FILE_BEGIN);
994 			ReadFile (rif_file, (long *) &flags, 4, &bytes_read, 0);
995 			ReadFile (rif_file, (long *) locker, 16, &bytes_read, 0);
996 
997 			// go to version number
998 			SetFilePointer(rif_file,enumchhl.first_entry() + 32,0,FILE_BEGIN);
999 			ReadFile (rif_file, (long *) &v_no, 4, &bytes_read, 0);
1000 
1001 			if (enumhead->version_no < v_no)
1002 			{
1003 				enumch->updated_outside = TRUE;
1004 			}
1005 			if (flags & GENERAL_FLAG_LOCKED)
1006 			{
1007 				if (!enumch->local_lock) {
1008 					enumch->external_lock = TRUE;
1009 					strncpy(enumhead->lock_user, locker,16);
1010 					enumhead->lock_user[16] = '\0';
1011 				}
1012 				else if (strncmp(enumhead->lock_user, locker,16)) {
1013 					enumch->external_lock = TRUE;
1014 					strncpy(enumhead->lock_user, locker,16);
1015 					enumhead->lock_user[16] = '\0';
1016 				}
1017 			}
1018 		}
1019 	}
1020 
1021 	CloseHandle (rif_file);
1022 
1023 	return TRUE;
1024 	#endif
1025 }
1026 
1027 
update_file()1028 BOOL File_Chunk::update_file()
1029 {
1030 
1031 	#if DisableLock
1032 	if (!filename) return FALSE;
1033 
1034 	char tempname [256];
1035 	strcpy (tempname, filename);
1036 
1037 	List<Shape_Chunk *> slist;
1038 	list_shapes(&slist);
1039 	List<Object_Chunk *> olist;
1040 	list_objects(&olist);
1041 
1042 	for (LIF<Shape_Chunk *> sli(&slist); !sli.done(); sli.next())
1043 	{
1044 		if (sli()->deleted)
1045 		{
1046 			delete sli();
1047 		}
1048 	}
1049 
1050 	for (LIF<Object_Chunk *> oli(&olist); !oli.done(); oli.next())
1051 	{
1052 		if (oli()->deleted)
1053 		{
1054 			delete oli();
1055 		}
1056 	}
1057 
1058 
1059 	return(write_file(tempname));
1060 
1061 	#else
1062 
1063 	if (!filename) return FALSE;
1064 
1065 	twprintf("Updating %s\n",filename);
1066 
1067 	check_file();
1068 
1069 	HANDLE rif_file;
1070 	unsigned long bytes_read;
1071 
1072 	int tries = 0;
1073 
1074 	//twprintf("Opening file\n");
1075 
1076 	rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
1077 				FILE_FLAG_RANDOM_ACCESS, 0);
1078 
1079 	if (rif_file == INVALID_HANDLE_VALUE)
1080 	{
1081 		DWORD error_num = GetLastError();
1082 		switch (error_num)
1083 		{
1084 			case ERROR_SHARING_VIOLATION:
1085 				twprintf("Sharing violation - retrying\n");
1086 				break;
1087 			case ERROR_ACCESS_DENIED:
1088 				twprintf("File is Read Only\n");
1089 				return FALSE;
1090 			default:
1091 				twprintf("Unknown error updating file, Error code %#08x\n",error_num);
1092 				return FALSE;
1093 		}
1094 	}
1095 
1096 	while(rif_file == INVALID_HANDLE_VALUE && tries<10)
1097 	{
1098 		twprintf("Again...\n");
1099 	 	rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
1100 	 				FILE_FLAG_RANDOM_ACCESS, 0);
1101 	 	tries ++;
1102 		clock_t ctime = clock();
1103 		double secs	= (double)ctime / (double)CLOCKS_PER_SEC;
1104 		double secsgone;
1105 		do
1106 		{
1107 			ctime = clock();
1108 			secsgone = (double)ctime / (double)CLOCKS_PER_SEC;
1109 		}
1110 		while( (secsgone-secs)<1);
1111 	}
1112 
1113 	if (rif_file == INVALID_HANDLE_VALUE) {
1114 		error_code = CHECK_FAILED_NOT_OPEN;
1115 		twprintf("ERROR - SHARING VIOLATION UNRESOLVED\n\n");
1116 		return FALSE;
1117 	}
1118 
1119 	//twprintf("Opened\n\n");
1120 
1121 	prepare_for_output();
1122 
1123 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
1124 
1125 	//twprintf("Version info\n");
1126 
1127 	List<int> verinf; list_chunks_in_file(& verinf, rif_file, "RIFVERIN");
1128 
1129 // taking first entry of this list, if there are more - tough ha ha
1130 // there shouldn't be
1131 
1132 // Just increment it by one and reoutput
1133 // check_file sets the internal copy of the chunk to the current file
1134 // setting, so we need to increment that as well
1135 
1136 	if (verinf.size()) {
1137 
1138 		int f_version_num;
1139 		SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
1140 		ReadFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0);
1141 
1142 		SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
1143 
1144 		RIF_Version_Num_Chunk* rvnc=(RIF_Version_Num_Chunk*)lookup_single_child ("RIFVERIN");
1145 
1146 		if (rvnc)
1147 			rvnc->file_version_no++;
1148 
1149 		f_version_num++;
1150 
1151 		WriteFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0);
1152 
1153 	}
1154 
1155 //	go through the list of shape chunks looking for shape chunks to output
1156 	//twprintf("\nShapes\n");
1157 
1158 	List<Chunk *> shplst;
1159 	lookup_child ("REBSHAPE",shplst);
1160 
1161 	if (shplst.size())
1162 		for (LIF<Chunk *> sli(&shplst); !sli.done(); sli.next()) {
1163 
1164 			Shape_Chunk * tmpshpptr = ((Shape_Chunk *)sli());
1165 
1166 			if (tmpshpptr->updated &&
1167 				!(tmpshpptr->updated_outside || tmpshpptr->external_lock))
1168 				tmpshpptr->update_chunk_in_file(rif_file);
1169 		}
1170 
1171 
1172 //	go through the list of object chunks looking for chunks to output
1173 	//twprintf("\nObjects\n");
1174 
1175 	List<Chunk *> oblst;
1176 	lookup_child ("RBOBJECT",oblst);
1177 
1178 	if (oblst.size())
1179 		for (LIF<Chunk *> oli(&oblst); !oli.done(); oli.next()) {
1180 
1181 			Object_Chunk * tmpobptr = ((Object_Chunk *)oli());
1182 
1183 			if (tmpobptr->updated && !(tmpobptr->updated_outside || tmpobptr->external_lock))
1184 				tmpobptr->update_chunk_in_file(rif_file);
1185 
1186 		}
1187 
1188 
1189 	//twprintf("\nSprites\n");
1190 
1191 	List<Chunk *> sprfptrs;
1192 	lookup_child ("RSPRITES",sprfptrs);
1193 	AllSprites_Chunk * sprch;
1194 
1195 	if (sprfptrs.size())
1196 	{
1197 		sprch = (AllSprites_Chunk *)sprfptrs.first_entry();
1198 		if (sprch->updated &&
1199 			!(sprch->updated_outside || sprch->external_lock))
1200 			sprch->update_chunk_in_file(rif_file);
1201 	}
1202 
1203 	//twprintf("\nEnvironment data\n");
1204 
1205 	Environment_Data_Chunk * ed;
1206 
1207 	ed = (Environment_Data_Chunk *)lookup_single_child ("REBENVDT");
1208 	if (ed)
1209 	{
1210 		if (ed->updated &&
1211 			!(ed->updated_outside || ed->external_lock))
1212 			ed->update_chunk_in_file(rif_file);
1213 	}
1214 
1215 	//twprintf("\nEnum data\n");
1216 
1217 	List<Chunk *> enumfptrs;
1218 	lookup_child ("REBENUMS",enumfptrs);
1219 	Enum_Chunk * enumch;
1220 
1221 	if (enumfptrs.size())
1222 	{
1223 		enumch = (Enum_Chunk *)enumfptrs.first_entry();
1224 		if (enumch->updated &&
1225 			!(enumch->updated_outside || enumch->external_lock))
1226 			enumch->update_chunk_in_file(rif_file);
1227 	}
1228 
1229 	//
1230 
1231 	int file_length = GetFileSize(rif_file,0);
1232 	SetFilePointer (rif_file,8,0,FILE_BEGIN);
1233 
1234 	WriteFile (rif_file, (long *) &file_length, 4, &bytes_read, 0);
1235 
1236 	CloseHandle (rif_file);
1237 
1238 	return TRUE;
1239 
1240 	#endif //DisableLock
1241 }
1242 
update_chunks_from_file()1243 BOOL File_Chunk::update_chunks_from_file()
1244 {
1245 	#if DisableLock
1246 	return(TRUE);
1247 	#endif
1248 
1249 	if (!filename) return FALSE;
1250 	check_file();
1251 
1252 	HANDLE rif_file;
1253 	unsigned long bytes_read;
1254 
1255 	rif_file = CreateFileA (filename, GENERIC_WRITE + GENERIC_READ, 0, 0, OPEN_EXISTING,
1256 					FILE_FLAG_RANDOM_ACCESS, 0);
1257 
1258 	if (rif_file == INVALID_HANDLE_VALUE) {
1259 		error_code = CHECK_FAILED_NOT_OPEN;
1260 		return FALSE;
1261 	}
1262 
1263 	SetFilePointer (rif_file,0,0,FILE_BEGIN);
1264 
1265 	List<int> verinf; list_chunks_in_file(& verinf, rif_file, "RIFVERIN");
1266 
1267 	if (verinf.size()) {
1268 
1269 		int f_version_num;
1270 		SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
1271 		ReadFile (rif_file, (long *) &f_version_num, 4, &bytes_read, 0);
1272 
1273 		SetFilePointer (rif_file,verinf.first_entry() + 12,0,FILE_BEGIN);
1274 
1275 		List<Chunk *> lverinf;
1276 		lookup_child ("RIFVERIN",lverinf);
1277 
1278 		if (lverinf.size())
1279 			if (f_version_num == ((RIF_Version_Num_Chunk *)(lverinf.first_entry()))->file_version_no){
1280 				CloseHandle (rif_file);
1281 				return TRUE;
1282 			}
1283 
1284 	}
1285 
1286 	//	go through the list of object chunks looking for chunks to input
1287 
1288 	List<Chunk *> oblst;
1289 	lookup_child ("RBOBJECT",oblst);
1290 
1291 	if (oblst.size())
1292 		for (LIF<Chunk *> oli(&oblst); !oli.done(); oli.next()) {
1293 
1294 			Object_Chunk * tmpobptr = ((Object_Chunk *)oli());
1295 
1296 			if (tmpobptr->updated_outside) {
1297 			// find the chunk, then input it to a buffer and create a new object
1298 			// from the buffer
1299 				SetFilePointer (rif_file,0,0,FILE_BEGIN);
1300 
1301 				List<int> obfptrs; list_chunks_in_file(& obfptrs, rif_file, "RBOBJECT");
1302 
1303 				char name[50];
1304 
1305 				LIF<int> ofpl(&obfptrs);
1306 
1307 				if (obfptrs.size()) {
1308 					for (; !ofpl.done(); ofpl.next()) {
1309 
1310 						SetFilePointer (rif_file, ofpl(),0,FILE_BEGIN);
1311 						// get header list
1312 						List<int> obhead; list_chunks_in_file(& obhead, rif_file, "OBJHEAD1");
1313 
1314 						assert (obhead.size() == 1);
1315 
1316 						// get object identifier
1317 						SetFilePointer(rif_file,obhead.first_entry() + 96,0,FILE_BEGIN);
1318 						int i = 0;
1319 						do ReadFile (rif_file, (long *) (name + i), 1, &bytes_read, 0);
1320 						while (name[i++] != 0);
1321 
1322 						if (!strcmp(name, tmpobptr->object_data.o_name)) break;
1323 					}
1324 				}
1325 
1326 				if (!ofpl.done()) {
1327 
1328 					char * buffer;
1329 
1330 					SetFilePointer (rif_file,ofpl()+8,0,FILE_BEGIN);
1331 					int length;
1332 					ReadFile(rif_file, (long *) &length, 4, &bytes_read, 0);
1333 					buffer = new char [length];
1334 					ReadFile(rif_file, (long *) buffer, length-12, &bytes_read, 0);
1335 					new Object_Chunk (this, buffer, length-12);
1336 					delete [] buffer;
1337 					if (tmpobptr->get_header())
1338 						if (tmpobptr->get_header()->associated_shape)
1339 							tmpobptr->deassoc_with_shape(tmpobptr->get_header()->associated_shape);
1340 					delete tmpobptr;
1341 
1342 				}
1343 
1344 
1345 			}
1346 
1347 		}
1348 
1349 //	go through the list of shape chunks looking for shape chunks to input
1350 
1351 	List<Chunk *> shplst;
1352 	lookup_child ("REBSHAPE",shplst);
1353 
1354 	if (shplst.size())
1355 		for (LIF<Chunk *> sli(&shplst); !sli.done(); sli.next()) {
1356 
1357 			Shape_Chunk * tmpshpptr = ((Shape_Chunk *)sli());
1358 
1359 			Shape_Header_Chunk * shhead = tmpshpptr->get_header();
1360 
1361 			if (!shhead) continue;
1362 
1363 			if (tmpshpptr->updated_outside) {
1364 			// find the chunk, then input it to a buffer and create a new object
1365 			// from the buffer
1366 				SetFilePointer (rif_file,0,0,FILE_BEGIN);
1367 
1368 				List<int> shfptrs; list_chunks_in_file(& shfptrs, rif_file, "REBSHAPE");
1369 
1370 				LIF<int> sfpl(&shfptrs);
1371 
1372 				if (shfptrs.size()) {
1373 					for (sfpl.restart(); !sfpl.done(); sfpl.next()) {
1374 
1375 						SetFilePointer (rif_file, sfpl(),0,FILE_BEGIN);
1376 						// get header list
1377 						List<int> shphead; list_chunks_in_file(& shphead, rif_file, "SHPHEAD1");
1378 
1379 						assert (shphead.size() == 1);
1380 
1381 						// get object identifier
1382 						SetFilePointer(rif_file,shphead.first_entry() + 32,0,FILE_BEGIN);
1383 						int sh_number;
1384 						ReadFile (rif_file, (long *) &sh_number, 4, &bytes_read, 0);
1385 
1386 						if (sh_number == shhead->file_id_num) break;
1387 					}
1388 				}
1389 
1390 				if (!sfpl.done()) {
1391 
1392 					char * buffer;
1393 
1394 					SetFilePointer (rif_file,sfpl()+8,0,FILE_BEGIN);
1395 					int length;
1396 					ReadFile(rif_file, (long *) &length, 4, &bytes_read, 0);
1397 					buffer = new char [length];
1398 					ReadFile(rif_file, (long *) buffer, length-12, &bytes_read, 0);
1399 					new Shape_Chunk (this, buffer, length-12);
1400 					delete [] buffer;
1401 					// Associate with the new objects
1402 					if ((shhead->associated_objects_store).size())
1403 					{
1404 						for (LIF<Object_Chunk *> aol(&(shhead->associated_objects_store)); !aol.done(); aol.next())
1405 						{
1406 							tmpshpptr->deassoc_with_object(aol());
1407 						}
1408 					}
1409 					delete tmpshpptr;
1410 				}
1411 			}
1412 		}
1413 
1414 	post_input_processing();
1415 
1416 	CloseHandle(rif_file);
1417 
1418 	return TRUE;
1419 
1420 }
1421 
list_objects(List<Object_Chunk * > * pList)1422 void File_Chunk::list_objects(List<Object_Chunk *> * pList)
1423 {
1424 	Chunk * child_ptr = children;
1425 
1426 	while (pList->size())
1427 		pList->delete_first_entry();
1428 
1429 	if (children)
1430 		while	(child_ptr != NULL) {
1431 			if (strncmp ("RBOBJECT", child_ptr->identifier, 8) == 0)
1432 			{
1433 				assert (!child_ptr->r_u_miscellaneous());
1434 				pList->add_entry((Object_Chunk *)child_ptr);
1435 			}
1436 			child_ptr = child_ptr->next;
1437 		}
1438 
1439 }
1440 
list_shapes(List<Shape_Chunk * > * pList)1441 void File_Chunk::list_shapes(List<Shape_Chunk *> * pList)
1442 {
1443 	Chunk * child_ptr = children;
1444 
1445 	while (pList->size())
1446 		pList->delete_first_entry();
1447 
1448 	if (children)
1449 		while	(child_ptr != NULL) {
1450 			if (strncmp ("REBSHAPE", child_ptr->identifier, 8) == 0)
1451 			{
1452 				assert (!child_ptr->r_u_miscellaneous());
1453 				pList->add_entry((Shape_Chunk *)child_ptr);
1454 			}
1455 			child_ptr = child_ptr->next;
1456 		}
1457 
1458 }
1459 
list_dummy_objects(List<Dummy_Object_Chunk * > * pList)1460 void File_Chunk::list_dummy_objects(List<Dummy_Object_Chunk *> * pList){
1461 	Chunk * child_ptr = children;
1462 
1463 	while (pList->size())
1464 		pList->delete_first_entry();
1465 
1466 	if (children)
1467 		while	(child_ptr != NULL) {
1468 			if (strncmp ("DUMMYOBJ", child_ptr->identifier, 8) == 0)
1469 			{
1470 				assert (!child_ptr->r_u_miscellaneous());
1471 				pList->add_entry((Dummy_Object_Chunk *)child_ptr);
1472 			}
1473 			child_ptr = child_ptr->next;
1474 		}
1475 
1476 }
1477 
get_env_data()1478 Environment_Data_Chunk * File_Chunk::get_env_data()
1479 {
1480 	List<Environment_Data_Chunk *> e_list;
1481 	Chunk * child_ptr = children;
1482 
1483 	if (children)
1484 		while	(child_ptr != NULL) {
1485 			if (strncmp ("REBENVDT", child_ptr->identifier, 8) == 0)
1486 			{
1487 				assert (!child_ptr->r_u_miscellaneous());
1488 				e_list.add_entry((Environment_Data_Chunk *)child_ptr);
1489 			}
1490 			child_ptr = child_ptr->next;
1491 		}
1492 
1493 	// There can be only ONE.
1494 	assert (e_list.size() < 2);
1495 
1496 	if (e_list.size())
1497 		return e_list.first_entry();
1498 	return 0;
1499 }
1500 
build_object_array()1501 void File_Chunk::build_object_array()
1502 {
1503 	List<Object_Chunk*> oblist;
1504 	list_objects(&oblist);
1505 
1506 	if(object_array)
1507 	{
1508 		free(object_array);
1509 		object_array=0;
1510 	}
1511 	object_array_size=0;
1512 
1513 	LIF<Object_Chunk*> oblif(&oblist);
1514 
1515 	//find the highest object index
1516 	for(oblif.restart();!oblif.done();oblif.next())
1517 	{
1518 		object_array_size=max(object_array_size,oblif()->object_data.index_num+1);
1519 	}
1520 
1521 	if(object_array_size<=0) return;
1522 
1523 	object_array = (Object_Chunk**) malloc(sizeof(Object_Chunk*)*object_array_size);
1524 	for(int i=0;i<object_array_size;i++)
1525 	{
1526 		object_array[i]=0;
1527 	}
1528 
1529 	//now fill in object array
1530 
1531 	for(oblif.restart();!oblif.done();oblif.next())
1532 	{
1533 		int index=oblif()->object_data.index_num;
1534 		if(index>=0)
1535 		{
1536 			object_array[index]=oblif();
1537 		}
1538 	}
1539 }
1540 
get_object_by_index(int index)1541 Object_Chunk* File_Chunk::get_object_by_index(int index)
1542 {
1543 	if(!object_array) build_object_array();
1544 	if(index<0 || index>=object_array_size)return 0;
1545 	return object_array[index];
1546 }
1547 
assign_index_to_object(Object_Chunk * object)1548 void File_Chunk::assign_index_to_object(Object_Chunk* object)
1549 {
1550 	assert(object);
1551 
1552 	if(!object_array) build_object_array();
1553 	//see if there is a free index
1554 
1555 	for(int i=0;i<object_array_size;i++)
1556 	{
1557 		if(!object_array[i])
1558 		{
1559 			object->object_data_store->index_num=i;
1560 			object_array[i]=object;
1561 			return;
1562 		}
1563 	}
1564 
1565 	//add a new entry on the end of the array
1566 	object_array_size++;
1567 
1568 	object_array=(Object_Chunk**) realloc(object_array,sizeof(Object_Chunk*)*object_array_size);
1569 
1570 
1571 	object->object_data_store->index_num=object_array_size-1;;
1572 	object_array[object_array_size-1]=object;
1573 }
1574 
1575 /////////////////////////////////////////
1576 
1577 // Class GodFather_Chunk functions
1578 
1579 /*
1580 Children for GodFather_Chunk :
1581 "REBSHAPE"		Shape_Chunk
1582 "RSPRITES"		AllSprites_Chunk
1583 "RBOBJECT"		Object_Chunk
1584 "RIFVERIN"		RIF_Version_Num_Chunk
1585 "REBENVDT"		Environment_Data_Chunk
1586 "REBENUMS"		Enum_Chunk
1587 "OBJCHIER"		Object_Hierarchy_Chunk
1588 "OBHALTSH"		Object_Hierarchy_Alternate_Shape_Set_Chunk
1589 
1590 */
1591 
GodFather_Chunk(char * buffer,size_t size)1592 GodFather_Chunk::GodFather_Chunk(char * buffer, size_t size)
1593 : Chunk_With_Children (NULL, "REBINFF2")
1594 {
1595 	Parent_File = this;
1596 
1597 	char * buffer_ptr = buffer;
1598 
1599 	// The start of the first chunk
1600 
1601 	while ((buffer_ptr-buffer)< ((signed)size-12) && !error_code) {
1602 
1603 		if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)size-12)) {
1604 			error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
1605 			break;
1606 		}
1607 
1608 		DynCreate(buffer_ptr);
1609 		buffer_ptr += *(int *)(buffer_ptr + 8);
1610 
1611 	}
1612 
1613 }
1614 
1615 /////////////////////////////////////////
1616 
1617 // Class RIF_Version_Num_Chunk functions
1618 
1619 RIF_IMPLEMENT_DYNCREATE("RIFVERIN",RIF_Version_Num_Chunk)
1620 
fill_data_block(char * data_start)1621 void RIF_Version_Num_Chunk::fill_data_block(char * data_start)
1622 {
1623 	strncpy (data_start, identifier, 8);
1624 
1625 	data_start += 8;
1626 
1627 	*((int *) data_start) = chunk_size;
1628 
1629 	data_start += 4;
1630 
1631 	*((int *) data_start) = file_version_no;
1632 
1633 }
1634 
1635 
1636 /////////////////////////////////////////
1637 
1638 // Class RIF_Name_Chunk functions
1639 RIF_IMPLEMENT_DYNCREATE("RIFFNAME",RIF_Name_Chunk)
1640 
RIF_Name_Chunk(Chunk_With_Children * parent,const char * rname)1641 RIF_Name_Chunk::RIF_Name_Chunk (Chunk_With_Children * parent, const char * rname)
1642 : Chunk (parent, "RIFFNAME")
1643 {
1644 	rif_name = new char [strlen(rname)+1];
1645 	strcpy (rif_name, rname);
1646 }
1647 
RIF_Name_Chunk(Chunk_With_Children * parent,const char * rdata,size_t)1648 RIF_Name_Chunk::RIF_Name_Chunk (Chunk_With_Children * parent, const char * rdata, size_t /*rsize*/)
1649 : Chunk (parent, "RIFFNAME")
1650 {
1651 	rif_name = new char [strlen(rdata)+1];
1652 	strcpy (rif_name, rdata);
1653 }
1654 
~RIF_Name_Chunk()1655 RIF_Name_Chunk::~RIF_Name_Chunk ()
1656 {
1657 	if (rif_name)
1658 		delete [] rif_name;
1659 }
1660 
1661 
fill_data_block(char * data_start)1662 void RIF_Name_Chunk::fill_data_block (char * data_start)
1663 {
1664 	strncpy (data_start, identifier, 8);
1665 
1666 	data_start += 8;
1667 
1668 	*((int *) data_start) = chunk_size;
1669 
1670 	data_start += 4;
1671 
1672 	strcpy (data_start, rif_name);
1673 
1674 }
1675 
1676 
1677 ///////////////////////////////////////
1678 
1679 /*
1680 Children for RIF_File_Chunk :
1681 "REBSHAPE"		Shape_Chunk
1682 "RSPRITES"		AllSprites_Chunk
1683 "RBOBJECT"		Object_Chunk
1684 "RIFVERIN"		RIF_Version_Num_Chunk
1685 "REBENVDT"		Environment_Data_Chunk
1686 "OBJCHIER"		Object_Hierarchy_Chunk
1687 "OBHALTSH"		Object_Hierarchy_Alternate_Shape_Set_Chunk
1688 
1689 */
1690 
1691 
RIF_File_Chunk(Chunk_With_Children * parent,const char * file_name)1692 RIF_File_Chunk::RIF_File_Chunk (Chunk_With_Children * parent, const char * file_name)
1693 : Chunk_With_Children (parent, "SUBRIFFL")
1694 {
1695 	char rifIsCompressed = FALSE;
1696 	char *uncompressedData = NULL;
1697 	FILE *rif_file;
1698 	DWORD file_size;
1699 	DWORD file_size_from_file;
1700 	char * buffer;
1701 	char * buffer_ptr;
1702 	char id_buffer[9];
1703 
1704 
1705 	Chunk * ParentFileStore = Parent_File;
1706 
1707 	Parent_File = this;
1708 
1709 	error_code = 0;
1710 
1711 	rif_file = OpenGameFile(file_name, FILEMODE_READONLY, FILETYPE_PERM);
1712 
1713 	if (rif_file == NULL) {
1714 		error_code = CHUNK_FAILED_ON_LOAD;
1715 		Parent_File = ParentFileStore;
1716 		return;
1717 	}
1718 
1719 	fseek(rif_file, 0, SEEK_END);
1720 	file_size = ftell(rif_file);
1721 	rewind(rif_file);
1722 
1723 	if (fread(id_buffer, 1, 8, rif_file) != 8) {
1724 		error_code = CHUNK_FAILED_ON_LOAD;
1725 		fclose(rif_file);
1726 		Parent_File = ParentFileStore;
1727 		return;
1728 	}
1729 
1730 	//check for compressed rif
1731 	if (!strncmp (id_buffer, COMPRESSED_RIF_IDENTIFIER, 8))
1732 	{
1733 		rifIsCompressed = TRUE;
1734 	}
1735 	else if (strncmp (id_buffer, "REBINFF2", 8)) {
1736 		error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
1737 		fclose(rif_file);
1738 		Parent_File = ParentFileStore;
1739 		return;
1740 	}
1741 
1742 	buffer = new char [file_size];
1743 
1744 	/* KJL 17:57:44 19/09/98 - if the rif is compressed, we must load the whole
1745 	file in and then pass it to the decompression routine, which will return a
1746 	pointer to the original data. */
1747 	if (rifIsCompressed)
1748 	{
1749 		if (fread(buffer+8, 1, (file_size-8), rif_file) != (file_size-8)) {
1750 			error_code = CHUNK_FAILED_ON_LOAD;
1751 			fclose(rif_file);
1752 			Parent_File = ParentFileStore;
1753 			delete [] buffer;
1754 			return;
1755 		}
1756 		uncompressedData = HuffmanDecompress((HuffmanPackage*)buffer);
1757 		file_size = ((HuffmanPackage*)buffer)->UncompressedDataSize;
1758 
1759 		delete [] buffer; // kill the buffer the compressed file was loaded into
1760 
1761 		buffer_ptr = buffer = uncompressedData+12; // skip header data
1762 	}
1763 	else // the normal uncompressed approach:
1764 	{
1765 		//get the file size stored in the rif file
1766 		if (fread(&file_size_from_file, 1, 4, rif_file) != 4) {
1767 			error_code = CHUNK_FAILED_ON_LOAD;
1768 			fclose(rif_file);
1769 			Parent_File = ParentFileStore;
1770 			delete [] buffer;
1771 			return;
1772 		}
1773 
1774 		//and compare with the actual file size
1775 		if (file_size != file_size_from_file) {
1776 			error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
1777 			fclose(rif_file);
1778 			Parent_File = ParentFileStore;
1779 			delete [] buffer;
1780 			return;
1781 		}
1782 
1783 		//read the rest of the file into the buffer
1784 		if (fread(buffer, 1, (file_size-12), rif_file) != (file_size-12)) {
1785 			error_code = CHUNK_FAILED_ON_LOAD;
1786 			fclose(rif_file);
1787 			Parent_File = ParentFileStore;
1788 			delete [] buffer;
1789 			return;
1790 		}
1791 		buffer_ptr = buffer;
1792 	}
1793 
1794 	fclose(rif_file);
1795 
1796 
1797 	// Process the RIF
1798 
1799 	// The start of the first chunk
1800 
1801 	while ((buffer_ptr-buffer)< ((signed) file_size-12) && !error_code) {
1802 
1803 		if ((*(int *)(buffer_ptr + 8)) + (buffer_ptr-buffer) > ((signed)file_size-12)) {
1804 			error_code = CHUNK_FAILED_ON_LOAD_NOT_RECOGNISED;
1805 			break;
1806 		}
1807 
1808 		DynCreate(buffer_ptr);
1809 		buffer_ptr += *(int *)(buffer_ptr + 8);
1810 	}
1811 
1812 	/* KJL 17:59:42 19/09/98 - release the memory holding the rif */
1813 	if (rifIsCompressed)
1814 	{
1815 		free(uncompressedData);
1816 	}
1817 	else
1818 	{
1819 		delete [] buffer;
1820 	}
1821 
1822 	post_input_processing();
1823 
1824 	Parent_File = ParentFileStore;
1825 }
1826 
post_input_processing()1827 void RIF_File_Chunk::post_input_processing()
1828 {
1829 	List<Shape_Chunk *> shplist;
1830 	List<Object_Chunk *> objlist;
1831 
1832 	List<Chunk *> child_lists;
1833 
1834 	lookup_child("REBSHAPE",child_lists);
1835 
1836 	while (child_lists.size()) {
1837 		shplist.add_entry((Shape_Chunk *)child_lists.first_entry());
1838 		child_lists.delete_first_entry();
1839 	}
1840 
1841 	lookup_child("RBOBJECT",child_lists);
1842 
1843 
1844 	while (child_lists.size()) {
1845 		objlist.add_entry((Object_Chunk *)child_lists.first_entry());
1846 		child_lists.delete_first_entry();
1847 	}
1848 
1849 	for (LIF<Object_Chunk *> ol(&objlist); !ol.done(); ol.next()) {
1850 
1851 		if (ol()->get_header()) {
1852 
1853 			for (LIF<Shape_Chunk *> sl(&shplist);
1854 					 !sl.done(); sl.next()) {
1855 				if (sl()->get_header())
1856 					if (sl()->get_header()->file_id_num == ol()->get_header()->shape_id_no){
1857 						ol()->assoc_with_shape(sl());
1858 						break;
1859 					}
1860 			}
1861 		}
1862 
1863 	}
1864 
1865 	for (LIF<Shape_Chunk *> sli(&shplist); !sli.done(); sli.next())
1866 	{
1867 		Shape_Chunk::max_id = max (Shape_Chunk::max_id,sli()->get_header()->file_id_num);
1868 	}
1869 
1870 	Chunk_With_Children::post_input_processing();
1871 }
1872 
1873 
list_objects(List<Object_Chunk * > * pList)1874 void RIF_File_Chunk::list_objects(List<Object_Chunk *> * pList)
1875 {
1876 	Chunk * child_ptr = children;
1877 
1878 	while (pList->size())
1879 		pList->delete_first_entry();
1880 
1881 	if (children)
1882 		while	(child_ptr != NULL) {
1883 			if (strncmp ("RBOBJECT", child_ptr->identifier, 8) == 0)
1884 			{
1885 				assert (!child_ptr->r_u_miscellaneous());
1886 				pList->add_entry((Object_Chunk *)child_ptr);
1887 			}
1888 			child_ptr = child_ptr->next;
1889 		}
1890 }
1891 
list_shapes(List<Shape_Chunk * > * pList)1892 void RIF_File_Chunk::list_shapes(List<Shape_Chunk *> * pList)
1893 {
1894 	Chunk * child_ptr = children;
1895 
1896 	while (pList->size())
1897 		pList->delete_first_entry();
1898 
1899 	if (children)
1900 		while	(child_ptr != NULL) {
1901 			if (strncmp ("REBSHAPE", child_ptr->identifier, 8) == 0)
1902 			{
1903 				assert (!child_ptr->r_u_miscellaneous());
1904 				pList->add_entry((Shape_Chunk *)child_ptr);
1905 			}
1906 			child_ptr = child_ptr->next;
1907 		}
1908 
1909 }
1910 
get_env_data()1911 Environment_Data_Chunk * RIF_File_Chunk::get_env_data()
1912 {
1913 	List<Environment_Data_Chunk *> e_list;
1914 	Chunk * child_ptr = children;
1915 
1916 	if (children)
1917 		while	(child_ptr != NULL) {
1918 			if (strncmp ("REBENVDT", child_ptr->identifier, 8) == 0)
1919 			{
1920 				assert (!child_ptr->r_u_miscellaneous());
1921 				e_list.add_entry((Environment_Data_Chunk *)child_ptr);
1922 			}
1923 			child_ptr = child_ptr->next;
1924 		}
1925 
1926 	// There can be only ONE.
1927 	assert (e_list.size() < 2);
1928 
1929 	if (e_list.size())
1930 		return e_list.first_entry();
1931 	return 0;
1932 }
1933