/* ** 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; }