/*
** 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. //
// //
////////////////////////////////////////////////////////////////////////////////
///////// Win32LocalFileSystem.cpp /////////////////////////
// Bryan Cleveland, August 2002
////////////////////////////////////////////////////////////
#include
#include "Common/AsciiString.h"
#include "Common/GameMemory.h"
#include "Common/PerfTimer.h"
#include "Win32Device/Common/Win32LocalFileSystem.h"
#include "Win32Device/Common/Win32LocalFile.h"
#include
Win32LocalFileSystem::Win32LocalFileSystem() : LocalFileSystem()
{
}
Win32LocalFileSystem::~Win32LocalFileSystem() {
}
//DECLARE_PERF_TIMER(Win32LocalFileSystem_openFile)
File * Win32LocalFileSystem::openFile(const Char *filename, Int access /* = 0 */)
{
//USE_PERF_TIMER(Win32LocalFileSystem_openFile)
Win32LocalFile *file = newInstance( Win32LocalFile );
// sanity check
if (strlen(filename) <= 0) {
return NULL;
}
if (access & File::WRITE) {
// if opening the file for writing, we need to make sure the directory is there
// before we try to create the file.
AsciiString string;
string = filename;
AsciiString token;
AsciiString dirName;
string.nextToken(&token, "\\/");
dirName = token;
while ((token.find('.') == NULL) || (string.find('.') != NULL)) {
createDirectory(dirName);
string.nextToken(&token, "\\/");
dirName.concat('\\');
dirName.concat(token);
}
}
if (file->open(filename, access) == FALSE) {
file->close();
file->deleteInstance();
file = NULL;
} else {
file->deleteOnClose();
}
// this will also need to play nice with the STREAMING type that I added, if we ever enable this
// srj sez: this speeds up INI loading, but makes BIG files unusable.
// don't enable it without further tweaking.
//
// unless you like running really slowly.
// if (!(access&File::WRITE)) {
// // Return a ramfile.
// RAMFile *ramFile = newInstance( RAMFile );
// if (ramFile->open(file)) {
// file->close(); // is deleteonclose, so should delete.
// ramFile->deleteOnClose();
// return ramFile;
// } else {
// ramFile->close();
// ramFile->deleteInstance();
// }
// }
return file;
}
void Win32LocalFileSystem::update()
{
}
void Win32LocalFileSystem::init()
{
}
void Win32LocalFileSystem::reset()
{
}
//DECLARE_PERF_TIMER(Win32LocalFileSystem_doesFileExist)
Bool Win32LocalFileSystem::doesFileExist(const Char *filename) const
{
//USE_PERF_TIMER(Win32LocalFileSystem_doesFileExist)
if (_access(filename, 0) == 0) {
return TRUE;
}
return FALSE;
}
void Win32LocalFileSystem::getFileListInDirectory(const AsciiString& currentDirectory, const AsciiString& originalDirectory, const AsciiString& searchName, FilenameList & filenameList, Bool searchSubdirectories) const
{
HANDLE fileHandle = NULL;
WIN32_FIND_DATA findData;
char search[_MAX_PATH];
AsciiString asciisearch;
asciisearch = originalDirectory;
asciisearch.concat(currentDirectory);
asciisearch.concat(searchName);
strcpy(search, asciisearch.str());
Bool done = FALSE;
fileHandle = FindFirstFile(search, &findData);
done = (fileHandle == INVALID_HANDLE_VALUE);
while (!done) {
if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(strcmp(findData.cFileName, ".") && strcmp(findData.cFileName, ".."))) {
// if we haven't already, add this filename to the list.
// a stl set should only allow one copy of each filename
AsciiString newFilename;
newFilename = originalDirectory;
newFilename.concat(currentDirectory);
newFilename.concat(findData.cFileName);
if (filenameList.find(newFilename) == filenameList.end()) {
filenameList.insert(newFilename);
}
}
done = (FindNextFile(fileHandle, &findData) == 0);
}
FindClose(fileHandle);
if (searchSubdirectories) {
AsciiString subdirsearch;
subdirsearch = originalDirectory;
subdirsearch.concat(currentDirectory);
subdirsearch.concat("*.");
fileHandle = FindFirstFile(subdirsearch.str(), &findData);
done = fileHandle == INVALID_HANDLE_VALUE;
while (!done) {
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(strcmp(findData.cFileName, ".") && strcmp(findData.cFileName, ".."))) {
AsciiString tempsearchstr;
tempsearchstr.concat(currentDirectory);
tempsearchstr.concat(findData.cFileName);
tempsearchstr.concat('\\');
// recursively add files in subdirectories if required.
getFileListInDirectory(tempsearchstr, originalDirectory, searchName, filenameList, searchSubdirectories);
}
done = (FindNextFile(fileHandle, &findData) == 0);
}
FindClose(fileHandle);
}
}
Bool Win32LocalFileSystem::getFileInfo(const AsciiString& filename, FileInfo *fileInfo) const
{
WIN32_FIND_DATA findData;
HANDLE findHandle = NULL;
findHandle = FindFirstFile(filename.str(), &findData);
if (findHandle == INVALID_HANDLE_VALUE) {
return FALSE;
}
fileInfo->timestampHigh = findData.ftLastWriteTime.dwHighDateTime;
fileInfo->timestampLow = findData.ftLastWriteTime.dwLowDateTime;
fileInfo->sizeHigh = findData.nFileSizeHigh;
fileInfo->sizeLow = findData.nFileSizeLow;
FindClose(findHandle);
return TRUE;
}
Bool Win32LocalFileSystem::createDirectory(AsciiString directory)
{
if ((directory.getLength() > 0) && (directory.getLength() < _MAX_DIR)) {
return (CreateDirectory(directory.str(), NULL) != 0);
}
return FALSE;
}