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