Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
tagblock.cpp
Go to the documentation of this file.
1/*
2** Command & Conquer Generals Zero Hour(tm)
3** Copyright 2025 Electronic Arts Inc.
4**
5** This program is free software: you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation, either version 3 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/* $Header: /G/wwlib/tagblock.cpp 5 11/30/99 3:46p Scott_b $ */
20/***********************************************************************************************
21 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
22 ***********************************************************************************************
23 * *
24 * Project Name : WWLib *
25 * *
26 * $Archive:: /G/wwlib/tagblock.cpp $*
27 * *
28 * $Author:: Scott_b $*
29 * *
30 * $Modtime:: 11/29/99 6:42p $*
31 * *
32 * $Revision:: 5 $*
33 * *
34 *---------------------------------------------------------------------------------------------*
35 * Functions: *
36 * TagBlockFile::TagBlockFile -- Create/open tag file *
37 * TagBlockFile::~TagBlockFile -- Close down the tag file. *
38 * TagBlockFile::Create_Index -- Create a index into the IndexList sorted by CRC. *
39 * TagBlockFile::Find_Block -- Find block assocated with name. *
40 * TagBlockFile::Open_Tag -- Open an existing tag block. *
41 * TagBlockFile::Create_Tag -- Create a new tag at the end of the block. *
42 * TagBlockFile::Close_Tag -- Close the handle that Create or Open made. *
43 * TagBlockFile::Destroy_Handle -- Shut down a handle. *
44 * TagBlockFile::End_Write_Access -- Stop write access for handle - flushes data bug keeps ha*
45 * TagBlockFile::Reset_File -- Clear file so no blocks exist. *
46 * TagBlockFile::Empty_Index_List -- Clear out tag block list in memory *
47 *---------------------------------------------------------------------------------------------*
48 * TagBlockHandle::Write -- Write data to the block. *
49 * TagBlockHandle::Read -- Read from a tag block. *
50 * TagBlockHandle::Seek -- Seek within the file. *
51 * TagBlockHandle::~TagBlockHandle -- Destroy handle. *
52 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
53
54
55#include "tagblock.h"
56#include "realcrc.h"
57
58#include <assert.h>
59
60int TagBlockHandle::_InDestructor = 0;
61
65{
66public:
67 TagBlockIndex(const char *tagname, int blockoffset):
68 CRC(CRC_Stringi(tagname)),
69 BlockOffset(blockoffset),
70 DataOffset(TagBlockFile::Calc_Data_Offset(blockoffset, tagname))
71 {}
72
73 unsigned Get_CRC() {
74 return(CRC);
75 }
77 return(BlockOffset);
78 }
80 return(TagBlockFile::Calc_Tag_Offset(BlockOffset));
81 }
83 return(DataOffset - Get_TagOffset());
84 }
86 return(DataOffset);
87 }
88private:
89
90 // The index file is sorted by the CRC of the file name for
91 // quicker retrieval. The filename is saved in the texture file.
92 unsigned long CRC;
93
94 // Start of the block - this is the start of TagBlockFile::BlockHeader.
95 int BlockOffset;
96
97 // Offset of block inside of TagFile.
98 // This is first byte after header and TagName.
99 // It is actual data used by external methods.
100 int DataOffset;
101};
102
106
107
108/***********************************************************************************************
109 * RawFileClass -- Open up the tag file (it may not exist). *
110 * *
111 * INPUT: *
112 * const char *fname - name of file that is or wants to be a TagBlockFile. *
113 * *
114 * OUTPUT: *
115 * Will assume a file that has invalid data to be corrupt and will write over it. *
116 * So don't pass in a file that is not a tag file. *
117 * *
118 * WARNINGS: *
119 * *
120 * HISTORY: *
121 * 05/11/1999 SKB : Created. *
122 *=============================================================================================*/
123TagBlockFile::TagBlockFile(const char *fname):
124 RawFileClass(),
125 Header(),
128 IndexList()
129{
130 // Open file up, create it if it does not exist.
131 // Pass in name to Open function so that the file name will be strdup'd.
132 Open(fname, READ|WRITE);
133
135
136 // Read in header so we can tell if it is proper file.
137 Read(&Header, sizeof(Header));
138
139 // See if there is any data in file (or was it just created?)
140 if (Header.Version == FILE_VERSION) {
141 TagBlockIndex *lasttag = NULL;
142 int curpos = sizeof(Header);
143
144 // Loop through each block in file and create an in memory index for it.
145 int block;
146 for (block = 0; block < Header.NumBlocks; block++) {
147 BlockHeader blockheader;
148
149 // Read in next header.
150 Seek(curpos, SEEK_SET);
151 Read(&blockheader, sizeof(blockheader));
152
153 // Make sure things are in order.
154 if (blockheader.Index == block) {
155 char tagname[MAX_TAG_NAME_SIZE];
156
157 // Read in tag name, this includes the NULL at end of string.
158 Read(tagname, blockheader.TagSize);
159
160 // Create new tag index for fast retrievel.
161 lasttag = Create_Index(tagname, curpos);
162
163 // Now get past the data.
164 curpos = Calc_Tag_Offset(curpos) + blockheader.TagSize + blockheader.DataSize;
165 } else {
166 break;
167 }
168 }
169
170 // See if there is a difference between the header and actual data.
171 if ((curpos != Header.FileSize) || (block != Header.NumBlocks)) {
172 Header.NumBlocks = block;
173 Header.FileSize = curpos;
174
175 // Start at begining of file and write out our new header.
176 Seek(0, SEEK_SET);
177 Write(&Header, sizeof(Header));
178 }
179
180 } else {
181 Reset_File();
182 }
183}
184
185/***********************************************************************************************
186 * TagBlockFile::~TagBlockFile -- Close down the tag file. *
187 * *
188 * INPUT: *
189 * *
190 * OUTPUT: *
191 * *
192 * WARNINGS: *
193 * Any TagBlockHandles that have not been deleted are now invalide but cannot be deleted.*
194 * You must delete any handles associated with this before closing the TagFile. *
195 * *
196 * HISTORY: *
197 * 05/11/1999 SKB : Created. *
198 *=============================================================================================*/
203
204/***********************************************************************************************
205 * TagBlockFile::Reset_File -- Clear file so no blocks exist. *
206 * *
207 * INPUT: *
208 * *
209 * OUTPUT: *
210 * *
211 * WARNINGS: *
212 * *
213 * HISTORY: *
214 * 11/29/1999 SKB : Created. *
215 *=============================================================================================*/
217{
219
220 // Save a clean header out.
221 Header.Version = FILE_VERSION;
222 Header.NumBlocks = 0;
223 Header.FileSize = sizeof(Header);
224
225 Save_Header();
226
227 // Close, then open file so we get a new time stamp on it.
228 Close();
229 Open(READ|WRITE);
230
231 // Reget file creation time.
233}
234
235/***********************************************************************************************
236 * *TagBlockFile::Open_Tag -- Open an existing tag block. *
237 * *
238 * INPUT: *
239 * *
240 * OUTPUT: *
241 * *
242 * WARNINGS: *
243 * *
244 * HISTORY: *
245 * 05/11/1999 SKB : Created. *
246 *=============================================================================================*/
248{
249 // Find tag to open up.
250 TagBlockIndex *index = Find_Block(tagname);
251 if (!index) {
252 return(NULL);
253 }
254
255 // Load up the block header information.
256 BlockHeader *blockheader = W3DNEW BlockHeader();
257 Seek(index->Get_BlockOffset(), SEEK_SET);
258 Read(blockheader, sizeof(*blockheader));
259
260 // Now that we have all that we need, create the
261 TagBlockHandle *handle = W3DNEW TagBlockHandle(this, index, blockheader);
262
263 // Keep track of how many handles there are so we can assert if they are not all shut down.
265
266 // Return with our new handle.
267 return(handle);
268}
269
270/***********************************************************************************************
271 * *TagBlockFile::Create_Tag -- Create a new tag at the end of the block. *
272 * *
273 * INPUT: *
274 * *
275 * OUTPUT: *
276 * *
277 * WARNINGS: *
278 * *
279 * HISTORY: *
280 * 05/11/1999 SKB : Created. *
281 *=============================================================================================*/
283{
284 // Only allow one handle to be creating open at a time.
285 if (CreateHandle) {
286 return(NULL);
287 }
288
289 // Create a new index that we can write too.
290 TagBlockIndex *index = Create_Index(tagname, Header.FileSize);
291
292 // An index may not be created if a tag of the same name already exists.
293 if (!index) {
294 return(NULL);
295 }
296
297 // Create a header.
298 // Use -1 for index to indecate that block is not yet written out competely.
299 BlockHeader *blockheader = W3DNEW BlockHeader(-1, index->Get_TagSize(), 0);
300
301 // Write out the block header and the tag.
302 Seek(index->Get_BlockOffset(), SEEK_SET);
303 Write(blockheader, sizeof(*blockheader));
304 Write(tagname, strlen(tagname) + 1);
305
306 // Now that we have all that we need, create the
307 CreateHandle = W3DNEW TagBlockHandle(this, index, blockheader);
308
309 // Keep track of how many handles there are so we can assert if they are not all shut down.
311
312 return(CreateHandle);
313}
314
315/***********************************************************************************************
316 * TagBlockFile::Close_Tag -- Close the handle that Create or Open made. *
317 * *
318 * INPUT: *
319 * *
320 * OUTPUT: *
321 * *
322 * WARNINGS: *
323 * *
324 * HISTORY: *
325 * 05/12/1999 SKB : Created. *
326 *=============================================================================================*/
328{
329 delete handle;
330}
331
332/***********************************************************************************************
333 * TagBlockFile::Destroy_Handle -- Shut down a handle. *
334 * *
335 * INPUT: *
336 * *
337 * OUTPUT: *
338 * *
339 * WARNINGS: *
340 * *
341 * HISTORY: *
342 * 05/12/1999 SKB : Created. *
343 *=============================================================================================*/
345{
346 // Make sure those sneaky programmers aren't trying to fool me.
347 assert(handle->Called_By_Destructor());
348
349 // If we had write access to handle, flush it out.
350 End_Write_Access(handle);
351
352 // This was allocated by TagBlockFile::Create_Tag() or Open_Tag().
353 delete handle->BlockHeader;
354
355 // Keep track of how many handles there are so we can assert if they are not all shut down.
357}
358
359/***********************************************************************************************
360 * TagBlockFile::End_Write_Access -- Stop write access for handle - flushes data bug keeps han *
361 * *
362 * INPUT: *
363 * *
364 * OUTPUT: *
365 * *
366 * WARNINGS: *
367 * *
368 * HISTORY: *
369 * 06/02/1999 SKB : Created. *
370 *=============================================================================================*/
372{
373 // Make sure this handle is the proper one.
374 if (CreateHandle == handle) {
375 // Update file header and block header.
376 handle->BlockHeader->Index = Header.NumBlocks;
377 Header.NumBlocks++;
378 Header.FileSize = handle->Index->Get_DataOffset();
379 Header.FileSize += handle->BlockHeader->DataSize;
380
381 // Write both headers out.
382 Seek(handle->Index->Get_BlockOffset(), SEEK_SET);
383 Write(handle->BlockHeader, sizeof(*handle->BlockHeader));
384 Save_Header();
385
386 // Don't allow writing with this handle anymore.
388 return(true);
389 }
390 return(false);
391}
392
393
394/***********************************************************************************************
395 * *TagBlockFile::Create_Index -- Create a index into the IndexList sorted by CRC. *
396 * *
397 * INPUT: *
398 * *
399 * OUTPUT: *
400 * *
401 * WARNINGS: *
402 * *
403 * HISTORY: *
404 * 05/11/1999 SKB : Created. *
405 *=============================================================================================*/
406TagBlockIndex *TagBlockFile::Create_Index(const char *tagname, int blockoffset)
407{
408 // Don't allow duplicate tags.
409 if (Find_Block(tagname)) {
410 return(NULL);
411 }
412
413 TagBlockIndex *index;
414 index = W3DNEW TagBlockIndex(tagname, blockoffset);
415
416 // Put it into the list.
417 if (IndexList.Is_Empty()) {
418 IndexList.Add_Head(index);
419 } else {
420 // Put in list sorted by CRC, smallest to largest.
421 SLNode<TagBlockIndex> *node = IndexList.Head();
422 while (node) {
423 TagBlockIndex *cur = node->Data();
424 if (index->Get_CRC() > cur->Get_CRC()) {
425 IndexList.Insert_Before(index, cur);
426 break;
427 }
428 node = node->Next();
429 }
430 // If we did not find a place, then add at end of list.
431 if (!node) {
432 IndexList.Add_Tail(index);
433 }
434 }
435 return (index);
436}
437
438/***********************************************************************************************
439 * *TagBlockFile::Find_Block -- Find block assocated with name. *
440 * *
441 * INPUT: *
442 * *
443 * OUTPUT: *
444 * *
445 * WARNINGS: *
446 * *
447 * HISTORY: *
448 * 05/11/1999 SKB : Created. *
449 *=============================================================================================*/
451{
452 if (IndexList.Is_Empty()) {
453 return(NULL);
454 }
455
456 unsigned long crc = CRC_Stringi(tagname);
457
458 SLNode<TagBlockIndex> *node = IndexList.Head();
459 while (node) {
460 TagBlockIndex *cur = node->Data();
461
462 // Did we find it?
463 if (cur->Get_CRC() == crc) {
464 // Now read from file to verify that it is the right name.
465 char name[MAX_TAG_NAME_SIZE];
466 Seek(cur->Get_TagOffset(), SEEK_SET);
467
468 // Read in the name.
469 Read(name, cur->Get_TagSize());
470
471 // Is it a match?
472 assert(name != NULL);
473 assert(tagname != NULL);
474 if (!strcmpi(name, tagname)) {
475 return(cur);
476 }
477 }
478
479 // Are we out of range?
480 if (cur->Get_CRC() < crc) {
481 break;
482 }
483
484 // Next in line please.
485 node = node->Next();
486 }
487
488 return(NULL);
489}
490
491
492/***********************************************************************************************
493 * TagBlockFile::Empty_Index_List -- Clear out tag block list in memory *
494 * *
495 * INPUT: *
496 * *
497 * OUTPUT: *
498 * *
499 * WARNINGS: *
500 * *
501 * HISTORY: *
502 * 11/29/1999 SKB : Created. *
503 *=============================================================================================*/
505{
506 assert(!NumOpenHandles);
507
508 // Get rid of index list in memory.
509 while (!IndexList.Is_Empty()) {
510 TagBlockIndex *index = IndexList.Remove_Head();
511 delete index;
512 }
513
514}
515
516
520
521/***********************************************************************************************
522 * Position -- Create a handle for user to access the TagBlock. *
523 * *
524 * INPUT: *
525 * *
526 * OUTPUT: *
527 * *
528 * WARNINGS: *
529 * *
530 * HISTORY: *
531 * 05/12/1999 SKB : Created. *
532 *=============================================================================================*/
533TagBlockHandle::TagBlockHandle(TagBlockFile *tagfile, TagBlockIndex *tagindex, TagBlockFile::BlockHeader *blockheader):
534 File(tagfile),
535 Index(tagindex),
536 BlockHeader(blockheader),
537 Position(0)
538{
539}
540
541/***********************************************************************************************
542 * TagBlockHandle::~TagBlockHandle -- Destroy handle. *
543 * *
544 * INPUT: *
545 * *
546 * OUTPUT: *
547 * *
548 * WARNINGS: *
549 * *
550 * HISTORY: *
551 * 05/12/1999 SKB : Created. *
552 *=============================================================================================*/
554{
555 _InDestructor++;
556 File->Destroy_Handle(this);
557 _InDestructor--;
558}
559
560/***********************************************************************************************
561 * TagBlockHandle::Write -- Write data to the block. *
562 * *
563 * INPUT: *
564 * *
565 * OUTPUT: *
566 * *
567 * WARNINGS: *
568 * *
569 * HISTORY: *
570 * 05/12/1999 SKB : Created. *
571 *=============================================================================================*/
572int TagBlockHandle::Write(const void *buf, int nbytes)
573{
574 // Make sure this handle is the proper one.
575 if (!File->Handle_Can_Write(this)) {
576 return(-1);
577 }
578
579 // Get to correct position to write out and write the buffer.
580 File->Seek(Index->Get_DataOffset() + Position, SEEK_SET);
581 nbytes = File->Write(buf, nbytes);
582
583 // Advance the EOF marker for the block.
584 Position += nbytes;
585 if (Position > BlockHeader->DataSize) {
586 BlockHeader->DataSize = Position;
587 }
588
589 // Return about written out.
590 return(nbytes);
591}
592
593/***********************************************************************************************
594 * TagBlockHandle::Read -- Read from a tag block. *
595 * *
596 * INPUT: *
597 * *
598 * OUTPUT: *
599 * *
600 * WARNINGS: *
601 * *
602 * HISTORY: *
603 * 05/12/1999 SKB : Created. *
604 *=============================================================================================*/
605int TagBlockHandle::Read(void *buf, int nbytes)
606{
607 // Make sure user does not read past end of buffer.
608 if ((Position + nbytes) > BlockHeader->DataSize) {
609 nbytes = BlockHeader->DataSize - Position;
610 }
611
612 // Get to correct position to write out and read in the buffer.
613 File->Seek(Index->Get_DataOffset() + Position, SEEK_SET);
614 nbytes = File->Read(buf, nbytes);
615
616 // Adjust the read head.
617 Position += nbytes;
618
619 // Tell user how much was read from the file.
620 return(nbytes);
621}
622
623/***********************************************************************************************
624 * TagBlockHandle::Seek -- Seek within the file. *
625 * *
626 * INPUT: *
627 * *
628 * OUTPUT: *
629 * *
630 * WARNINGS: *
631 * *
632 * HISTORY: *
633 * 05/12/1999 SKB : Created. *
634 *=============================================================================================*/
635int TagBlockHandle::Seek(int pos, int dir)
636{
637 switch (dir) {
638 case SEEK_CUR:
639 Position += pos;
640 break;
641 case SEEK_SET:
642 Position = pos;
643 break;
644 case SEEK_END:
645 Position = BlockHeader->DataSize + pos;
646 break;
647 }
648 return(Position);
649}
650
651// EOF
#define NULL
Definition BaseType.h:92
#define SEEK_SET
Definition WWFILE.H:55
#define SEEK_CUR
Definition WWFILE.H:56
#define SEEK_END
Definition WWFILE.H:57
#define W3DNEW
Definition always.h:109
unsigned long CRC_Stringi(const char *string, unsigned long crc)
Definition realcrc.cpp:168
char dir[_MAX_DIR]
Definition autorun.cpp:215
Definition crc.h:59
@ WRITE
Definition WWFILE.H:72
Definition file.h:83
virtual int Open(char const *filename, int rights=READ)
Definition rawfile.cpp:356
virtual int Seek(int pos, int dir=SEEK_CUR)
Definition rawfile.cpp:773
RawFileClass(char const *filename)
Definition rawfile.cpp:246
virtual int Write(void const *buffer, int size)
Definition rawfile.cpp:698
virtual void Close(void)
Definition rawfile.cpp:561
virtual unsigned long Get_Date_Time(void)
Definition rawfile.cpp:1024
virtual int Read(void *buffer, int size)
Definition rawfile.cpp:614
SLNode< T > * Next(void)
Definition SLNODE.H:99
T * Data(void)
Definition SLNODE.H:100
virtual void Reset_File()
Definition tagblock.cpp:216
FileHeader Header
Definition TagBlock.h:163
void Close_Tag(TagBlockHandle *handle)
Definition tagblock.cpp:327
SList< TagBlockIndex > IndexList
Definition TagBlock.h:178
TagBlockHandle * Create_Tag(const char *tagname)
Definition tagblock.cpp:282
virtual ~TagBlockFile()
Definition tagblock.cpp:199
TagBlockIndex * Find_Block(const char *tagname)
Definition tagblock.cpp:450
TagBlockHandle * CreateHandle
Definition TagBlock.h:167
void Empty_Index_List()
Definition tagblock.cpp:504
int End_Write_Access(TagBlockHandle *handle)
Definition tagblock.cpp:371
static int Calc_Tag_Offset(int blockoffset)
Definition TagBlock.h:100
@ MAX_TAG_NAME_SIZE
Definition TagBlock.h:114
TagBlockHandle * Open_Tag(const char *tagname)
Definition tagblock.cpp:247
TagBlockIndex * Create_Index(const char *tagname, int blockoffset)
Definition tagblock.cpp:406
void Save_Header()
Definition TagBlock.h:202
int NumOpenHandles
Definition TagBlock.h:171
unsigned long FileTime
Definition TagBlock.h:174
void Destroy_Handle(TagBlockHandle *handle)
Definition tagblock.cpp:344
friend class TagBlockHandle
Definition TagBlock.h:209
TagBlockFile(const char *fname)
Definition tagblock.cpp:123
int Read(void *buf, int nbytes)
Definition tagblock.cpp:605
int Write(const void *buf, int nbytes)
Definition tagblock.cpp:572
int Seek(int pos, int dir=SEEK_CUR)
Definition tagblock.cpp:635
int Get_BlockOffset()
Definition tagblock.cpp:76
int Get_TagSize()
Definition tagblock.cpp:82
unsigned Get_CRC()
Definition tagblock.cpp:73
TagBlockIndex(const char *tagname, int blockoffset)
Definition tagblock.cpp:67
int Get_DataOffset()
Definition tagblock.cpp:85
int Get_TagOffset()
Definition tagblock.cpp:79