Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

ds-fs.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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-1307, USA.
 *
 */

#include "common/str.h"
#include "common/util.h"
//#include <NDS/ARM9/console.h> //basic print funcionality
#include "backends/fs/ds/ds-fs.h"
#include "backends/fs/stdiostream.h"
#include "dsmain.h"
#include "fat/gba_nds_fat.h"



namespace DS {

//////////////////////////////////////////////////////////////
// DSFileSystemNode - Flash ROM file system using Zip files //
//////////////////////////////////////////////////////////////

ZipFile*    DSFileSystemNode::_zipFile = NULL;
char        currentDir[128];
bool        readPastEndOfFile = false;

00043 DSFileSystemNode::DSFileSystemNode() {
      _displayName = "ds:/";
      _path = "ds:/";
      _isValid = true;
      _isDirectory = true;
      _path = "ds:/";

/*    if (!_archive) {
            _archive = (GBFS_FILE *) find_first_gbfs_file(scummdata);
            if (!_archive) consolePrintf("No GBFS archive found!\n");
      }*/

      if (!_zipFile) {
            _zipFile = new ZipFile();
      }
}

00060 DSFileSystemNode::DSFileSystemNode(const Common::String& path) {
//    consolePrintf("--%s ",path.c_str());

      int lastSlash = 3;
      for (int r = 0; r < (int) path.size() - 1; r++) {
            if (path[r] == '\\') {
                  lastSlash = r;
            }
      }

      _displayName = Common::String(path.c_str() + lastSlash + 1);
      _path = path;
//    _isValid = true;
//    _isDirectory = false;

      const char *pathStr = path.c_str();

      if (path.hasPrefix("ds:/")) {
            pathStr += 4;
      }

      if (*pathStr == '\0') {
            _isValid = true;
            _isDirectory = true;
            return;
      }

      _zipFile->setAllFilesVisible(true);
      if (_zipFile->findFile(pathStr)) {
            _isValid = true;
            _isDirectory = _zipFile->isDirectory();
      } else {
            _isValid = false;
            _isDirectory = false;
      }
      _zipFile->setAllFilesVisible(false);

//    consolePrintf("%s - Found: %d, Dir: %d\n", pathStr, _isValid, _isDirectory);
}

00100 DSFileSystemNode::DSFileSystemNode(const Common::String& path, bool isDir) {
//    consolePrintf("--%s ",path.c_str());

      int lastSlash = 3;
      for (int r = 0; r < (int) path.size() - 1; r++) {
            if (path[r] == '\\') {
                  lastSlash = r;
            }
      }

      _displayName = Common::String(path.c_str() + lastSlash + 1);
      _path = path;
      _isValid = true;
      _isDirectory = isDir;

//    consolePrintf("Found: %d, Dir: %d\n", _isValid, _isDirectory);
}

00118 DSFileSystemNode::DSFileSystemNode(const DSFileSystemNode* node) {
      //TODO: not implemented?
}

00122 AbstractFSNode *DSFileSystemNode::getChild(const Common::String& n) const {
      if (_path.lastChar() == '\\') {
            return new DSFileSystemNode(_path + n);
      } else {
            return new DSFileSystemNode(_path + "\\" + n);
      }

      return NULL;
}

00132 bool DSFileSystemNode::getChildren(AbstractFSList &dirList, ListMode mode, bool hidden) const {
//    consolePrintf("Listdir\n");
//    consolePrintf("Directory\n");

      //TODO: honor the hidden flag

//    consolePrintf("This dir: %s\n", _path.c_str());

      if (_path.hasPrefix("ds:/")) {
            if (_path.size() > 4) {
                  _zipFile->changeDirectory(_path.c_str() + 4);
            } else {
                  _zipFile->changeToRoot();

/*                // This is the root dir, so add the RAM folder
                  DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/ram");
                  dsfsn->_isDirectory = true;
                  dirList->push_back(wrap(dsfsn));
*/
            }
      } else {
            _zipFile->changeDirectory(_path.c_str());
      }

      if (_zipFile->restartFile()) {
            do {
                  char n[128];
                  _zipFile->getFileName(n);

//                consolePrintf("file: %s\n", n);
                  if ( (_zipFile->isDirectory() && ((mode == Common::FSNode::kListDirectoriesOnly) || (mode == Common::FSNode::kListAll)) )
                        || (!_zipFile->isDirectory() && ((mode == Common::FSNode::kListFilesOnly) || (mode == Common::FSNode::kListAll)) ) )
                  {
                        DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + Common::String(n), _zipFile->isDirectory());
                        dsfsn->_isDirectory = _zipFile->isDirectory();
                        dirList.push_back((dsfsn));
                  }

            } while (_zipFile->skipFile());
      }

