123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482 |
- /* GCSx
- ** FILE.CPP
- **
- ** Basic file access with exceptions
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** 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 2 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, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- string* mainDir = NULL;
- string* resourceDir = NULL;
- File::File(const char* fFilename, int fMode) throw_File { start_func
- filename = fFilename;
- mode = fMode;
- if (fMode == FILE_MODE_OVERWRITE) {
- filePtr = fopen(filename, "w+b");
- mode = FILE_MODE_READWRITE;
- }
- else {
- filePtr = fopen(filename, fMode == FILE_MODE_READ ? "rb" : "r+b");
- }
- if (!filePtr) {
- throw FileException("Unable to load file %s: %s", filename, strerror(errno));
- }
- lastOperation = OPER_SEEK;
- offset = ftell(filePtr);
- }
- File::~File() { start_func
- if (filePtr) fclose(filePtr);
- }
- char File::copyBuffer[COPY_BUFFER_SIZE + 1];
- void File::reseek() { start_func
- assert(filePtr);
- fseek(filePtr, 0, SEEK_CUR);
- }
- /*
- int File::readStr(string& str) throw_File { start_func
- assert(filePtr);
- // (sets read mode)
- int size = readInt16();
- int origSize = size;
- int first = 1;
- if (size) {
- while (size) {
- int amount = min(size, COPY_BUFFER_SIZE);
- read(copyBuffer, amount);
- copyBuffer[amount] = 0;
- if (first) str = copyBuffer;
- else str += copyBuffer;
- size -= amount;
- }
- }
- else {
- str = blankString;
- }
-
- return origSize + 2;
- }
- */
- void File::read(void* ptr, int size) throw_File { start_func
- assert(size >= 0);
- assert(filePtr);
- assert(ptr);
-
- if (size) {
- if (lastOperation == OPER_WRITE) reseek();
- lastOperation = OPER_READ;
- if (fread(ptr, size, 1, filePtr) != 1) {
- offset = ftell(filePtr);
- if (ferror(filePtr)) {
- throw FileException("File read error: %s", strerror(errno));
- }
- else {
- throw FileException("Unexpected end-of-file");
- }
- }
-
- offset += size;
- }
- }
- Uint32 File::readInt() throw_File { start_func
- #if SDL_BYTEORDER == SDL_LIL_ENDIAN
- Uint32 result;
- read(&result, 4);
- return result;
- #else
- Uint8 bytes[4];
- read(bytes, 4);
- return (Uint32)bytes[0] | ((Uint32)bytes[1] << 8) | ((Uint32)bytes[2] << 16) | ((Uint32)bytes[1] << 24);
- #endif
- }
- /*
- Uint16 File::readInt16() throw_File { start_func
- #if SDL_BYTEORDER == SDL_LIL_ENDIAN
- Uint16 result;
- read(&result, 2);
- return result;
- #else
- Uint8 bytes[2];
- read(bytes, 2);
- return (Uint16)bytes[0] | ((Uint16)bytes[1] << 8);
- #endif
- }
- */
- /*
- int File::writeStr(const string& str) throw_File { start_func
- assert(filePtr);
- // (sets write mode)
- writeInt16(str.size());
- write(str.c_str(), str.size());
-
- return str.size() + 2;
- }
- */
- void File::write(const void* ptr, int size) throw_File { start_func
- assert(size >= 0);
- assert(filePtr);
- assert(ptr);
-
- if (size) {
- if (lastOperation == OPER_READ) reseek();
- lastOperation = OPER_WRITE;
-
- if (fwrite(ptr, size, 1, filePtr) == 0) {
- offset = ftell(filePtr);
- throw FileException("File write error: %s", strerror(errno));
- }
-
- offset += size;
- }
- }
- void File::writeInt(Uint32 value) throw_File { start_func
- #if SDL_BYTEORDER == SDL_LIL_ENDIAN
- write(&value, 4);
- #else
- Uint8 bytes[4];
- bytes[0] = value & 0xFF;
- bytes[1] = (value >> 8) & 0xFF;
- bytes[2] = (value >> 16) & 0xFF;
- bytes[3] = (value >> 24) & 0xFF;
- write(bytes, 4);
- #endif
- }
- /*
- void File::writeInt16(Uint16 value) throw_File { start_func
- #if SDL_BYTEORDER == SDL_LIL_ENDIAN
- write(&value, 2);
- #else
- Uint8 bytes[2];
- bytes[0] = value & 0xFF;
- bytes[1] = (value >> 8) & 0xFF;
- write(bytes, 2);
- #endif
- }
- */
- void File::writeBlanks(int size) throw_File { start_func
- assert(size >= 0);
- assert(filePtr);
-
- if (size) {
- if (lastOperation == OPER_READ) reseek();
- lastOperation = OPER_WRITE;
-
- while (size--) {
- if (fputc(0, filePtr) == EOF) {
- throw FileException("File write error: %s", strerror(errno));
- }
- ++offset;
- }
- }
- }
- void File::copy(File* copyFrom, int size) throw_File { start_func
- assert(size >= 0);
- assert(filePtr);
- assert(copyFrom);
-
- if (size) {
- if (lastOperation == OPER_READ) reseek();
- lastOperation = OPER_WRITE;
-
- while (size > COPY_BUFFER_SIZE) {
- copyFrom->read(copyBuffer, COPY_BUFFER_SIZE);
- write(copyBuffer, COPY_BUFFER_SIZE);
- size -= COPY_BUFFER_SIZE;
- }
-
- if (size) {
- copyFrom->read(copyBuffer, size);
- write(copyBuffer, size);
- }
- }
- }
- void File::flush() throw_File { start_func
- if (fflush(filePtr)) {
- throw FileException("File flush error: %s", strerror(errno));
- }
- }
- void File::skip(int size) throw_File { start_func
- assert(filePtr);
- if (fseek(filePtr, size, SEEK_CUR)) {
- offset = ftell(filePtr);
- throw FileException("File seek error: %s", strerror(errno));
- }
- lastOperation = OPER_SEEK;
- offset += size;
- }
- void File::seek(int position) throw_File { start_func
- assert(filePtr);
-
- if (offset != position) {
- if (fseek(filePtr, position, SEEK_SET)) {
- offset = ftell(filePtr);
- throw FileException("File seek error: %s", strerror(errno));
- }
- lastOperation = OPER_SEEK;
- offset = position;
- }
- }
- int File::tell() const { start_func
- assert(filePtr);
-
- return offset;
- }
- const char* topDir() { start_func
- return FILESYSTEM_ABSOLUTEPREFIX;
- }
- int findFiles(const char* rootdir, const char* match, vector<string>& result) { start_func
- assert(rootdir);
- string searchterm;
-
- if ((FILESYSTEM_DRIVE_SEP) && (!myStricmp(rootdir, FILESYSTEM_ABSOLUTEPREFIX))) {
- #ifdef WIN32
- // Return all drives, but only on WIN32/similar
- if (match) return 0;
-
- Uint32 drives = GetLogicalDrives();
- char driveName[3] = "A?";
- driveName[1] = FILESYSTEM_DRIVE_SEP;
- while (drives) {
- if (drives & 1) result.push_back(driveName);
- ++driveName[0];
- drives = drives >> 1;
- }
-
- return 1;
- #endif
- // Any other OS that supports drives?
- return 0;
- }
- int matches = 0;
-
- DIR* dirPtr;
-
- // Drives must be opened in a special way
- if ((FILESYSTEM_DRIVE_SEP) && (rootdir[0] != 0) && (rootdir[1] == FILESYSTEM_DRIVE_SEP) && (rootdir[2] == 0)) {
- char drivedir[strlen(rootdir) + strlen(FILESYSTEM_PREFERREDSEP)];
- strcpy(drivedir, rootdir);
- strcat(drivedir, FILESYSTEM_PREFERREDSEP);
- dirPtr = opendir(drivedir);
- }
- else {
- dirPtr = opendir(rootdir);
- }
-
- if (!dirPtr) return 0;
-
- struct dirent* entry;
- struct stat inode;
-
- int matchlen;
- if (match) matchlen = strlen(match);
-
- // (assignment intentional)
- while ( (entry = readdir(dirPtr)) ) {
- // Skip entries beginning with .
- if (entry->d_name[0] == '.') continue;
-
- string fullpath;
- createFilename(rootdir, entry->d_name, fullpath);
- // Skip entries we can't stat
- if (stat(fullpath.c_str(), &inode) < 0) continue;
-
- if (match) {
- // @TODO: We could also support links- if (S_ISLNK (inode.st_mode))
- if (S_ISREG (inode.st_mode)) {
- // Match extension to end of string; always case insensitive
- int len = strlen(entry->d_name);
- if (len > matchlen) {
- if (!myStricmp(entry->d_name + (len - matchlen), match)) {
- ++matches;
- result.push_back(entry->d_name);
- }
- }
- }
- }
- else {
- if (S_ISDIR (inode.st_mode)) {
- ++matches;
- result.push_back(entry->d_name);
- }
- }
- }
-
- closedir(dirPtr);
- return matches;
- }
- int existFiles(const char* rootdir, const char* match) { start_func
- assert(rootdir);
- string searchterm;
- // For drives, always return "yes" to whether subdirectories exist
- // to prevent needless drive accesses
- if (FILESYSTEM_DRIVE_SEP) {
- // Also, if we have drives, topdir has drives in it
- if (!myStricmp(rootdir, FILESYSTEM_ABSOLUTEPREFIX)) {
- if (match) return 0;
- return 1;
- }
-
- if ((rootdir[0] != 0) && (rootdir[1] == FILESYSTEM_DRIVE_SEP) && (rootdir[2] == 0) && (match == NULL)) return 1;
- }
- DIR* dirPtr = opendir(rootdir);
- if (!dirPtr) return 0;
-
- struct dirent* entry;
- struct stat inode;
- int matchlen;
- if (match) matchlen = strlen(match);
- // @TODO: update GUI/show delay in some way (stat'ing a large network directory, etc.)
- // (assignment intentional)
- while ( (entry = readdir(dirPtr)) ) {
- // Skip entries beginning with .
- if (entry->d_name[0] == '.') continue;
-
- string fullpath;
- createFilename(rootdir, entry->d_name, fullpath);
- // Skip entries we can't stat
- if (stat(fullpath.c_str(), &inode) < 0) continue;
-
- if (match) {
- // #TODO: We could also support links- if (S_ISLNK (inode.st_mode))
- if (S_ISREG (inode.st_mode)) {
- // Match extension to end of string; always case insensitive
- int len = strlen(entry->d_name);
- if (len > matchlen) {
- if (!myStricmp(entry->d_name + (len - matchlen), match)) {
- closedir(dirPtr);
- return 1;
- }
- }
- }
- }
- else {
- if (S_ISDIR (inode.st_mode)) {
- closedir(dirPtr);
- return 1;
- }
- }
- }
- closedir(dirPtr);
- return 0;
- }
- void createDirname(const char* rootdir, const char* subdir, string& newRootdir) { start_func
- assert(rootdir);
- assert(subdir);
- newRootdir = rootdir;
- // Only add separator if not absolute root directory
- if (myStricmp(rootdir, FILESYSTEM_ABSOLUTEPREFIX)) newRootdir += FILESYSTEM_PREFERREDSEP;
- newRootdir += subdir;
- }
- void createFilename(const char* rootdir, const char* filename, string& fullFilename) { start_func
- assert(rootdir);
- assert(filename);
-
- // Absolute path if starts with any separator
- if ((strchr(FILESYSTEM_SEPARATORS, filename[0])) ||
- // Also an absolute path if begins with a drive
- ((FILESYSTEM_DRIVE_SEP) && (filename[0] != 0) && (filename[1] == FILESYSTEM_DRIVE_SEP))
- ) {
- fullFilename = filename;
- }
-
- // Relative path- add to rootdir
- else {
- createDirname(rootdir, filename, fullFilename);
- }
- }
- void splitFilename(const char* filename, vector<string>& result) { start_func
- assert(filename);
-
- string file = filename;
- string::size_type prev = 0;
- string::size_type found = 0;
-
- while (1) {
- found = file.find_first_of(FILESYSTEM_SEPARATORS, found);
- if (found >= string::npos) {
- result.push_back(file.substr(prev));
- break;
- }
-
- if (found > prev) {
- result.push_back(file.substr(prev, found - prev));
- }
- ++found;
- prev = found;
- }
- }
- void getPathname(const char* filename, string& result) { start_func
- assert(filename);
- string file = filename;
- string::size_type found = file.find_last_of(FILESYSTEM_SEPARATORS);
- if (found >= string::npos) result = FILESYSTEM_ABSOLUTEPREFIX;
- else result = file.substr(0, found);
- }
|