scummvm/backends/fs/ds/ds-fs.cpp
Torbjörn Andersson 16e7a12878 Some very obvious cleanups.
svn-id: r25635
2007-02-16 17:13:29 +00:00

869 lines
18 KiB
C++

/* ScummVMDS - Scumm Interpreter DS Port
* Copyright (C) 2002-2004 The ScummVM project and Neil Millstone
*
* 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 "stdafx.h"
#include "str.h"
#include "fs.h"
#include "common/util.h"
#include <NDS/ARM9/console.h> //basic print funcionality
#include "ds-fs.h"
#include "dsmain.h"
#include "gba_nds_fat.h"
namespace DS {
//////////////////////////////////////////////////////////////
// DSFileSystemNode - Flash ROM file system using Zip files
//////////////////////////////////////////////////////////////
ZipFile* DSFileSystemNode::_zipFile = NULL;
char currentDir[128];
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();
}
}
DSFileSystemNode::DSFileSystemNode(const String& path) {
// consolePrintf("--%s ",path.c_str());
char disp[128];
char* pathStr = (char *) path.c_str();
int lastSlash = 3;
for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
if (path[r] == '\\') {
lastSlash = r;
}
}
strcpy(disp, pathStr + lastSlash + 1);
_displayName = String(disp);
_path = path;
// _isValid = true;
// _isDirectory = false;
if (!strncmp(pathStr, "ds:/", 4)) {
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);
}
DSFileSystemNode::DSFileSystemNode(const String& path, bool isDir) {
// consolePrintf("--%s ",path.c_str());
char disp[128];
char* pathStr = (char *) path.c_str();
int lastSlash = 3;
for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
if (path[r] == '\\') {
lastSlash = r;
}
}
strcpy(disp, pathStr + lastSlash + 1);
_displayName = String(disp);
_path = path;
_isValid = true;
_isDirectory = isDir;
// consolePrintf("Found: %d, Dir: %d\n", _isValid, _isDirectory);
}
DSFileSystemNode::DSFileSystemNode(const DSFileSystemNode* node) {
}
AbstractFilesystemNode* DSFileSystemNode::parent() const {
// consolePrintf("parent\n");
DSFileSystemNode *p;
if (_path != "ds:/") {
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 DSFileSystemNode(String(path, lastSlash));
((DSFileSystemNode *) (p))->_isDirectory = true;
} else {
p = new DSFileSystemNode();
}
return p;
}
AbstractFilesystemNode *DSFileSystemNode::child(const Common::String& n) const {
if (_path.lastChar() == '\\') {
return new DSFileSystemNode(_path + n);
} else {
return new DSFileSystemNode(_path + "\\" + n);
}
return NULL;
}
bool DSFileSystemNode::listDir(AbstractFSList &dirList, ListMode mode) const {
// consolePrintf("Listdir\n");
// consolePrintf("Directory\n");
char temp[128];
strcpy(temp, _path.c_str());
// consolePrintf("This dir: %s\n", temp);
if ((temp[0] == 'd') && (temp[1] == 's') && (temp[2] == ':') && (temp[3] == '/')) {
if (strlen(temp) != 4) {
_zipFile->changeDirectory(&temp[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(temp);
}
if (_zipFile->restartFile()) {
do {
char n[128];
_zipFile->getFileName(n);
// consolePrintf("file: %s\n", n);
if ( (_zipFile->isDirectory() && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)) )
|| (!_zipFile->isDirectory() && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll)) ) )
{
DSFileSystemNode* dsfsn = new DSFileSystemNode("ds:/" + String(n), _zipFile->isDirectory());
dsfsn->_isDirectory = _zipFile->isDirectory();
dirList.push_back((dsfsn));
}
} while (_zipFile->skipFile());
}
return true;
}
/////////////////////////////////////////////////////////////////////////
// GBAMPFileSystemNode - File system using GBA Movie Player and CF card
/////////////////////////////////////////////////////////////////////////
GBAMPFileSystemNode::GBAMPFileSystemNode() {
_displayName = "mp:/";
_path = "mp:/";
_isValid = true;
_isDirectory = true;
_path = "mp:/";
}
GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path) {
// consolePrintf("'%s'",path.c_str());
char disp[128];
char* pathStr = (char *) path.c_str();
int lastSlash = 3;
for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
if ((path[r] == '\\') || (path[r] == '/')) {
lastSlash = r;
}
}
strcpy(disp, pathStr + lastSlash + 1);
char check[128];
int success;
memset(check, 0, 128);
if (strlen(pathStr) > 3) {
strcpy(check, pathStr + 3);
if (check[strlen(check) - 1] == '/') {
check[strlen(check) - 1] = 0;
}
success = FAT_FileExists(check);
} else {
success = FT_DIR;
}
// consolePrintf("Path: %s (%d)\n", check, success);
_displayName = String(disp);
_path = path;
_isValid = success == FT_FILE;
_isDirectory = success == FT_DIR;
}
GBAMPFileSystemNode::GBAMPFileSystemNode(const String& path, bool isDirectory) {
// consolePrintf("'%s'",path.c_str());
char disp[128];
char* pathStr = (char *) path.c_str();
int lastSlash = 3;
for (int r = 0; r < (int) strlen(pathStr) - 1; r++) {
if ((path[r] == '\\') || (path[r] == '/')) {
lastSlash = r;
}
}
strcpy(disp, pathStr + lastSlash + 1);
_displayName = String(disp);
_path = path;
_isValid = true;
_isDirectory = isDirectory;
}
GBAMPFileSystemNode::GBAMPFileSystemNode(const GBAMPFileSystemNode* node) {
}
AbstractFilesystemNode* GBAMPFileSystemNode::parent() 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(String(path, lastSlash));
p->_isDirectory = true;
} else {
p = new GBAMPFileSystemNode();
}
return p;
}
AbstractFilesystemNode *GBAMPFileSystemNode::child(const Common::String& n) const {
if (_path.lastChar() == '\\') {
return new DSFileSystemNode(_path + n);
} else {
return new DSFileSystemNode(_path + "\\" + n);
}
return NULL;
}
bool GBAMPFileSystemNode::listDir(AbstractFSList& dirList, ListMode mode) const {
// consolePrintf("Listdir\n");
enum { TYPE_NO_MORE = 0, TYPE_FILE = 1, TYPE_DIR = 2 };
char temp[128], fname[128], *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_FindFirstFile(fname);
while (entryType != TYPE_NO_MORE) {
if ( ((entryType == TYPE_DIR) && ((mode == FilesystemNode::kListDirectoriesOnly) || (mode == FilesystemNode::kListAll)))
|| ((entryType == TYPE_FILE) && ((mode == FilesystemNode::kListFilesOnly) || (mode == FilesystemNode::kListAll))) ) {
GBAMPFileSystemNode* dsfsn;
if (strcmp(fname, ".") && strcmp(fname, "..")) {
if (!strcmp(path, "/")) {
dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String(fname), entryType == TYPE_DIR);
} else {
dsfsn = new GBAMPFileSystemNode("mp:" + String(path) + String("/") + String(fname), entryType == TYPE_DIR);
}
// dsfsn->_isDirectory = entryType == DIR;
dirList.push_back((dsfsn));
}
} else {
// consolePrintf("Skipping %s\n", fname);
}
entryType = FAT_FindNextFile(fname);
}
// consolePrintf("No more");
FAT_chdir("/");
return true;
}
// 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]", realName, mode);
if (DS::isGBAMPAvailable()) {
FAT_chdir("/");
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 (fileHandle *) result;
}
// Fail to open file for writing. It's in ROM!
// Allocate a file handle
int r = 0;
while (handle[r].used) r++;
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);
}
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()) {
int bytes = FAT_fread((void *) ptr, size, numItems, (FAT_FILE *) handle);
if (!std_feof(handle)) {
return numItems;
} else {
// consolePrintf("Read past end of file: %d read out of %d\n", bytes / size, numItems);
return bytes / size;
}
return numItems;
/* int item = 0;
u8* data = (u8 *) ptr;
while ((item < numItems) && (!FAT_feof((FAT_FILE *) handle))) {
int bytes = 0;
while ((bytes < size) && (!FAT_feof((FAT_FILE *) handle))) {
*data++ = FAT_fgetc((FAT_FILE *) handle);
bytes++;
}
item++;
}
return item;*/
int items = 0;
//for (int r = 0; r < numItems; r++) {
if (!std_feof(handle)) {
/* for (int t = 0; t < size; t++) {
if (feof(handle)) eof = true;
*(((char *) (ptr)) + r * size + t) = getc(handle);
}*/
int left = size * numItems;
int bytesRead = -1;
while ((left > 0) && (!FAT_feof((FAT_FILE *) handle))) {
int amount = left > 8192? 8192: left;
// do {
bytesRead = FAT_fread((void *) ptr, 1, amount, (FAT_FILE *) handle);
/* if (bytesRead == 0) {
consolePrintf("Pos:%d items:%d num:%d amount:%d read:%d\n", ftell(handle), items, numItems, amount, bytesRead);
left++;
int pos = ftell(handle);
fseek(handle, 0, SEEK_SET);
int c = getc(handle);
fseek(handle, pos - 1024, SEEK_SET);
fread(ptr, 1024, 1, handle);
swiWaitForVBlank();
//while (true);
}*/
//} while (bytesRead == 0);
left -= bytesRead;
ptr = ((char *) (ptr)) + bytesRead;
}
items = numItems - (left / size);
// FAT_fread((void *) ptr, size, 1, ((int) (handle)) - 1);
// ptr = ((char *) (ptr)) + size;
}
//}
// consolePrintf("...done %d \n", items)
return items;
}
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 (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;
}
}
void std_fprintf(FILE* handle, const char* fmt, ...) {
consolePrintf(fmt);
}
bool std_feof(FILE* handle) {
// consolePrintf("feof ");
if (DS::isGBAMPAvailable()) {
return 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;
}
void std_fflush(FILE* handle) {
// consolePrintf("fflush ");
}
char* std_fgets(char* str, int size, FILE* file) {
// consolePrintf("fgets file=%d ", file);
if (DS::isGBAMPAvailable()) {
char* s = str;
while ((*s++ = std_getc(file)) >= 32) {
// consolePrintf("%d ", *s);
}
*s = 0;
// consolePrintf("Read:%s\n", str);
return str;
}
if (file->sramFile) {
file->pos--;
int p = -1;
do {
file->pos++;
p++;
file->sramFile->read((char *) &str[p], 1);
// consolePrintf("%d,", str[p]);
} while ((str[p] >= 32) && (!feof(file)) && (p < size));
str[p + 1] = 0;
file->pos++;
// consolePrintf("Read:%s\n", str);
return str;
}
return NULL;
}
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;
}
void std_clearerr(FILE* handle) {
// consolePrintf("clearerr ");
}
int std_getc(FILE* handle) {
if (DS::isGBAMPAvailable()) {
char c;
FAT_fread(&c, 1, 1, (FAT_FILE *) handle);
return c;
}
// consolePrintf("fgetc ");
return 0; // Not supported yet
}
char* std_getcwd(char* dir, int dunno) {
// consolePrintf("getcwd ");
dir[0] = '\0';
return dir; // Not supported yet
}
void std_cwd(char* dir) {
char buffer[128];
strcpy(buffer, dir);
char* realName = buffer;
if (DS::isGBAMPAvailable()) {
if ((strlen(dir) >= 4) && (dir[0] == 'm') && (dir[1] == 'p') && (dir[2] == ':') && (dir[3] == '/')) {
realName += 4;
}
// consolePrintf("Real cwd:%d\n", realName);
char* p = realName;
while (*p) {
if (*p == '\\') *p = '/';
p++;
}
// consolePrintf("Real cwd:%d\n", realName);
FAT_chdir(realName);
} else {
if ((strlen(dir) >= 4) && (dir[0] == 'd') && (dir[1] == 's') && (dir[2] == ':') && (dir[3] == '/')) {
realName += 4;
}
char* p = realName;
while (*p) {
if (*p == '\\') *p = '/';
p++;
}
strcpy(currentDir, realName);
if (*(currentDir + strlen(currentDir) - 1) == '/') {
*(currentDir + strlen(currentDir) - 1) = '\0';
}
consolePrintf("CWD: %s\n", currentDir);
}
}
int std_ferror(FILE* handle) {
return 0;
}
} // namespace DS
// These functions are added to AbstractFileSystemNode and are therefore outside
// the DS namespace.
AbstractFilesystemNode *AbstractFilesystemNode::getCurrentDirectory() {
// consolePrintf("New node");
if (DS::isGBAMPAvailable()) {
return new DS::GBAMPFileSystemNode();
} else {
return new DS::DSFileSystemNode();
}
}
AbstractFilesystemNode* AbstractFilesystemNode::getNodeForPath(const String& path) {
if (DS::isGBAMPAvailable()) {
return new DS::GBAMPFileSystemNode(path);
} else {
return new DS::DSFileSystemNode(path);
}
}