      return true;
}

00176 AbstractFSNode* DSFileSystemNode::getParent() const {
//    consolePrintf("parent\n");
      DSFileSystemNode *p;

      if (_path != "ds:/") {
            char *path = (char *) _path.c_str();
            int lastSlash = 4;

            for (int r = 4; r < (int) _path.size(); r++) {
                  if (path[r] == '\\') {
                        lastSlash = r;
                  }
            }

            p = new DSFileSystemNode(Common::String(path, lastSlash));
            p->_isDirectory = true;
      } else {
            p = new DSFileSystemNode();
      }

      return p;
}

00199 Common::SeekableReadStream *DSFileSystemNode::createReadStream() {
      return DSFileStream::makeFromPath(getPath().c_str(), false);
}

00203 Common::WriteStream *DSFileSystemNode::createWriteStream() {
      return DSFileStream::makeFromPath(getPath().c_str(), true);
}

//////////////////////////////////////////////////////////////////////////
// GBAMPFileSystemNode - File system using GBA Movie Player and CF card //
//////////////////////////////////////////////////////////////////////////

00211 GBAMPFileSystemNode::GBAMPFileSystemNode() {
      _displayName = "mp:/";
      _path = "mp:/";
      _isValid = false;
      _isDirectory = true;
}

00218 GBAMPFileSystemNode::GBAMPFileSystemNode(const Common::String& path) {
//    consolePrintf("'%s'",path.c_str());

      int lastSlash = 3;
      for (int r = 0; r < (int) path.size() - 1; r++) {
            if ((path[r] == '\\') || (path[r] == '/')) {
                  lastSlash = r;
            }
      }

      if (path == "mp:/") {
            // This is the root directory
            _isDirectory = true;
            _isValid = false;       // Old code returned false here, but I'm not sure why
      } else {
            char check[128];
            memset(check, 0, 128);

            if (path.size() > 4 && path.hasPrefix("mp:/")) {
                  // Files which start with mp:/
                  // Clear the filename to 128 bytes, because a libfat bug occasionally tries to read in this area.
                  strcpy(check, path.c_str() + 3);
            } else {
                  // Clear the filename to 128 bytes, because a libfat bug occationally tries to read in this area.
                  strcpy(check, path.c_str());
            }

            // Remove terminating slash - FileExists fails without this
            if (check[strlen(check) - 1] == '/') {
                  check[strlen(check) - 1] = 0;
            }
            int fileOrDir = FAT_FileExists(check);

            _isDirectory = fileOrDir == FT_DIR;
            _isValid = fileOrDir == FT_FILE;
      }


//    consolePrintf("Path: %s \n", check);

      _displayName = Common::String(path.c_str() + lastSlash + 1);
      _path = path;
}

00262 GBAMPFileSystemNode::GBAMPFileSystemNode(const Common::String& path, bool isDirectory) {
      //consolePrintf("'%s'",path.c_str());

      int lastSlash = 3;
      for (int r = 0; r < (int) path.size() - 1; r++) {
            if ((path[r] == '\\') || (path[r] == '/')) {
                  lastSlash = r;
            }
      }

      _displayName = Common::String(path.c_str() + lastSlash + 1);
      _path = path;
      _isValid = true;
      _isDirectory = isDirectory;
}


00279 GBAMPFileSystemNode::GBAMPFileSystemNode(const GBAMPFileSystemNode* node) {
      //TODO: not implemented?
}

00283 AbstractFSNode *GBAMPFileSystemNode::getChild(const Common::String& n) const {
      if (_path.lastChar() == '\\') {
            return new GBAMPFileSystemNode(_path + n);
      } else {
            return new GBAMPFileSystemNode(_path + "\\" + n);
      }

      return NULL;
}

