/*
** Command & Conquer Generals(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 .
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: W3DFileSystem.cpp ////////////////////////////////////////////////////////////////////////
//
// W3D implementation of a file factory. This replaces the W3D file factory,
// and uses GDI assets, so that
// W3D files and targa files are loaded using the GDI file interface.
// Note - this only servers up read only files.
//
// Author: John Ahlquist, Sept 2001
// Colin Day, November 2001
//
///////////////////////////////////////////////////////////////////////////////////////////////////
// INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
// for now we maintain old legacy files
// #define MAINTAIN_LEGACY_FILES
#include "Common/Debug.h"
#include "Common/File.h"
#include "Common/FileSystem.h"
#include "Common/GlobalData.h"
#include "Common/MapObject.h"
#include "Common/Registry.h"
#include "W3DDevice/GameClient/W3DFileSystem.h"
// DEFINES ////////////////////////////////////////////////////////////////////////////////////////
#include
//-------------------------------------------------------------------------------------------------
/** Game file access. At present this allows us to access test assets, assets from
* legacy GDI assets, and the current flat directory access for textures, models etc */
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
typedef enum
{
FILE_TYPE_UNKNOWN = 0,
FILE_TYPE_W3D,
FILE_TYPE_TGA,
FILE_TYPE_DDS,
} GameFileType;
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
GameFileClass::GameFileClass( char const *filename )
{
m_fileExists = FALSE;
m_theFile = NULL;
m_filePath[ 0 ] = 0;
m_filename[0] = 0;
if( filename )
Set_Name( filename );
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
GameFileClass::GameFileClass( void )
{
m_fileExists = FALSE;
m_theFile = NULL;
m_filePath[ 0 ] = 0;
m_filename[ 0 ] = 0;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
GameFileClass::~GameFileClass()
{
Close();
}
//-------------------------------------------------------------------------------------------------
/** Gets the file name */
//-------------------------------------------------------------------------------------------------
char const * GameFileClass::File_Name( void ) const
{
return m_filename;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
inline static Bool isImageFileType( GameFileType fileType )
{
return (fileType == FILE_TYPE_TGA || fileType == FILE_TYPE_DDS);
}
//-------------------------------------------------------------------------------------------------
/** Sets the file name, and finds the GDI asset if present. */
//-------------------------------------------------------------------------------------------------
char const * GameFileClass::Set_Name( char const *filename )
{
if( Is_Open() )
Close();
// save the filename
strncpy( m_filename, filename, _MAX_PATH );
char name[_MAX_PATH];
const Int EXT_LEN = 32;
char extension[EXT_LEN];
extension[0] = 0;
strcpy(name, filename);
Int i = strlen(name);
i--;
Int extLen = 1;
while(i>0 && extLen < EXT_LEN) {
if (name[i] == '.') {
strcpy(extension, name+i);
name[i] = 0;
break;
}
i--;
extLen++;
}
Int j = 0;
// Strip out spaces.
for (i=0; name[i]; i++) {
if (name[i] != ' ') {
name[j] = name[i];
j++;
}
}
name[j] = 0;
// test the extension to recognize a few key file types
GameFileType fileType = FILE_TYPE_UNKNOWN;
if( stricmp( extension, ".w3d" ) == 0 )
fileType = FILE_TYPE_W3D;
else if( stricmp( extension, ".tga" ) == 0 )
fileType = FILE_TYPE_TGA;
else if( stricmp( extension, ".dds" ) == 0 )
fileType = FILE_TYPE_DDS;
// all .w3d files are in W3D_DIR_PATH, all .tga files are in TGA_DIR_PATH
if( fileType == FILE_TYPE_W3D )
{
strcpy( m_filePath, W3D_DIR_PATH );
strcat( m_filePath, filename );
} // end if
else if( isImageFileType(fileType) )
{
strcpy( m_filePath, TGA_DIR_PATH );
strcat( m_filePath, filename );
} // end else if
else
strcpy( m_filePath, filename );
// see if the file exists
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
// maintain legacy compatibility directories for now
#ifdef MAINTAIN_LEGACY_FILES
if( m_fileExists == FALSE )
{
if( fileType == FILE_TYPE_W3D )
{
strcpy( m_filePath, LEGACY_W3D_DIR_PATH );
strcat( m_filePath, filename );
} // end if
else if( isImageFileType(fileType) )
{
strcpy( m_filePath, LEGACY_TGA_DIR_PATH );
strcat( m_filePath, filename );
} // end else if
// see if the file exists
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
} // end if
#endif
// if file is still not found, try the test art folders
#ifdef LOAD_TEST_ASSETS
if( m_fileExists == FALSE )
{
if( fileType == FILE_TYPE_W3D )
{
strcpy( m_filePath, TEST_W3D_DIR_PATH );
strcat( m_filePath, filename );
} // end if
else if( isImageFileType(fileType) )
{
strcpy( m_filePath, TEST_TGA_DIR_PATH );
strcat( m_filePath, filename );
} // end else if
// see if the file exists
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
} // end if
#endif
// We allow the user to load their own images for various assets (like the control bar)
if( m_fileExists == FALSE && TheGlobalData)
{
if( fileType == FILE_TYPE_W3D )
{
sprintf(m_filePath,USER_W3D_DIR_PATH, TheGlobalData->getPath_UserData().str());
//strcpy( m_filePath, USER_W3D_DIR_PATH );
strcat( m_filePath, filename );
} // end if
if( isImageFileType(fileType) )
{
sprintf(m_filePath,USER_TGA_DIR_PATH, TheGlobalData->getPath_UserData().str());
//strcpy( m_filePath, USER_TGA_DIR_PATH );
strcat( m_filePath, filename );
} // end else if
// see if the file exists
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
} // end if
// We Need to be able to "temporarily copy over the map preview for whichever directory it came from
if( m_fileExists == FALSE && TheGlobalData)
{
if( fileType == FILE_TYPE_TGA ) // just TGA, since we don't dds previews
{
sprintf(m_filePath,MAP_PREVIEW_DIR_PATH, TheGlobalData->getPath_UserData().str());
//strcpy( m_filePath, USER_TGA_DIR_PATH );
strcat( m_filePath, filename );
} // end else if
// see if the file exists
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
} // end if
// We need to be able to grab images from a localization dir, because Art has a fetish for baked-in text. Munkee.
if( m_fileExists == FALSE )
{
if( isImageFileType(fileType) )
{
static const char *localizedPathFormat = "Data/%s/Art/Textures/";
sprintf(m_filePath,localizedPathFormat, GetRegistryLanguage().str());
strcat( m_filePath, filename );
} // end else if
// see if the file exists
m_fileExists = TheFileSystem->doesFileExist( m_filePath );
} // end if
return m_filename;
}
//-------------------------------------------------------------------------------------------------
/** If we found a gdi asset, the file is available. */
//-------------------------------------------------------------------------------------------------
bool GameFileClass::Is_Available( int forced )
{
// not maintaining any GDF compatibility, all files should be where the m_filePath says
return m_fileExists;
}
//-------------------------------------------------------------------------------------------------
/** Is the file open. */
//-------------------------------------------------------------------------------------------------
bool GameFileClass::Is_Open(void) const
{
return m_theFile != NULL;
}
//-------------------------------------------------------------------------------------------------
/** Open the named file. */
//-------------------------------------------------------------------------------------------------
int GameFileClass::Open(char const *filename, int rights)
{
Set_Name(filename);
if (Is_Available(false)) {
return(Open(rights));
}
return(false);
}
//-------------------------------------------------------------------------------------------------
/** Open the file using the current file name. */
//-------------------------------------------------------------------------------------------------
int GameFileClass::Open(int rights)
{
if( rights != READ )
{
return(false);
}
// just open up the file in m_filePath
m_theFile = TheFileSystem->openFile( m_filePath, File::READ | File::BINARY );
return (m_theFile != NULL);
}
//-------------------------------------------------------------------------------------------------
/** Read. */
//-------------------------------------------------------------------------------------------------
int GameFileClass::Read(void *buffer, int len)
{
if (m_theFile) {
return m_theFile->read(buffer, len);
}
return(0);
}
//-------------------------------------------------------------------------------------------------
/** Seek. */
//-------------------------------------------------------------------------------------------------
int GameFileClass::Seek(int pos, int dir)
{
File::seekMode mode = File::CURRENT;
switch (dir) {
default:
case SEEK_CUR: mode = File::CURRENT; break;
case SEEK_SET: mode = File::START; break;
case SEEK_END: mode = File::END; break;
}
if (m_theFile) {
return m_theFile->seek(pos, mode);
}
return 0xFFFFFFFF;
}
//-------------------------------------------------------------------------------------------------
/** Size. */
//-------------------------------------------------------------------------------------------------
int GameFileClass::Size(void)
{
if (m_theFile) {
return m_theFile->size();
}
return 0xFFFFFFFF;
}
//-------------------------------------------------------------------------------------------------
/** Write. */
//-------------------------------------------------------------------------------------------------
int GameFileClass::Write(void const *buffer, Int len)
{
#ifdef _DEBUG
#endif
return(0);
}
//-------------------------------------------------------------------------------------------------
/** Close. */
//-------------------------------------------------------------------------------------------------
void GameFileClass::Close(void)
{
if (m_theFile) {
m_theFile->close();
m_theFile = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// W3DFileSystem Class ////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
extern W3DFileSystem *TheW3DFileSystem = NULL;
//-------------------------------------------------------------------------------------------------
/** Constructor. Creating an instance of this class overrices the default
W3D file factory. */
//-------------------------------------------------------------------------------------------------
W3DFileSystem::W3DFileSystem(void)
{
_TheFileFactory = this; // override the w3d file factory.
}
//-------------------------------------------------------------------------------------------------
/** Destructor. This removes the W3D file factory, so shouldn't be done until
after W3D is shutdown. */
//-------------------------------------------------------------------------------------------------
W3DFileSystem::~W3DFileSystem(void)
{
_TheFileFactory = NULL; // remove the w3d file factory.
}
//-------------------------------------------------------------------------------------------------
/** Gets a file with the specified filename. */
//-------------------------------------------------------------------------------------------------
FileClass * W3DFileSystem::Get_File( char const *filename )
{
return NEW GameFileClass( filename ); // poolify
}
//-------------------------------------------------------------------------------------------------
/** Releases a file returned by Get_File. */
//-------------------------------------------------------------------------------------------------
void W3DFileSystem::Return_File( FileClass *file )
{
delete file;
}