mirror of
https://github.com/electronicarts/CnC_Renegade.git
synced 2025-12-16 07:31:40 -05:00
Initial commit of Command & Conquer Renegade source code.
This commit is contained in:
310
Code/wwlib/ffactory.cpp
Normal file
310
Code/wwlib/ffactory.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
** Command & Conquer Renegade(tm)
|
||||
** Copyright 2025 Electronic Arts Inc.
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/***********************************************************************************************
|
||||
*** 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 ***
|
||||
***********************************************************************************************
|
||||
* *
|
||||
* Project Name : Command & Conquer *
|
||||
* *
|
||||
* $Archive:: /Commando/Code/wwlib/ffactory.cpp $*
|
||||
* *
|
||||
* $Author:: Jani_p $*
|
||||
* *
|
||||
* $Modtime:: 8/24/01 11:50a $*
|
||||
* *
|
||||
* $Revision:: 17 $*
|
||||
* *
|
||||
*---------------------------------------------------------------------------------------------*
|
||||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
#include "ffactory.h"
|
||||
#include "rawfile.h"
|
||||
#include "bufffile.h"
|
||||
#include "realcrc.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
** Statics
|
||||
** NOTE: If _TheFileFactory is ever changed to point to an object of a different class which does
|
||||
** not derive from SimpleFileFactoryClass, _TheSimpleFileFactory should be set to NULL.
|
||||
*/
|
||||
SimpleFileFactoryClass _DefaultFileFactory;
|
||||
FileFactoryClass * _TheFileFactory = &_DefaultFileFactory;
|
||||
SimpleFileFactoryClass * _TheSimpleFileFactory = &_DefaultFileFactory;
|
||||
|
||||
SimpleFileFactoryClass _DefaultWritingFileFactory;
|
||||
FileFactoryClass * _TheWritingFileFactory = &_DefaultWritingFileFactory;
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
file_auto_ptr::file_auto_ptr(FileFactoryClass *fac, const char *filename) :
|
||||
_Ptr(NULL), _Fac(fac)
|
||||
{
|
||||
assert(_Fac);
|
||||
_Ptr=_Fac->Get_File(filename);
|
||||
if ( _Ptr == NULL ) {
|
||||
_Ptr = new BufferedFileClass();
|
||||
}
|
||||
}
|
||||
|
||||
file_auto_ptr::~file_auto_ptr()
|
||||
{
|
||||
_Fac->Return_File(_Ptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** RawFileFactoryClass implementation
|
||||
*/
|
||||
FileClass * RawFileFactoryClass::Get_File( char const *filename )
|
||||
{
|
||||
return new RawFileClass( filename );
|
||||
}
|
||||
|
||||
void RawFileFactoryClass::Return_File( FileClass *file )
|
||||
{
|
||||
delete file;
|
||||
}
|
||||
|
||||
/*
|
||||
** SimpleFileFactoryClass implementation
|
||||
*/
|
||||
|
||||
SimpleFileFactoryClass::SimpleFileFactoryClass( void ) :
|
||||
IsStripPath( false ),
|
||||
Mutex( )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SimpleFileFactoryClass::Get_Sub_Directory( StringClass& new_dir ) const
|
||||
{
|
||||
// BEGIN SERIALIZATION
|
||||
|
||||
// We cannot return a const char * here because the StringClass
|
||||
// may reallocate its buffer during a call to Set_Sub_Directory.
|
||||
// I opted to return a StringClass instead of a reference to
|
||||
// StringClass because it seems like that would behave more
|
||||
// reasonably. (no sudden changes from or to empty string in
|
||||
// the middle of a calling function.) (DRM, 04/19/01)
|
||||
|
||||
// Jani: Returning a StringClass object causes a memory allocation
|
||||
// and release so it is better to take a reference to the
|
||||
// destination StringClass object and modify that.
|
||||
|
||||
CriticalSectionClass::LockClass lock(Mutex);
|
||||
new_dir=SubDirectory;
|
||||
// END SERIALIZATION
|
||||
}
|
||||
|
||||
|
||||
void SimpleFileFactoryClass::Set_Sub_Directory( const char * sub_directory )
|
||||
{
|
||||
// BEGIN SERIALIZATION
|
||||
|
||||
// StringClass makes no guarantees on the atomicity of assignment.
|
||||
// Just to be safe, we lock before executing the assignment code.
|
||||
// (DRM, 04/19/01)
|
||||
|
||||
CriticalSectionClass::LockClass lock(Mutex);
|
||||
SubDirectory = sub_directory;
|
||||
// END SERIALIZATION
|
||||
}
|
||||
|
||||
|
||||
void SimpleFileFactoryClass::Prepend_Sub_Directory( const char * sub_directory )
|
||||
{
|
||||
int sub_len = strlen(sub_directory);
|
||||
// Overflow prevention
|
||||
if (sub_len > 1021) {
|
||||
WWASSERT(0);
|
||||
return;
|
||||
} else if (sub_len < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure sub_directory ends with a slash, and append a semicolon
|
||||
char temp_sub_dir[1024];
|
||||
strcpy(temp_sub_dir, sub_directory);
|
||||
if (temp_sub_dir[sub_len - 1] != '\\') {
|
||||
temp_sub_dir[sub_len] = '\\';
|
||||
temp_sub_dir[sub_len + 1] = 0;
|
||||
sub_len++;
|
||||
}
|
||||
temp_sub_dir[sub_len] = ';';
|
||||
temp_sub_dir[sub_len + 1] = 0;
|
||||
|
||||
// BEGIN SERIALIZATION
|
||||
|
||||
// StringClass makes no guarantees on the atomicity of concatenation.
|
||||
// Just to be safe, we lock before executing the concatenation code.
|
||||
// (NH, 04/23/01)
|
||||
|
||||
CriticalSectionClass::LockClass lock(Mutex);
|
||||
SubDirectory = temp_sub_dir + SubDirectory;
|
||||
|
||||
// END SERIALIZATION
|
||||
}
|
||||
|
||||
|
||||
void SimpleFileFactoryClass::Append_Sub_Directory( const char * sub_directory )
|
||||
{
|
||||
int sub_len = strlen(sub_directory);
|
||||
// Overflow prevention
|
||||
if (sub_len > 1022) {
|
||||
WWASSERT(0);
|
||||
return;
|
||||
} else if (sub_len < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure sub_directory ends with a slash
|
||||
char temp_sub_dir[1024];
|
||||
strcpy(temp_sub_dir, sub_directory);
|
||||
if (temp_sub_dir[sub_len - 1] != '\\') {
|
||||
temp_sub_dir[sub_len] = '\\';
|
||||
temp_sub_dir[sub_len + 1] = 0;
|
||||
sub_len++;
|
||||
}
|
||||
|
||||
// BEGIN SERIALIZATION
|
||||
|
||||
// We are doing various dependent operations on SubDirectory.
|
||||
// Just to be safe, we lock before this section.
|
||||
// (NH, 04/23/01)
|
||||
|
||||
CriticalSectionClass::LockClass lock(Mutex);
|
||||
|
||||
// Ensure a trailing semicolon is present, unless the directory list is empty
|
||||
int len = SubDirectory.Get_Length();
|
||||
if (len && SubDirectory[len - 1] != ';') {
|
||||
SubDirectory += ';';
|
||||
}
|
||||
|
||||
SubDirectory += temp_sub_dir;
|
||||
// END SERIALIZATION
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Is_Full_Path
|
||||
*/
|
||||
static bool
|
||||
Is_Full_Path (const char *path)
|
||||
{
|
||||
bool retval = false;
|
||||
|
||||
if (path != NULL && path[0] != 0) {
|
||||
|
||||
// Check for drive designation
|
||||
retval = bool(path[1] == ':');
|
||||
|
||||
// Check for network path
|
||||
retval |= bool((path[0] == '\\') && (path[1] == '\\'));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
*/
|
||||
FileClass * SimpleFileFactoryClass::Get_File( char const *filename )
|
||||
{
|
||||
// strip off the path (if needed). Note that if path stripping is off, and the requested file
|
||||
// has a path in its name, and the current subdirectory is not empty, the paths will just be
|
||||
// concatenated which may not produce reasonable results.
|
||||
StringClass stripped_name(true);
|
||||
if (IsStripPath) {
|
||||
const char * ptr = ::strrchr( filename, '\\' );
|
||||
|
||||
if (ptr != 0) {
|
||||
ptr++;
|
||||
stripped_name = ptr;
|
||||
} else {
|
||||
stripped_name = filename;
|
||||
}
|
||||
} else {
|
||||
stripped_name = filename;
|
||||
}
|
||||
|
||||
RawFileClass *file = new BufferedFileClass();// new RawWritingFileClass();
|
||||
assert( file );
|
||||
|
||||
//
|
||||
// Do we need to find the path for this file request?
|
||||
//
|
||||
StringClass new_name(stripped_name,true);
|
||||
if (Is_Full_Path ( new_name ) == false) {
|
||||
|
||||
// BEGIN SERIALIZATION
|
||||
|
||||
// We need to lock here because we are using the contents of SubDirectory
|
||||
// in two places. I'd rather be overly cautious about the implementation
|
||||
// of StringClass and wrap all calls to it. We can optimize later if this
|
||||
// proves too slow. (DRM, 04/19/01)
|
||||
|
||||
CriticalSectionClass::LockClass lock(Mutex);
|
||||
|
||||
if (!SubDirectory.Is_Empty()) {
|
||||
|
||||
//
|
||||
// SubDirectory may contain a semicolon seperated search path...
|
||||
// If the file doesn't exist, we'll set the path to the last dir in
|
||||
// the search path. Therefore newly created files will always go in the
|
||||
// last dir in the search path.
|
||||
//
|
||||
StringClass subdir(SubDirectory,true);
|
||||
|
||||
if (strchr(subdir,';'))
|
||||
{
|
||||
char *tokstart=subdir.Peek_Buffer();
|
||||
const char *tok;
|
||||
while((tok=strtok(tokstart, ";")) != NULL) {
|
||||
tokstart=NULL;
|
||||
new_name.Format("%s%s",tok,stripped_name.Peek_Buffer());
|
||||
file->Set_Name( new_name ); // Call Set_Name to force an allocated name
|
||||
if (file->Open()) {
|
||||
file->Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new_name.Format("%s%s",SubDirectory,stripped_name);
|
||||
}
|
||||
}
|
||||
|
||||
// END SERIALIZATION
|
||||
}
|
||||
|
||||
file->Set_Name( new_name ); // Call Set_Name to force an allocated name
|
||||
return file;
|
||||
}
|
||||
|
||||
void SimpleFileFactoryClass::Return_File( FileClass *file )
|
||||
{
|
||||
delete file;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user