| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627 |
- /*
- ** 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 <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- //----------------------------------------------------------------------------
- //
- // Westwood Studios Pacific.
- //
- // Confidential Information
- // Copyright(C) 2001 - All Rights Reserved
- //
- //----------------------------------------------------------------------------
- //
- // Project: WSYS Library
- //
- // Module: IO_
- //
- // File name: IO_LocalFile.cpp
- //
- // Created: 4/23/01
- //
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Includes
- //----------------------------------------------------------------------------
- #include "PreRTS.h"
- #include <stdio.h>
- #include <fcntl.h>
- #include <io.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include "Common/LocalFile.h"
- #include "Common/RAMFile.h"
- #include "Lib/BaseType.h"
- #include "Common/PerfTimer.h"
-
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //----------------------------------------------------------------------------
- // Externals
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Defines
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Types
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Data
- //----------------------------------------------------------------------------
- static Int s_totalOpen = 0;
- //----------------------------------------------------------------------------
- // Public Data
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Prototypes
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Functions
- //----------------------------------------------------------------------------
- //=================================================================
- // LocalFile::LocalFile
- //=================================================================
- LocalFile::LocalFile()
- #ifdef USE_BUFFERED_IO
- : m_file(NULL)
- #else
- : m_handle(-1)
- #endif
- {
- }
- //----------------------------------------------------------------------------
- // Public Functions
- //----------------------------------------------------------------------------
- //=================================================================
- // LocalFile::~LocalFile
- //=================================================================
- LocalFile::~LocalFile()
- {
- #ifdef USE_BUFFERED_IO
- if (m_file)
- {
- fclose(m_file);
- m_file = NULL;
- --s_totalOpen;
- }
- #else
- if( m_handle != -1 )
- {
- _close( m_handle );
- m_handle = -1;
- --s_totalOpen;
- }
- #endif
- File::close();
- }
- //=================================================================
- // LocalFile::open
- //=================================================================
- /**
- * This function opens a file using the standard C open() call. Access flags
- * are mapped to the appropriate open flags. Returns true if file was opened
- * successfully.
- */
- //=================================================================
- //DECLARE_PERF_TIMER(LocalFile)
- Bool LocalFile::open( const Char *filename, Int access )
- {
- //USE_PERF_TIMER(LocalFile)
- if( !File::open( filename, access) )
- {
- return FALSE;
- }
- /* here we translate WSYS file access to the std C equivalent */
- #ifdef USE_BUFFERED_IO
- char mode[32];
- char* m = mode;
- if (m_access & APPEND)
- {
- DEBUG_CRASH(("not yet supported by buffered mode"));
- }
- if (m_access & TRUNCATE)
- {
- DEBUG_CRASH(("not yet supported by buffered mode"));
- }
- if((m_access & READWRITE ) == READWRITE )
- {
- if (m_access & CREATE)
- {
- *m++ = 'w';
- *m++ = '+';
- }
- else
- {
- *m++ = 'r';
- *m++ = '+';
- }
- }
- else if(m_access & WRITE)
- {
- *m++ = 'w';
- }
- else
- {
- *m++ = 'r';
- DEBUG_ASSERTCRASH(!(m_access & TRUNCATE), ("cannot truncate with read-only"));
- }
- if (m_access & TEXT)
- {
- *m++ = 't';
- }
- if (m_access & BINARY)
- {
- *m++ = 'b';
- }
- *m++ = 0;
- m_file = fopen(filename, mode);
- if (m_file == NULL)
- {
- goto error;
- }
-
- //setvbuf(m_file, m_vbuf, _IOFBF, sizeof(BUF_SIZE));
- #else
- int flags = 0;
- if (m_access & CREATE)
- {
- flags |= _O_CREAT;
- }
- if (m_access & TRUNCATE)
- {
- flags |= _O_TRUNC;
- }
- if (m_access & APPEND)
- {
- flags |= _O_APPEND;
- }
- if (m_access & TEXT)
- {
- flags |= _O_TEXT;
- }
- if (m_access & BINARY)
- {
- flags |= _O_BINARY;
- }
- if((m_access & READWRITE )== READWRITE )
- {
- flags |= _O_RDWR;
- }
- else if(m_access & WRITE)
- {
- flags |= _O_WRONLY;
- flags |= _O_CREAT;
- }
- else
- {
- flags |= _O_RDONLY;
- }
- m_handle = _open( filename, flags , _S_IREAD | _S_IWRITE);
- if( m_handle == -1 )
- {
- goto error;
- }
- #endif
- ++s_totalOpen;
- /// DEBUG_LOG(("LocalFile::open %s (total %d)\n",filename,s_totalOpen));
- if ( m_access & APPEND )
- {
- if ( seek ( 0, END ) < 0 )
- {
- goto error;
- }
- }
- return TRUE;
- error:
- close();
- return FALSE;
- }
- //=================================================================
- // LocalFile::close
- //=================================================================
- /**
- * Closes the current file if it is open.
- * Must call LocalFile::close() for each successful LocalFile::open() call.
- */
- //=================================================================
- void LocalFile::close( void )
- {
- File::close();
- }
- //=================================================================
- // LocalFile::read
- //=================================================================
- Int LocalFile::read( void *buffer, Int bytes )
- {
- //USE_PERF_TIMER(LocalFile)
- if( !m_open )
- {
- return -1;
- }
- if (buffer == NULL)
- {
- #ifdef USE_BUFFERED_IO
- fseek(m_file, bytes, SEEK_CUR);
- #else
- _lseek(m_handle, bytes, SEEK_CUR);
- #endif
- return bytes;
- }
- #ifdef USE_BUFFERED_IO
- Int ret = fread(buffer, 1, bytes, m_file);
- #else
- Int ret = _read( m_handle, buffer, bytes );
- #endif
- return ret;
- }
- //=================================================================
- // LocalFile::write
- //=================================================================
- Int LocalFile::write( const void *buffer, Int bytes )
- {
- if( !m_open || !buffer )
- {
- return -1;
- }
- #ifdef USE_BUFFERED_IO
- Int ret = fwrite(buffer, 1, bytes, m_file);
- #else
- Int ret = _write( m_handle, buffer, bytes );
- #endif
- return ret;
- }
- //=================================================================
- // LocalFile::seek
- //=================================================================
- Int LocalFile::seek( Int pos, seekMode mode)
- {
- int lmode;
- switch( mode )
- {
- case START:
- lmode = SEEK_SET;
- break;
- case CURRENT:
- lmode = SEEK_CUR;
- break;
- case END:
- DEBUG_ASSERTCRASH(pos <= 0, ("LocalFile::seek - pos should be <= 0 for a seek starting at the end of the file"));
- lmode = SEEK_END;
- break;
- default:
- // bad seek mode
- return -1;
- }
- #ifdef USE_BUFFERED_IO
- Int ret = fseek(m_file, pos, lmode);
- if (ret == 0)
- return ftell(m_file);
- else
- return -1;
- #else
- Int ret = _lseek( m_handle, pos, lmode );
- #endif
- return ret;
- }
- //=================================================================
- // LocalFile::scanInt
- //=================================================================
- // skips preceding whitespace and stops at the first non-number
- // or at EOF
- Bool LocalFile::scanInt(Int &newInt)
- {
- newInt = 0;
- AsciiString tempstr;
- Char c;
- Int val;
- // skip preceding non-numeric characters
- do {
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read( m_handle, &c, 1);
- #endif
- } while ((val != 0) && (((c < '0') || (c > '9')) && (c != '-')));
- if (val == 0) {
- return FALSE;
- }
- do {
- tempstr.concat(c);
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read( m_handle, &c, 1);
- #endif
- } while ((val != 0) && ((c >= '0') && (c <= '9')));
- // put the last read char back, since we didn't use it.
- if (val != 0) {
- #ifdef USE_BUFFERED_IO
- fseek(m_file, -1, SEEK_CUR);
- #else
- _lseek(m_handle, -1, SEEK_CUR);
- #endif
- }
- newInt = atoi(tempstr.str());
- return TRUE;
- }
- //=================================================================
- // LocalFile::scanReal
- //=================================================================
- // skips preceding whitespace and stops at the first non-number
- // or at EOF
- Bool LocalFile::scanReal(Real &newReal)
- {
- newReal = 0.0;
- AsciiString tempstr;
- Char c;
- Int val;
- Bool sawDec = FALSE;
- // skip the preceding white space
- do {
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read( m_handle, &c, 1);
- #endif
- } while ((val != 0) && (((c < '0') || (c > '9')) && (c != '-') && (c != '.')));
- if (val == 0) {
- return FALSE;
- }
- do {
- tempstr.concat(c);
- if (c == '.') {
- sawDec = TRUE;
- }
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read(m_handle, &c, 1);
- #endif
- } while ((val != 0) && (((c >= '0') && (c <= '9')) || ((c == '.') && !sawDec)));
- if (val != 0) {
- #ifdef USE_BUFFERED_IO
- fseek(m_file, -1, SEEK_CUR);
- #else
- _lseek(m_handle, -1, SEEK_CUR);
- #endif
- }
- newReal = atof(tempstr.str());
- return TRUE;
- }
- //=================================================================
- // LocalFile::scanString
- //=================================================================
- // skips preceding whitespace and stops at the first whitespace
- // or at EOF
- Bool LocalFile::scanString(AsciiString &newString)
- {
- Char c;
- Int val;
- newString.clear();
- // skip the preceding whitespace
- do {
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read(m_handle, &c, 1);
- #endif
- } while ((val != 0) && (isspace(c)));
- if (val == 0) {
- return FALSE;
- }
- do {
- newString.concat(c);
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read(m_handle, &c, 1);
- #endif
- } while ((val != 0) && (!isspace(c)));
- if (val != 0) {
- #ifdef USE_BUFFERED_IO
- fseek(m_file, -1, SEEK_CUR);
- #else
- _lseek(m_handle, -1, SEEK_CUR);
- #endif
- }
- return TRUE;
- }
- //=================================================================
- // LocalFile::nextLine
- //=================================================================
- // scans to the first character after a new-line or at EOF
- void LocalFile::nextLine(Char *buf, Int bufSize)
- {
- Char c = 0;
- Int val;
- Int i = 0;
- // seek to the next new-line.
- do {
- if ((buf == NULL) || (i >= (bufSize-1))) {
- #ifdef USE_BUFFERED_IO
- val = fread(&c, 1, 1, m_file);
- #else
- val = _read(m_handle, &c, 1);
- #endif
- } else {
- #ifdef USE_BUFFERED_IO
- val = fread(buf + i, 1, 1, m_file);
- #else
- val = _read(m_handle, buf + i, 1);
- #endif
- c = buf[i];
- }
- ++i;
- } while ((val != 0) && (c != '\n'));
- if (buf != NULL) {
- if (i < bufSize) {
- buf[i] = 0;
- } else {
- buf[bufSize] = 0;
- }
- }
- }
- //=================================================================
- //=================================================================
- File* LocalFile::convertToRAMFile()
- {
- RAMFile *ramFile = newInstance( RAMFile );
- if (ramFile->open(this))
- {
- if (this->m_deleteOnClose)
- {
- ramFile->deleteOnClose();
- this->close(); // is deleteonclose, so should delete.
- }
- else
- {
- this->close();
- this->deleteInstance();
- }
- return ramFile;
- }
- else
- {
- ramFile->close();
- ramFile->deleteInstance();
- return this;
- }
- }
- //=================================================================
- // LocalFile::readEntireAndClose
- //=================================================================
- /**
- Allocate a buffer large enough to hold entire file, read
- the entire file into the buffer, then close the file.
- the buffer is owned by the caller, who is responsible
- for freeing is (via delete[]). This is a Good Thing to
- use because it minimizes memory copies for BIG files.
- */
- char* LocalFile::readEntireAndClose()
- {
- UnsignedInt fileSize = size();
- char* buffer = NEW char[fileSize];
- read(buffer, fileSize);
- close();
- return buffer;
- }
|