CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

CCFILE.CPP (29010B)


      1 //
      2 // Copyright 2020 Electronic Arts Inc.
      3 //
      4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
      5 // software: you can redistribute it and/or modify it under the terms of 
      6 // the GNU General Public License as published by the Free Software Foundation, 
      7 // either version 3 of the License, or (at your option) any later version.
      8 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /***********************************************************************************************
     17  ***             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               ***
     18  ***********************************************************************************************
     19  *                                                                                             *
     20  *                 Project Name : Command & Conquer                                            *
     21  *                                                                                             *
     22  *                    File Name : CCFILE.CPP                                                   *
     23  *                                                                                             *
     24  *                   Programmer : Joe L. Bostic                                                *
     25  *                                                                                             *
     26  *                   Start Date : August 8, 1994                                               *
     27  *                                                                                             *
     28  *                  Last Update : March 20, 1995 [JLB]                                         *
     29  *                                                                                             *
     30  *---------------------------------------------------------------------------------------------*
     31  * Functions:                                                                                  *
     32  *   CCFileClass::CCFileClass -- Default constructor for file object.                          *
     33  *   CCFileClass::CCFileClass -- Filename based constructor for C&C file.                      *
     34  *   CCFileClass::Close -- Closes the file.                                                    *
     35  *   CCFileClass::Is_Available -- Checks for existence of file on disk or in mixfile.          *
     36  *   CCFileClass::Is_Open -- Determines if the file is open.                                   *
     37  *   CCFileClass::Open -- Opens a file from either the mixfile system or the rawfile system.   *
     38  *   CCFileClass::Read -- Reads data from the file.                                            *
     39  *   CCFileClass::Seek -- Moves the current file pointer in the file.                          *
     40  *   CCFileClass::Size -- Determines the size of the file.                                     *
     41  *   CCFileClass::Write -- Writes data to the file (non mixfile files only).                   *
     42  *   CCFileClass::Error -- Handles displaying a file error message.                            *
     43  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     44 
     45 
     46 #include	"function.h"
     47 //#include	<direct.h>
     48 //#include	<fcntl.h>
     49 //#include	<io.h>
     50 //#include	<dos.h>
     51 //#include	<errno.h>
     52 //#include	<share.h>
     53 //#include	"ccfile.h"
     54 
     55 
     56 /***********************************************************************************************
     57  * CCFileClass::Error -- Handles displaying a file error message.                              *
     58  *                                                                                             *
     59  *    Display an error message as indicated. If it is allowed to retry, then pressing a key    *
     60  *    will return from this function. Otherwise, it will exit the program with "exit()".       *
     61  *                                                                                             *
     62  * INPUT:   error    -- The error number (same as the DOSERR.H error numbers).                 *
     63  *                                                                                             *
     64  *          canretry -- Can this routine exit normally so that retrying can occur? If this is  *
     65  *                      false, then the program WILL exit in this routine.                     *
     66  *                                                                                             *
     67  *          filename -- Optional filename to report with this error. If no filename is         *
     68  *                      supplied, then no filename is listed in the error message.             *
     69  *                                                                                             *
     70  * OUTPUT:  none, but this routine might not return at all if the "canretry" parameter is      *
     71  *          false or the player pressed ESC.                                                   *
     72  *                                                                                             *
     73  * WARNINGS:   This routine may not return at all. It handles being in text mode as well as    *
     74  *             if in a graphic mode.                                                           *
     75  *                                                                                             *
     76  * HISTORY:                                                                                    *
     77  *   10/17/1994 JLB : Created.                                                                 *
     78  *=============================================================================================*/
     79 void CCFileClass::Error(int , int , char const * )
     80 {
     81 #ifdef DEMO
     82 	if (strstr(File_Name(), "\\")) {
     83 		if (!Force_CD_Available(-1)) {
     84 			Prog_End();
     85 			if (!RunningAsDLL) {
     86 				exit(EXIT_FAILURE);
     87 			}
     88 		}
     89 	}
     90 
     91 #else
     92 
     93 	if (!Force_CD_Available(RequiredCD)) {
     94 		Prog_End("CCFileClass::Error CD not found", true);
     95 		if (!RunningAsDLL) {
     96 			exit(EXIT_FAILURE);
     97 		}
     98 	}
     99 
    100 #endif
    101 }
    102 
    103 
    104 /***********************************************************************************************
    105  * CCFileClass::CCFileClass -- Filename based constructor for C&C file.                        *
    106  *                                                                                             *
    107  *    Use this constructor for a file when the filename is known at construction time.         *
    108  *                                                                                             *
    109  * INPUT:   filename -- Pointer to the filename to use for this file object.                   *
    110  *                                                                                             *
    111  * OUTPUT:  none                                                                               *
    112  *                                                                                             *
    113  * WARNINGS:   The filename pointer is presumed to be inviolate throughout the duration of     *
    114  *             the file object. If this is not guaranteed, then use the default constructor    *
    115  *             and then set the name manually.                                                 *
    116  *                                                                                             *
    117  * HISTORY:                                                                                    *
    118  *   03/20/1995 JLB : Created.                                                                 *
    119  *=============================================================================================*/
    120 CCFileClass::CCFileClass(char const *filename) :
    121 	CDFileClass(),
    122 	FromDisk(false),
    123 	Pointer(0),
    124 	Position(0),
    125 	Length(0),
    126 	Start(0)
    127 {
    128 	Set_Name(filename);
    129 }
    130 
    131 
    132 /***********************************************************************************************
    133  * CCFileClass::CCFileClass -- Default constructor for file object.                            *
    134  *                                                                                             *
    135  *    This is the default constructor for a C&C file object.                                   *
    136  *                                                                                             *
    137  * INPUT:   none                                                                               *
    138  *                                                                                             *
    139  * OUTPUT:  none                                                                               *
    140  *                                                                                             *
    141  * WARNINGS:   none                                                                            *
    142  *                                                                                             *
    143  * HISTORY:                                                                                    *
    144  *   03/20/1995 JLB : Created.                                                                 *
    145  *=============================================================================================*/
    146 CCFileClass::CCFileClass(void)
    147 {
    148 	FromDisk = false;
    149 	Pointer = 0;
    150 	Position = 0;
    151 	Length = 0;
    152 	Start = 0;
    153 }
    154 
    155 
    156 /***********************************************************************************************
    157  * CCFileClass::Write -- Writes data to the file (non mixfile files only).                     *
    158  *                                                                                             *
    159  *    This routine will write data to the file, but NOT to a file that is part of a mixfile.   *
    160  *                                                                                             *
    161  * INPUT:   buffer   -- Pointer to the buffer that holds the data to be written.               *
    162  *                                                                                             *
    163  *          size     -- The number of bytes to write.                                          *
    164  *                                                                                             *
    165  * OUTPUT:  Returns the number of bytes actually written.                                      *
    166  *                                                                                             *
    167  * WARNINGS:   none                                                                            *
    168  *                                                                                             *
    169  * HISTORY:                                                                                    *
    170  *   08/08/1994 JLB : Created.                                                                 *
    171  *=============================================================================================*/
    172 long CCFileClass::Write(void const *buffer, long size)
    173 {
    174 
    175 	/*
    176 	**	If this is part of a mixfile, then writing is not allowed. Error out with a fatal
    177 	**	message.
    178 	*/
    179 	if (Pointer || FromDisk) {
    180 		Error(EACCES, false, File_Name());
    181 	}
    182 
    183 	return(CDFileClass::Write(buffer, size));
    184 }
    185 
    186 
    187 /***********************************************************************************************
    188  * CCFileClass::Read -- Reads data from the file.                                              *
    189  *                                                                                             *
    190  *    This routine determines if the file is part of the mixfile system. If it is, then        *
    191  *    the file is copied from RAM if it is located there. Otherwise it is read from disk       *
    192  *    according to the correct position of the file within the parent mixfile.                 *
    193  *                                                                                             *
    194  * INPUT:   buffer   -- Pointer to the buffer to place the read data.                          *
    195  *                                                                                             *
    196  *          size     -- The number of bytes to read.                                           *
    197  *                                                                                             *
    198  * OUTPUT:  Returns the actual number of bytes read (this could be less than requested).       *
    199  *                                                                                             *
    200  * WARNINGS:   none                                                                            *
    201  *                                                                                             *
    202  * HISTORY:                                                                                    *
    203  *   08/08/1994 JLB : Created.                                                                 *
    204  *=============================================================================================*/
    205 long CCFileClass::Read(void *buffer, long size)
    206 {
    207 	int opened = false;
    208 
    209 	if (!Is_Open()) {
    210 		if (Open()) {
    211 			opened = true;
    212 		}
    213 	}
    214 
    215 	/*
    216 	**	If the file is part of a loaded mixfile, then a mere copy is
    217 	**	all that is required for the read.
    218 	*/
    219 	if (Pointer) {
    220 		long	maximum = Length - Position;
    221 
    222 		size = MIN(maximum, size);
    223 		if (size) {
    224 			Mem_Copy(Add_Long_To_Pointer(Pointer, Position), buffer, size);
    225 			Position += size;
    226 		}
    227 		if (opened) Close();
    228 		return(size);
    229 	}
    230 
    231 	/*
    232 	**	If the file is part of a mixfile, but the mixfile is located
    233 	**	on disk, then a special read operation is necessary.
    234 	*/
    235 	if (FromDisk) {
    236 		long	maximum = Length - Position;
    237 
    238 		size = MIN(maximum, size);
    239 		if (size > 0) {
    240 			CDFileClass::Seek(Start + Position, SEEK_SET);
    241 			size = CDFileClass::Read(buffer, size);
    242 			Position += size;
    243 		}
    244 		if (opened) Close();
    245 		return(size);
    246 	}
    247 
    248 	long s = CDFileClass::Read(buffer, size);
    249 	if (opened) Close();
    250 	return(s);
    251 }
    252 
    253 
    254 /***********************************************************************************************
    255  * CCFileClass::Seek -- Moves the current file pointer in the file.                            *
    256  *                                                                                             *
    257  *    This routine will change the current file pointer to the position specified. It follows  *
    258  *    the same rules the a normal Seek() does, but if the file is part of the mixfile system,  *
    259  *    then only the position value needs to be updated.                                        *
    260  *                                                                                             *
    261  * INPUT:   pos      -- The position to move the file to relative to the position indicated    *
    262  *                      by the "dir" parameter.                                                *
    263  *                                                                                             *
    264  *          dir      -- The direction to affect the position change against. This can be       *
    265  *                      either SEEK_CUR, SEEK_END, or SEEK_SET.                                *
    266  *                                                                                             *
    267  * OUTPUT:  Returns with the position of the new location.                                     *
    268  *                                                                                             *
    269  * WARNINGS:   none                                                                            *
    270  *                                                                                             *
    271  * HISTORY:                                                                                    *
    272  *   08/08/1994 JLB : Created.                                                                 *
    273  *=============================================================================================*/
    274 long CCFileClass::Seek(long pos, int dir)
    275 {
    276 	if (Pointer || FromDisk) {
    277 		switch (dir) {
    278 			case SEEK_END:
    279 				Position = Length;
    280 				break;
    281 
    282 			case SEEK_SET:
    283 				Position = 0;
    284 				break;
    285 
    286 			case SEEK_CUR:
    287 			default:
    288 				break;
    289 		}
    290 		Position += pos;
    291 		if (Position < 0) Position = 0;
    292 		if (Position > Length) Position = Length;
    293 		return(Position);
    294 	}
    295 	return(CDFileClass::Seek(pos, dir));
    296 }
    297 
    298 
    299 /***********************************************************************************************
    300  * CCFileClass::Size -- Determines the size of the file.                                       *
    301  *                                                                                             *
    302  *    If the file is part of the mixfile system, then the size of the file is already          *
    303  *    determined and available. Otherwise, go to the low level system to find the file         *
    304  *    size.                                                                                    *
    305  *                                                                                             *
    306  * INPUT:   none                                                                               *
    307  *                                                                                             *
    308  * OUTPUT:  Returns with the size of the file in bytes.                                        *
    309  *                                                                                             *
    310  * WARNINGS:   none                                                                            *
    311  *                                                                                             *
    312  * HISTORY:                                                                                    *
    313  *   08/08/1994 JLB : Created.                                                                 *
    314  *=============================================================================================*/
    315 long CCFileClass::Size(void)
    316 {
    317 	if (Pointer || FromDisk) return(Length);
    318 
    319 	return(CDFileClass::Size());
    320 }
    321 
    322 
    323 /***********************************************************************************************
    324  * CCFileClass::Is_Available -- Checks for existence of file on disk or in mixfile.            *
    325  *                                                                                             *
    326  *    This routine will examine the mixfile system looking for the file. If the file could     *
    327  *    not be found there, then the disk is examined directly.                                  *
    328  *                                                                                             *
    329  * INPUT:   none                                                                               *
    330  *                                                                                             *
    331  * OUTPUT:  bool; Is the file available for opening?                                           *
    332  *                                                                                             *
    333  * WARNINGS:   none                                                                            *
    334  *                                                                                             *
    335  * HISTORY:                                                                                    *
    336  *   08/08/1994 JLB : Created.                                                                 *
    337  *=============================================================================================*/
    338 int CCFileClass::Is_Available(int )
    339 {
    340 	if (MixFileClass::Offset(File_Name())) {
    341 		return(true);
    342 	}
    343 	return(CDFileClass::Is_Available());
    344 }
    345 
    346 
    347 /***********************************************************************************************
    348  * CCFileClass::Is_Open -- Determines if the file is open.                                     *
    349  *                                                                                             *
    350  *    A mixfile is open if there is a pointer to the mixfile data. In absence of this,         *
    351  *    the the file is open if the file handle is valid.                                        *
    352  *                                                                                             *
    353  * INPUT:   none                                                                               *
    354  *                                                                                             *
    355  * OUTPUT:  bool; Is the file open?                                                            *
    356  *                                                                                             *
    357  * WARNINGS:   none                                                                            *
    358  *                                                                                             *
    359  * HISTORY:                                                                                    *
    360  *   08/08/1994 JLB : Created.                                                                 *
    361  *=============================================================================================*/
    362 int CCFileClass::Is_Open(void) const
    363 {
    364 
    365 	/*
    366 	**	If the file is part of a cached file, then return that it is opened. A closed file
    367 	**	doesn't have a valid pointer.
    368 	*/
    369 	if (Pointer) return(true);
    370 	return(CDFileClass::Is_Open());
    371 }
    372 
    373 
    374 /***********************************************************************************************
    375  * CCFileClass::Close -- Closes the file.                                                      *
    376  *                                                                                             *
    377  *    If this is a mixfile file, then only the pointers need to be adjusted.                   *
    378  *                                                                                             *
    379  * INPUT:   none                                                                               *
    380  *                                                                                             *
    381  * OUTPUT:  none                                                                               *
    382  *                                                                                             *
    383  * WARNINGS:   none                                                                            *
    384  *                                                                                             *
    385  * HISTORY:                                                                                    *
    386  *   08/08/1994 JLB : Created.                                                                 *
    387  *=============================================================================================*/
    388 void CCFileClass::Close(void)
    389 {
    390 	FromDisk = false;
    391 	Pointer = 0;
    392 	Position = 0;				// Starts at beginning offset.
    393 	Start = 0;
    394 	Length = 0;
    395 	CDFileClass::Close();
    396 }
    397 
    398 
    399 /***********************************************************************************************
    400  * CCFileClass::Open -- Opens a file from either the mixfile system or the rawfile system.     *
    401  *                                                                                             *
    402  *    This routine will open the specified file. It examines the mixfile system to find a      *
    403  *    match. If one is found then the file is "opened" in a special cached way. Otherwise      *
    404  *    it is opened as a standard DOS file.                                                     *
    405  *                                                                                             *
    406  * INPUT:   rights   -- The access rights desired.                                             *
    407  *                                                                                             *
    408  * OUTPUT:  bool; Was the file opened successfully?                                            *
    409  *                                                                                             *
    410  * WARNINGS:   none                                                                            *
    411  *                                                                                             *
    412  * HISTORY:                                                                                    *
    413  *   08/08/1994 JLB : Created.                                                                 *
    414  *=============================================================================================*/
    415 int CCFileClass::Open(int rights)
    416 {
    417 	/*
    418 	**	Always close the file if it was open.
    419 	*/
    420 	Close();
    421 
    422 	/*
    423 	**	Perform a preliminary check to see if the specified file
    424 	**	exists on the disk. If it does, then open this file regardless
    425 	**	of whether it also exists in RAM. This is slower, but allows
    426 	**	upgrade files to work.
    427 	*/
    428 	if ((rights & WRITE) || CDFileClass::Is_Available()) {
    429 		return(CDFileClass::Open(rights));
    430 	}
    431 
    432 	/*
    433 	**	Check to see if file is part of a mixfile and that mixfile is currently loaded
    434 	**	into RAM.
    435 	*/
    436 	MixFileClass *mixfile = 0;
    437 	if (MixFileClass::Offset(File_Name(), &Pointer, &mixfile, &Start, &Length)) {
    438 
    439 		/*
    440 		**	If the mixfile is located on disk, then fake out the file system to read from
    441 		**	the mixfile, but think it is reading from a solitary file.
    442 		*/
    443 		if (!Pointer) {
    444 			long	start = Start;
    445 			long	length = Length;
    446 
    447 			/*
    448 			**	This is a legitimate open to the file. All access to the file through this
    449 			**	file object will be appropriately adjusted for mixfile support however. Also
    450 			**	note that the filename attached to this object is NOT the same as the file
    451 			**	attached to the file handle.
    452 			*/
    453 			char const * dupfile = strdup(File_Name());
    454 			Open(mixfile->Filename, READ);
    455 			Searching(false);				// Disable multi-drive search.
    456 			Set_Name(dupfile);
    457 			Searching(true);
    458 			if (dupfile) free((void *)dupfile);
    459 			Start = start;
    460 			Length = length;
    461 			FromDisk = true;
    462 		}
    463 
    464 	} else {
    465 
    466 		/*
    467 		**	The file cannot be found in any mixfile, so it must reside as
    468 		** an individual file on the disk. Or else it is just plain missing.
    469 		*/
    470 		return(CDFileClass::Open(rights));
    471 	}
    472 	return(true);
    473 }
    474 
    475 
    476 /***********************************************************************************
    477 ** Backward compatibility section.
    478 */
    479 //extern "C" {
    480 
    481 static CCFileClass Handles[10];
    482 
    483 #ifdef NEVER
    484 bool __cdecl Set_Search_Drives(char const *)
    485 {
    486 	CCFileClass::Set_Search_Path(path);
    487 	return(true);
    488 }
    489 #endif
    490 
    491 int __cdecl Open_File(char const *file_name, int mode)
    492 {
    493 	for (int index = 0; index < sizeof(Handles)/sizeof(Handles[0]); index++) {
    494 		if (!Handles[index].Is_Open()) {
    495 			Handles[index].Set_Name(file_name);
    496 			if (Handles[index].Open(mode)) {
    497 //			if (Handles[index].Open(file_name, mode)) {
    498 				return(index);
    499 			}
    500 			break;
    501 		}
    502 	}
    503 	return(WW_ERROR);
    504 }
    505 
    506 VOID __cdecl Close_File(int handle)
    507 {
    508 	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
    509 		Handles[handle].Close();
    510 	}
    511 }
    512 
    513 LONG __cdecl Read_File(int handle, VOID *buf, ULONG bytes)
    514 {
    515 	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
    516 		return(Handles[handle].Read(buf, bytes));
    517 	}
    518 	return(0);
    519 }
    520 
    521 LONG __cdecl Write_File(int handle, VOID const *buf, ULONG bytes)
    522 {
    523 	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
    524 		return(Handles[handle].Write(buf, bytes));
    525 	}
    526 	return(0);
    527 }
    528 
    529 int __cdecl Find_File(char const *file_name)
    530 {
    531 	CCFileClass file(file_name);
    532 	return(file.Is_Available());
    533 }
    534 
    535 #ifdef NEVER
    536 int __cdecl Delete_File(char const *file_name)
    537 {
    538 	return(CCFileClass(file_name).Delete());
    539 }
    540 
    541 int __cdecl Create_File(char const *file_name)
    542 {
    543 	return(CCFileClass(file_name).Create());
    544 }
    545 
    546 ULONG __cdecl Load_Data(char const *name, VOID *ptr, ULONG size)
    547 {
    548 	return(CCFileClass(name).Read(ptr, size));
    549 }
    550 #endif
    551 
    552 VOID * __cdecl Load_Alloc_Data(char const *name, int )
    553 {
    554 	CCFileClass file(name);
    555 
    556 	return(Load_Alloc_Data(file));
    557 }
    558 
    559 ULONG __cdecl File_Size(int handle)
    560 {
    561 	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
    562 		return(Handles[handle].Size());
    563 	}
    564 	return(0);
    565 }
    566 
    567 #ifdef NEVER
    568 ULONG __cdecl Write_Data(char const *name, VOID const *ptr, ULONG size)
    569 {
    570 	return(CCFileClass(name).Write(ptr, size));
    571 }
    572 #endif
    573 
    574 ULONG __cdecl Seek_File(int handle, LONG offset, int starting)
    575 {
    576 	if (handle != WW_ERROR && Handles[handle].Is_Open()) {
    577 		return(Handles[handle].Seek(offset, starting));
    578 	}
    579 	return(0);
    580 }
    581 
    582 void WWDOS_Shutdown(void)
    583 {
    584 	for (int index = 0; index < 10; index++) {
    585 		Handles[index].Set_Name(NULL);
    586 	}
    587 }
    588 
    589 #ifdef NEVER
    590 bool __cdecl Multi_Drive_Search(bool on)
    591 {
    592 //	return(CCFileClass::Multi_Drive_Search(on));
    593 	return(on);
    594 }
    595 
    596 VOID __cdecl WWDOS_Init(VOID)
    597 {
    598 }
    599 
    600 VOID __cdecl WWDOS_Shutdown(VOID)
    601 {
    602 }
    603 
    604 int __cdecl Find_Disk_Number(char const *)
    605 {
    606 	return(0);
    607 }
    608 #endif
    609 
    610 //ULONG cdecl Load_Uncompress(BYTE const *file, BuffType uncomp_buff, BuffType dest_buff, VOID *reserved_data)
    611 //{
    612 //	return(Load_Uncompress(CCFileClass(file), uncomp_buff, dest_buff, reserved_data));
    613 //	return(CCFileClass(file).Load_Uncompress(uncomp_buff, dest_buff, reserved_data));
    614 //}
    615 
    616 //extern "C" {
    617 //int MaxDevice;
    618 //int DefaultDrive;
    619 //char CallingDOSInt;
    620 
    621 //}
    622 
    623 
    624 void Unfragment_File_Cache(void)
    625 {
    626 }