00293 bool GBAMPFileSystemNode::getChildren(AbstractFSList& dirList, ListMode mode, bool hidden) const {
//    consolePrintf("Listdir\n");

      //TODO: honor the hidden flag

      enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };

      char temp[128], fname[256], *path, *pathTemp;
      strcpy(temp, _path.c_str());

      path = temp + 3;

      pathTemp = path;
      while (*pathTemp) {
            if (*pathTemp == '\\') {
                  *pathTemp = '/';
            }
            pathTemp++;
      }

      // consolePrintf("This dir: %s\n", path);
      FAT_chdir(path);

      int entryType = FAT_FindFirstFileLFN(fname);

      while (entryType != TYPE_NO_MORE) {

            if ( ((entryType == TYPE_DIR) && ((mode == Common::FSNode::kListDirectoriesOnly) || (mode == Common::FSNode::kListAll)))
            ||   ((entryType == TYPE_FILE) && ((mode == Common::FSNode::kListFilesOnly) || (mode == Common::FSNode::kListAll))) ) {
                  GBAMPFileSystemNode* dsfsn;

                  //consolePrintf("Fname: %s\n", fname);

                  if (strcmp(fname, ".") && strcmp(fname, "..")) {

                        if (!strcmp(path, "/")) {
                              dsfsn = new GBAMPFileSystemNode("mp:" + Common::String(path) + Common::String(fname), entryType == TYPE_DIR);
                        } else {
                              dsfsn = new GBAMPFileSystemNode("mp:" + Common::String(path) + Common::String("/") + Common::String(fname), entryType == TYPE_DIR);
                        }

//                      dsfsn->_isDirectory = entryType == DIR;
                        dirList.push_back((dsfsn));
                  }
            } else {
//                consolePrintf("Skipping %s\n", fname);
            }

            entryType = FAT_FindNextFileLFN(fname);
      }

//    consolePrintf("No more");

      FAT_chdir("/");

      return true;
}

00351 AbstractFSNode* GBAMPFileSystemNode::getParent() const {
//    consolePrintf("parent\n");
      GBAMPFileSystemNode *p;

      if (_path != "mp:/") {
            char *path = (char *) _path.c_str();
            int lastSlash = 4;

            for (int r = 4; r < (int) strlen((char *) path); r++) {
                  if (path[r] == '/') {
                        lastSlash = r;
                  }
            }

            p = new GBAMPFileSystemNode(Common::String(path, lastSlash));
            p->_isDirectory = true;
      } else {
            p = new GBAMPFileSystemNode();
      }

      return p;
}

00374 Common::SeekableReadStream *GBAMPFileSystemNode::createReadStream() {
//    consolePrintf("Opening: %s\n", getPath().c_str());

      if (!strncmp(getPath().c_str(), "mp:/", 4)) {
            return DSFileStream::makeFromPath(getPath().c_str() + 3, false);
      } else {
            return DSFileStream::makeFromPath(getPath().c_str(), false);
      }
}

00384 Common::WriteStream *GBAMPFileSystemNode::createWriteStream() {
      return DSFileStream::makeFromPath(getPath().c_str(), true);
}




DSFileStream::DSFileStream(void *handle) : _handle(handle) {
      assert(handle);
      _writeBufferPos = 0;
}

DSFileStream::~DSFileStream() {
      if (_writeBufferPos > 0) {
            flush();
      }
      std_fclose((FILE *)_handle);
}

00403 bool DSFileStream::err() const {
      return std_ferror((FILE *)_handle) != 0;
}

00407 void DSFileStream::clearErr() {
      std_clearerr((FILE *)_handle);
}

00411 bool DSFileStream::eos() const {
      return std_feof((FILE *)_handle) != 0;
}

00415 int32 DSFileStream::pos() const {
      if (_writeBufferPos > 0) {
            // Discard constness.  Bad, but I can't see another way.
            ((DSFileStream *) (this))->flush();
      }
      return std_ftell((FILE *)_handle);
}

00423 int32 DSFileStream::size() const {
      if (_writeBufferPos > 0) {
            // Discard constness.  Bad, but I can't see another way.
            ((DSFileStream *) (this))->flush();
      }
      int32 oldPos = std_ftell((FILE *)_handle);
      std_fseek((FILE *)_handle, 0, SEEK_END);
      int32 length = std_ftell((FILE *)_handle);
      std_fseek((FILE *)_handle, oldPos, SEEK_SET);

      return length;
}

00436 bool DSFileStream::seek(int32 offs, int whence) {
      if (_writeBufferPos > 0) {
            flush();
      }
      return std_fseek((FILE *)_handle, offs, whence) == 0;
}

00443 uint32 DSFileStream::read(void *ptr, uint32 len) {
      if (_writeBufferPos > 0) {
            flush();
      }
      return std_fread((byte *)ptr, 1, len, (FILE *)_handle);
}

00450 uint32 DSFileStream::write(const void *ptr, uint32 len) {
      if (_writeBufferPos + len < WRITE_BUFFER_SIZE) {
            memcpy(_writeBuffer + _writeBufferPos, ptr, len);
            _writeBufferPos += len;
      }
      else
      {
            if (_writeBufferPos > 0) {
                  flush();
            }
            return std_fwrite(ptr, 1, len, (FILE *)_handle);
      }
}

00464 bool DSFileStream::flush() {

      if (_writeBufferPos > 0) {
            std_fwrite(_writeBuffer, 1, _writeBufferPos, (FILE *) _handle);
            _writeBufferPos = 0;
      }

      return std_fflush((FILE *)_handle) == 0;
}

00474 DSFileStream *DSFileStream::makeFromPath(const Common::String &path, bool writeMode) {
      FILE *handle = std_fopen(path.c_str(), writeMode ? "wb" : "rb");

      if (handle)
            return new DSFileStream(handle);
      return 0;
}




// Stdio replacements
#define MAX_FILE_HANDLES 32

bool inited = false;
DS::fileHandle handle[MAX_FILE_HANDLES];

FILE* std_fopen(const char* name, const char* mode) {
      if (!inited) {
            for (int r = 0; r < MAX_FILE_HANDLES; r++) {
                  handle[r].used = false;
            }
            inited = true;
            currentDir[0] = '\0';
      }

      char* realName = (char *) name;

      // Remove file system prefix
      if ((name[0] == 'd') && (name[1] == 's') && (name[2] == ':') && (name[3] == '/')) {
            realName += 4;
      }

      if ((name[0] == 'm') && (name[1] == 'p') && (name[2] == ':') && (name[3] == '/')) {
            realName += 4;
      }

//    consolePrintf("Open file:");
//    consolePrintf("'%s', [%s]", name, realName);

      if (DS::isGBAMPAvailable()) {
            FAT_chdir("/");

            // Turn all back slashes into forward slashes for gba_nds_fat
            char* p = realName;
            while (*p) {
                  if (*p == '\\') *p = '/';
                  p++;
            }

            FAT_FILE* result = FAT_fopen(realName, mode);

            if (result == 0) {
//                consolePrintf("Error code %d\n", result);
                  //consolePrintf("Opening file %s\n", realName);
            } else {
//                consolePrintf("Opened file %d\n", result);
            }
//          MT_memoryReport();

            return (FILE *) result;
      }

      // Fail to open file for writing.  It's in ROM!

      // Allocate a file handle
      int r = 0;
      while (handle[r].used) {
            r++;
            assert(r < MAX_FILE_HANDLES);
      }

#ifdef GBA_SRAM_SAVE
      if (strchr(mode, 'w')) {
//          consolePrintf("Writing %s\n", realName);
            handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, true);
      } else {
//          consolePrintf("Reading %s\n", realName);
            handle[r].sramFile = (DSSaveFile *) DSSaveFileManager::instance()->openSavefile(realName, false);
      }
#endif

      if (handle[r].sramFile) {
            handle[r].used = true;
            handle[r].pos = 0;
            handle[r].data = NULL;
            handle[r].size = handle[r].sramFile->getSize();
//          consolePrintf("Found it");
            return &handle[r];
      }

//    consolePrintf("Not in SRAM!");

      char* data;

      ZipFile* zip = DSFileSystemNode::getZip();
      if (!zip) {
//          consolePrintf("No zip yet!");
            return NULL;
      }

      // Grab the data if it exists

      zip->setAllFilesVisible(true);

      if (currentDir[0] != 0) {
            char nameWithPath[128];
            sprintf(nameWithPath, "%s\%s", currentDir, realName);
            strcpy(realName, nameWithPath);
      }

//    consolePrintf("fopen(%s, %s)\n", realName, name);

      if (zip->findFile(realName)) {
            data = zip->getFile();
            zip->setAllFilesVisible(false);

            // Allocate a file handle
            int r = 0;
            while (handle[r].used) r++;


            handle[r].used = true;
            handle[r].pos = 0;
            handle[r].data = data;
            handle[r].size = zip->getFileSize();

//          consolePrintf("Opened file %d: %s (%s)   ", r, realName, name);
            return &handle[r];
      } else {
            zip->setAllFilesVisible(false);
//          consolePrintf("Not found: %s (%s)  ", realName, name);
            return NULL;
      }
}

void std_fclose(FILE* handle) {

      if (DS::isGBAMPAvailable()) {
            FAT_fclose((FAT_FILE *) handle);
            return;
      }

      handle->used = false;
      if (handle->sramFile) {
            delete handle->sramFile;
            handle->sramFile = NULL;
      }
}

size_t std_fread(const void* ptr, size_t size, size_t numItems, FILE* handle) {
//    consolePrintf("fread %d,%d %d ", size, numItems, ptr);

      if (DS::isGBAMPAvailable()) {
            readPastEndOfFile = false;

            int bytes = FAT_fread((void *) ptr, size, numItems, (FAT_FILE *) handle);
            if (!FAT_feof((FAT_FILE *) handle)) {
                  return numItems;
            } else {
//                consolePrintf("Read past end of file: %d read out of %d\n", bytes / size, numItems);
                  if ((size_t)bytes != size * numItems) readPastEndOfFile = true;
                  return bytes / size;
            }
            return numItems;
      }

      if (handle->sramFile) {
            int bytes = 0;
            int result = 1;
            //consolePrintf("fread size=", size * numItems);
            for (int r = 0; (r < (s32) size * (s32) numItems) && (result > 0); r++) {
                  result = handle->sramFile->read((void *) ( ((char *) (ptr)) + r), 1);
                  bytes += result;
                  //consolePrintf("'%d',", ((char *) (ptr))[0]);
            }

            handle->pos += bytes;

            return bytes / size;
      }

      if ((int)(handle->pos + size * numItems) > handle->size) {
            numItems = (handle->size - handle->pos) / size;
            if (numItems < 0) numItems = 0;
      }

//    consolePrintf("read %d  ", size * numItems);

      memcpy((void *) ptr, handle->data + handle->pos, size * numItems);
      handle->pos += size * numItems;

      return numItems;
}

size_t std_fwrite(const void* ptr, size_t size, size_t numItems, FILE* handle) {
      if ((handle == stdin)) return 0;

      if ((handle == stderr) || (handle == stdout)) {
//          consolePrintf((char *) ptr);
            return size;
      }

      //consolePrintf("fwrite size=%d\n", size * numItems);

      if (DS::isGBAMPAvailable()) {
            FAT_fwrite(((char *) (ptr)), size, numItems, (FAT_FILE *) handle);
            return numItems;

            int length = size * numItems;
            int pos = 0;

            while (pos < length) {
                  int amount = length > 512? 512: length;

                  FAT_fwrite(((char *) (ptr)) + pos, 1, amount, (FAT_FILE *) handle);
                  length -= amount;
                  pos += amount;
            }

            return numItems;
      }

      if (handle->sramFile) {
            handle->sramFile->write(ptr, size);
            return size;
      } else {
            return 0;
      }
}

bool std_feof(FILE* handle) {
//    consolePrintf("feof ");

      if (DS::isGBAMPAvailable()) {
            return readPastEndOfFile && FAT_feof((FAT_FILE *) handle);
      }

      if (handle->sramFile) {
            return handle->sramFile->eos();
      }

//    consolePrintf("feof %s", handle->pos >= handle->size? "true": "false");
      return handle->pos >= handle->size;
}

int std_fflush(FILE* handle) {
      //FIXME: not implemented?
//    consolePrintf("fflush ");
      return 0;
}

long int std_ftell(FILE* handle) {
      if (DS::isGBAMPAvailable()) {
            return FAT_ftell((FAT_FILE *) handle);
      }

      return handle->pos;
}

int std_fseek(FILE* handle, long int offset, int whence) {
//    consolePrintf("fseek %d %d ", offset, whence);

      if (DS::isGBAMPAvailable()) {
            return FAT_fseek((FAT_FILE *) handle, offset, whence);
      }

      switch (whence) {
            case SEEK_CUR:
                  handle->pos += offset;
                  break;
            case SEEK_SET:
                  handle->pos = offset;
                  break;
            case SEEK_END:
                  handle->pos = handle->size + offset;
                  break;
            default:
                  handle->pos = offset;
                  break;
      }

      return 0;
}

int std_ferror(FILE* handle) {
      //FIXME: not implemented?
//    consolePrintf("ferror ");

      return readPastEndOfFile;
}

void std_clearerr(FILE* handle) {
      //FIXME: not implemented?
      readPastEndOfFile = false;
//    consolePrintf("clearerr ");
}

void std_fprintf(FILE* handle, const char* fmt, ...) {
      consolePrintf("%s", fmt);
}


} // namespace DS

Generated by  Doxygen 1.6.0   Back to index