Initial commit
This commit is contained in:
41
backends/fs/abstract-fs.cpp
Normal file
41
backends/fs/abstract-fs.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
const char *AbstractFSNode::lastPathComponent(const Common::String &str, const char sep) {
|
||||
// TODO: Get rid of this eventually! Use Common::lastPathComponent instead
|
||||
if (str.empty())
|
||||
return "";
|
||||
|
||||
const char *start = str.c_str();
|
||||
const char *cur = start + str.size() - 2;
|
||||
|
||||
while (cur >= start && *cur != sep) {
|
||||
--cur;
|
||||
}
|
||||
|
||||
return cur + 1;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *AbstractFSNode::createReadStreamForAltStream(Common::AltStreamType altStreamType) {
|
||||
return nullptr;
|
||||
}
|
||||
219
backends/fs/abstract-fs.h
Normal file
219
backends/fs/abstract-fs.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_ABSTRACT_FS_H
|
||||
#define BACKENDS_ABSTRACT_FS_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
#include "common/fs.h"
|
||||
|
||||
class AbstractFSNode;
|
||||
|
||||
typedef Common::Array<AbstractFSNode *> AbstractFSList;
|
||||
|
||||
/**
|
||||
* Abstract file system node. Private subclasses implement the actual
|
||||
* functionality.
|
||||
*
|
||||
* Most of the methods correspond directly to methods in class FSNode,
|
||||
* so if they are not documented here, look there for more information about
|
||||
* the semantics.
|
||||
*/
|
||||
class AbstractFSNode {
|
||||
protected:
|
||||
friend class Common::FSNode;
|
||||
typedef Common::FSNode::ListMode ListMode;
|
||||
|
||||
/**
|
||||
* Returns the child node with the given name. When called on a non-directory
|
||||
* node, it should handle this gracefully by returning 0.
|
||||
* When called with a name not matching any of the files/dirs contained in this
|
||||
* directory, a valid node should be returned, which returns 'false' upon calling
|
||||
* the exists() method. The idea is that this node can then still can be used to
|
||||
* create a new file via the createWriteStream() method.
|
||||
*
|
||||
* Example:
|
||||
* Calling getChild() for a node with path "/foo/bar" using name="file.txt",
|
||||
* would produce a new node with "/foo/bar/file.txt" as path.
|
||||
*
|
||||
* @note Handling calls on non-dir nodes gracefully makes it possible to
|
||||
* switch to a lazy type detection scheme in the future.
|
||||
*
|
||||
* @param name String containing the name of the child to create a new node.
|
||||
*/
|
||||
virtual AbstractFSNode *getChild(const Common::String &name) const = 0;
|
||||
|
||||
/**
|
||||
* The parent node of this directory.
|
||||
* The parent of the root is the root itself.
|
||||
*/
|
||||
virtual AbstractFSNode *getParent() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the last component of a given path.
|
||||
*
|
||||
* Examples:
|
||||
* /foo/bar.txt would return /bar.txt
|
||||
* /foo/bar/ would return /bar/
|
||||
*
|
||||
* @param str String containing the path.
|
||||
* @param sep character used to separate path components
|
||||
* @return Pointer to the first char of the last component inside str.
|
||||
*/
|
||||
static const char *lastPathComponent(const Common::String &str, const char sep);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a FSNode object from an AbstractFSNode object.
|
||||
*
|
||||
* This is a helper to create Common::FSNode objects when the backend's
|
||||
* FileSystemFactory cannot create the given AbstractFSNode object itself.
|
||||
* All other code is supposed to use Common::FSNode's constructor itself.
|
||||
*
|
||||
* @param realNode Pointer to a heap allocated instance. FSNode will take
|
||||
* ownership of the pointer.
|
||||
*/
|
||||
static Common::FSNode makeFSNode(AbstractFSNode *realNode) {
|
||||
return Common::FSNode(realNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~AbstractFSNode() {}
|
||||
|
||||
/*
|
||||
* Indicates whether the object referred by this path exists in the filesystem or not.
|
||||
*/
|
||||
virtual bool exists() const = 0;
|
||||
|
||||
/**
|
||||
* Return a list of child nodes of this directory node. If called on a node
|
||||
* that does not represent a directory, false is returned.
|
||||
*
|
||||
* @param list List to put the contents of the directory in.
|
||||
* @param mode Mode to use while listing the directory.
|
||||
* @param hidden Whether to include hidden files or not in the results.
|
||||
*
|
||||
* @return true if successful, false otherwise (e.g. when the directory does not exist).
|
||||
*/
|
||||
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const = 0;
|
||||
|
||||
/**
|
||||
* Returns a human readable path string.
|
||||
*
|
||||
* @note By default, this method returns the value of getName().
|
||||
*/
|
||||
virtual Common::U32String getDisplayName() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the last component of the path pointed by this FSNode.
|
||||
*
|
||||
* Examples (POSIX):
|
||||
* /foo/bar.txt would return /bar.txt
|
||||
* /foo/bar/ would return /bar/
|
||||
*
|
||||
* @note This method is very architecture dependent, please check the concrete implementation for more information.
|
||||
*/
|
||||
virtual Common::String getName() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the 'path' of the current node, usable in fopen().
|
||||
*/
|
||||
virtual Common::String getPath() const = 0;
|
||||
|
||||
/**
|
||||
* Indicates whether this path refers to a directory or not.
|
||||
*/
|
||||
virtual bool isDirectory() const = 0;
|
||||
|
||||
/**
|
||||
* Indicates whether the object referred by this path can be read from or not.
|
||||
*
|
||||
* If the path refers to a directory, readability implies being able to read
|
||||
* and list the directory entries.
|
||||
*
|
||||
* If the path refers to a file, readability implies being able to read the
|
||||
* contents of the file.
|
||||
*
|
||||
* @return bool true if the object can be read, false otherwise.
|
||||
*/
|
||||
virtual bool isReadable() const = 0;
|
||||
|
||||
/**
|
||||
* Indicates whether the object referred by this path can be written to or not.
|
||||
*
|
||||
* If the path refers to a directory, writability implies being able to modify
|
||||
* the directory entry (i.e. rename the directory, remove it or write files inside of it).
|
||||
*
|
||||
* If the path refers to a file, writability implies being able to write data
|
||||
* to the file.
|
||||
*
|
||||
* @return bool true if the object can be written to, false otherwise.
|
||||
*/
|
||||
virtual bool isWritable() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SeekableReadStream instance corresponding to the file
|
||||
* referred by this node. This assumes that the node actually refers
|
||||
* to a readable file. If this is not the case, 0 is returned.
|
||||
*
|
||||
* @return pointer to the stream object, 0 in case of a failure
|
||||
*/
|
||||
virtual Common::SeekableReadStream *createReadStream() = 0;
|
||||
|
||||
/**
|
||||
* Creates a SeekableReadStream instance corresponding to an alternate
|
||||
* stream of the file referred by this node. This assumes that the node
|
||||
* actually refers to a readable file and the alt stream exists.
|
||||
* If either is not the case, 0 is returned.
|
||||
*
|
||||
* @return pointer to the stream object, 0 in case of a failure
|
||||
*/
|
||||
virtual Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType);
|
||||
|
||||
/**
|
||||
* Creates a WriteStream instance corresponding to the file
|
||||
* referred by this node. This assumes that the node actually refers
|
||||
* to a readable file. If this is not the case, 0 is returned.
|
||||
*
|
||||
* When an atomic write stream is requested, the backend will write
|
||||
* the data in a temporary file before moving it to its final destination.
|
||||
*
|
||||
* @param atomic Request for an atomic file write when closing.
|
||||
*
|
||||
* @return pointer to the stream object, 0 in case of a failure
|
||||
*/
|
||||
virtual Common::SeekableWriteStream *createWriteStream(bool atomic) = 0;
|
||||
|
||||
/**
|
||||
* Creates a directory referred by this node.
|
||||
*
|
||||
* @return true if the directory is created successfully
|
||||
*/
|
||||
virtual bool createDirectory() = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif //BACKENDS_ABSTRACT_FS_H
|
||||
38
backends/fs/amigaos/amigaos-fs-factory.cpp
Normal file
38
backends/fs/amigaos/amigaos-fs-factory.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__amigaos4__)
|
||||
|
||||
#include "backends/fs/amigaos/amigaos-fs-factory.h"
|
||||
#include "backends/fs/amigaos/amigaos-fs.h"
|
||||
|
||||
AbstractFSNode *AmigaOSFilesystemFactory::makeRootFileNode() const {
|
||||
return new AmigaOSFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *AmigaOSFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
return new AmigaOSFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *AmigaOSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
return new AmigaOSFilesystemNode(path);
|
||||
}
|
||||
#endif
|
||||
39
backends/fs/amigaos/amigaos-fs-factory.h
Normal file
39
backends/fs/amigaos/amigaos-fs-factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AMIGAOS_FILESYSTEM_FACTORY_H
|
||||
#define AMIGAOS_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates AmigaOSFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class AmigaOSFilesystemFactory final : public FilesystemFactory {
|
||||
public:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*AMIGAOS_FILESYSTEM_FACTORY_H*/
|
||||
376
backends/fs/amigaos/amigaos-fs.cpp
Normal file
376
backends/fs/amigaos/amigaos-fs.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__amigaos4__)
|
||||
|
||||
#include "backends/fs/amigaos/amigaos-fs.h"
|
||||
#include "backends/fs/stdiostream.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/util.h"
|
||||
|
||||
/**
|
||||
* Returns the last component of a given path
|
||||
*
|
||||
* @param str Common::String containing the path
|
||||
* @return Pointer to the first char of the last component inside str
|
||||
*/
|
||||
const char *lastPathComponent(const Common::String &str) {
|
||||
int pathOffset = str.size();
|
||||
|
||||
if (pathOffset <= 0) {
|
||||
debug(6, "lastPathComponent() failed -> Bad offset (Empty path received)!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *p = str.c_str();
|
||||
|
||||
while (pathOffset > 0 && (p[pathOffset - 1] == '/' || p[pathOffset - 1] == ':'))
|
||||
pathOffset--;
|
||||
while (pathOffset > 0 && (p[pathOffset - 1] != '/' && p[pathOffset - 1] != ':'))
|
||||
pathOffset--;
|
||||
return p + pathOffset;
|
||||
}
|
||||
|
||||
AmigaOSFilesystemNode::AmigaOSFilesystemNode() {
|
||||
_sDisplayName = "Available HDDs/Partitions";
|
||||
_bIsValid = true;
|
||||
_bIsDirectory = true;
|
||||
_sPath = "";
|
||||
_pFileLock = 0;
|
||||
// Protection is ignored for the root volume
|
||||
_nProt = 0;
|
||||
}
|
||||
|
||||
AmigaOSFilesystemNode::AmigaOSFilesystemNode(const Common::String &p) {
|
||||
int nodeOffset = p.size();
|
||||
|
||||
if (nodeOffset <= 0) {
|
||||
debug(6, "AmigaOSFileSystemNode() failed -> Bad offset (No Path received)!");
|
||||
return;
|
||||
}
|
||||
|
||||
_sPath = p;
|
||||
_sDisplayName = ::lastPathComponent(_sPath);
|
||||
_pFileLock = 0;
|
||||
_bIsDirectory = false;
|
||||
_bIsValid = false;
|
||||
|
||||
// Check whether the node exists and if it's a directory
|
||||
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_StringNameInput,_sPath.c_str(),TAG_END);
|
||||
if (pExd) {
|
||||
_nProt = pExd->Protection;
|
||||
if (EXD_IS_DIRECTORY(pExd)) {
|
||||
_bIsDirectory = true;
|
||||
_pFileLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
|
||||
_bIsValid = (_pFileLock != 0);
|
||||
|
||||
// Add a trailing slash, if needed
|
||||
if (_sPath.lastChar() != '/' && _sPath.lastChar() != ':')
|
||||
_sPath += '/';
|
||||
} else {
|
||||
_bIsValid = true;
|
||||
}
|
||||
IDOS->FreeDosObject(DOS_EXAMINEDATA, pExd);
|
||||
}
|
||||
}
|
||||
|
||||
AmigaOSFilesystemNode::AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayName) {
|
||||
int bufSize = MAXPATHLEN;
|
||||
_pFileLock = 0;
|
||||
|
||||
while (true) {
|
||||
char *n = new char[bufSize];
|
||||
if (IDOS->NameFromLock(pLock, (STRPTR)n, bufSize) != DOSFALSE) {
|
||||
_sPath = n;
|
||||
_sDisplayName = pDisplayName ? pDisplayName : IDOS->FilePart((STRPTR)n);
|
||||
delete[] n;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IDOS->IoErr() != ERROR_LINE_TOO_LONG) {
|
||||
_bIsValid = false;
|
||||
debug(6, "IDOS->IoErr() failed -> MAXPATHLEN exceeded!");
|
||||
delete[] n;
|
||||
return;
|
||||
}
|
||||
|
||||
bufSize *= 2;
|
||||
delete[] n;
|
||||
}
|
||||
|
||||
_bIsDirectory = false;
|
||||
_bIsValid = false;
|
||||
|
||||
// Check whether the node exists and if it's a directory
|
||||
struct ExamineData * pExd = IDOS->ExamineObjectTags(EX_FileLockInput,pLock,TAG_END);
|
||||
if (pExd) {
|
||||
_nProt = pExd->Protection;
|
||||
if (EXD_IS_DIRECTORY(pExd)) {
|
||||
_bIsDirectory = true;
|
||||
_pFileLock = IDOS->DupLock(pLock);
|
||||
_bIsValid = _pFileLock != 0;
|
||||
// Add a trailing slash, if needed
|
||||
if (_sPath.lastChar() != '/' && _sPath.lastChar() != ':')
|
||||
_sPath += '/';
|
||||
} else {
|
||||
_bIsValid = true;
|
||||
}
|
||||
|
||||
IDOS->FreeDosObject(DOS_EXAMINEDATA, pExd);
|
||||
} else {
|
||||
debug(6, "IDOS->ExamineObjectTags() failed -> Not a directory (or it doesn't exist)!");
|
||||
}
|
||||
}
|
||||
|
||||
// We need the custom copy constructor because of DupLock()
|
||||
AmigaOSFilesystemNode::AmigaOSFilesystemNode(const AmigaOSFilesystemNode& node)
|
||||
: AbstractFSNode() {
|
||||
_sDisplayName = node._sDisplayName;
|
||||
_bIsValid = node._bIsValid;
|
||||
_bIsDirectory = node._bIsDirectory;
|
||||
_sPath = node._sPath;
|
||||
_pFileLock = IDOS->DupLock(node._pFileLock);
|
||||
_nProt = node._nProt;
|
||||
}
|
||||
|
||||
AmigaOSFilesystemNode::~AmigaOSFilesystemNode() {
|
||||
if (_pFileLock)
|
||||
IDOS->UnLock(_pFileLock);
|
||||
}
|
||||
|
||||
bool AmigaOSFilesystemNode::exists() const {
|
||||
if (_sPath.empty())
|
||||
return false;
|
||||
bool nodeExists = false;
|
||||
|
||||
BPTR pLock = IDOS->Lock(_sPath.c_str(), SHARED_LOCK);
|
||||
if (pLock) {
|
||||
nodeExists = true;
|
||||
IDOS->UnLock(pLock);
|
||||
}
|
||||
|
||||
return nodeExists;
|
||||
}
|
||||
|
||||
AbstractFSNode *AmigaOSFilesystemNode::getChild(const Common::String &n) const {
|
||||
if (!_bIsDirectory) {
|
||||
debug(6, "AmigaOSFileSystemNode::getChild() failed -> Not a directory!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::String newPath(_sPath);
|
||||
if (_sPath.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return new AmigaOSFilesystemNode(newPath);
|
||||
}
|
||||
|
||||
bool AmigaOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
if (!_bIsValid) {
|
||||
debug(6, "AmigaOSFileSystemNode::getChildren() failed -> Invalid node (Not a Volume)!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_bIsDirectory) {
|
||||
debug(6, "AmigaOSFileSystemNode::getChildren() failed -> Invalid node (Not a directory)!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isRootNode()) {
|
||||
myList = listVolumes();
|
||||
return true;
|
||||
}
|
||||
|
||||
APTR context = IDOS->ObtainDirContextTags( EX_FileLockInput, _pFileLock,
|
||||
EX_DoCurrentDir, TRUE, /* for softlinks */
|
||||
EX_DataFields, (EXF_NAME|EXF_LINK|EXF_TYPE),
|
||||
TAG_END);
|
||||
if (context) {
|
||||
// No need to free the value after usage, everything will be dealt with
|
||||
// by the DirContext release
|
||||
struct ExamineData * pExd = NULL;
|
||||
|
||||
AmigaOSFilesystemNode *entry;
|
||||
while ((pExd = IDOS->ExamineDir(context))) {
|
||||
if ((EXD_IS_FILE(pExd) && (Common::FSNode::kListFilesOnly == mode))
|
||||
|| (EXD_IS_DIRECTORY(pExd) && (Common::FSNode::kListDirectoriesOnly == mode))
|
||||
|| Common::FSNode::kListAll == mode
|
||||
)
|
||||
{
|
||||
BPTR pLock = IDOS->Lock(pExd->Name, SHARED_LOCK);
|
||||
if (pLock) {
|
||||
entry = new AmigaOSFilesystemNode(pLock, pExd->Name);
|
||||
if (entry) {
|
||||
myList.push_back(entry);
|
||||
}
|
||||
|
||||
IDOS->UnLock(pLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ERROR_NO_MORE_ENTRIES != IDOS->IoErr()) {
|
||||
debug(6, "IDOS->ExamineDir() failed -> End of list exceeded!");
|
||||
return false;
|
||||
}
|
||||
|
||||
IDOS->ReleaseDirContext(context);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
debug(6, "IDOS->ObtainDirContext() failed!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *AmigaOSFilesystemNode::getParent() const {
|
||||
if (isRootNode()) {
|
||||
return new AmigaOSFilesystemNode(*this);
|
||||
}
|
||||
|
||||
BPTR pLock = _pFileLock;
|
||||
if (!_bIsDirectory) {
|
||||
assert(!pLock);
|
||||
pLock = IDOS->Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
|
||||
assert(pLock);
|
||||
}
|
||||
|
||||
AmigaOSFilesystemNode *node;
|
||||
|
||||
BPTR parentDir = IDOS->ParentDir(pLock);
|
||||
if (parentDir) {
|
||||
node = new AmigaOSFilesystemNode(parentDir);
|
||||
IDOS->UnLock(parentDir);
|
||||
} else
|
||||
node = new AmigaOSFilesystemNode();
|
||||
|
||||
if (!_bIsDirectory) {
|
||||
IDOS->UnLock(pLock);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool AmigaOSFilesystemNode::isReadable() const {
|
||||
if (!_bIsValid)
|
||||
return false;
|
||||
|
||||
// Regular RWED protection flags are low-active or inverted,
|
||||
// thus the negation. Moreover, a pseudo root filesystem is
|
||||
// always readable, whatever the protection says
|
||||
bool readable = !(_nProt & EXDF_OTR_READ) || isRootNode();
|
||||
|
||||
return readable;
|
||||
}
|
||||
|
||||
bool AmigaOSFilesystemNode::isWritable() const {
|
||||
if (!_bIsValid)
|
||||
return false;
|
||||
|
||||
// Regular RWED protection flags are low-active or inverted,
|
||||
// thus the negation. Moreover, a pseudo root filesystem is
|
||||
// never writable (due of it's pseudo nature), whatever the protection says
|
||||
bool writable = !(_nProt & EXDF_OTR_WRITE) && !isRootNode();
|
||||
|
||||
return writable;
|
||||
}
|
||||
|
||||
AbstractFSList AmigaOSFilesystemNode::listVolumes() const {
|
||||
AbstractFSList myList;
|
||||
|
||||
const uint32 kLockFlags = LDF_READ | LDF_VOLUMES;
|
||||
char buffer[MAXPATHLEN];
|
||||
|
||||
struct DosList *dosList = IDOS->LockDosList(kLockFlags);
|
||||
if (!dosList) {
|
||||
debug(6, "IDOS->LockDOSList() failed! -> No Volumes found!");
|
||||
return myList;
|
||||
}
|
||||
|
||||
dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES);
|
||||
while (dosList) {
|
||||
if (dosList->dol_Type == DLT_VOLUME &&
|
||||
dosList->dol_Name && dosList->dol_Port) {
|
||||
// Copy name to buffer
|
||||
IDOS->CopyStringBSTRToC(dosList->dol_Name, buffer, MAXPATHLEN);
|
||||
|
||||
// Volume name + '\0'
|
||||
size_t volNameSize = strlen(buffer) + 1;
|
||||
char *volName = new char [volNameSize];
|
||||
Common::strcpy_s(volName, volNameSize, buffer);
|
||||
Common::strcat_s(buffer, ":");
|
||||
|
||||
BPTR volumeLock = IDOS->Lock((STRPTR)buffer, SHARED_LOCK);
|
||||
if (volumeLock) {
|
||||
char *devName = new char [MAXPATHLEN];
|
||||
|
||||
// Find device name
|
||||
IDOS->DevNameFromLock(volumeLock, devName, MAXPATHLEN, DN_DEVICEONLY);
|
||||
snprintf(buffer, MAXPATHLEN, "%s (%s)", volName, devName);
|
||||
delete[] devName;
|
||||
|
||||
AmigaOSFilesystemNode *entry = new AmigaOSFilesystemNode(volumeLock, buffer);
|
||||
if (entry) {
|
||||
myList.push_back(entry);
|
||||
}
|
||||
|
||||
IDOS->UnLock(volumeLock);
|
||||
}
|
||||
|
||||
delete[] volName;
|
||||
}
|
||||
dosList = IDOS->NextDosEntry(dosList, LDF_VOLUMES);
|
||||
}
|
||||
|
||||
IDOS->UnLockDosList(kLockFlags);
|
||||
return myList;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *AmigaOSFilesystemNode::createReadStream() {
|
||||
return StdioStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
|
||||
Common::SeekableWriteStream *AmigaOSFilesystemNode::createWriteStream(bool atomic) {
|
||||
return StdioStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
}
|
||||
|
||||
bool AmigaOSFilesystemNode::createDirectory() {
|
||||
Common::String createPath = _sPath;
|
||||
if (createPath.lastChar() == '/') {
|
||||
createPath = createPath.substr(0, createPath.size() - 1);
|
||||
}
|
||||
|
||||
BPTR dirLock = IDOS->CreateDir(createPath.c_str());
|
||||
if (dirLock) {
|
||||
IDOS->UnLock(dirLock);
|
||||
_bIsValid = true;
|
||||
_bIsDirectory = true;
|
||||
} else {
|
||||
debug(6, "AmigaOSFilesystemNode::createDirectory() failed -> Directory '%s' could not be created!", createPath.c_str());
|
||||
}
|
||||
|
||||
return _bIsValid && _bIsDirectory;
|
||||
}
|
||||
|
||||
#endif
|
||||
122
backends/fs/amigaos/amigaos-fs.h
Normal file
122
backends/fs/amigaos/amigaos-fs.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AMIGAOS_FILESYSTEM_H
|
||||
#define AMIGAOS_FILESYSTEM_H
|
||||
|
||||
#ifdef __USE_INLINE__
|
||||
#undef __USE_INLINE__
|
||||
#endif
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/dos.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef USE_NEWLIB
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class AmigaOSFilesystemNode final : public AbstractFSNode {
|
||||
protected:
|
||||
/**
|
||||
* The main file lock.
|
||||
* If this is NULL but _bIsValid is true, then this Node references
|
||||
* the virtual filesystem root.
|
||||
*/
|
||||
BPTR _pFileLock;
|
||||
|
||||
Common::String _sDisplayName;
|
||||
Common::String _sPath;
|
||||
bool _bIsDirectory;
|
||||
bool _bIsValid;
|
||||
uint32 _nProt;
|
||||
|
||||
/**
|
||||
* Creates a list with all the volumes present in the root node.
|
||||
*/
|
||||
virtual AbstractFSList listVolumes() const;
|
||||
|
||||
/**
|
||||
* True if this is the pseudo root filesystem.
|
||||
*/
|
||||
bool isRootNode() const { return _bIsValid && _bIsDirectory && _pFileLock == 0; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an AmigaOSFilesystemNode with the root node as path.
|
||||
*/
|
||||
AmigaOSFilesystemNode();
|
||||
|
||||
/**
|
||||
* Creates an AmigaOSFilesystemNode for a given path.
|
||||
*
|
||||
* @param path Common::String with the path the new node should point to.
|
||||
*/
|
||||
AmigaOSFilesystemNode(const Common::String &p);
|
||||
|
||||
/**
|
||||
* Creates an AmigaOSFilesystemNode given its lock and display name.
|
||||
*
|
||||
* @param pLock BPTR to the lock.
|
||||
* @param pDisplayName name to be used for display, in case not supplied the FilePart() of the filename will be used.
|
||||
*
|
||||
* @note This shouldn't even be public as it's only internally, at best it should have been protected if not private.
|
||||
*/
|
||||
AmigaOSFilesystemNode(BPTR pLock, const char *pDisplayName = 0);
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @note Needed because it duplicates the file lock.
|
||||
*/
|
||||
AmigaOSFilesystemNode(const AmigaOSFilesystemNode &node);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~AmigaOSFilesystemNode() override;
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _sDisplayName; }
|
||||
Common::String getName() const override { return _sDisplayName; }
|
||||
Common::String getPath() const override { return _sPath; }
|
||||
bool isDirectory() const override { return _bIsDirectory; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
131
backends/fs/android/android-fs-factory.cpp
Normal file
131
backends/fs/android/android-fs-factory.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "backends/platform/android/jni-android.h"
|
||||
|
||||
#include "backends/fs/android/android-fs-factory.h"
|
||||
#include "backends/fs/android/android-posix-fs.h"
|
||||
#include "backends/fs/android/android-saf-fs.h"
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(AndroidFilesystemFactory);
|
||||
}
|
||||
|
||||
AndroidFilesystemFactory::AndroidFilesystemFactory() : _withSAF(false), _config(this) {
|
||||
}
|
||||
|
||||
void AndroidFilesystemFactory::initSAF() {
|
||||
_withSAF = true;
|
||||
AndroidSAFFilesystemNode::initJNI();
|
||||
}
|
||||
|
||||
AbstractFSNode *AndroidFilesystemFactory::makeRootFileNode() const {
|
||||
return new AndroidPOSIXFilesystemNode(_config);
|
||||
}
|
||||
|
||||
AbstractFSNode *AndroidFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
// As current working directory can point outside of our data don't take any risk
|
||||
return makeRootFileNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *AndroidFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
if (path.empty() || path.equals("/")) {
|
||||
return makeRootFileNode();
|
||||
}
|
||||
|
||||
// If SAF works, it was a SAF URL
|
||||
if (_withSAF) {
|
||||
// Accept /saf as it can be used to create the tree in DumpFile
|
||||
if (path == AddSAFFakeNode::SAF_ADD_FAKE_PATH) {
|
||||
// Not a SAF mount point
|
||||
return new AddSAFFakeNode(true);
|
||||
}
|
||||
|
||||
AbstractFSNode *node = AndroidSAFFilesystemNode::makeFromPath(path);
|
||||
if (node) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return new AndroidPOSIXFilesystemNode(path, _config);
|
||||
}
|
||||
|
||||
AndroidFilesystemFactory::Config::Config(const AndroidFilesystemFactory *factory) : _factory(factory),
|
||||
_storages(JNI::getAllStorageLocations()) {
|
||||
}
|
||||
|
||||
void AndroidFilesystemFactory::getSAFTrees(AbstractFSList &list, bool allowSAFadd) const {
|
||||
if (!_withSAF) {
|
||||
// Nothing if no SAF
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Array<jobject> trees = JNI::getSAFTrees();
|
||||
|
||||
list.reserve(trees.size() + (allowSAFadd ? 1 : 0));
|
||||
|
||||
for (Common::Array<jobject>::iterator it = trees.begin(); it != trees.end(); it++) {
|
||||
AbstractFSNode *node = AndroidSAFFilesystemNode::makeFromTree(*it);
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.push_back(node);
|
||||
}
|
||||
|
||||
if (allowSAFadd) {
|
||||
list.push_back(new AddSAFFakeNode(false));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool AndroidFilesystemFactory::Config::getDrives(AbstractFSList &list, bool hidden) const {
|
||||
// For SAF
|
||||
_factory->getSAFTrees(list, true);
|
||||
|
||||
list.reserve(list.size() + _storages.size() / 2);
|
||||
|
||||
// For old POSIX way
|
||||
for (Common::Array<Common::String>::const_iterator it = _storages.begin(); it != _storages.end(); ++it) {
|
||||
const Common::String &driveName = *it;
|
||||
++it;
|
||||
const Common::String &drivePath = *it;
|
||||
|
||||
AndroidPOSIXFilesystemNode *node = new AndroidPOSIXFilesystemNode(drivePath, *this);
|
||||
node->_displayName = driveName;
|
||||
|
||||
list.push_back(node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AndroidFilesystemFactory::Config::isDrive(const Common::String &path) const {
|
||||
// This function is called from DrivePOSIXFilesystemNode::isDrive
|
||||
// DrivePOSIXFilesystemNode is only used for POSIX code so no need to look for SAF
|
||||
|
||||
for (Common::Array<Common::String>::const_iterator it = _storages.begin(); it != _storages.end(); it++) {
|
||||
++it;
|
||||
if (*it == path) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
63
backends/fs/android/android-fs-factory.h
Normal file
63
backends/fs/android/android-fs-factory.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_FILESYSTEM_FACTORY_H
|
||||
#define ANDROID_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
#include "common/singleton.h"
|
||||
#include "backends/fs/posix-drives/posix-drives-fs.h"
|
||||
|
||||
/**
|
||||
* Creates AndroidFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class AndroidFilesystemFactory final : public FilesystemFactory,
|
||||
public Common::Singleton<AndroidFilesystemFactory> {
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
protected:
|
||||
AndroidFilesystemFactory();
|
||||
public:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
void initSAF();
|
||||
bool hasSAF() const { return _withSAF; }
|
||||
void getSAFTrees(AbstractFSList &list, bool allowSAFadd) const;
|
||||
private:
|
||||
struct Config : public DrivePOSIXFilesystemNode::Config {
|
||||
Config(const AndroidFilesystemFactory *factory);
|
||||
|
||||
bool getDrives(AbstractFSList &list, bool hidden) const override;
|
||||
bool isDrive(const Common::String &path) const override;
|
||||
|
||||
private:
|
||||
const AndroidFilesystemFactory *_factory;
|
||||
Common::Array<Common::String> _storages;
|
||||
};
|
||||
|
||||
bool _withSAF;
|
||||
Config _config;
|
||||
};
|
||||
|
||||
#endif /*ANDROID_FILESYSTEM_FACTORY_H*/
|
||||
35
backends/fs/android/android-fs.h
Normal file
35
backends/fs/android/android-fs.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_FILESYSTEM_H
|
||||
#define ANDROID_FILESYSTEM_H
|
||||
|
||||
/**
|
||||
* Common interface for Android filesystem types: SAF and POSIX
|
||||
* Currently, only a remove function to delete files.
|
||||
*/
|
||||
class AndroidFSNode {
|
||||
public:
|
||||
virtual ~AndroidFSNode() {}
|
||||
virtual int remove() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
44
backends/fs/android/android-posix-fs.cpp
Normal file
44
backends/fs/android/android-posix-fs.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// For remove()
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "backends/fs/android/android-fs-factory.h"
|
||||
#include "backends/fs/android/android-posix-fs.h"
|
||||
#include "backends/fs/android/android-saf-fs.h"
|
||||
|
||||
AbstractFSNode *AndroidPOSIXFilesystemNode::makeNode() const {
|
||||
return new AndroidPOSIXFilesystemNode(_config);
|
||||
}
|
||||
|
||||
AbstractFSNode *AndroidPOSIXFilesystemNode::makeNode(const Common::String &path) const {
|
||||
return AndroidFilesystemFactory::instance().makeFileNodePath(path);
|
||||
}
|
||||
|
||||
int AndroidPOSIXFilesystemNode::remove() {
|
||||
if (::remove(_path.c_str()) != 0)
|
||||
return errno;
|
||||
|
||||
setFlags();
|
||||
return 0;
|
||||
}
|
||||
45
backends/fs/android/android-posix-fs.h
Normal file
45
backends/fs/android/android-posix-fs.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_FILESYSTEM_ROOT_H
|
||||
#define ANDROID_FILESYSTEM_ROOT_H
|
||||
|
||||
#include "backends/fs/posix-drives/posix-drives-fs.h"
|
||||
|
||||
#include "backends/fs/android/android-fs.h"
|
||||
|
||||
class AndroidPOSIXFilesystemNode : public DrivePOSIXFilesystemNode, public AndroidFSNode {
|
||||
// To let the factory redefine the displayed name
|
||||
friend class AndroidFilesystemFactory;
|
||||
protected:
|
||||
AbstractFSNode *makeNode() const override;
|
||||
AbstractFSNode *makeNode(const Common::String &path) const override;
|
||||
|
||||
int remove() override;
|
||||
|
||||
public:
|
||||
AndroidPOSIXFilesystemNode(const Common::String &path, const Config &config)
|
||||
: DrivePOSIXFilesystemNode(path, config) { }
|
||||
AndroidPOSIXFilesystemNode(const Config &config)
|
||||
: DrivePOSIXFilesystemNode(config) { _path = "/"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
930
backends/fs/android/android-saf-fs.cpp
Normal file
930
backends/fs/android/android-saf-fs.cpp
Normal file
@@ -0,0 +1,930 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Allow use of stuff in <time.h> and abort()
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_abort
|
||||
|
||||
// Disable printf override in common/forbidden.h to avoid
|
||||
// clashes with log.h from the Android SDK.
|
||||
// That header file uses
|
||||
// __attribute__ ((format(printf, 3, 4)))
|
||||
// which gets messed up by our override mechanism; this could
|
||||
// be avoided by either changing the Android SDK to use the equally
|
||||
// legal and valid
|
||||
// __attribute__ ((format(__printf__, 3, 4)))
|
||||
// or by refining our printf override to use a varadic macro
|
||||
// (which then wouldn't be portable, though).
|
||||
// Anyway, for now we just disable the printf override globally
|
||||
// for the Android port
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
||||
|
||||
// Allow calling of fdopen
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
|
||||
// Allow calling of close system call
|
||||
#include <unistd.h>
|
||||
#include <errno.h> // For remove error codes
|
||||
|
||||
#include "backends/platform/android/android.h"
|
||||
#include "backends/platform/android/jni-android.h"
|
||||
|
||||
#include "backends/fs/android/android-fs-factory.h"
|
||||
#include "backends/fs/android/android-saf-fs.h"
|
||||
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/translation.h"
|
||||
#include "common/util.h"
|
||||
|
||||
jclass AndroidSAFFilesystemNode::_CLS_SAFFSTree = nullptr;
|
||||
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_addNodeRef = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_decNodeRef = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_refToNode = 0;
|
||||
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_getTreeId = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_pathToNode = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_getChildren = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_getChild = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_createDirectory = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_createFile = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_createReadStream = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_createWriteStream = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_removeNode = 0;
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_removeTree = 0;
|
||||
|
||||
jfieldID AndroidSAFFilesystemNode::_FID__treeName = 0;
|
||||
jfieldID AndroidSAFFilesystemNode::_FID__root = 0;
|
||||
|
||||
jmethodID AndroidSAFFilesystemNode::_MID_addRef = 0;
|
||||
|
||||
jfieldID AndroidSAFFilesystemNode::_FID__parent = 0;
|
||||
jfieldID AndroidSAFFilesystemNode::_FID__path = 0;
|
||||
jfieldID AndroidSAFFilesystemNode::_FID__documentId = 0;
|
||||
jfieldID AndroidSAFFilesystemNode::_FID__flags = 0;
|
||||
|
||||
bool AndroidSAFFilesystemNode::_JNIinit = false;
|
||||
|
||||
const char AndroidSAFFilesystemNode::SAF_MOUNT_POINT[] = "/saf/";
|
||||
|
||||
void AndroidSAFFilesystemNode::initJNI() {
|
||||
if (_JNIinit) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
// We can't call error here as the backend is not built yet
|
||||
#define FIND_STATIC_METHOD(prefix, name, signature) do { \
|
||||
_MID_ ## prefix ## name = env->GetStaticMethodID(cls, #name, signature); \
|
||||
if (_MID_ ## prefix ## name == 0) { \
|
||||
LOGE("Can't find method ID " #name); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#define FIND_METHOD(prefix, name, signature) do { \
|
||||
_MID_ ## prefix ## name = env->GetMethodID(cls, #name, signature); \
|
||||
if (_MID_ ## prefix ## name == 0) { \
|
||||
LOGE("Can't find method ID " #name); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#define FIND_FIELD(prefix, name, signature) do { \
|
||||
_FID_ ## prefix ## name = env->GetFieldID(cls, #name, signature); \
|
||||
if (_FID_ ## prefix ## name == 0) { \
|
||||
LOGE("Can't find field ID " #name); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
#define SAFFSNodeSig "Lorg/scummvm/scummvm/SAFFSTree$SAFFSNode;"
|
||||
|
||||
jclass cls = env->FindClass("org/scummvm/scummvm/SAFFSTree");
|
||||
_CLS_SAFFSTree = (jclass)env->NewGlobalRef(cls);
|
||||
|
||||
FIND_STATIC_METHOD(, addNodeRef, "(J)V");
|
||||
FIND_STATIC_METHOD(, decNodeRef, "(J)V");
|
||||
FIND_STATIC_METHOD(, refToNode, "(J)" SAFFSNodeSig);
|
||||
|
||||
FIND_METHOD(, getTreeId, "()Ljava/lang/String;");
|
||||
FIND_METHOD(, pathToNode, "(Ljava/lang/String;Z)" SAFFSNodeSig);
|
||||
FIND_METHOD(, getChildren, "(J)[" SAFFSNodeSig);
|
||||
FIND_METHOD(, getChild, "(JLjava/lang/String;)" SAFFSNodeSig);
|
||||
FIND_METHOD(, createDirectory, "(JLjava/lang/String;)" SAFFSNodeSig);
|
||||
FIND_METHOD(, createFile, "(JLjava/lang/String;)" SAFFSNodeSig);
|
||||
FIND_METHOD(, createReadStream, "(J)I");
|
||||
FIND_METHOD(, createWriteStream, "(J)I");
|
||||
FIND_METHOD(, removeNode, "(J)I");
|
||||
FIND_METHOD(, removeTree, "()V");
|
||||
|
||||
FIND_FIELD(, _treeName, "Ljava/lang/String;");
|
||||
FIND_FIELD(, _root, SAFFSNodeSig);
|
||||
|
||||
env->DeleteLocalRef(cls);
|
||||
cls = env->FindClass("org/scummvm/scummvm/SAFFSTree$SAFFSNode");
|
||||
|
||||
FIND_METHOD(, addRef, "()J");
|
||||
|
||||
FIND_FIELD(, _parent, SAFFSNodeSig);
|
||||
FIND_FIELD(, _path, "Ljava/lang/String;");
|
||||
FIND_FIELD(, _documentId, "Ljava/lang/String;");
|
||||
FIND_FIELD(, _flags, "I");
|
||||
|
||||
env->DeleteLocalRef(cls);
|
||||
#undef SAFFSNodeSig
|
||||
#undef FIND_FIELD
|
||||
#undef FIND_METHOD
|
||||
#undef FIND_STATIC_METHOD
|
||||
|
||||
_JNIinit = true;
|
||||
}
|
||||
|
||||
void AndroidSAFFilesystemNode::GlobalRef::Deleter::operator()(_jobject *obj) {
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
env->DeleteGlobalRef((jobject)obj);
|
||||
}
|
||||
|
||||
void AndroidSAFFilesystemNode::NodeRef::reset() {
|
||||
if (_ref == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
env->CallStaticVoidMethod(_CLS_SAFFSTree, _MID_decNodeRef, _ref);
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::decNodeRef failed");
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
_ref = 0;
|
||||
}
|
||||
|
||||
void AndroidSAFFilesystemNode::NodeRef::reset(const NodeRef &r) {
|
||||
if (_ref == 0 && r._ref == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
if (_ref) {
|
||||
env->CallStaticVoidMethod(_CLS_SAFFSTree, _MID_decNodeRef, _ref);
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::decNodeRef failed");
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
_ref = r._ref;
|
||||
if (!_ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
env->CallStaticVoidMethod(_CLS_SAFFSTree, _MID_addNodeRef, _ref);
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::addNodeRef failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
_ref = 0;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSAFFilesystemNode::NodeRef::reset(JNIEnv *env, jobject node) {
|
||||
if (_ref == 0 && node == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_ref) {
|
||||
env->CallStaticVoidMethod(_CLS_SAFFSTree, _MID_decNodeRef, _ref);
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::decNodeRef failed");
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
if (node == nullptr) {
|
||||
_ref = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_ref = env->CallLongMethod(node, _MID_addRef);
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSNode::addRef failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
_ref = 0;
|
||||
abort();
|
||||
}
|
||||
|
||||
assert(_ref != 0);
|
||||
}
|
||||
|
||||
jobject AndroidSAFFilesystemNode::NodeRef::localRef(JNIEnv *env) const {
|
||||
if (_ref == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jobject localRef = env->CallStaticObjectMethod(_CLS_SAFFSTree, _MID_refToNode, _ref);
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::refToNode failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return localRef;
|
||||
}
|
||||
|
||||
AndroidSAFFilesystemNode *AndroidSAFFilesystemNode::makeFromPath(const Common::String &path) {
|
||||
if (!path.hasPrefix(SAF_MOUNT_POINT)) {
|
||||
// Not a SAF mount point
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Path is in the form /saf/<treeid>/<path>
|
||||
size_t pos = path.findFirstOf('/', sizeof(SAF_MOUNT_POINT) - 1);
|
||||
Common::String treeId;
|
||||
Common::String realPath;
|
||||
if (pos == Common::String::npos) {
|
||||
treeId = path.substr(sizeof(SAF_MOUNT_POINT) - 1);
|
||||
} else {
|
||||
treeId = path.substr(sizeof(SAF_MOUNT_POINT) - 1, pos - sizeof(SAF_MOUNT_POINT) + 1);
|
||||
realPath = path.substr(pos);
|
||||
}
|
||||
|
||||
jobject safTree = JNI::findSAFTree(treeId);
|
||||
if (!safTree) {
|
||||
LOGW("AndroidSAFFilesystemNode::makeFromPath: tree id %s not found", treeId.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jstring pathObj = env->NewStringUTF(realPath.c_str());
|
||||
|
||||
jobject node = env->CallObjectMethod(safTree, _MID_pathToNode, pathObj, false);
|
||||
|
||||
env->DeleteLocalRef(pathObj);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::pathToNode failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
env->DeleteLocalRef(safTree);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
AndroidSAFFilesystemNode *ret = new AndroidSAFFilesystemNode(GlobalRef(env, safTree), node);
|
||||
|
||||
env->DeleteLocalRef(node);
|
||||
env->DeleteLocalRef(safTree);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Node doesn't exist: we will try to make a node from the parent and
|
||||
// if it works we will create a non-existent node
|
||||
|
||||
pos = realPath.findLastOf('/');
|
||||
if (pos == Common::String::npos || pos == 0) {
|
||||
// No / in path or at root, no parent and we have a tree: it's all good
|
||||
if (pos == 0) {
|
||||
realPath = realPath.substr(1);
|
||||
}
|
||||
AndroidSAFFilesystemNode *parent = makeFromTree(safTree);
|
||||
AndroidSAFFilesystemNode *ret = static_cast<AndroidSAFFilesystemNode *>(parent->getChild(realPath));
|
||||
delete parent;
|
||||
|
||||
// safTree has already been released by makeFromTree
|
||||
return ret;
|
||||
}
|
||||
|
||||
Common::String baseName(realPath.substr(pos + 1));
|
||||
realPath.erase(pos);
|
||||
|
||||
pathObj = env->NewStringUTF(realPath.c_str());
|
||||
|
||||
node = env->CallObjectMethod(safTree, _MID_pathToNode, pathObj, false);
|
||||
|
||||
env->DeleteLocalRef(pathObj);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::pathToNode failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
env->DeleteLocalRef(safTree);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
AndroidSAFFilesystemNode *parent = new AndroidSAFFilesystemNode(GlobalRef(env, safTree), node);
|
||||
env->DeleteLocalRef(node);
|
||||
env->DeleteLocalRef(safTree);
|
||||
|
||||
AndroidSAFFilesystemNode *ret = static_cast<AndroidSAFFilesystemNode *>(parent->getChild(baseName));
|
||||
delete parent;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(safTree);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AndroidSAFFilesystemNode *AndroidSAFFilesystemNode::makeFromTree(jobject safTree) {
|
||||
assert(safTree);
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jobject node = env->GetObjectField(safTree, _FID__root);
|
||||
if (!node) {
|
||||
env->DeleteLocalRef(safTree);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AndroidSAFFilesystemNode *ret = new AndroidSAFFilesystemNode(GlobalRef(env, safTree), node);
|
||||
|
||||
env->DeleteLocalRef(node);
|
||||
env->DeleteLocalRef(safTree);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AndroidSAFFilesystemNode::AndroidSAFFilesystemNode(const GlobalRef &safTree, jobject safNode) :
|
||||
_flags(0) {
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
_safTree = safTree;
|
||||
assert(_safTree != nullptr);
|
||||
|
||||
_safNode.reset(env, safNode);
|
||||
cacheData(env, safNode);
|
||||
}
|
||||
|
||||
AndroidSAFFilesystemNode::AndroidSAFFilesystemNode(const GlobalRef &safTree, jobject safParent,
|
||||
const Common::String &path, const Common::String &name) : _flags(0) {
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
_safTree = safTree;
|
||||
_safParent.reset(env, safParent);
|
||||
|
||||
// In this case _path is the parent
|
||||
_path = path;
|
||||
_newName = name;
|
||||
}
|
||||
|
||||
AndroidSAFFilesystemNode::AndroidSAFFilesystemNode(const GlobalRef &safTree,
|
||||
const NodeRef &safParent, const Common::String &path,
|
||||
const Common::String &name) : _flags(0) {
|
||||
|
||||
_safTree = safTree;
|
||||
_safParent = safParent;
|
||||
|
||||
// In this case _path is the parent
|
||||
_path = path;
|
||||
_newName = name;
|
||||
}
|
||||
|
||||
Common::String AndroidSAFFilesystemNode::getName() const {
|
||||
if (!_safNode || !_safParent) {
|
||||
// _newName is for non-existent paths or root node pretty name
|
||||
return _newName;
|
||||
}
|
||||
|
||||
return lastPathComponent(_path, '/');
|
||||
}
|
||||
|
||||
Common::String AndroidSAFFilesystemNode::getPath() const {
|
||||
assert(_safTree != nullptr);
|
||||
|
||||
if (_safNode) {
|
||||
return _path;
|
||||
}
|
||||
|
||||
// When no node, it means _path is the parent node
|
||||
return _path + "/" + _newName;
|
||||
}
|
||||
|
||||
AbstractFSNode *AndroidSAFFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(_safTree != nullptr);
|
||||
assert(_safNode);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jstring name = env->NewStringUTF(n.c_str());
|
||||
|
||||
jobject child = env->CallObjectMethod(_safTree, _MID_getChild, _safNode.get(), name);
|
||||
|
||||
env->DeleteLocalRef(name);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::getChild failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (child) {
|
||||
AndroidSAFFilesystemNode *ret = new AndroidSAFFilesystemNode(_safTree, child);
|
||||
env->DeleteLocalRef(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return new AndroidSAFFilesystemNode(_safTree, _safNode, _path, n);
|
||||
}
|
||||
|
||||
bool AndroidSAFFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode,
|
||||
bool hidden) const {
|
||||
assert(_flags & DIRECTORY);
|
||||
|
||||
assert(_safTree != nullptr);
|
||||
if (!_safNode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jobjectArray array =
|
||||
(jobjectArray)env->CallObjectMethod(_safTree, _MID_getChildren, _safNode.get());
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::getChildren failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!array) {
|
||||
// Fetching children failed: a log error has already been produced in Java code
|
||||
return false;
|
||||
}
|
||||
|
||||
myList.clear();
|
||||
|
||||
jsize size = env->GetArrayLength(array);
|
||||
myList.reserve(size);
|
||||
|
||||
for (jsize i = 0; i < size; ++i) {
|
||||
jobject node = env->GetObjectArrayElement(array, i);
|
||||
|
||||
myList.push_back(new AndroidSAFFilesystemNode(_safTree, node));
|
||||
|
||||
env->DeleteLocalRef(node);
|
||||
}
|
||||
env->DeleteLocalRef(array);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *AndroidSAFFilesystemNode::getParent() const {
|
||||
assert(_safTree != nullptr);
|
||||
// No need to check for _safNode: if node doesn't exist yet parent is its parent
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
if (!_safParent) {
|
||||
return AndroidFilesystemFactory::instance().makeRootFileNode();
|
||||
}
|
||||
|
||||
jobject parent = _safParent.localRef(env);
|
||||
assert(parent);
|
||||
|
||||
AndroidSAFFilesystemNode *ret = new AndroidSAFFilesystemNode(_safTree, parent);
|
||||
env->DeleteLocalRef(parent);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *AndroidSAFFilesystemNode::createReadStream() {
|
||||
assert(_safTree != nullptr);
|
||||
|
||||
if (!_safNode) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jint fd = env->CallIntMethod(_safTree, _MID_createReadStream, _safNode.get());
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::createReadStream failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FILE *f = fdopen(fd, "r");
|
||||
if (!f) {
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new PosixIoStream(f);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *AndroidSAFFilesystemNode::createWriteStream(bool atomic) {
|
||||
assert(_safTree != nullptr);
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
if (!_safNode) {
|
||||
assert(_safParent);
|
||||
jstring name = env->NewStringUTF(_newName.c_str());
|
||||
|
||||
// TODO: Add atomic support if possible
|
||||
jobject child = env->CallObjectMethod(_safTree, _MID_createFile, _safParent.get(), name);
|
||||
|
||||
env->DeleteLocalRef(name);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::createFile failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!child) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_safNode.reset(env, child);
|
||||
cacheData(env, child);
|
||||
|
||||
env->DeleteLocalRef(child);
|
||||
}
|
||||
|
||||
jint fd = env->CallIntMethod(_safTree, _MID_createWriteStream, _safNode.get());
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::createWriteStream failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FILE *f = fdopen(fd, "w");
|
||||
if (!f) {
|
||||
close(fd);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new PosixIoStream(f);
|
||||
}
|
||||
|
||||
bool AndroidSAFFilesystemNode::createDirectory() {
|
||||
assert(_safTree != nullptr);
|
||||
|
||||
if (_safNode) {
|
||||
return _flags & DIRECTORY;
|
||||
}
|
||||
|
||||
assert(_safParent);
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jstring name = env->NewStringUTF(_newName.c_str());
|
||||
|
||||
jobject child = env->CallObjectMethod(_safTree, _MID_createDirectory, _safParent.get(), name);
|
||||
|
||||
env->DeleteLocalRef(name);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::createDirectory failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!child) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_safNode.reset(env, child);
|
||||
|
||||
cacheData(env, child);
|
||||
|
||||
env->DeleteLocalRef(child);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int AndroidSAFFilesystemNode::remove() {
|
||||
assert(_safTree != nullptr);
|
||||
|
||||
if (!_safNode) {
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
if (!_safParent) {
|
||||
// It's the root of the tree: we can't delete it
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
if (isDirectory()) {
|
||||
// Don't delete folders (yet?)
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
jint result = env->CallIntMethod(_safTree, _MID_removeNode, _safNode.get());
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::removeNode failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
return EIO;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
_safNode.reset();
|
||||
|
||||
// Create the parent node to fetch informations needed to make us a non-existent node
|
||||
|
||||
jobject jparent = _safParent.localRef(env);
|
||||
if (!jparent)
|
||||
return EIO;
|
||||
|
||||
AndroidSAFFilesystemNode *parent = new AndroidSAFFilesystemNode(_safTree, jparent);
|
||||
env->DeleteLocalRef(jparent);
|
||||
|
||||
size_t pos = _path.findLastOf('/');
|
||||
if (pos == Common::String::npos) {
|
||||
_newName = _path;
|
||||
} else {
|
||||
_newName = _path.substr(pos + 1);
|
||||
}
|
||||
_path = parent->_path;
|
||||
|
||||
delete parent;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AndroidSAFFilesystemNode::removeTree() {
|
||||
assert(!_safParent);
|
||||
|
||||
JNIEnv *env = JNI::getEnv();
|
||||
|
||||
env->CallVoidMethod(_safTree, _MID_removeTree);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
LOGE("SAFFSTree::removeTree failed");
|
||||
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
|
||||
void AndroidSAFFilesystemNode::cacheData(JNIEnv *env, jobject node) {
|
||||
_flags = env->GetIntField(node, _FID__flags);
|
||||
|
||||
jobject safParent = env->GetObjectField(node, _FID__parent);
|
||||
_safParent.reset(env, safParent);
|
||||
|
||||
if (!_safParent) {
|
||||
jstring nameObj = (jstring)env->GetObjectField(_safTree, _FID__treeName);
|
||||
const char *nameP = env->GetStringUTFChars(nameObj, 0);
|
||||
if (nameP != 0) {
|
||||
_newName = Common::String(nameP);
|
||||
env->ReleaseStringUTFChars(nameObj, nameP);
|
||||
}
|
||||
env->DeleteLocalRef(nameObj);
|
||||
}
|
||||
|
||||
Common::String workingPath;
|
||||
|
||||
jstring pathObj = (jstring)env->GetObjectField(node, _FID__path);
|
||||
const char *path = env->GetStringUTFChars(pathObj, 0);
|
||||
if (path == nullptr) {
|
||||
env->DeleteLocalRef(pathObj);
|
||||
error("SAFFSNode::_path is null");
|
||||
return;
|
||||
}
|
||||
workingPath = Common::String(path);
|
||||
env->ReleaseStringUTFChars(pathObj, path);
|
||||
env->DeleteLocalRef(pathObj);
|
||||
|
||||
jstring idObj = (jstring)env->CallObjectMethod(_safTree, _MID_getTreeId);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
|
||||
env->ReleaseStringUTFChars(pathObj, path);
|
||||
env->DeleteLocalRef(pathObj);
|
||||
error("SAFFSTree::getTreeId failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!idObj) {
|
||||
error("SAFFSTree::getTreeId returned null");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *id = env->GetStringUTFChars(idObj, 0);
|
||||
if (id == nullptr) {
|
||||
error("Failed to get string from SAFFSTree::getTreeId");
|
||||
env->DeleteLocalRef(idObj);
|
||||
return;
|
||||
}
|
||||
|
||||
_path = Common::String(SAF_MOUNT_POINT);
|
||||
_path += id;
|
||||
_path += workingPath;
|
||||
env->ReleaseStringUTFChars(idObj, id);
|
||||
env->DeleteLocalRef(idObj);
|
||||
}
|
||||
|
||||
const char AddSAFFakeNode::SAF_ADD_FAKE_PATH[] = "/saf";
|
||||
|
||||
AddSAFFakeNode::~AddSAFFakeNode() {
|
||||
delete _proxied;
|
||||
}
|
||||
|
||||
Common::U32String AddSAFFakeNode::getDisplayName() const {
|
||||
// I18N: This is displayed in the file browser to let the user choose a new folder for Android Storage Attached Framework
|
||||
return Common::U32String::format("\x01<%s>", _("Add a new folder").c_str());
|
||||
}
|
||||
|
||||
Common::String AddSAFFakeNode::getName() const {
|
||||
return Common::String::format("\x01<%s>", _("Add a new folder").encode().c_str());
|
||||
}
|
||||
|
||||
AbstractFSNode *AddSAFFakeNode::getChild(const Common::String &name) const {
|
||||
if (_fromPath) {
|
||||
// When starting from /saf try to get the tree node
|
||||
return AndroidSAFFilesystemNode::makeFromPath(Common::String(AndroidSAFFilesystemNode::SAF_MOUNT_POINT) + name);
|
||||
}
|
||||
// We can't call getChild as it's protected
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AbstractFSNode *AddSAFFakeNode::getParent() const {
|
||||
// We are always just below the root and getParent is protected
|
||||
return AndroidFilesystemFactory::instance().makeRootFileNode();
|
||||
}
|
||||
|
||||
bool AddSAFFakeNode::exists() const {
|
||||
if (_fromPath) {
|
||||
// /saf always exists when created as a path
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
makeProxySAF();
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _proxied->exists();
|
||||
}
|
||||
|
||||
bool AddSAFFakeNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const {
|
||||
if (_fromPath) {
|
||||
// When built from path, /saf lists all SAF node but never proposes to add one
|
||||
if (mode == Common::FSNode::kListFilesOnly) {
|
||||
// All directories
|
||||
return true;
|
||||
}
|
||||
AndroidFilesystemFactory::instance().getSAFTrees(list, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
makeProxySAF();
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _proxied->getChildren(list, mode, hidden);
|
||||
}
|
||||
|
||||
Common::String AddSAFFakeNode::getPath() const {
|
||||
if (_fromPath) {
|
||||
return SAF_ADD_FAKE_PATH;
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
makeProxySAF();
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return _proxied->getPath();
|
||||
}
|
||||
|
||||
bool AddSAFFakeNode::isReadable() const {
|
||||
if (_fromPath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
makeProxySAF();
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _proxied->isReadable();
|
||||
}
|
||||
|
||||
bool AddSAFFakeNode::isWritable() const {
|
||||
if (_fromPath) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
makeProxySAF();
|
||||
}
|
||||
|
||||
if (!_proxied) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _proxied->isWritable();
|
||||
}
|
||||
|
||||
int AddSAFFakeNode::remove() {
|
||||
return EPERM;
|
||||
}
|
||||
|
||||
void AddSAFFakeNode::makeProxySAF() const {
|
||||
assert(!_fromPath);
|
||||
|
||||
if (_proxied) {
|
||||
return;
|
||||
}
|
||||
|
||||
// I18N: This may be displayed in the Android UI used to add a Storage Attach Framework authorization
|
||||
jobject saftree = JNI::getNewSAFTree(true, "", _("Choose a new folder"));
|
||||
if (!saftree) {
|
||||
return;
|
||||
}
|
||||
|
||||
_proxied = AndroidSAFFilesystemNode::makeFromTree(saftree);
|
||||
}
|
||||
273
backends/fs/android/android-saf-fs.h
Normal file
273
backends/fs/android/android-saf-fs.h
Normal file
@@ -0,0 +1,273 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANDROID_SAF_FILESYSTEM_H
|
||||
#define ANDROID_SAF_FILESYSTEM_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
#include "common/ptr.h"
|
||||
|
||||
#include "backends/fs/android/android-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class AndroidSAFFilesystemNode final : public AbstractFSNode, public AndroidFSNode {
|
||||
protected:
|
||||
/**
|
||||
* A class managing a global reference.
|
||||
*
|
||||
* This handles the reference management and avoids duplicating them in JNI.
|
||||
*/
|
||||
class GlobalRef final : public Common::SharedPtr<_jobject> {
|
||||
struct Deleter {
|
||||
void operator()(_jobject *obj);
|
||||
};
|
||||
public:
|
||||
GlobalRef() : Common::SharedPtr<_jobject>() {}
|
||||
GlobalRef(const GlobalRef &ref) : Common::SharedPtr<_jobject>(ref) {}
|
||||
GlobalRef(JNIEnv *env, jobject jobj) : Common::SharedPtr<_jobject>(jobj ? env->NewGlobalRef(jobj) : nullptr, Deleter()) {
|
||||
// Make sure NewGlobalRef succeeded
|
||||
assert((jobj == nullptr) == (get() == nullptr));
|
||||
}
|
||||
GlobalRef &operator=(const GlobalRef &r) {
|
||||
Common::SharedPtr<_jobject>::reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator jobject() {
|
||||
return Common::SharedPtr<_jobject>::get();
|
||||
}
|
||||
operator jobject() const {
|
||||
return Common::SharedPtr<_jobject>::get();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class managing our SAFFSNode references.
|
||||
*
|
||||
* Reference counting is managed by SAFFSNode in Java and this class uses
|
||||
* RAII to call the reference counting methods at the appropriate time.
|
||||
*/
|
||||
class NodeRef final {
|
||||
private:
|
||||
jlong _ref;
|
||||
|
||||
public:
|
||||
NodeRef() : _ref(0) {}
|
||||
~NodeRef() { reset(); }
|
||||
NodeRef(const NodeRef &r) { reset(r); }
|
||||
NodeRef(JNIEnv *env, jobject node) { reset(env, node); }
|
||||
|
||||
void reset();
|
||||
void reset(const NodeRef &r);
|
||||
void reset(JNIEnv *env, jobject node);
|
||||
|
||||
NodeRef &operator=(const NodeRef &r) {
|
||||
reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const NodeRef &r) const {
|
||||
return _ref == r._ref;
|
||||
}
|
||||
|
||||
bool operator!=(const NodeRef &r) const {
|
||||
return _ref != r._ref;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return _ref != 0;
|
||||
}
|
||||
|
||||
jlong get() const { return _ref; }
|
||||
jobject localRef(JNIEnv *env) const;
|
||||
};
|
||||
|
||||
// SAFFSTree
|
||||
static jclass _CLS_SAFFSTree;
|
||||
|
||||
static jmethodID _MID_addNodeRef;
|
||||
static jmethodID _MID_decNodeRef;
|
||||
static jmethodID _MID_refToNode;
|
||||
static jmethodID _MID_getTreeId;
|
||||
static jmethodID _MID_pathToNode;
|
||||
static jmethodID _MID_getChildren;
|
||||
static jmethodID _MID_getChild;
|
||||
static jmethodID _MID_createDirectory;
|
||||
static jmethodID _MID_createFile;
|
||||
static jmethodID _MID_createReadStream;
|
||||
static jmethodID _MID_createWriteStream;
|
||||
static jmethodID _MID_removeNode;
|
||||
static jmethodID _MID_removeTree;
|
||||
|
||||
static jfieldID _FID__treeName;
|
||||
static jfieldID _FID__root;
|
||||
|
||||
// SAFFSNode
|
||||
static jmethodID _MID_addRef;
|
||||
|
||||
static jfieldID _FID__parent;
|
||||
static jfieldID _FID__path;
|
||||
static jfieldID _FID__documentId;
|
||||
static jfieldID _FID__flags;
|
||||
|
||||
static bool _JNIinit;
|
||||
|
||||
protected:
|
||||
static const int DIRECTORY = 1;
|
||||
static const int WRITABLE = 2;
|
||||
static const int READABLE = 4;
|
||||
|
||||
GlobalRef _safTree;
|
||||
// When 0, node doesn't exist yet
|
||||
// In this case _path is the parent path, _newName the node name and _safParent the parent SAF object
|
||||
NodeRef _safNode;
|
||||
|
||||
Common::String _path;
|
||||
int _flags;
|
||||
NodeRef _safParent;
|
||||
|
||||
// Used when creating a new node
|
||||
// Also used for root node to store its pretty name
|
||||
Common::String _newName;
|
||||
|
||||
public:
|
||||
static const char SAF_MOUNT_POINT[];
|
||||
|
||||
/**
|
||||
* Init JNI parts related to SAF
|
||||
* Called by AndroidFilesystemFactory::AndroidFilesystemFactory()
|
||||
*/
|
||||
static void initJNI();
|
||||
|
||||
/**
|
||||
* Creates an AndroidSAFFilesystemNode given its absolute path
|
||||
*
|
||||
* @param path Path of the node
|
||||
*/
|
||||
static AndroidSAFFilesystemNode *makeFromPath(const Common::String &path);
|
||||
|
||||
/**
|
||||
* Creates an AndroidSAFFilesystemNode given its tree object
|
||||
* @param safTree SAF root in Java side. Must be a local reference and must not be used after this call.
|
||||
*
|
||||
*/
|
||||
static AndroidSAFFilesystemNode *makeFromTree(jobject safTree);
|
||||
|
||||
bool exists() const override { return (bool)_safNode; }
|
||||
Common::U32String getDisplayName() const override { return Common::U32String(getName()); }
|
||||
Common::String getName() const override;
|
||||
Common::String getPath() const override;
|
||||
bool isDirectory() const override { return _flags & DIRECTORY; }
|
||||
bool isReadable() const override { return _flags & READABLE; }
|
||||
bool isWritable() const override { return _flags & WRITABLE; }
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
|
||||
int remove() override;
|
||||
|
||||
/**
|
||||
* Removes the SAF tree.
|
||||
* Only works on the root node
|
||||
*/
|
||||
void removeTree();
|
||||
protected:
|
||||
/**
|
||||
* Creates an AndroidSAFFilesystemNode given its tree and its node
|
||||
*
|
||||
* @param safTree SAF root in Java side
|
||||
* @param safNode SAF node in Java side
|
||||
*/
|
||||
AndroidSAFFilesystemNode(const GlobalRef &safTree, jobject safNode);
|
||||
|
||||
/**
|
||||
* Creates an non-existent AndroidSAFFilesystemNode given its tree, parent node and name
|
||||
*
|
||||
* @param safTree SAF root in Java side
|
||||
* @param safParent SAF parent node in Java side
|
||||
* @param path Parent path
|
||||
* @param name Item name
|
||||
*/
|
||||
AndroidSAFFilesystemNode(const GlobalRef &safTree, jobject safParent,
|
||||
const Common::String &path, const Common::String &name);
|
||||
|
||||
/**
|
||||
* Creates an non-existent AndroidSAFFilesystemNode given its tree, parent node and name
|
||||
*
|
||||
* @param safTree SAF root in Java side
|
||||
* @param safParent SAF parent node reference in Java side
|
||||
* @param path Parent path
|
||||
* @param name Item name
|
||||
*/
|
||||
AndroidSAFFilesystemNode(const GlobalRef &safTree, const NodeRef &safParent,
|
||||
const Common::String &path, const Common::String &name);
|
||||
|
||||
void cacheData(JNIEnv *env, jobject node);
|
||||
};
|
||||
|
||||
class AddSAFFakeNode final : public AbstractFSNode, public AndroidFSNode {
|
||||
protected:
|
||||
AbstractFSNode *getChild(const Common::String &name) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
public:
|
||||
static const char SAF_ADD_FAKE_PATH[];
|
||||
|
||||
AddSAFFakeNode(bool fromPath) : _proxied(nullptr), _fromPath(fromPath) { }
|
||||
~AddSAFFakeNode() override;
|
||||
|
||||
bool exists() const override;
|
||||
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
|
||||
// I18N: This is displayed in the file browser to let the user choose a new folder for Android Storage Attached Framework
|
||||
Common::U32String getDisplayName() const override;
|
||||
Common::String getName() const override;
|
||||
Common::String getPath() const override;
|
||||
|
||||
bool isDirectory() const override { return true; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override { return nullptr; }
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override { return nullptr; }
|
||||
|
||||
bool createDirectory() override { return false; }
|
||||
int remove() override;
|
||||
|
||||
private:
|
||||
void makeProxySAF() const;
|
||||
|
||||
bool _fromPath;
|
||||
mutable AbstractFSNode *_proxied;
|
||||
};
|
||||
#endif
|
||||
76
backends/fs/atari/atari-fs-factory.cpp
Normal file
76
backends/fs/atari/atari-fs-factory.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Disable symbol overrides so that we can use system headers.
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/atari/atari-fs-factory.h"
|
||||
#include "backends/fs/atari/atari-fs.h"
|
||||
|
||||
#include <mint/osbind.h>
|
||||
#include <unistd.h> // getcwd
|
||||
|
||||
AtariFilesystemFactory::AtariFilesystemFactory() {
|
||||
_fileHashMap["cryomni3.dat"] = "cryomni3d.dat";
|
||||
_fileHashMap["neverhoo.dat"] = "neverhood.dat";
|
||||
_fileHashMap["supernov.dat"] = "supernova.dat";
|
||||
_fileHashMap["teenagen.dat"] = "teenagent.dat";
|
||||
|
||||
uint32 drvMap = Drvmap();
|
||||
for (int i = 0; i < 26; i++) {
|
||||
if (drvMap & 1) {
|
||||
char driveRoot[] = "A:";
|
||||
driveRoot[0] += i;
|
||||
|
||||
addDrive(driveRoot);
|
||||
}
|
||||
|
||||
drvMap >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *AtariFilesystemFactory::makeRootFileNode() const {
|
||||
return new AtariFilesystemNode(_config, _fileHashMap);
|
||||
}
|
||||
|
||||
AbstractFSNode *AtariFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
if (getcwd(buf, MAXPATHLEN) != NULL) {
|
||||
if (buf[0] == '/') {
|
||||
// de-mintlib'ize the path
|
||||
if (buf[1] == 'd' && buf[2] == 'e' && buf[3] == 'v') {
|
||||
// /dev/<drive>/<path> -> /<drive>/<path>
|
||||
strcpy(buf, &buf[4]);
|
||||
}
|
||||
// /<drive>/<path> -> <DRIVE>:/<path>
|
||||
buf[0] = toupper(buf[1]);
|
||||
buf[1] = ':';
|
||||
}
|
||||
return new AtariFilesystemNode(buf, _config, _fileHashMap);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *AtariFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
return new AtariFilesystemNode(path, _config, _fileHashMap);
|
||||
}
|
||||
45
backends/fs/atari/atari-fs-factory.h
Normal file
45
backends/fs/atari/atari-fs-factory.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ATARI_FILESYSTEM_FACTORY_H
|
||||
#define ATARI_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/posix-drives/posix-drives-fs-factory.h"
|
||||
#include "backends/fs/atari/atari-fs.h"
|
||||
|
||||
/**
|
||||
* Creates AtariFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class AtariFilesystemFactory final : public DrivesPOSIXFilesystemFactory {
|
||||
public:
|
||||
AtariFilesystemFactory();
|
||||
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
private:
|
||||
AtariFilesystemNode::FileHashMap _fileHashMap;
|
||||
};
|
||||
|
||||
#endif /*ATARI_FILESYSTEM_FACTORY_H*/
|
||||
36
backends/fs/atari/atari-fs.cpp
Normal file
36
backends/fs/atari/atari-fs.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Disable symbol overrides so that we can use system headers.
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/atari/atari-fs.h"
|
||||
|
||||
void AtariFilesystemNode::setFlags() {
|
||||
DrivePOSIXFilesystemNode::setFlags();
|
||||
|
||||
if (!_displayNameChecked) {
|
||||
if (_fileHashMap.contains(_displayName))
|
||||
_displayName = _fileHashMap[_displayName];
|
||||
|
||||
_displayNameChecked = true;
|
||||
}
|
||||
}
|
||||
64
backends/fs/atari/atari-fs.h
Normal file
64
backends/fs/atari/atari-fs.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ATARI_FILESYSTEM_H
|
||||
#define ATARI_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/posix-drives/posix-drives-fs.h"
|
||||
|
||||
#include "common/hash-str.h"
|
||||
#include "common/hashmap.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on DrivePOSIX with translation to 8+3 filenames.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class AtariFilesystemNode final : public DrivePOSIXFilesystemNode {
|
||||
protected:
|
||||
AbstractFSNode *makeNode() const override {
|
||||
return new AtariFilesystemNode(_config, _fileHashMap);
|
||||
}
|
||||
AbstractFSNode *makeNode(const Common::String &path) const override {
|
||||
return new AtariFilesystemNode(path, _config, _fileHashMap);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Common::HashMap<Common::String, Common::String, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileHashMap;
|
||||
|
||||
AtariFilesystemNode(const Config &config, const FileHashMap &fileHashMap)
|
||||
: DrivePOSIXFilesystemNode(config)
|
||||
, _fileHashMap(fileHashMap) {
|
||||
}
|
||||
AtariFilesystemNode(const Common::String &path, const Config &config, const FileHashMap &fileHashMap)
|
||||
: DrivePOSIXFilesystemNode(path, config)
|
||||
, _fileHashMap(fileHashMap) {
|
||||
}
|
||||
|
||||
protected:
|
||||
void setFlags() override;
|
||||
|
||||
private:
|
||||
const FileHashMap &_fileHashMap;
|
||||
bool _displayNameChecked = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
87
backends/fs/chroot/chroot-fs-factory.cpp
Normal file
87
backends/fs/chroot/chroot-fs-factory.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(POSIX)
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_random
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_srandom
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backends/fs/chroot/chroot-fs-factory.h"
|
||||
#include "backends/fs/chroot/chroot-fs.h"
|
||||
|
||||
ChRootFilesystemFactory::ChRootFilesystemFactory(const Common::String &root)
|
||||
: _root(root) {
|
||||
}
|
||||
|
||||
AbstractFSNode *ChRootFilesystemFactory::makeRootFileNode() const {
|
||||
return new ChRootFilesystemNode(_root, "/");
|
||||
}
|
||||
|
||||
AbstractFSNode *ChRootFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
if (getcwd(buf, MAXPATHLEN) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Common::String curPath(buf);
|
||||
if (curPath.hasPrefix(_root + Common::String("/"))) {
|
||||
return new ChRootFilesystemNode(_root, buf + _root.size());
|
||||
}
|
||||
for (auto it = _virtualDrives.begin() ; it != _virtualDrives.end() ; ++it) {
|
||||
if (curPath.hasPrefix(it->_value + Common::String("/")))
|
||||
return new ChRootFilesystemNode(it->_value, buf + it->_value.size(), it->_key);
|
||||
}
|
||||
|
||||
return new ChRootFilesystemNode(_root, "/");
|
||||
}
|
||||
|
||||
AbstractFSNode *ChRootFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
size_t driveEnd = path.findFirstOf('/');
|
||||
if (driveEnd != Common::String::npos && driveEnd > 0) {
|
||||
auto it = _virtualDrives.find(path.substr(0, driveEnd));
|
||||
if (it != _virtualDrives.end())
|
||||
return new ChRootFilesystemNode(it->_value, path.substr(driveEnd), it->_key);
|
||||
}
|
||||
return new ChRootFilesystemNode(_root, path);
|
||||
}
|
||||
|
||||
void ChRootFilesystemFactory::addVirtualDrive(const Common::String &name, const Common::String &path) {
|
||||
_virtualDrives[name] = path;
|
||||
}
|
||||
|
||||
Common::String ChRootFilesystemFactory::getSystemFullPath(const Common::String& path) const {
|
||||
size_t driveEnd = path.findFirstOf('/');
|
||||
if (driveEnd != Common::String::npos && driveEnd > 0) {
|
||||
auto it = _virtualDrives.find(path.substr(0, driveEnd));
|
||||
if (it != _virtualDrives.end())
|
||||
return it->_value + path.substr(driveEnd);
|
||||
}
|
||||
return _root + path;
|
||||
}
|
||||
|
||||
#endif
|
||||
50
backends/fs/chroot/chroot-fs-factory.h
Normal file
50
backends/fs/chroot/chroot-fs-factory.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H
|
||||
#define BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* FIXME: Warning, using this factory in your backend may silently break some
|
||||
* features. Instances are, for example, the FluidSynth code, and the POSIX
|
||||
* plugin code.
|
||||
*/
|
||||
class ChRootFilesystemFactory final : public FilesystemFactory {
|
||||
public:
|
||||
explicit ChRootFilesystemFactory(const Common::String &root);
|
||||
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
void addVirtualDrive(const Common::String &name, const Common::String &path);
|
||||
|
||||
Common::String getSystemFullPath(const Common::String& path) const override;
|
||||
|
||||
private:
|
||||
const Common::String _root;
|
||||
Common::StringMap _virtualDrives;
|
||||
};
|
||||
|
||||
#endif /* BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H */
|
||||
124
backends/fs/chroot/chroot-fs.cpp
Normal file
124
backends/fs/chroot/chroot-fs.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(POSIX)
|
||||
|
||||
#include "backends/fs/chroot/chroot-fs.h"
|
||||
|
||||
ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *node, const Common::String &drive) {
|
||||
_root = Common::normalizePath(root, '/');
|
||||
_drive = drive;
|
||||
_realNode = node;
|
||||
}
|
||||
|
||||
ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, const Common::String &path, const Common::String &drive) {
|
||||
_root = Common::normalizePath(root, '/');
|
||||
_drive = drive;
|
||||
_realNode = new POSIXFilesystemNode(addPathComponent(root, path));
|
||||
}
|
||||
|
||||
ChRootFilesystemNode::~ChRootFilesystemNode() {
|
||||
delete _realNode;
|
||||
}
|
||||
|
||||
bool ChRootFilesystemNode::exists() const {
|
||||
return _realNode->exists();
|
||||
}
|
||||
|
||||
Common::U32String ChRootFilesystemNode::getDisplayName() const {
|
||||
return _realNode->getDisplayName();
|
||||
}
|
||||
|
||||
Common::String ChRootFilesystemNode::getName() const {
|
||||
return _realNode->getName();
|
||||
}
|
||||
|
||||
Common::String ChRootFilesystemNode::getPath() const {
|
||||
Common::String path = _realNode->getPath();
|
||||
if (path.size() > _root.size())
|
||||
return _drive + Common::String(path.c_str() + _root.size());
|
||||
return _drive + "/";
|
||||
}
|
||||
|
||||
bool ChRootFilesystemNode::isDirectory() const {
|
||||
return _realNode->isDirectory();
|
||||
}
|
||||
|
||||
bool ChRootFilesystemNode::isReadable() const {
|
||||
return _realNode->isReadable();
|
||||
}
|
||||
|
||||
bool ChRootFilesystemNode::isWritable() const {
|
||||
// Assume virtual drives are not writable
|
||||
if (!_drive.empty())
|
||||
return false;
|
||||
return _realNode->isWritable();
|
||||
}
|
||||
|
||||
AbstractFSNode *ChRootFilesystemNode::getChild(const Common::String &n) const {
|
||||
return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getChild(n), _drive);
|
||||
}
|
||||
|
||||
bool ChRootFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const {
|
||||
AbstractFSList tmp;
|
||||
if (!_realNode->getChildren(tmp, mode, hidden)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (AbstractFSList::iterator i=tmp.begin(); i!=tmp.end(); ++i) {
|
||||
list.push_back(new ChRootFilesystemNode(_root, (POSIXFilesystemNode *) *i, _drive));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *ChRootFilesystemNode::getParent() const {
|
||||
if (getPath() == _drive + "/")
|
||||
return nullptr;
|
||||
return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getParent(), _drive);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *ChRootFilesystemNode::createReadStream() {
|
||||
return _realNode->createReadStream();
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *ChRootFilesystemNode::createWriteStream(bool atomic) {
|
||||
return _realNode->createWriteStream(atomic);
|
||||
}
|
||||
|
||||
bool ChRootFilesystemNode::createDirectory() {
|
||||
return _realNode->createDirectory();
|
||||
}
|
||||
|
||||
Common::String ChRootFilesystemNode::addPathComponent(const Common::String &path, const Common::String &component) {
|
||||
const char sep = '/';
|
||||
if (path.lastChar() == sep && component.firstChar() == sep) {
|
||||
return Common::String::format("%s%s", path.c_str(), component.c_str() + 1);
|
||||
}
|
||||
|
||||
if (path.lastChar() == sep || component.firstChar() == sep) {
|
||||
return Common::String::format("%s%s", path.c_str(), component.c_str());
|
||||
}
|
||||
|
||||
return Common::String::format("%s%c%s", path.c_str(), sep, component.c_str());
|
||||
}
|
||||
|
||||
#endif
|
||||
58
backends/fs/chroot/chroot-fs.h
Normal file
58
backends/fs/chroot/chroot-fs.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_FS_CHROOT_CHROOT_FS_H
|
||||
#define BACKENDS_FS_CHROOT_CHROOT_FS_H
|
||||
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
|
||||
class ChRootFilesystemNode final : public AbstractFSNode {
|
||||
Common::String _root;
|
||||
Common::String _drive;
|
||||
POSIXFilesystemNode *_realNode;
|
||||
|
||||
ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *, const Common::String &drive);
|
||||
|
||||
public:
|
||||
ChRootFilesystemNode(const Common::String &root, const Common::String &path, const Common::String &drive = Common::String());
|
||||
~ChRootFilesystemNode() override;
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override;
|
||||
Common::String getName() const override;
|
||||
Common::String getPath() const override;
|
||||
bool isDirectory() const override;
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
|
||||
private:
|
||||
static Common::String addPathComponent(const Common::String &path, const Common::String &component);
|
||||
};
|
||||
|
||||
#endif /* BACKENDS_FS_CHROOT_CHROOT_FS_H */
|
||||
43
backends/fs/devoptab/devoptab-fs-factory.cpp
Normal file
43
backends/fs/devoptab/devoptab-fs-factory.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__DS__)
|
||||
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/devoptab/devoptab-fs-factory.h"
|
||||
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
DevoptabFilesystemFactory::DevoptabFilesystemFactory() {
|
||||
// skip in, out and err
|
||||
for (uint8 i = 3; i < STD_MAX; ++i) {
|
||||
const devoptab_t *dt = devoptab_list[i];
|
||||
|
||||
if (!dt || !dt->name || !dt->open_r || !dt->diropen_r)
|
||||
continue;
|
||||
|
||||
addDrive(Common::String(dt->name) + ":/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
37
backends/fs/devoptab/devoptab-fs-factory.h
Normal file
37
backends/fs/devoptab/devoptab-fs-factory.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DEVOPTAB_FILESYSTEM_FACTORY_H
|
||||
#define DEVOPTAB_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/posix-drives/posix-drives-fs-factory.h"
|
||||
|
||||
/**
|
||||
* A FilesystemFactory implementation for filesystems with a special
|
||||
* top-level directory listing all registered devoptab devices but
|
||||
* that otherwise implement the POSIX APIs.
|
||||
*/
|
||||
class DevoptabFilesystemFactory final : public DrivesPOSIXFilesystemFactory {
|
||||
public:
|
||||
DevoptabFilesystemFactory();
|
||||
};
|
||||
|
||||
#endif
|
||||
205
backends/fs/emscripten/cloud-fs.cpp
Normal file
205
backends/fs/emscripten/cloud-fs.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
|
||||
#include "backends/fs/emscripten/cloud-fs.h"
|
||||
#include "backends/cloud/downloadrequest.h"
|
||||
#include "backends/fs/fs-factory.h"
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
Common::HashMap<Common::String, AbstractFSList> CloudFilesystemNode::_cloudFolders = Common::HashMap<Common::String, AbstractFSList>();
|
||||
|
||||
CloudFilesystemNode::CloudFilesystemNode(const Common::String &p) : _isDirectory(false), _isValid(false), _path(p), _storageFileId(nullptr) {
|
||||
debug(5, "CloudFilesystemNode::CloudFilesystemNode(Common::String %s)", p.c_str());
|
||||
assert(p.size() > 0);
|
||||
|
||||
// Normalize the path (that is, remove unneeded slashes etc.)
|
||||
_path = Common::normalizePath(_path, '/');
|
||||
_displayName = Common::lastPathComponent(_path, '/');
|
||||
if (_path == CLOUD_FS_PATH) { // need special case for handling the root of the cloud-filesystem
|
||||
_displayName = "[" + Common::lastPathComponent(_path, '/') + "]";
|
||||
_isDirectory = true;
|
||||
_isValid = true;
|
||||
return;
|
||||
} else { // we need to peek in the parent folder to see if file exists and if it's a directory
|
||||
AbstractFSNode *parent = getParent();
|
||||
AbstractFSList tmp = AbstractFSList();
|
||||
parent->getChildren(tmp, Common::FSNode::kListAll, true);
|
||||
for (AbstractFSList::iterator i = tmp.begin(); i != tmp.end(); ++i) {
|
||||
CloudFilesystemNode *child = (CloudFilesystemNode *)*i;
|
||||
if (child->getPath() == _path) {
|
||||
_isDirectory = child->isDirectory();
|
||||
_isValid = true;
|
||||
_storageFileId = child->_storageFileId;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *CloudFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(!_path.empty());
|
||||
assert(_isDirectory);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
// We assume here that _path is already normalized (hence don't bother to call
|
||||
// Common::normalizePath on the final path).
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return makeNode(newPath);
|
||||
}
|
||||
|
||||
void CloudFilesystemNode::directoryListedCallback(const Cloud::Storage::ListDirectoryResponse &response) {
|
||||
debug(5, "CloudFilesystemNode::directoryListedCallback %s", _path.c_str());
|
||||
Common::Array<Cloud::StorageFile> storageFiles = response.value;
|
||||
AbstractFSList *dirList = new AbstractFSList();
|
||||
|
||||
for (Common::Array<Cloud::StorageFile>::iterator i = storageFiles.begin(); i != storageFiles.end(); ++i) {
|
||||
Cloud::StorageFile storageFile = *i;
|
||||
CloudFilesystemNode *file_node = new CloudFilesystemNode();
|
||||
file_node->_isDirectory = storageFile.isDirectory();
|
||||
file_node->_path = _path + "/" + storageFile.name();
|
||||
file_node->_isValid = true;
|
||||
file_node->_displayName = "" + storageFile.name();
|
||||
file_node->_storageFileId = storageFile.id();
|
||||
dirList->push_back(file_node);
|
||||
}
|
||||
_cloudFolders[_path] = *dirList;
|
||||
}
|
||||
|
||||
void CloudFilesystemNode::directoryListedErrorCallback(const Networking::ErrorResponse &_error) {
|
||||
// _workingRequest = nullptr; // TODO: HANDLE THIS SOMEWHERE
|
||||
error("Response %ld: %s", _error.httpResponseCode, _error.response.c_str());
|
||||
}
|
||||
|
||||
void CloudFilesystemNode::fileDownloadedCallback(const Cloud::Storage::BoolResponse &response) {
|
||||
// _workingRequest = nullptr; // TODO: HANDLE THIS SOMEWHERE
|
||||
debug(5, "CloudFilesystemNode::fileDownloadedCallback %s", _path.c_str());
|
||||
}
|
||||
|
||||
void CloudFilesystemNode::fileDownloadedErrorCallback(const Networking::ErrorResponse &_error) {
|
||||
// _workingRequest = nullptr; // TODO: HANDLE THIS SOMEWHERE
|
||||
error("Response %ld: %s", _error.httpResponseCode, _error.response.c_str());
|
||||
}
|
||||
|
||||
bool CloudFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
if (!_cloudFolders.contains(_path)) {
|
||||
debug(5, "CloudFilesystemNode::getChildren Fetching Children: %s", _path.c_str());
|
||||
Common::String _cloud_path = _path.substr(sizeof(CLOUD_FS_PATH), _path.size() - sizeof(CLOUD_FS_PATH));
|
||||
|
||||
CloudMan.listDirectory(
|
||||
_cloud_path,
|
||||
new Common::Callback<CloudFilesystemNode, const Cloud::Storage::ListDirectoryResponse &>((CloudFilesystemNode *)this, &CloudFilesystemNode::directoryListedCallback),
|
||||
new Common::Callback<CloudFilesystemNode, const Networking::ErrorResponse &>((CloudFilesystemNode *)this, &CloudFilesystemNode::directoryListedErrorCallback),
|
||||
false);
|
||||
|
||||
while (!_cloudFolders.contains(_path)) {
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
debug(5, "CloudFilesystemNode::getChildren %s size %u", _path.c_str(), _cloudFolders[_path].size());
|
||||
}
|
||||
|
||||
for (AbstractFSList::iterator i = _cloudFolders[_path].begin(); i != _cloudFolders[_path].end(); ++i) {
|
||||
// TODO: Respect mode and hidden getChildren parameters
|
||||
CloudFilesystemNode *node = (CloudFilesystemNode *)*i;
|
||||
// we need to copy node here as FSNode will take ownership of the pointer and destroy it after use
|
||||
myList.push_back(new CloudFilesystemNode(*node));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *CloudFilesystemNode::getParent() const {
|
||||
if (_path == "/")
|
||||
return 0; // The filesystem root has no parent
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = start + _path.size();
|
||||
|
||||
// Strip of the last component. We make use of the fact that at this
|
||||
// point, _path is guaranteed to be normalized
|
||||
while (end > start && *(end - 1) != '/')
|
||||
end--;
|
||||
|
||||
if (end == start) {
|
||||
// This only happens if we were called with a relative path, for which
|
||||
// there simply is no parent.
|
||||
// TODO: We could also resolve this by assuming that the parent is the
|
||||
// current working directory, and returning a node referring to that.
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::String _parent_path = Common::normalizePath(Common::String(start, end), '/');
|
||||
FilesystemFactory *factory = g_system->getFilesystemFactory();
|
||||
return factory->makeFileNodePath(_parent_path);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *CloudFilesystemNode::createReadStream() {
|
||||
debug(5, "CloudFilesystemNode::createReadStream() %s", _path.c_str());
|
||||
Common::String fsCachePath = Common::normalizePath("/.cache/" + _path, '/');
|
||||
POSIXFilesystemNode *cacheFile = new POSIXFilesystemNode(fsCachePath);
|
||||
if (!cacheFile->exists()) {
|
||||
Cloud::Storage *_storage = CloudMan.getCurrentStorage();
|
||||
Networking::Request *_workingRequest = _storage->downloadById(
|
||||
_storageFileId,
|
||||
Common::Path(fsCachePath),
|
||||
new Common::Callback<CloudFilesystemNode, const Cloud::Storage::BoolResponse &>(this, &CloudFilesystemNode::fileDownloadedCallback),
|
||||
new Common::Callback<CloudFilesystemNode, const Networking::ErrorResponse &>(this, &CloudFilesystemNode::fileDownloadedErrorCallback));
|
||||
while (_workingRequest->state() != Networking::RequestState::FINISHED) {
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
debug(5, "CloudFilesystemNode::createReadStream() file written %s", fsCachePath.c_str());
|
||||
}
|
||||
return PosixIoStream::makeFromPath(fsCachePath, StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *CloudFilesystemNode::createWriteStream(bool atomic) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CloudFilesystemNode::createDirectory() {
|
||||
return false;
|
||||
}
|
||||
bool CloudFilesystemNode::exists() const {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
bool CloudFilesystemNode::isReadable() const {
|
||||
return exists();
|
||||
}
|
||||
|
||||
bool CloudFilesystemNode::isWritable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // #if defined(EMSCRIPTEN)
|
||||
95
backends/fs/emscripten/cloud-fs.h
Normal file
95
backends/fs/emscripten/cloud-fs.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CLOUD_FILESYSTEM_H
|
||||
#define CLOUD_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
#ifdef USE_CLOUD
|
||||
#include "backends/cloud/cloudmanager.h"
|
||||
#include "backends/cloud/storage.h"
|
||||
#include "backends/cloud/storagefile.h"
|
||||
#include "backends/networking/http/connectionmanager.h"
|
||||
#include "backends/networking/http/httpjsonrequest.h"
|
||||
#include "backends/networking/http/request.h"
|
||||
#endif
|
||||
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on POSIX.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class CloudFilesystemNode : public AbstractFSNode {
|
||||
#define CLOUD_FS_PATH "/cloud"
|
||||
protected:
|
||||
static Common::HashMap<Common::String, AbstractFSList> _cloudFolders;
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
Common::String _storageFileId;
|
||||
bool _isDirectory;
|
||||
bool _isValid;
|
||||
|
||||
/**
|
||||
* Plain constructor, for internal use only (hence protected).
|
||||
*/
|
||||
CloudFilesystemNode() : _isDirectory(false), _isValid(false), _storageFileId(nullptr) {}
|
||||
|
||||
virtual AbstractFSNode *makeNode(const Common::String &path) const {
|
||||
return new CloudFilesystemNode(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callbacks for network calls (file download and directory listing)
|
||||
*/
|
||||
void directoryListedCallback(const Cloud::Storage::ListDirectoryResponse &response);
|
||||
void directoryListedErrorCallback(const Networking::ErrorResponse &error);
|
||||
void fileDownloadedCallback(const Cloud::Storage::BoolResponse &response);
|
||||
void fileDownloadedErrorCallback(const Networking::ErrorResponse &error);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a CloudFilesystemNode for a given path.
|
||||
*
|
||||
* @param path the path the new node should point to.
|
||||
*/
|
||||
CloudFilesystemNode(const Common::String &path);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
95
backends/fs/emscripten/emscripten-fs-factory.cpp
Normal file
95
backends/fs/emscripten/emscripten-fs-factory.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#include "backends/fs/emscripten/emscripten-fs-factory.h"
|
||||
#include "backends/fs/emscripten/emscripten-posix-fs.h"
|
||||
#include "backends/fs/emscripten/http-fs.h"
|
||||
#include "common/debug.h"
|
||||
#ifdef USE_CLOUD
|
||||
#include "backends/fs/emscripten/cloud-fs.h"
|
||||
#endif
|
||||
|
||||
#include <emscripten.h>
|
||||
|
||||
EM_ASYNC_JS(void, _initSettings, (const char *pathPtr), {
|
||||
try {
|
||||
const path = UTF8ToString(pathPtr);
|
||||
const settingsPath = path + "/scummvm.ini";
|
||||
|
||||
// Mount the filesystem
|
||||
FS.mount(IDBFS, { autoPersist: true }, path);
|
||||
|
||||
// Sync the filesystem
|
||||
await new Promise((resolve, reject) => {
|
||||
FS.syncfs(true, (err) => err ? reject(err) : resolve());
|
||||
});
|
||||
|
||||
// Check if settings file exists and download if needed
|
||||
if (!FS.analyzePath(settingsPath).exists) {
|
||||
const response = await fetch("scummvm.ini");
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
FS.writeFile(settingsPath, text);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error initializing files:", err);
|
||||
alert("Error initializing files: " + err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
|
||||
EmscriptenFilesystemFactory::EmscriptenFilesystemFactory() {
|
||||
_initSettings(getenv("HOME"));
|
||||
_httpNodes = new Common::HashMap<Common::String, HTTPFilesystemNode *>();
|
||||
}
|
||||
|
||||
AbstractFSNode *EmscriptenFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
// getcwd() defaults to root on emscripten and ScummVM doesn't use setcwd()
|
||||
return makeRootFileNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *EmscriptenFilesystemFactory::makeRootFileNode() const {
|
||||
return new EmscriptenPOSIXFilesystemNode("/");
|
||||
}
|
||||
|
||||
AbstractFSNode *EmscriptenFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
debug(5, "EmscriptenFilesystemFactory::makeFileNodePath(%s)", path.c_str());
|
||||
assert(!path.empty());
|
||||
if (path.hasPrefix(DATA_PATH)) {
|
||||
if (!_httpNodes->contains(path)) {
|
||||
// finding a node by path requires a http request to the server, so we cache the nodes
|
||||
_httpNodes->setVal(path, new HTTPFilesystemNode(path));
|
||||
}
|
||||
return new HTTPFilesystemNode(*(_httpNodes->getVal(path)));
|
||||
#ifdef USE_CLOUD
|
||||
} else if (path.hasPrefix(CLOUD_FS_PATH) && CloudMan.isStorageEnabled()) {
|
||||
return new CloudFilesystemNode(path);
|
||||
#endif
|
||||
} else {
|
||||
return new EmscriptenPOSIXFilesystemNode(path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
45
backends/fs/emscripten/emscripten-fs-factory.h
Normal file
45
backends/fs/emscripten/emscripten-fs-factory.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EMSCRIPTEN_FILESYSTEM_FACTORY_H
|
||||
#define EMSCRIPTEN_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/emscripten/http-fs.h"
|
||||
#include "backends/fs/fs-factory.h"
|
||||
#include "common/singleton.h"
|
||||
|
||||
/**
|
||||
* Creates POSIXFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class EmscriptenFilesystemFactory : public FilesystemFactory {
|
||||
public:
|
||||
EmscriptenFilesystemFactory();
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
private:
|
||||
Common::HashMap<Common::String, HTTPFilesystemNode *> *_httpNodes;
|
||||
};
|
||||
|
||||
#endif /*EMSCRIPTEN_FILESYSTEM_FACTORY_H*/
|
||||
58
backends/fs/emscripten/emscripten-posix-fs.cpp
Normal file
58
backends/fs/emscripten/emscripten-posix-fs.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
|
||||
#include <stdio.h>
|
||||
|
||||
#include "backends/fs/emscripten/emscripten-fs-factory.h"
|
||||
#include "backends/fs/emscripten/emscripten-posix-fs.h"
|
||||
#include "backends/fs/emscripten/http-fs.h"
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#ifdef USE_CLOUD
|
||||
#include "backends/cloud/cloudmanager.h"
|
||||
#include "backends/fs/emscripten/cloud-fs.h"
|
||||
#endif
|
||||
|
||||
AbstractFSNode *EmscriptenPOSIXFilesystemNode::makeNode(const Common::String &path) const {
|
||||
return g_system->getFilesystemFactory()->makeFileNodePath(path);
|
||||
}
|
||||
|
||||
EmscriptenPOSIXFilesystemNode::EmscriptenPOSIXFilesystemNode(const Common::String &path) : POSIXFilesystemNode(path) {}
|
||||
EmscriptenPOSIXFilesystemNode::EmscriptenPOSIXFilesystemNode() : POSIXFilesystemNode() {}
|
||||
|
||||
bool EmscriptenPOSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
|
||||
if (_path == "/") {
|
||||
HTTPFilesystemNode *data_entry = new HTTPFilesystemNode(DATA_PATH);
|
||||
myList.push_back(data_entry);
|
||||
|
||||
#ifdef USE_CLOUD
|
||||
if (CloudMan.isStorageEnabled()) {
|
||||
CloudFilesystemNode *cloud_entry = new CloudFilesystemNode(CLOUD_FS_PATH);
|
||||
myList.push_back(cloud_entry);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return POSIXFilesystemNode::getChildren(myList, mode, hidden);
|
||||
}
|
||||
36
backends/fs/emscripten/emscripten-posix-fs.h
Normal file
36
backends/fs/emscripten/emscripten-posix-fs.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef EMSCRIPTEN_FILESYSTEM_H
|
||||
#define EMSCRIPTEN_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
|
||||
class EmscriptenPOSIXFilesystemNode : public POSIXFilesystemNode {
|
||||
|
||||
public:
|
||||
EmscriptenPOSIXFilesystemNode(const Common::String &path);
|
||||
EmscriptenPOSIXFilesystemNode();
|
||||
bool getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *makeNode(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
272
backends/fs/emscripten/http-fs.cpp
Normal file
272
backends/fs/emscripten/http-fs.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
// Disable symbol overrides so that we can use system headers.
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
|
||||
#include "backends/fs/emscripten/http-fs.h"
|
||||
#include "backends/cloud/downloadrequest.h"
|
||||
#include "backends/fs/fs-factory.h"
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/formats/json.h"
|
||||
#include <emscripten.h>
|
||||
|
||||
HTTPFilesystemNode::HTTPFilesystemNode(const Common::String &path, const Common::String &displayName, const Common::String &baseUrl, bool isValid, bool isDirectory, int size) : _path(path), _displayName(displayName), _url(baseUrl), _isValid(isValid), _isDirectory(isDirectory), _size(size) {
|
||||
debug(5, "HTTPFilesystemNode::HTTPFilesystemNode(%s, %s)", path.c_str(), baseUrl.c_str());
|
||||
assert(path.size() > 0);
|
||||
assert(isDirectory || size >= 0 || !isValid);
|
||||
_children = new AbstractFSList();
|
||||
}
|
||||
|
||||
HTTPFilesystemNode::HTTPFilesystemNode(const Common::String &p) : _path(p), _isValid(false), _isDirectory(false), _size(-1) {
|
||||
debug(5, "HTTPFilesystemNode::HTTPFilesystemNode(%s)", p.c_str());
|
||||
assert(p.size() > 0);
|
||||
_children = new AbstractFSList();
|
||||
|
||||
// Normalize the path (that is, remove unneeded slashes etc.)
|
||||
_path = Common::normalizePath(_path, '/');
|
||||
_displayName = Common::lastPathComponent(_path, '/');
|
||||
if (_path == DATA_PATH) { // need special case for handling the root of the http-filesystem
|
||||
_isDirectory = true;
|
||||
_isValid = true;
|
||||
_url = _path;
|
||||
} else { // we need to peek in the parent folder to see if the node exists and if it's a directory
|
||||
AbstractFSNode *parent = getParent();
|
||||
AbstractFSList tmp = AbstractFSList();
|
||||
parent->getChildren(tmp, Common::FSNode::kListAll, true);
|
||||
for (AbstractFSList::iterator i = tmp.begin(); i != tmp.end(); ++i) {
|
||||
AbstractFSNode *child = *i;
|
||||
if (child->getPath() == _path) {
|
||||
_isDirectory = child->isDirectory();
|
||||
_isValid = true;
|
||||
_url = ((HTTPFilesystemNode *)child)->_url;
|
||||
_size = ((HTTPFilesystemNode *)child)->_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(_isDirectory || _size >= 0 || !_isValid);
|
||||
debug(5, "HTTPFilesystemNode::HTTPFilesystemNode(%s) - %s isValid %s isDirectory %s", p.c_str(), _url.c_str(), _isValid ? "True" : "false", _isDirectory ? "True" : "false");
|
||||
}
|
||||
|
||||
AbstractFSNode *HTTPFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(!_path.empty());
|
||||
assert(_isDirectory);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
// We assume here that _path is already normalized (hence don't bother to call
|
||||
// Common::normalizePath on the final path).
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return makeNode(newPath);
|
||||
}
|
||||
|
||||
EM_ASYNC_JS(char *, _httpFsFetchIndex, (const char *url), {
|
||||
globalThis['httpFsIndexCache'] = globalThis['httpFsIndexCache'] || {};
|
||||
returnString = "";
|
||||
url = UTF8ToString(url);
|
||||
console.debug("Downloading %s", url);
|
||||
if (globalThis['httpFsIndexCache'][url]) {
|
||||
console.debug("Cache hit for %s", url);
|
||||
returnString = globalThis['httpFsIndexCache'][url];
|
||||
} else {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (response.ok) {
|
||||
returnString = await response.text();
|
||||
globalThis['httpFsIndexCache'][url] = returnString;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
var size = lengthBytesUTF8(returnString) + 1;
|
||||
var ret = Module._malloc(size);
|
||||
stringToUTF8Array(returnString, HEAP8, ret, size);
|
||||
return ret;
|
||||
});
|
||||
|
||||
EM_ASYNC_JS(bool, _httpFsFetchFile, (const char *url, byte *dataPtr, int dataSize), {
|
||||
returnBytes = new Uint8Array();
|
||||
url = UTF8ToString(url);
|
||||
console.debug("Downloading %s", url);
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (response.ok) {
|
||||
returnBytes = await response.bytes();
|
||||
if (returnBytes.length == dataSize) {
|
||||
Module.writeArrayToMemory(returnBytes, dataPtr);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
console.error("HTTPFilesystemNode::_httpFsFetchFile: %s", response.statusText);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
bool HTTPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
if (!_isValid) {
|
||||
return false;
|
||||
}
|
||||
assert(_isDirectory);
|
||||
if (_children->size() == 0) {
|
||||
// if we don't have a children list yet, we need to fetch it from the server
|
||||
debug(5, "HTTPFilesystemNode::getChildren Fetching Children: %s at %s", _path.c_str(), _url.c_str());
|
||||
Common::String url = _url + "/index.json";
|
||||
char *response = _httpFsFetchIndex(url.c_str());
|
||||
if (strcmp(response, "") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::JSONObject jsonObj = Common::JSON::parse(response)->asObject();
|
||||
// add dummy element so we know that we fetched the list
|
||||
_children->push_back(new HTTPFilesystemNode(_path, ".", _url, false, false, 0));
|
||||
for (typename Common::HashMap<Common::String, Common::JSONValue *>::iterator i = jsonObj.begin(); i != jsonObj.end(); ++i) {
|
||||
Common::String name = i->_key;
|
||||
bool isDir = false;
|
||||
int size = -1;
|
||||
Common::String baseUrl = _url + "/" + name;
|
||||
|
||||
if (i->_value->isObject()) {
|
||||
isDir = true;
|
||||
if (i->_value->asObject().contains("baseUrl")) {
|
||||
debug(5, "HTTPFilesystemNode::directoryListedCallback - Directory with baseUrl %s", name.c_str());
|
||||
baseUrl = i->_value->asObject()["baseUrl"]->asString();
|
||||
}
|
||||
} else if (i->_value->isIntegerNumber()) {
|
||||
size = i->_value->asIntegerNumber();
|
||||
}
|
||||
HTTPFilesystemNode *file_node = new HTTPFilesystemNode(_path + "/" + name, name, baseUrl, true, isDir, size);
|
||||
_children->push_back(file_node);
|
||||
}
|
||||
}
|
||||
for (AbstractFSList::iterator i = (*_children).begin(); i != (*_children).end(); ++i) {
|
||||
HTTPFilesystemNode *node = (HTTPFilesystemNode *)*i;
|
||||
|
||||
if (node->_isValid && (mode == Common::FSNode::kListAll ||
|
||||
(mode == Common::FSNode::kListFilesOnly && !node->_isDirectory) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && node->_isDirectory))) {
|
||||
// we need to copy node here as FSNode will take ownership of the pointer and destroy it after use
|
||||
HTTPFilesystemNode *file_node = new HTTPFilesystemNode(*node);
|
||||
myList.push_back(file_node);
|
||||
} else {
|
||||
debug(5, "HTTPFilesystemNode::getChildren - skipping %s", node->_path.c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *HTTPFilesystemNode::getParent() const {
|
||||
if (_path == "/")
|
||||
return 0; // The filesystem root has no parent
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = start + _path.size();
|
||||
|
||||
// Strip of the last component. We make use of the fact that at this
|
||||
// point, _path is guaranteed to be normalized
|
||||
while (end > start && *(end - 1) != '/')
|
||||
end--;
|
||||
|
||||
if (end == start) {
|
||||
// This only happens if we were called with a relative path, for which
|
||||
// there simply is no parent.
|
||||
// TODO: We could also resolve this by assuming that the parent is the
|
||||
// current working directory, and returning a node referring to that.
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::String _parent_path = Common::normalizePath(Common::String(start, end), '/');
|
||||
FilesystemFactory *factory = g_system->getFilesystemFactory();
|
||||
return factory->makeFileNodePath(_parent_path);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *HTTPFilesystemNode::createReadStream() {
|
||||
debug(5, "*HTTPFilesystemNode::createReadStream() %s (size %d) ", _path.c_str(), _size);
|
||||
Common::String fsCachePath = Common::normalizePath("/.cache/" + _path, '/');
|
||||
POSIXFilesystemNode *cacheFile = new POSIXFilesystemNode(fsCachePath);
|
||||
// todo: this should not be cached on the filesystem, but in memory
|
||||
// and support range requests
|
||||
// port https://github.com/emscripten-core/emscripten/blob/main/src/lib/libwasmfs_fetch.js over
|
||||
if (!cacheFile->exists() && _size > 0) {
|
||||
byte *buffer = new byte[_size];
|
||||
bool success = _httpFsFetchFile(_url.c_str(), buffer, _size);
|
||||
if (success) {
|
||||
Common::DumpFile *_localFile = new Common::DumpFile();
|
||||
if (!_localFile->open(Common::Path(fsCachePath), true)) {
|
||||
error("Storage: unable to open file to download into");
|
||||
return 0;
|
||||
}
|
||||
debug(5, "HTTPFilesystemNode::createReadStream() file downloaded %s", _path.c_str());
|
||||
_localFile->write(buffer, _size);
|
||||
_localFile->close();
|
||||
free(buffer);
|
||||
} else {
|
||||
warning("Storage: unable to download file %s", _url.c_str());
|
||||
free(buffer);
|
||||
return 0;
|
||||
}
|
||||
} else if (_size == 0) {
|
||||
debug(5, "HTTPFilesystemNode::createReadStream() file empty %s", _path.c_str());
|
||||
Common::DumpFile *_localFile = new Common::DumpFile();
|
||||
if (!_localFile->open(Common::Path(fsCachePath), true)) {
|
||||
warning("Storage: unable to open file to download into");
|
||||
return 0;
|
||||
}
|
||||
_localFile->close();
|
||||
}
|
||||
|
||||
return PosixIoStream::makeFromPath(fsCachePath, StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *HTTPFilesystemNode::createWriteStream(bool atomic) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool HTTPFilesystemNode::createDirectory() {
|
||||
return false;
|
||||
}
|
||||
bool HTTPFilesystemNode::exists() const {
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
bool HTTPFilesystemNode::isReadable() const {
|
||||
return exists();
|
||||
}
|
||||
|
||||
bool HTTPFilesystemNode::isWritable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // #if defined(EMSCRIPTEN)
|
||||
78
backends/fs/emscripten/http-fs.h
Normal file
78
backends/fs/emscripten/http-fs.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HTTP_FILESYSTEM_H
|
||||
#define HTTP_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on POSIX.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class HTTPFilesystemNode : public AbstractFSNode {
|
||||
protected:
|
||||
static Common::HashMap<Common::String, AbstractFSList> _httpFolders;
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
Common::String _url;
|
||||
AbstractFSList *_children;
|
||||
bool _isDirectory;
|
||||
bool _isValid;
|
||||
int _size;
|
||||
|
||||
/**
|
||||
* Full constructor, for internal use only (hence protected).
|
||||
*/
|
||||
HTTPFilesystemNode(const Common::String &path, const Common::String &displayName, const Common::String &baseUrl, bool isValid, bool isDirectory, int size);
|
||||
|
||||
virtual AbstractFSNode *makeNode(const Common::String &path) const {
|
||||
return new HTTPFilesystemNode(path);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a HTTPFilesystemNode for a given path.
|
||||
*
|
||||
* @param path the path the new node should point to.
|
||||
*/
|
||||
HTTPFilesystemNode(const Common::String &path);
|
||||
~HTTPFilesystemNode() {}
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
77
backends/fs/fs-factory.h
Normal file
77
backends/fs/fs-factory.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FILESYSTEM_FACTORY_H
|
||||
#define FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Creates concrete FSNode objects depending on the current architecture.
|
||||
*/
|
||||
class FilesystemFactory {
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~FilesystemFactory() {}
|
||||
|
||||
/**
|
||||
* Returns a node representing the "current directory".
|
||||
* If your system does not support this concept, you can either try to
|
||||
* emulate it or simply return some "sensible" default directory node,
|
||||
* e.g. the same value as getRoot() returns.
|
||||
*/
|
||||
virtual AbstractFSNode *makeCurrentDirectoryFileNode() const = 0;
|
||||
|
||||
/**
|
||||
* Construct a node based on a path; the path is in the same format as it
|
||||
* would be for calls to fopen().
|
||||
*
|
||||
* Furthermore getNodeForPath(oldNode.path()) should create a new node
|
||||
* identical to oldNode. Hence, we can use the "path" value for persistent
|
||||
* storage e.g. in the config file.
|
||||
*
|
||||
* @param path The path string to create a FSNode for.
|
||||
*/
|
||||
virtual AbstractFSNode *makeFileNodePath(const Common::String &path) const = 0;
|
||||
|
||||
/**
|
||||
* Returns a special node representing the filesystem root.
|
||||
* The starting point for any file system browsing.
|
||||
*
|
||||
* On Unix, this will be simply the node for / (the root directory).
|
||||
* On Windows, it will be a special node which "contains" all drives (C:, D:, E:).
|
||||
*/
|
||||
virtual AbstractFSNode *makeRootFileNode() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a path suitable for systen functions such as fopen() for the given ScummVM path,
|
||||
*
|
||||
* In most cases the returned path is the same as the given path, but it may be different, for
|
||||
* example when the application is sandboxed and ScummVM path are relative to the saandbox
|
||||
* root.
|
||||
*/
|
||||
virtual Common::String getSystemFullPath(const Common::String& path) const { return path; }
|
||||
};
|
||||
|
||||
#endif /*FILESYSTEM_FACTORY_H*/
|
||||
49
backends/fs/kolibrios/kolibrios-fs-factory.cpp
Normal file
49
backends/fs/kolibrios/kolibrios-fs-factory.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
|
||||
// Also with clock() in sys/time.h in some macOS SDKs.
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_random
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_srandom
|
||||
|
||||
#include "backends/fs/kolibrios/kolibrios-fs-factory.h"
|
||||
#include "backends/fs/kolibrios/kolibrios-fs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
AbstractFSNode *KolibriOSFilesystemFactory::makeRootFileNode() const {
|
||||
return new KolibriOSFilesystemNode("/");
|
||||
}
|
||||
|
||||
AbstractFSNode *KolibriOSFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
_ksys_getcwd(buf, MAXPATHLEN);
|
||||
return new KolibriOSFilesystemNode(buf);
|
||||
}
|
||||
|
||||
AbstractFSNode *KolibriOSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
return new KolibriOSFilesystemNode(path);
|
||||
}
|
||||
39
backends/fs/kolibrios/kolibrios-fs-factory.h
Normal file
39
backends/fs/kolibrios/kolibrios-fs-factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KOLIBRIOS_FILESYSTEM_FACTORY_H
|
||||
#define KOLIBRIOS_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates KolibriOSFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class KolibriOSFilesystemFactory : public FilesystemFactory {
|
||||
protected:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*KOLIBRIOS_FILESYSTEM_FACTORY_H*/
|
||||
288
backends/fs/kolibrios/kolibrios-fs.cpp
Normal file
288
backends/fs/kolibrios/kolibrios-fs.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
|
||||
|
||||
#include "backends/fs/kolibrios/kolibrios-fs.h"
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ksys.h>
|
||||
|
||||
#include "common/pack-start.h" // START STRUCT PACKING
|
||||
|
||||
struct kol_readdir_result_entry {
|
||||
ksys_file_info_t bdfe;
|
||||
char fileName[520];
|
||||
} PACKED_STRUCT;
|
||||
|
||||
struct kol_readdir_result {
|
||||
ksys_dir_entry_header_t header;
|
||||
kol_readdir_result_entry entries[0];
|
||||
} PACKED_STRUCT;
|
||||
|
||||
#include "common/pack-end.h" // END STRUCT PACKING
|
||||
|
||||
namespace {
|
||||
|
||||
// opendir/readdir are buggy. And they encourage using syscalls. Whatever
|
||||
kol_readdir_result *kol_readdir(const char *path, uint32 max_blocks) {
|
||||
ksys_file_status_t ret_result;
|
||||
int result_buffer_size = sizeof (ksys_dir_entry_header_t)
|
||||
+ max_blocks * sizeof (kol_readdir_result_entry);
|
||||
kol_readdir_result *result_buffer = (kol_readdir_result *) malloc (result_buffer_size);
|
||||
if (!result_buffer)
|
||||
return nullptr;
|
||||
memset(result_buffer, 0, result_buffer_size);
|
||||
|
||||
ret_result = _ksys_file_read_dir(path, 0, KSYS_FILE_UTF8, max_blocks, result_buffer);
|
||||
|
||||
// KSYS_FS_ERR_SUCCESS (0) is returned for normal dirs, KSYS_FS_ERR_EOF (6) for virtual directories
|
||||
if (ret_result.status != 0 && ret_result.status != KSYS_FS_ERR_EOF) {
|
||||
free (result_buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return result_buffer;
|
||||
}
|
||||
|
||||
kol_readdir_result *kol_readdir(const char *path) {
|
||||
kol_readdir_result *res = kol_readdir(path, 2);
|
||||
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
uint32 tot_blocks = res->header.files;
|
||||
free(res);
|
||||
|
||||
return kol_readdir(path, tot_blocks);
|
||||
}
|
||||
|
||||
bool getFileAttrs(Common::String path, uint32& attrs) {
|
||||
ksys_file_info_t info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.attr = KSYS_FILE_ATTR_DIR;
|
||||
|
||||
if(_ksys_file_info(path.c_str(), &info)) {
|
||||
attrs = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
attrs = info.attr;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool KolibriOSFilesystemNode::exists() const {
|
||||
uint32 attrs;
|
||||
return getFileAttrs(_path, attrs);
|
||||
}
|
||||
|
||||
bool KolibriOSFilesystemNode::isReadable() const {
|
||||
uint32 attrs;
|
||||
return getFileAttrs(_path, attrs);
|
||||
}
|
||||
|
||||
bool KolibriOSFilesystemNode::isWritable() const {
|
||||
uint32 attrs;
|
||||
return getFileAttrs(_path, attrs) && !(attrs & 0x01);
|
||||
}
|
||||
|
||||
void KolibriOSFilesystemNode::setFlags() {
|
||||
_isValid = getFileAttrs(_path, _attributes);
|
||||
}
|
||||
|
||||
KolibriOSFilesystemNode::KolibriOSFilesystemNode(const Common::String &p) {
|
||||
assert(p.size() > 0);
|
||||
|
||||
_path = p;
|
||||
|
||||
// Normalize the path (that is, remove unneeded slashes etc.)
|
||||
_path = Common::normalizePath(_path, '/');
|
||||
_displayName = Common::lastPathComponent(_path, '/');
|
||||
|
||||
setFlags();
|
||||
}
|
||||
|
||||
AbstractFSNode *KolibriOSFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(!_path.empty());
|
||||
assert(isDirectory());
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
// We assume here that _path is already normalized (hence don't bother to call
|
||||
// Common::normalizePath on the final path).
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return makeNode(newPath);
|
||||
}
|
||||
|
||||
bool KolibriOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
kol_readdir_result *res = kol_readdir(_path.c_str());
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < (int) res->header.blocks; i++)
|
||||
{
|
||||
// Skip 'invisible' files if necessary
|
||||
if (res->entries[i].fileName[0] == '.' && !hidden) {
|
||||
continue;
|
||||
}
|
||||
// Skip '.' and '..' to avoid cycles
|
||||
if ((res->entries[i].fileName[0] == '.' && res->entries[i].fileName[1] == 0)
|
||||
|| (res->entries[i].fileName[0] == '.' && res->entries[i].fileName[1] == '.' && res->entries[i].fileName[2] == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start with a clone of this node, with the correct path set
|
||||
KolibriOSFilesystemNode entry(*this);
|
||||
entry._displayName = res->entries[i].fileName;
|
||||
if (_path.lastChar() != '/')
|
||||
entry._path += '/';
|
||||
entry._path += entry._displayName;
|
||||
|
||||
entry._isValid = true;
|
||||
entry._attributes = res->entries[i].bdfe.attr;
|
||||
|
||||
// Honor the chosen mode
|
||||
if ((mode == Common::FSNode::kListFilesOnly && entry.isDirectory()) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !entry.isDirectory()))
|
||||
continue;
|
||||
|
||||
myList.push_back(new KolibriOSFilesystemNode(entry));
|
||||
|
||||
}
|
||||
|
||||
free(res);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *KolibriOSFilesystemNode::getParent() const {
|
||||
if (_path == "/")
|
||||
return 0; // The filesystem root has no parent
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = start + _path.size();
|
||||
|
||||
// Strip of the last component. We make use of the fact that at this
|
||||
// point, _path is guaranteed to be normalized
|
||||
while (end > start && *(end-1) != '/')
|
||||
end--;
|
||||
|
||||
if (end == start) {
|
||||
// This only happens if we were called with a relative path, for which
|
||||
// there simply is no parent.
|
||||
// TODO: We could also resolve this by assuming that the parent is the
|
||||
// current working directory, and returning a node referring to that.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return makeNode(Common::String(start, end));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *KolibriOSFilesystemNode::createReadStream() {
|
||||
return PosixIoStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *KolibriOSFilesystemNode::createWriteStream(bool atomic) {
|
||||
return PosixIoStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
}
|
||||
|
||||
bool KolibriOSFilesystemNode::createDirectory() {
|
||||
if (mkdir(_path.c_str(), 0755) == 0)
|
||||
setFlags();
|
||||
|
||||
return isDirectory();
|
||||
}
|
||||
|
||||
namespace KolibriOS {
|
||||
|
||||
bool assureDirectoryExists(const Common::String &dir, const char *prefix) {
|
||||
|
||||
// Check whether the prefix exists if one is supplied.
|
||||
if (prefix) {
|
||||
uint32 attrs;
|
||||
if (!getFileAttrs(prefix, attrs) || !KolibriOSFilesystemNode::isDirectory(attrs)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain absolute path.
|
||||
Common::String path;
|
||||
if (prefix) {
|
||||
path = prefix;
|
||||
path += '/';
|
||||
path += dir;
|
||||
} else {
|
||||
path = dir;
|
||||
}
|
||||
|
||||
path = Common::normalizePath(path, '/');
|
||||
|
||||
const Common::String::iterator end = path.end();
|
||||
Common::String::iterator cur = path.begin();
|
||||
if (cur[0] == '/' && cur[1] >= 1 && cur[1] <= 3 && cur[2] == '/')
|
||||
cur += 2;
|
||||
if (*cur == '/')
|
||||
++cur;
|
||||
|
||||
do {
|
||||
if (cur + 1 != end) {
|
||||
if (*cur != '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is kind of ugly and against the purpose of Common::String to
|
||||
// insert 0s inside, but this is just for a local string and
|
||||
// simplifies the code a lot.
|
||||
*cur = '\0';
|
||||
}
|
||||
|
||||
if (mkdir(path.c_str(), 0755) != 0) {
|
||||
uint32 attrs;
|
||||
if (!getFileAttrs(path, attrs) || !KolibriOSFilesystemNode::isDirectory(attrs))
|
||||
return false;
|
||||
}
|
||||
|
||||
*cur = '/';
|
||||
} while (cur++ != end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace KolibriOS
|
||||
93
backends/fs/kolibrios/kolibrios-fs.h
Normal file
93
backends/fs/kolibrios/kolibrios-fs.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef KOLIBRIOS_FS_H
|
||||
#define KOLIBRIOS_FS_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on KolibriOS.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class KolibriOSFilesystemNode : public AbstractFSNode {
|
||||
public:
|
||||
/**
|
||||
* Creates a KolibriOSFilesystemNode for a given path.
|
||||
*
|
||||
* @param path the path the new node should point to.
|
||||
*/
|
||||
KolibriOSFilesystemNode(const Common::String &path);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
static bool isDirectory(uint32 attrs) { return attrs & 0x18; }
|
||||
bool isDirectory() const override { return isDirectory(_attributes); }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
uint32 _attributes;
|
||||
bool _isValid;
|
||||
|
||||
virtual AbstractFSNode *makeNode(const Common::String &path) const {
|
||||
return new KolibriOSFilesystemNode(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain constructor, for internal use only (hence protected).
|
||||
*/
|
||||
KolibriOSFilesystemNode() : _attributes(0), _isValid(false) {}
|
||||
|
||||
/**
|
||||
* Tests and sets the _isValid and _isDirectory flags, using the stat() function.
|
||||
*/
|
||||
virtual void setFlags();
|
||||
};
|
||||
|
||||
namespace KolibriOS {
|
||||
|
||||
/**
|
||||
* Assure that a directory path exists.
|
||||
*
|
||||
* @param dir The path which is required to exist.
|
||||
* @param prefix An (optional) prefix which should not be created if non existent.
|
||||
* prefix is prepended to dir if supplied.
|
||||
* @return true in case the directory exists (or was created), false otherwise.
|
||||
*/
|
||||
bool assureDirectoryExists(const Common::String &dir, const char *prefix = nullptr);
|
||||
|
||||
} // End of namespace KolibriOS
|
||||
|
||||
#endif
|
||||
38
backends/fs/morphos/morphos-fs-factory.cpp
Normal file
38
backends/fs/morphos/morphos-fs-factory.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__MORPHOS__)
|
||||
|
||||
#include "backends/fs/morphos/morphos-fs-factory.h"
|
||||
#include "backends/fs/morphos/morphos-fs.h"
|
||||
|
||||
AbstractFSNode *MorphOSFilesystemFactory::makeRootFileNode() const {
|
||||
return new MorphOSFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *MorphOSFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
return new MorphOSFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *MorphOSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
return new MorphOSFilesystemNode(path);
|
||||
}
|
||||
#endif
|
||||
39
backends/fs/morphos/morphos-fs-factory.h
Normal file
39
backends/fs/morphos/morphos-fs-factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MORPHOS_FILESYSTEM_FACTORY_H
|
||||
#define MORPHOS_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates MorphOSFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class MorphOSFilesystemFactory final : public FilesystemFactory {
|
||||
public:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*MORPHOS_FILESYSTEM_FACTORY_H*/
|
||||
377
backends/fs/morphos/morphos-fs.cpp
Normal file
377
backends/fs/morphos/morphos-fs.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__MORPHOS__)
|
||||
|
||||
#include "backends/fs/morphos/morphos-fs.h"
|
||||
#include "backends/fs/stdiostream.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/util.h"
|
||||
|
||||
/**
|
||||
* Returns the last component of a given path.
|
||||
*
|
||||
* @param str Common::String containing the path.
|
||||
* @return Pointer to the first char of the last component inside str.
|
||||
*/
|
||||
const char *lastPathComponent(const Common::String &str) {
|
||||
|
||||
int offset = str.size();
|
||||
|
||||
if (offset <= 0) {
|
||||
debug(6, "Bad offset");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *p = str.c_str();
|
||||
|
||||
while (offset > 0 && (p[offset-1] == '/' || p[offset-1] == ':'))
|
||||
offset--;
|
||||
|
||||
while (offset > 0 && (p[offset-1] != '/' && p[offset-1] != ':'))
|
||||
offset--;
|
||||
|
||||
return p + offset;
|
||||
}
|
||||
|
||||
MorphOSFilesystemNode::MorphOSFilesystemNode() {
|
||||
|
||||
_sDisplayName = "Available HDDs/Partitions";
|
||||
_bIsValid = true;
|
||||
_bIsDirectory = true;
|
||||
_sPath = "";
|
||||
_pFileLock = 0;
|
||||
_nProt = 0; // Protection is ignored for the root volume
|
||||
}
|
||||
|
||||
MorphOSFilesystemNode::MorphOSFilesystemNode(const Common::String &p) {
|
||||
|
||||
int offset = p.size();
|
||||
if (offset <= 0) {
|
||||
debug(6, "Bad offset");
|
||||
return;
|
||||
}
|
||||
|
||||
_sPath = p;
|
||||
_sDisplayName = ::lastPathComponent(_sPath);
|
||||
_pFileLock = 0;
|
||||
_bIsDirectory = false;
|
||||
_bIsValid = false;
|
||||
|
||||
struct FileInfoBlock *fib = (struct FileInfoBlock*) AllocDosObject(DOS_FIB, NULL);
|
||||
|
||||
if (fib == NULL) {
|
||||
debug(6,"Failed...");
|
||||
return;
|
||||
}
|
||||
|
||||
BPTR pLock = Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
|
||||
if (pLock) {
|
||||
if (Examine(pLock, fib) != DOSFALSE) {
|
||||
if (fib->fib_EntryType > 0) {
|
||||
_bIsDirectory = true;
|
||||
_pFileLock = DupLock(pLock);
|
||||
_bIsValid = (_pFileLock != 0);
|
||||
const char c = _sPath.lastChar();
|
||||
if (c != '/' && c != ':')
|
||||
_sPath += '/';
|
||||
} else {
|
||||
_bIsDirectory = false;
|
||||
_bIsValid = false;
|
||||
}
|
||||
}
|
||||
UnLock(pLock);
|
||||
}
|
||||
FreeDosObject(DOS_FIB, fib);
|
||||
}
|
||||
|
||||
MorphOSFilesystemNode::MorphOSFilesystemNode(BPTR pLock, const char *pDisplayName) {
|
||||
|
||||
int bufSize = MAXPATHLEN;
|
||||
_pFileLock = 0;
|
||||
|
||||
while (true) {
|
||||
char *n = new char[bufSize];
|
||||
if (NameFromLock(pLock, (STRPTR)n, bufSize) != DOSFALSE) {
|
||||
_sPath = n;
|
||||
_sDisplayName = pDisplayName ? pDisplayName : FilePart((STRPTR)n);
|
||||
delete[] n;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IoErr() != ERROR_LINE_TOO_LONG) {
|
||||
_bIsValid = false;
|
||||
debug(6, "IoErr() != ERROR_LINE_TOO_LONG");
|
||||
delete[] n;
|
||||
return;
|
||||
}
|
||||
|
||||
bufSize *= 2;
|
||||
delete[] n;
|
||||
}
|
||||
|
||||
_bIsValid = false;
|
||||
_bIsDirectory = false;
|
||||
|
||||
FileInfoBlock *fib = (FileInfoBlock*) AllocDosObject(DOS_FIB, NULL);
|
||||
|
||||
if (fib == NULL) {
|
||||
debug(6,"Failed...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Examine(pLock, fib) != DOSFALSE) {
|
||||
_bIsDirectory = fib->fib_EntryType >0;
|
||||
if (_bIsDirectory) {
|
||||
if (fib->fib_EntryType != ST_ROOT)
|
||||
_sPath += '/';
|
||||
_pFileLock = DupLock(pLock);
|
||||
if (_pFileLock) _bIsValid = true;
|
||||
} else {
|
||||
_bIsValid = true;
|
||||
}
|
||||
}
|
||||
FreeDosObject(DOS_FIB, fib);
|
||||
}
|
||||
|
||||
// We need the custom copy constructor because of DupLock()
|
||||
MorphOSFilesystemNode::MorphOSFilesystemNode(const MorphOSFilesystemNode& node)
|
||||
: AbstractFSNode() {
|
||||
|
||||
_sDisplayName = node._sDisplayName;
|
||||
_bIsValid = node._bIsValid;
|
||||
_bIsDirectory = node._bIsDirectory;
|
||||
_sPath = node._sPath;
|
||||
_pFileLock = DupLock(node._pFileLock);
|
||||
_nProt = node._nProt;
|
||||
}
|
||||
|
||||
MorphOSFilesystemNode::~MorphOSFilesystemNode() {
|
||||
|
||||
if (_pFileLock)
|
||||
UnLock(_pFileLock);
|
||||
}
|
||||
|
||||
bool MorphOSFilesystemNode::exists() const {
|
||||
|
||||
if (_sPath.empty())
|
||||
return false;
|
||||
|
||||
bool nodeExists = false;
|
||||
|
||||
BPTR pLock = Lock(_sPath.c_str(), SHARED_LOCK);
|
||||
if (pLock) {
|
||||
nodeExists = true;
|
||||
UnLock(pLock);
|
||||
}
|
||||
|
||||
return nodeExists;
|
||||
}
|
||||
|
||||
AbstractFSNode *MorphOSFilesystemNode::getChild(const Common::String &n) const {
|
||||
|
||||
if (!_bIsDirectory) {
|
||||
debug(6, "Not a directory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Common::String newPath(_sPath);
|
||||
|
||||
if (_sPath.lastChar() != '/')
|
||||
newPath += '/';
|
||||
|
||||
newPath += n;
|
||||
|
||||
return new MorphOSFilesystemNode(newPath);
|
||||
}
|
||||
|
||||
bool MorphOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
|
||||
if (!_bIsValid) {
|
||||
debug(6, "Invalid node");
|
||||
return false; // Empty list
|
||||
}
|
||||
|
||||
if (!_bIsDirectory) {
|
||||
debug(6, "Not a directory");
|
||||
return false; // Empty list
|
||||
}
|
||||
|
||||
if (isRootNode()) {
|
||||
debug(6, "Root node");
|
||||
myList = listVolumes();
|
||||
return true;
|
||||
}
|
||||
|
||||
FileInfoBlock *fib = (FileInfoBlock*) AllocDosObject(DOS_FIB, NULL);
|
||||
|
||||
if (fib == NULL) {
|
||||
debug(6, "Failed to allocate memory for FileInfoBLock");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Examine(_pFileLock, fib) != DOSFALSE) {
|
||||
|
||||
MorphOSFilesystemNode *entry;
|
||||
|
||||
while (ExNext(_pFileLock, fib) != DOSFALSE) {
|
||||
Common::String full_path = NULL;
|
||||
BPTR pLock;
|
||||
if ((mode == Common::FSNode::kListAll) || (fib->fib_EntryType > 0 && (Common::FSNode::kListDirectoriesOnly == mode)) || (fib->fib_EntryType < 0 && (Common::FSNode::kListFilesOnly == mode ))) {
|
||||
full_path = _sPath;
|
||||
full_path += fib->fib_FileName;
|
||||
pLock = Lock(full_path.c_str(), SHARED_LOCK);
|
||||
if (pLock) {
|
||||
entry = new MorphOSFilesystemNode( pLock, fib->fib_FileName );
|
||||
if (entry) {
|
||||
myList.push_back(entry);
|
||||
}
|
||||
UnLock(pLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ERROR_NO_MORE_ENTRIES != IoErr() ) {
|
||||
debug(6, "An error occurred during ExamineDir");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FreeDosObject(DOS_FIB, fib);
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *MorphOSFilesystemNode::getParent() const {
|
||||
|
||||
if (isRootNode()) {
|
||||
debug(6, "Root node");
|
||||
return new MorphOSFilesystemNode(*this);
|
||||
}
|
||||
|
||||
BPTR pLock = _pFileLock;
|
||||
|
||||
if (!_bIsDirectory) {
|
||||
assert(!pLock);
|
||||
pLock = Lock((CONST_STRPTR)_sPath.c_str(), SHARED_LOCK);
|
||||
assert(pLock);
|
||||
}
|
||||
|
||||
MorphOSFilesystemNode *node;
|
||||
|
||||
BPTR parentDir = ParentDir( pLock );
|
||||
if (parentDir) {
|
||||
node = new MorphOSFilesystemNode(parentDir);
|
||||
UnLock(parentDir);
|
||||
} else
|
||||
node = new MorphOSFilesystemNode();
|
||||
|
||||
if (!_bIsDirectory) {
|
||||
UnLock(pLock);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
AbstractFSList MorphOSFilesystemNode::listVolumes() const {
|
||||
|
||||
AbstractFSList myList;
|
||||
DosList *dosList;
|
||||
const ULONG kLockFlags = LDF_READ | LDF_VOLUMES;
|
||||
char buffer[MAXPATHLEN];
|
||||
|
||||
dosList = LockDosList(kLockFlags);
|
||||
|
||||
if (dosList == NULL) {
|
||||
debug(6, "Cannot lock the DOS list");
|
||||
return myList;
|
||||
}
|
||||
|
||||
dosList = NextDosEntry(dosList, LDF_VOLUMES);
|
||||
|
||||
MorphOSFilesystemNode *entry;
|
||||
|
||||
while (dosList) {
|
||||
|
||||
if (dosList->dol_Type == DLT_VOLUME &&
|
||||
dosList->dol_Name &&
|
||||
dosList->dol_Task) {
|
||||
|
||||
CONST_STRPTR volName = (CONST_STRPTR)BADDR(dosList->dol_Name)+1;
|
||||
CONST_STRPTR devName = (CONST_STRPTR)((struct Task *)dosList->dol_Task->mp_SigTask)->tc_Node.ln_Name;
|
||||
BPTR volumeLock;
|
||||
|
||||
Common::strcpy_s(buffer, volName);
|
||||
Common::strcat_s(buffer, ":");
|
||||
|
||||
volumeLock = Lock(buffer, SHARED_LOCK);
|
||||
if (volumeLock) {
|
||||
|
||||
Common::sprintf_s(buffer, "%s (%s)", volName, devName);
|
||||
|
||||
entry = new MorphOSFilesystemNode(volumeLock, buffer);
|
||||
if (entry) {
|
||||
myList.push_back(entry);
|
||||
}
|
||||
|
||||
UnLock(volumeLock);
|
||||
}
|
||||
}
|
||||
dosList = NextDosEntry(dosList, LDF_VOLUMES);
|
||||
}
|
||||
|
||||
UnLockDosList(kLockFlags);
|
||||
|
||||
return myList;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *MorphOSFilesystemNode::createReadStream() {
|
||||
StdioStream *readStream = StdioStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
|
||||
if (readStream) {
|
||||
readStream->setBufferSize(8192);
|
||||
}
|
||||
|
||||
return readStream;
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *MorphOSFilesystemNode::createWriteStream(bool atomic) {
|
||||
return StdioStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
}
|
||||
|
||||
bool MorphOSFilesystemNode::createDirectory() {
|
||||
Common::String createPath = _sPath;
|
||||
if (createPath.lastChar() == '/') {
|
||||
createPath.deleteLastChar();
|
||||
}
|
||||
|
||||
BPTR dirLock = CreateDir(createPath.c_str());
|
||||
if (dirLock) {
|
||||
UnLock(dirLock);
|
||||
_bIsValid = true;
|
||||
_bIsDirectory = true;
|
||||
} else {
|
||||
debug(6, "MorphOSFilesystemNode::createDirectory() failed -> Directory '%s' could not be created!", createPath.c_str());
|
||||
}
|
||||
return _bIsValid && _bIsDirectory;
|
||||
}
|
||||
|
||||
#endif //defined(__MORPHOS__)
|
||||
123
backends/fs/morphos/morphos-fs.h
Normal file
123
backends/fs/morphos/morphos-fs.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MORPHOS_FILESYSTEM_H
|
||||
#define MORPHOS_FILESYSTEM_H
|
||||
|
||||
#ifdef __USE_INLINE__
|
||||
#undef __USE_INLINE__
|
||||
#endif
|
||||
|
||||
#include <proto/exec.h>
|
||||
#include <proto/dos.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef USE_NEWLIB
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class MorphOSFilesystemNode final : public AbstractFSNode {
|
||||
protected:
|
||||
/**
|
||||
* The main file lock.
|
||||
* If this is NULL but _bIsValid is true, then this Node references
|
||||
* the virtual filesystem root.
|
||||
*/
|
||||
BPTR _pFileLock;
|
||||
|
||||
Common::String _sDisplayName;
|
||||
Common::String _sPath;
|
||||
bool _bIsDirectory;
|
||||
bool _bIsValid;
|
||||
uint32 _nProt;
|
||||
|
||||
/**
|
||||
* Creates a list with all the volumes present in the root node.
|
||||
*/
|
||||
virtual AbstractFSList listVolumes() const;
|
||||
|
||||
/**
|
||||
* True if this is the pseudo root filesystem.
|
||||
*/
|
||||
bool isRootNode() const { return _bIsValid && _bIsDirectory && _pFileLock == 0; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a MorphOSFilesystemNode with the root node as path.
|
||||
*/
|
||||
MorphOSFilesystemNode();
|
||||
|
||||
/**
|
||||
* Creates a MorphOSFilesystemNode for a given path.
|
||||
*
|
||||
* @param path Common::String with the path the new node should point to.
|
||||
*/
|
||||
MorphOSFilesystemNode(const Common::String &p);
|
||||
|
||||
/**
|
||||
* Creates a MorphOSFilesystemNode given its lock and display name.
|
||||
*
|
||||
* @param pLock BPTR to the lock.
|
||||
* @param pDisplayName name to be used for display, in case not supplied the FilePart() of the filename will be used.
|
||||
*
|
||||
* @note This shouldn't even be public as it's only internally, at best it should have been protected if not private.
|
||||
*/
|
||||
MorphOSFilesystemNode(BPTR pLock, const char *pDisplayName = 0);
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @note Needed because it duplicates the file lock.
|
||||
*/
|
||||
MorphOSFilesystemNode(const MorphOSFilesystemNode &node);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~MorphOSFilesystemNode() override;
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _sDisplayName; }
|
||||
Common::String getName() const override { return _sDisplayName; }
|
||||
Common::String getPath() const override { return _sPath; }
|
||||
bool isDirectory() const override { return _bIsDirectory; }
|
||||
bool isReadable() const override { return true; }
|
||||
bool isWritable() const override { return true; }
|
||||
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
44
backends/fs/n64/n64-fs-factory.cpp
Normal file
44
backends/fs/n64/n64-fs-factory.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __N64__
|
||||
|
||||
#include <n64utils.h>
|
||||
#include <romfs.h>
|
||||
|
||||
#include "backends/fs/n64/n64-fs-factory.h"
|
||||
#include "backends/fs/n64/n64-fs.h"
|
||||
|
||||
AbstractFSNode *N64FilesystemFactory::makeRootFileNode() const {
|
||||
return new N64FilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *N64FilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
return romfs_getcwd(buf, MAXPATHLEN) ? new N64FilesystemNode(Common::String(buf), false) : NULL;
|
||||
}
|
||||
|
||||
AbstractFSNode *N64FilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
return new N64FilesystemNode(path, false);
|
||||
}
|
||||
|
||||
#endif
|
||||
38
backends/fs/n64/n64-fs-factory.h
Normal file
38
backends/fs/n64/n64-fs-factory.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef N64_FILESYSTEM_FACTORY_H
|
||||
#define N64_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates N64FilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class N64FilesystemFactory final : public FilesystemFactory {
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*N64_FILESYSTEM_FACTORY_H*/
|
||||
167
backends/fs/n64/n64-fs.cpp
Normal file
167
backends/fs/n64/n64-fs.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __N64__
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
|
||||
#include "backends/fs/n64/n64-fs.h"
|
||||
#include "backends/fs/n64/romfsstream.h"
|
||||
|
||||
#include <romfs.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <n64utils.h>
|
||||
|
||||
#define ROOT_PATH "/"
|
||||
|
||||
N64FilesystemNode::N64FilesystemNode() {
|
||||
_isDirectory = true;
|
||||
_displayName = "Root";
|
||||
_isValid = true;
|
||||
_path = ROOT_PATH;
|
||||
}
|
||||
|
||||
N64FilesystemNode::N64FilesystemNode(const Common::String &p, bool verify) {
|
||||
assert(p.size() > 0);
|
||||
|
||||
_path = p;
|
||||
_displayName = lastPathComponent(_path, '/');
|
||||
_isValid = true;
|
||||
_isDirectory = true;
|
||||
|
||||
// Check if it's a dir
|
||||
ROMFILE *tmpfd = romfs_open(p.c_str(), "r");
|
||||
if (tmpfd) {
|
||||
_isDirectory = (tmpfd->type == 0 || tmpfd->type == 1);
|
||||
romfs_close(tmpfd);
|
||||
}
|
||||
}
|
||||
|
||||
bool N64FilesystemNode::exists() const {
|
||||
int ret = -1;
|
||||
|
||||
ret = romfs_access(_path.c_str(), F_OK);
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
bool N64FilesystemNode::isReadable() const {
|
||||
int ret = -1;
|
||||
|
||||
ret = romfs_access(_path.c_str(), R_OK);
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
// We can't write on ROMFS!
|
||||
bool N64FilesystemNode::isWritable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
AbstractFSNode *N64FilesystemNode::getChild(const Common::String &n) const {
|
||||
// FIXME: Pretty lame implementation! We do no error checking to speak
|
||||
// of, do not check if this is a special node, etc.
|
||||
assert(_isDirectory);
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return new N64FilesystemNode(newPath, true);
|
||||
}
|
||||
|
||||
bool N64FilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
ROMDIR *dirp = romfs_opendir(_path.c_str());
|
||||
romfs_dirent *dp;
|
||||
|
||||
if (dirp == NULL)
|
||||
return false;
|
||||
|
||||
// loop over dir entries using readdir
|
||||
while ((dp = romfs_readdir(dirp)) != NULL) {
|
||||
// Skip 'invisible' files if necessary
|
||||
if (dp->entryname[0] == '.' && !hidden) {
|
||||
free(dp);
|
||||
continue;
|
||||
}
|
||||
// Skip '.' and '..' to avoid cycles
|
||||
if ((dp->entryname[0] == '.' && dp->entryname[1] == 0) || (dp->entryname[0] == '.' && dp->entryname[1] == '.')) {
|
||||
free(dp);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start with a clone of this node, with the correct path set
|
||||
N64FilesystemNode entry(*this);
|
||||
entry._displayName = dp->entryname;
|
||||
if (_path.lastChar() != '/')
|
||||
entry._path += '/';
|
||||
entry._path += entry._displayName;
|
||||
|
||||
// Force validity for now...
|
||||
entry._isValid = 1;
|
||||
|
||||
entry._isDirectory = (dp->type == 0 || dp->type == 1);
|
||||
|
||||
// Honor the chosen mode
|
||||
if ((mode == Common::FSNode::kListFilesOnly && entry._isDirectory) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !entry._isDirectory)) {
|
||||
|
||||
free(dp);
|
||||
continue;
|
||||
}
|
||||
|
||||
myList.push_back(new N64FilesystemNode(entry));
|
||||
|
||||
free(dp);
|
||||
}
|
||||
romfs_closedir(dirp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *N64FilesystemNode::getParent() const {
|
||||
if (_path == ROOT_PATH)
|
||||
return 0;
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = lastPathComponent(_path, '/');
|
||||
|
||||
return new N64FilesystemNode(Common::String(start, end - start), false);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *N64FilesystemNode::createReadStream() {
|
||||
return RomfsStream::makeFromPath(getPath(), false);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *N64FilesystemNode::createWriteStream(bool atomic) {
|
||||
// TODO: Add atomic support if possible
|
||||
return RomfsStream::makeFromPath(getPath(), true);
|
||||
}
|
||||
|
||||
bool N64FilesystemNode::createDirectory() {
|
||||
return _isValid && _isDirectory;
|
||||
}
|
||||
|
||||
#endif //#ifdef __N64__
|
||||
78
backends/fs/n64/n64-fs.h
Normal file
78
backends/fs/n64/n64-fs.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef N64_FILESYSTEM_H
|
||||
#define N64_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on N64 Hkz romfs.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class N64FilesystemNode final : public AbstractFSNode {
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
bool _isDirectory;
|
||||
bool _isValid;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a N64FilesystemNode with the root node as path.
|
||||
*/
|
||||
N64FilesystemNode();
|
||||
|
||||
/**
|
||||
* Creates a N64FilesystemNode for a given path.
|
||||
*
|
||||
* @param path Common::String with the path the new node should point to.
|
||||
* @param verify true if the isValid and isDirectory flags should be verified during the construction.
|
||||
*/
|
||||
N64FilesystemNode(const Common::String &p, bool verify = true);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override {
|
||||
return _displayName;
|
||||
}
|
||||
Common::String getName() const override {
|
||||
return _displayName;
|
||||
}
|
||||
Common::String getPath() const override {
|
||||
return _path;
|
||||
}
|
||||
bool isDirectory() const override {
|
||||
return _isDirectory;
|
||||
}
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
84
backends/fs/n64/romfsstream.cpp
Normal file
84
backends/fs/n64/romfsstream.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __N64__
|
||||
|
||||
#include <romfs.h>
|
||||
#include "backends/fs/n64/romfsstream.h"
|
||||
|
||||
RomfsStream::RomfsStream(void *handle) : _handle(handle) {
|
||||
assert(handle);
|
||||
}
|
||||
|
||||
RomfsStream::~RomfsStream() {
|
||||
romfs_close((ROMFILE *)_handle);
|
||||
}
|
||||
|
||||
bool RomfsStream::err() const {
|
||||
return romfs_error((ROMFILE *)_handle) != 0;
|
||||
}
|
||||
|
||||
void RomfsStream::clearErr() {
|
||||
romfs_clearerr((ROMFILE *)_handle);
|
||||
}
|
||||
|
||||
bool RomfsStream::eos() const {
|
||||
return romfs_eof((ROMFILE *)_handle) != 0;
|
||||
}
|
||||
|
||||
int64 RomfsStream::pos() const {
|
||||
return romfs_tell((ROMFILE *)_handle);
|
||||
}
|
||||
|
||||
int64 RomfsStream::size() const {
|
||||
int64 oldPos = romfs_tell((ROMFILE *)_handle);
|
||||
romfs_seek((ROMFILE *)_handle, 0, SEEK_END);
|
||||
int64 length = romfs_tell((ROMFILE *)_handle);
|
||||
romfs_seek((ROMFILE *)_handle, oldPos, SEEK_SET);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
bool RomfsStream::seek(int64 offs, int whence) {
|
||||
return romfs_seek((ROMFILE *)_handle, offs, whence) >= 0;
|
||||
}
|
||||
|
||||
uint32 RomfsStream::read(void *ptr, uint32 len) {
|
||||
return romfs_read((byte *)ptr, 1, len, (ROMFILE *)_handle);
|
||||
}
|
||||
|
||||
uint32 RomfsStream::write(const void *ptr, uint32 len) {
|
||||
return romfs_write(ptr, 1, len, (ROMFILE *)_handle);
|
||||
}
|
||||
|
||||
bool RomfsStream::flush() {
|
||||
return romfs_flush((ROMFILE *)_handle) == 0;
|
||||
}
|
||||
|
||||
RomfsStream *RomfsStream::makeFromPath(const Common::String &path, bool writeMode) {
|
||||
ROMFILE *handle = romfs_open(path.c_str(), writeMode ? "wb" : "rb");
|
||||
|
||||
if (handle)
|
||||
return new RomfsStream(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __N64__ */
|
||||
58
backends/fs/n64/romfsstream.h
Normal file
58
backends/fs/n64/romfsstream.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_FS_ROMFSSTREAM_H
|
||||
#define BACKENDS_FS_ROMFSSTREAM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/noncopyable.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/str.h"
|
||||
|
||||
class RomfsStream final : public Common::SeekableReadStream, public Common::SeekableWriteStream, public Common::NonCopyable {
|
||||
protected:
|
||||
/** File handle to the actual file. */
|
||||
void *_handle;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Given a path, invokes fopen on that path and wrap the result in a
|
||||
* RomfsStream instance.
|
||||
*/
|
||||
static RomfsStream *makeFromPath(const Common::String &path, bool writeMode);
|
||||
|
||||
RomfsStream(void *handle);
|
||||
~RomfsStream() override;
|
||||
|
||||
bool err() const override;
|
||||
void clearErr() override;
|
||||
bool eos() const override;
|
||||
|
||||
uint32 write(const void *dataPtr, uint32 dataSize) override;
|
||||
bool flush() override;
|
||||
|
||||
int64 pos() const override;
|
||||
int64 size() const override;
|
||||
bool seek(int64 offs, int whence = SEEK_SET) override;
|
||||
uint32 read(void *dataPtr, uint32 dataSize) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
70
backends/fs/posix-drives/posix-drives-fs-factory.cpp
Normal file
70
backends/fs/posix-drives/posix-drives-fs-factory.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(POSIX) || defined(PSP2) || defined(__DS__)
|
||||
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/posix-drives/posix-drives-fs-factory.h"
|
||||
#include "backends/fs/posix-drives/posix-drives-fs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
void DrivesPOSIXFilesystemFactory::addDrive(const Common::String &name) {
|
||||
_config.drives.push_back(Common::normalizePath(name, '/'));
|
||||
}
|
||||
|
||||
void DrivesPOSIXFilesystemFactory::configureBuffering(DrivePOSIXFilesystemNode::BufferingMode bufferingMode, uint32 bufferSize) {
|
||||
_config.bufferingMode = bufferingMode;
|
||||
_config.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
AbstractFSNode *DrivesPOSIXFilesystemFactory::makeRootFileNode() const {
|
||||
return new DrivePOSIXFilesystemNode(_config);
|
||||
}
|
||||
|
||||
AbstractFSNode *DrivesPOSIXFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
#if defined(PSP2) // The Vita does not have getcwd
|
||||
return makeRootFileNode();
|
||||
#else
|
||||
char buf[MAXPATHLEN];
|
||||
return getcwd(buf, MAXPATHLEN) ? new DrivePOSIXFilesystemNode(buf, _config) : makeRootFileNode();
|
||||
#endif
|
||||
}
|
||||
|
||||
AbstractFSNode *DrivesPOSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
return new DrivePOSIXFilesystemNode(path, _config);
|
||||
}
|
||||
|
||||
bool DrivesPOSIXFilesystemFactory::StaticDrivesConfig::getDrives(AbstractFSList &list, bool hidden) const {
|
||||
for (uint i = 0; i < drives.size(); i++) {
|
||||
list.push_back(_factory->makeFileNodePath(drives[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrivesPOSIXFilesystemFactory::StaticDrivesConfig::isDrive(const Common::String &path) const {
|
||||
DrivesArray::const_iterator drive = Common::find(drives.begin(), drives.end(), path);
|
||||
return drive != drives.end();
|
||||
}
|
||||
|
||||
#endif
|
||||
76
backends/fs/posix-drives/posix-drives-fs-factory.h
Normal file
76
backends/fs/posix-drives/posix-drives-fs-factory.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POSIX_DRIVES_FILESYSTEM_FACTORY_H
|
||||
#define POSIX_DRIVES_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
#include "backends/fs/posix-drives/posix-drives-fs.h"
|
||||
|
||||
/**
|
||||
* A FilesystemFactory implementation for filesystems with a special
|
||||
* top-level directory with hard-coded entries but that otherwise
|
||||
* implement the POSIX APIs.
|
||||
*
|
||||
* For used with paths like these:
|
||||
* - 'sdcard:/games/scummvm.ini'
|
||||
* - 'hdd1:/usr/bin'
|
||||
*/
|
||||
class DrivesPOSIXFilesystemFactory : public FilesystemFactory {
|
||||
public:
|
||||
DrivesPOSIXFilesystemFactory() : _config(this) { }
|
||||
|
||||
/**
|
||||
* Add a drive to the top-level directory
|
||||
*/
|
||||
void addDrive(const Common::String &name);
|
||||
|
||||
/**
|
||||
* Configure file stream buffering
|
||||
*
|
||||
* @param bufferingMode select the buffering implementation to use
|
||||
* @param bufferSize the size of the IO buffer in bytes. A buffer size of 0 means the default size should be used
|
||||
*/
|
||||
void configureBuffering(DrivePOSIXFilesystemNode::BufferingMode bufferingMode, uint32 bufferSize);
|
||||
|
||||
protected:
|
||||
// FilesystemFactory API
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
typedef Common::Array<Common::String> DrivesArray;
|
||||
struct StaticDrivesConfig : public DrivePOSIXFilesystemNode::Config {
|
||||
StaticDrivesConfig(const DrivesPOSIXFilesystemFactory *factory) : _factory(factory) { }
|
||||
|
||||
bool getDrives(AbstractFSList &list, bool hidden) const override;
|
||||
bool isDrive(const Common::String &path) const override;
|
||||
|
||||
DrivesArray drives;
|
||||
|
||||
private:
|
||||
const DrivesPOSIXFilesystemFactory *_factory;
|
||||
};
|
||||
|
||||
StaticDrivesConfig _config;
|
||||
};
|
||||
|
||||
#endif
|
||||
193
backends/fs/posix-drives/posix-drives-fs.cpp
Normal file
193
backends/fs/posix-drives/posix-drives-fs.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(POSIX) || defined(PSP2) || defined(__DS__)
|
||||
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/posix-drives/posix-drives-fs.h"
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
|
||||
#include "common/algorithm.h"
|
||||
#include "common/bufferedstream.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Common::String &path, const Config &config) :
|
||||
POSIXFilesystemNode(path),
|
||||
_isPseudoRoot(false),
|
||||
_config(config) {
|
||||
|
||||
if (isDrive(path)) {
|
||||
_isDirectory = true;
|
||||
_isValid = true;
|
||||
|
||||
// FIXME: Add a setting for deciding whether drive paths need to end with a slash
|
||||
if (!_path.hasSuffix("/")) {
|
||||
_path += "/";
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DrivePOSIXFilesystemNode::DrivePOSIXFilesystemNode(const Config &config) :
|
||||
_isPseudoRoot(true),
|
||||
_config(config) {
|
||||
_isDirectory = true;
|
||||
_isValid = false;
|
||||
}
|
||||
|
||||
void DrivePOSIXFilesystemNode::configureStream(StdioStream *stream) {
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_config.bufferingMode != kBufferingModeStdio) {
|
||||
// Disable stdio buffering
|
||||
stream->setBufferSize(0);
|
||||
} else if (_config.bufferSize) {
|
||||
stream->setBufferSize(_config.bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *DrivePOSIXFilesystemNode::createReadStream() {
|
||||
StdioStream *readStream = PosixIoStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
|
||||
configureStream(readStream);
|
||||
|
||||
if (_config.bufferingMode == kBufferingModeScummVM) {
|
||||
uint32 bufferSize = _config.bufferSize != 0 ? _config.bufferSize : 1024;
|
||||
return Common::wrapBufferedSeekableReadStream(readStream, bufferSize, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
return readStream;
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *DrivePOSIXFilesystemNode::createWriteStream(bool atomic) {
|
||||
StdioStream *writeStream = PosixIoStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
|
||||
configureStream(writeStream);
|
||||
|
||||
if (_config.bufferingMode == kBufferingModeScummVM) {
|
||||
uint32 bufferSize = _config.bufferSize != 0 ? _config.bufferSize : 1024;
|
||||
return Common::wrapBufferedWriteStream(writeStream, bufferSize);
|
||||
}
|
||||
|
||||
return writeStream;
|
||||
}
|
||||
|
||||
DrivePOSIXFilesystemNode *DrivePOSIXFilesystemNode::getChildWithKnownType(const Common::String &n, bool isDirectoryFlag) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
DrivePOSIXFilesystemNode *child = reinterpret_cast<DrivePOSIXFilesystemNode *>(makeNode());
|
||||
child->_path = newPath;
|
||||
child->_isValid = true;
|
||||
child->_isPseudoRoot = false;
|
||||
child->_isDirectory = isDirectoryFlag;
|
||||
child->_displayName = n;
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
AbstractFSNode *DrivePOSIXFilesystemNode::getChild(const Common::String &n) const {
|
||||
DrivePOSIXFilesystemNode *child = getChildWithKnownType(n, false);
|
||||
child->setFlags();
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
bool DrivePOSIXFilesystemNode::getChildren(AbstractFSList &list, AbstractFSNode::ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
if (_isPseudoRoot) {
|
||||
return _config.getDrives(list, hidden);
|
||||
} else {
|
||||
DIR *dirp = opendir(_path.c_str());
|
||||
struct dirent *dp;
|
||||
|
||||
if (!dirp)
|
||||
return false;
|
||||
|
||||
while ((dp = readdir(dirp)) != nullptr) {
|
||||
// Skip 'invisible' files if necessary
|
||||
if (dp->d_name[0] == '.' && !hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip '.' and '..' to avoid cycles
|
||||
if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AbstractFSNode *child = nullptr;
|
||||
|
||||
#if !defined(SYSTEM_NOT_SUPPORTING_D_TYPE)
|
||||
if (dp->d_type == DT_DIR || dp->d_type == DT_REG) {
|
||||
child = getChildWithKnownType(dp->d_name, dp->d_type == DT_DIR);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
child = getChild(dp->d_name);
|
||||
}
|
||||
|
||||
// Honor the chosen mode
|
||||
if ((mode == Common::FSNode::kListFilesOnly && child->isDirectory()) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !child->isDirectory())) {
|
||||
delete child;
|
||||
continue;
|
||||
}
|
||||
|
||||
list.push_back(child);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *DrivePOSIXFilesystemNode::getParent() const {
|
||||
if (_isPseudoRoot) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (isDrive(_path)) {
|
||||
return makeNode();
|
||||
}
|
||||
|
||||
return POSIXFilesystemNode::getParent();
|
||||
}
|
||||
|
||||
bool DrivePOSIXFilesystemNode::isDrive(const Common::String &path) const {
|
||||
Common::String normalizedPath = Common::normalizePath(path, '/');
|
||||
return _config.isDrive(normalizedPath);
|
||||
}
|
||||
|
||||
#endif //#if defined(POSIX)
|
||||
85
backends/fs/posix-drives/posix-drives-fs.h
Normal file
85
backends/fs/posix-drives/posix-drives-fs.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POSIX_DRIVES_FILESYSTEM_H
|
||||
#define POSIX_DRIVES_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
|
||||
class StdioStream;
|
||||
|
||||
/**
|
||||
* POSIX file system node where the top-level directory is a hardcoded
|
||||
* list of drives.
|
||||
*/
|
||||
class DrivePOSIXFilesystemNode : public POSIXFilesystemNode {
|
||||
protected:
|
||||
virtual AbstractFSNode *makeNode() const {
|
||||
return new DrivePOSIXFilesystemNode(_config);
|
||||
}
|
||||
AbstractFSNode *makeNode(const Common::String &path) const override {
|
||||
return new DrivePOSIXFilesystemNode(path, _config);
|
||||
}
|
||||
|
||||
public:
|
||||
enum BufferingMode {
|
||||
/** IO buffering is fully disabled */
|
||||
kBufferingModeDisabled,
|
||||
/** IO buffering is enabled and uses the libc implemenation */
|
||||
kBufferingModeStdio,
|
||||
/** IO buffering is enabled and uses ScummVM's buffering stream wraappers */
|
||||
kBufferingModeScummVM
|
||||
};
|
||||
|
||||
struct Config {
|
||||
// Use the default stdio buffer size
|
||||
Config() : bufferingMode(kBufferingModeStdio), bufferSize(0) { }
|
||||
virtual ~Config() { }
|
||||
|
||||
virtual bool getDrives(AbstractFSList &list, bool hidden) const = 0;
|
||||
virtual bool isDrive(const Common::String &path) const = 0;
|
||||
|
||||
BufferingMode bufferingMode;
|
||||
uint32 bufferSize;
|
||||
};
|
||||
|
||||
DrivePOSIXFilesystemNode(const Common::String &path, const Config &config);
|
||||
DrivePOSIXFilesystemNode(const Config &config);
|
||||
|
||||
// AbstractFSNode API
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
protected:
|
||||
const Config &_config;
|
||||
|
||||
private:
|
||||
bool _isPseudoRoot;
|
||||
|
||||
DrivePOSIXFilesystemNode *getChildWithKnownType(const Common::String &n, bool isDirectoryFlag) const;
|
||||
bool isDrive(const Common::String &path) const;
|
||||
void configureStream(StdioStream *stream);
|
||||
};
|
||||
|
||||
#endif
|
||||
67
backends/fs/posix/posix-fs-factory.cpp
Normal file
67
backends/fs/posix/posix-fs-factory.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(POSIX) || defined(PLAYSTATION3) || defined(__DS__)
|
||||
|
||||
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
|
||||
// Also with clock() in sys/time.h in some macOS SDKs.
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_random
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_srandom
|
||||
|
||||
#include "backends/fs/posix/posix-fs-factory.h"
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
AbstractFSNode *POSIXFilesystemFactory::makeRootFileNode() const {
|
||||
return new POSIXFilesystemNode("/");
|
||||
}
|
||||
|
||||
AbstractFSNode *POSIXFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
#if defined(__ANDROID__)
|
||||
// Keep this here if we still want to maintain support for the Android SDL port, since this affects that too
|
||||
//
|
||||
// For Android it does not make sense to have "." in Search Manager as a current directory file node, so we skip it here
|
||||
// Otherwise this can potentially lead to a crash since, in Android getcwd() returns the root path "/"
|
||||
// and when SearchMan is used (eg. SearchSet::createReadStreamForMember) and it tries to search root path (and calls POSIXFilesystemNode::getChildren())
|
||||
// then a JNI call is made (JNI::getAllStorageLocations()) which leads to a crash if done from the wrong context -- and is also useless overhead as a call in that case.
|
||||
// This fixes the error case: Loading "Beneath A Steel Sky" with Adlib or FluidSynth audio once, exiting to Launcher via in-game ScummVM menu and re-launching the game.
|
||||
// Don't return NULL here, since it causes crash with other engines (eg. Blade Runner)
|
||||
// Returning '.' here will cause POSIXFilesystemNode::getChildren() to ignore it
|
||||
//
|
||||
// We also skip adding the '.' directory to SearchManager (in archive.cpp, SearchManager::clear())
|
||||
char buf[MAXPATHLEN] = {'.', '\0'};
|
||||
return new POSIXFilesystemNode(buf);
|
||||
#else
|
||||
char buf[MAXPATHLEN];
|
||||
return getcwd(buf, MAXPATHLEN) ? new POSIXFilesystemNode(buf) : NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
AbstractFSNode *POSIXFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
return new POSIXFilesystemNode(path);
|
||||
}
|
||||
#endif
|
||||
39
backends/fs/posix/posix-fs-factory.h
Normal file
39
backends/fs/posix/posix-fs-factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POSIX_FILESYSTEM_FACTORY_H
|
||||
#define POSIX_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates POSIXFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class POSIXFilesystemFactory : public FilesystemFactory {
|
||||
protected:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*POSIX_FILESYSTEM_FACTORY_H*/
|
||||
368
backends/fs/posix/posix-fs.cpp
Normal file
368
backends/fs/posix/posix-fs.cpp
Normal file
@@ -0,0 +1,368 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(POSIX) || defined(PLAYSTATION3) || defined(PSP2) || defined(__DS__)
|
||||
|
||||
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
|
||||
// Also with clock() in sys/time.h in some macOS SDKs.
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit //Needed for IRIX's unistd.h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_random
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_srandom
|
||||
|
||||
#include "backends/fs/posix/posix-fs.h"
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
#include "common/algorithm.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef MACOSX
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef PSP2
|
||||
#include <psp2/io/stat.h>
|
||||
#define mkdir sceIoMkdir
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __OS2__
|
||||
#define INCL_DOS
|
||||
#include <os2.h>
|
||||
#endif
|
||||
|
||||
bool POSIXFilesystemNode::exists() const {
|
||||
return access(_path.c_str(), F_OK) == 0;
|
||||
}
|
||||
|
||||
bool POSIXFilesystemNode::isReadable() const {
|
||||
return access(_path.c_str(), R_OK) == 0;
|
||||
}
|
||||
|
||||
bool POSIXFilesystemNode::isWritable() const {
|
||||
return access(_path.c_str(), W_OK) == 0;
|
||||
}
|
||||
|
||||
void POSIXFilesystemNode::setFlags() {
|
||||
struct stat st;
|
||||
|
||||
_isValid = (0 == stat(_path.c_str(), &st));
|
||||
_isDirectory = _isValid ? S_ISDIR(st.st_mode) : false;
|
||||
}
|
||||
|
||||
POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p) {
|
||||
assert(p.size() > 0);
|
||||
|
||||
// Expand "~/" to the value of the HOME env variable
|
||||
if (p.hasPrefix("~/") || p == "~") {
|
||||
const char *home = getenv("HOME");
|
||||
if (home != NULL && strlen(home) < MAXPATHLEN) {
|
||||
_path = home;
|
||||
// Skip over the tilda.
|
||||
if (p.size() > 1)
|
||||
_path += p.c_str() + 1;
|
||||
}
|
||||
} else {
|
||||
_path = p;
|
||||
}
|
||||
|
||||
#ifdef __OS2__
|
||||
// On OS/2, 'X:/' is a root of drive X, so we should not remove that last
|
||||
// slash.
|
||||
if (!(_path.size() == 3 && _path.hasSuffix(":/")))
|
||||
#endif
|
||||
// Normalize the path (that is, remove unneeded slashes etc.)
|
||||
_path = Common::normalizePath(_path, '/');
|
||||
_displayName = Common::lastPathComponent(_path, '/');
|
||||
|
||||
// TODO: should we turn relative paths into absolute ones?
|
||||
// Pro: Ensures the "getParent" works correctly even for relative dirs.
|
||||
// Contra: The user may wish to use (and keep!) relative paths in his
|
||||
// config file, and converting relative to absolute paths may hurt him...
|
||||
//
|
||||
// An alternative approach would be to change getParent() to work correctly
|
||||
// if "_path" is the empty string.
|
||||
#if 0
|
||||
if (!_path.hasPrefix("/")) {
|
||||
char buf[MAXPATHLEN+1];
|
||||
getcwd(buf, MAXPATHLEN);
|
||||
Common::strcat_s(buf, "/");
|
||||
_path = buf + _path;
|
||||
}
|
||||
#endif
|
||||
// TODO: Should we enforce that the path is absolute at this point?
|
||||
//assert(_path.hasPrefix("/"));
|
||||
|
||||
setFlags();
|
||||
}
|
||||
|
||||
AbstractFSNode *POSIXFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(!_path.empty());
|
||||
assert(_isDirectory);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
// We assume here that _path is already normalized (hence don't bother to call
|
||||
// Common::normalizePath on the final path).
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return makeNode(newPath);
|
||||
}
|
||||
|
||||
bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
#ifdef __OS2__
|
||||
if (_path == "/") {
|
||||
// Special case for the root dir: List all DOS drives
|
||||
ULONG ulDrvNum;
|
||||
ULONG ulDrvMap;
|
||||
|
||||
DosQueryCurrentDisk(&ulDrvNum, &ulDrvMap);
|
||||
|
||||
for (int i = 0; i < 26; i++) {
|
||||
if (ulDrvMap & 1) {
|
||||
char drive_root[] = "A:/";
|
||||
drive_root[0] += i;
|
||||
|
||||
POSIXFilesystemNode *entry = new POSIXFilesystemNode();
|
||||
entry->_isDirectory = true;
|
||||
entry->_isValid = true;
|
||||
entry->_path = drive_root;
|
||||
entry->_displayName = "[" + Common::String(drive_root, 2) + "]";
|
||||
myList.push_back(entry);
|
||||
}
|
||||
|
||||
ulDrvMap >>= 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
DIR *dirp = opendir(_path.c_str());
|
||||
struct dirent *dp;
|
||||
|
||||
if (dirp == NULL)
|
||||
return false;
|
||||
|
||||
// loop over dir entries using readdir
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
// Skip 'invisible' files if necessary
|
||||
if (dp->d_name[0] == '.' && !hidden) {
|
||||
continue;
|
||||
}
|
||||
// Skip '.' and '..' to avoid cycles
|
||||
if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start with a clone of this node, with the correct path set
|
||||
POSIXFilesystemNode entry(*this);
|
||||
entry._displayName = dp->d_name;
|
||||
if (_path.lastChar() != '/')
|
||||
entry._path += '/';
|
||||
entry._path += entry._displayName;
|
||||
|
||||
#if defined(SYSTEM_NOT_SUPPORTING_D_TYPE)
|
||||
/* TODO: d_type is not part of POSIX, so it might not be supported
|
||||
* on some of our targets. For those systems where it isn't supported,
|
||||
* add this #elif case, which tries to use stat() instead.
|
||||
*
|
||||
* The d_type method is used to avoid costly recurrent stat() calls in big
|
||||
* directories.
|
||||
*/
|
||||
entry.setFlags();
|
||||
#else
|
||||
switch (dp->d_type) {
|
||||
case DT_DIR:
|
||||
case DT_REG:
|
||||
entry._isValid = true;
|
||||
entry._isDirectory = (dp->d_type == DT_DIR);
|
||||
break;
|
||||
case DT_LNK:
|
||||
entry._isValid = true;
|
||||
struct stat st;
|
||||
if (stat(entry._path.c_str(), &st) == 0)
|
||||
entry._isDirectory = S_ISDIR(st.st_mode);
|
||||
else
|
||||
entry._isDirectory = false;
|
||||
break;
|
||||
case DT_UNKNOWN:
|
||||
default:
|
||||
// Fall back to stat()
|
||||
//
|
||||
// It's important NOT to limit this to DT_UNKNOWN, because d_type can
|
||||
// be unreliable on some OSes and filesystems; a confirmed example is
|
||||
// macOS 10.4, where d_type can hold bogus values when iterating over
|
||||
// the files of a cddafs mount point (as used by MacOSXAudioCDManager).
|
||||
entry.setFlags();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Skip files that are invalid for some reason (e.g. because we couldn't
|
||||
// properly stat them).
|
||||
if (!entry._isValid)
|
||||
continue;
|
||||
|
||||
// Honor the chosen mode
|
||||
if ((mode == Common::FSNode::kListFilesOnly && entry._isDirectory) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !entry._isDirectory))
|
||||
continue;
|
||||
|
||||
myList.push_back(new POSIXFilesystemNode(entry));
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *POSIXFilesystemNode::getParent() const {
|
||||
if (_path == "/")
|
||||
return 0; // The filesystem root has no parent
|
||||
|
||||
#ifdef __OS2__
|
||||
if (_path.size() == 3 && _path.hasSuffix(":/"))
|
||||
// This is a root directory of a drive
|
||||
return makeNode("/"); // return a virtual root for a list of drives
|
||||
#endif
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = start + _path.size();
|
||||
|
||||
// Strip of the last component. We make use of the fact that at this
|
||||
// point, _path is guaranteed to be normalized
|
||||
while (end > start && *(end-1) != '/')
|
||||
end--;
|
||||
|
||||
if (end == start) {
|
||||
// This only happens if we were called with a relative path, for which
|
||||
// there simply is no parent.
|
||||
// TODO: We could also resolve this by assuming that the parent is the
|
||||
// current working directory, and returning a node referring to that.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return makeNode(Common::String(start, end));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *POSIXFilesystemNode::createReadStream() {
|
||||
return PosixIoStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *POSIXFilesystemNode::createReadStreamForAltStream(Common::AltStreamType altStreamType) {
|
||||
#ifdef MACOSX
|
||||
if (altStreamType == Common::AltStreamType::MacResourceFork) {
|
||||
// Check the actual fork on a Mac computer
|
||||
return PosixIoStream::makeFromPath(getPath() + "/..namedfork/rsrc", StdioStream::WriteMode_Read);
|
||||
}
|
||||
#endif
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *POSIXFilesystemNode::createWriteStream(bool atomic) {
|
||||
return PosixIoStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
}
|
||||
|
||||
bool POSIXFilesystemNode::createDirectory() {
|
||||
if (mkdir(_path.c_str(), 0755) == 0)
|
||||
setFlags();
|
||||
|
||||
return _isValid && _isDirectory;
|
||||
}
|
||||
|
||||
namespace Posix {
|
||||
|
||||
bool assureDirectoryExists(const Common::String &dir, const char *prefix) {
|
||||
struct stat sb;
|
||||
|
||||
// Check whether the prefix exists if one is supplied.
|
||||
if (prefix) {
|
||||
if (stat(prefix, &sb) != 0) {
|
||||
return false;
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain absolute path.
|
||||
Common::String path;
|
||||
if (prefix) {
|
||||
path = prefix;
|
||||
path += '/';
|
||||
path += dir;
|
||||
} else {
|
||||
path = dir;
|
||||
}
|
||||
|
||||
path = Common::normalizePath(path, '/');
|
||||
|
||||
const Common::String::iterator end = path.end();
|
||||
Common::String::iterator cur = path.begin();
|
||||
if (*cur == '/')
|
||||
++cur;
|
||||
|
||||
do {
|
||||
if (cur + 1 != end) {
|
||||
if (*cur != '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is kind of ugly and against the purpose of Common::String to
|
||||
// insert 0s inside, but this is just for a local string and
|
||||
// simplifies the code a lot.
|
||||
*cur = '\0';
|
||||
}
|
||||
|
||||
if (mkdir(path.c_str(), 0755) != 0) {
|
||||
if (errno == EEXIST) {
|
||||
if (stat(path.c_str(), &sb) != 0) {
|
||||
return false;
|
||||
} else if (!S_ISDIR(sb.st_mode)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*cur = '/';
|
||||
} while (cur++ != end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Posix
|
||||
|
||||
#endif //#if defined(POSIX)
|
||||
94
backends/fs/posix/posix-fs.h
Normal file
94
backends/fs/posix/posix-fs.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POSIX_FILESYSTEM_H
|
||||
#define POSIX_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on POSIX.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class POSIXFilesystemNode : public AbstractFSNode {
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
bool _isDirectory;
|
||||
bool _isValid;
|
||||
|
||||
virtual AbstractFSNode *makeNode(const Common::String &path) const {
|
||||
return new POSIXFilesystemNode(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain constructor, for internal use only (hence protected).
|
||||
*/
|
||||
POSIXFilesystemNode() : _isDirectory(false), _isValid(false) {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a POSIXFilesystemNode for a given path.
|
||||
*
|
||||
* @param path the path the new node should point to.
|
||||
*/
|
||||
POSIXFilesystemNode(const Common::String &path);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableReadStream *createReadStreamForAltStream(Common::AltStreamType altStreamType) override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Tests and sets the _isValid and _isDirectory flags, using the stat() function.
|
||||
*/
|
||||
virtual void setFlags();
|
||||
};
|
||||
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* Assure that a directory path exists.
|
||||
*
|
||||
* @param dir The path which is required to exist.
|
||||
* @param prefix An (optional) prefix which should not be created if non existent.
|
||||
* prefix is prepended to dir if supplied.
|
||||
* @return true in case the directoy exists (or was created), false otherwise.
|
||||
*/
|
||||
bool assureDirectoryExists(const Common::String &dir, const char *prefix = nullptr);
|
||||
|
||||
} // End of namespace Posix
|
||||
|
||||
#endif
|
||||
46
backends/fs/posix/posix-iostream.cpp
Normal file
46
backends/fs/posix/posix-iostream.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/posix/posix-iostream.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
PosixIoStream::PosixIoStream(void *handle) :
|
||||
StdioStream(handle) {
|
||||
}
|
||||
|
||||
int64 PosixIoStream::size() const {
|
||||
int fd = fileno((FILE *)_handle);
|
||||
if (fd == -1) {
|
||||
return StdioStream::size();
|
||||
}
|
||||
|
||||
// Using fstat to obtain the file size is generally faster than fseek / ftell
|
||||
// because it does not affect the IO buffer.
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1) {
|
||||
return StdioStream::size();
|
||||
}
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
42
backends/fs/posix/posix-iostream.h
Normal file
42
backends/fs/posix/posix-iostream.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_FS_POSIX_POSIXIOSTREAM_H
|
||||
#define BACKENDS_FS_POSIX_POSIXIOSTREAM_H
|
||||
|
||||
#include "backends/fs/stdiostream.h"
|
||||
|
||||
/**
|
||||
* A file input / output stream using POSIX interfaces
|
||||
*/
|
||||
class PosixIoStream final : public StdioStream {
|
||||
public:
|
||||
static StdioStream *makeFromPath(const Common::String &path, StdioStream::WriteMode writeMode) {
|
||||
return StdioStream::makeFromPathHelper(path, writeMode, [](void *handle) -> StdioStream * {
|
||||
return new PosixIoStream(handle);
|
||||
});
|
||||
}
|
||||
PosixIoStream(void *handle);
|
||||
|
||||
int64 size() const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
26
backends/fs/ps3/ps3-fs-factory.cpp
Normal file
26
backends/fs/ps3/ps3-fs-factory.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "backends/fs/ps3/ps3-fs-factory.h"
|
||||
|
||||
AbstractFSNode *PS3FilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
return makeRootFileNode();
|
||||
}
|
||||
36
backends/fs/ps3/ps3-fs-factory.h
Normal file
36
backends/fs/ps3/ps3-fs-factory.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PS3_FILESYSTEM_FACTORY_H
|
||||
#define PS3_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/posix/posix-fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates PS3FilesystemFactory objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class PS3FilesystemFactory final : public POSIXFilesystemFactory {
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
};
|
||||
|
||||
#endif /*PS3_FILESYSTEM_FACTORY_H*/
|
||||
69
backends/fs/psp/psp-fs-factory.cpp
Normal file
69
backends/fs/psp/psp-fs-factory.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__PSP__)
|
||||
|
||||
// Disable printf override in common/forbidden.h to avoid
|
||||
// clashes with pspdebug.h from the PSP SDK.
|
||||
// That header file uses
|
||||
// __attribute__((format(printf,1,2)));
|
||||
// which gets messed up by our override mechanism; this could
|
||||
// be avoided by either changing the PSP SDK to use the equally
|
||||
// legal and valid
|
||||
// __attribute__((format(__printf__,1,2)));
|
||||
// or by refining our printf override to use a varadic macro
|
||||
// (which then wouldn't be portable, though).
|
||||
// Anyway, for now we just disable the printf override globally
|
||||
// for the PSP port
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
|
||||
#include "backends/fs/psp/psp-fs-factory.h"
|
||||
#include "backends/fs/psp/psp-fs.h"
|
||||
#include "backends/platform/psp/powerman.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(PSPFilesystemFactory);
|
||||
}
|
||||
|
||||
AbstractFSNode *PSPFilesystemFactory::makeRootFileNode() const {
|
||||
return new PSPFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *PSPFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
char *ret = 0;
|
||||
|
||||
PowerMan.beginCriticalSection();
|
||||
ret = getcwd(buf, MAXPATHLEN);
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return (ret ? new PSPFilesystemNode(buf) : NULL);
|
||||
}
|
||||
|
||||
AbstractFSNode *PSPFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
return new PSPFilesystemNode(path, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
46
backends/fs/psp/psp-fs-factory.h
Normal file
46
backends/fs/psp/psp-fs-factory.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PSP_FILESYSTEM_FACTORY_H
|
||||
#define PSP_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "common/singleton.h"
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates PSPFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class PSPFilesystemFactory final : public FilesystemFactory, public Common::Singleton<PSPFilesystemFactory> {
|
||||
public:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
protected:
|
||||
PSPFilesystemFactory() {}
|
||||
|
||||
private:
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
};
|
||||
|
||||
#endif /*PSP_FILESYSTEM_FACTORY_H*/
|
||||
261
backends/fs/psp/psp-fs.cpp
Normal file
261
backends/fs/psp/psp-fs.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__PSP__)
|
||||
|
||||
// Disable printf override in common/forbidden.h to avoid
|
||||
// clashes with pspdebug.h from the PSP SDK.
|
||||
// That header file uses
|
||||
// __attribute__((format(printf,1,2)));
|
||||
// which gets messed up by our override mechanism; this could
|
||||
// be avoided by either changing the PSP SDK to use the equally
|
||||
// legal and valid
|
||||
// __attribute__((format(__printf__,1,2)));
|
||||
// or by refining our printf override to use a varadic macro
|
||||
// (which then wouldn't be portable, though).
|
||||
// Anyway, for now we just disable the printf override globally
|
||||
// for the PSP port
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
|
||||
#include "backends/fs/psp/psp-fs.h"
|
||||
#include "backends/fs/psp/psp-stream.h"
|
||||
#include "common/bufferedstream.h"
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <pspkernel.h>
|
||||
|
||||
#define ROOT_PATH "ms0:/"
|
||||
|
||||
//#define __PSP_PRINT_TO_FILE__
|
||||
//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
|
||||
//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
|
||||
#include "backends/platform/psp/trace.h"
|
||||
|
||||
PSPFilesystemNode::PSPFilesystemNode() {
|
||||
_isDirectory = true;
|
||||
_displayName = "Root";
|
||||
_isValid = true;
|
||||
_path = ROOT_PATH;
|
||||
}
|
||||
|
||||
PSPFilesystemNode::PSPFilesystemNode(const Common::String &p, bool verify) {
|
||||
DEBUG_ENTER_FUNC();
|
||||
assert(p.size() > 0);
|
||||
|
||||
_path = p;
|
||||
_displayName = lastPathComponent(_path, '/');
|
||||
_isValid = true;
|
||||
_isDirectory = true;
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("path [%s]\n", _path.c_str());
|
||||
|
||||
if (verify) {
|
||||
struct stat st;
|
||||
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
|
||||
PSP_DEBUG_PRINT_FUNC("Suspended\n");
|
||||
_isValid = (0 == stat(_path.c_str(), &st));
|
||||
PowerMan.endCriticalSection();
|
||||
_isDirectory = S_ISDIR(st.st_mode);
|
||||
}
|
||||
}
|
||||
|
||||
bool PSPFilesystemNode::exists() const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
int ret = 0;
|
||||
|
||||
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
|
||||
PSP_DEBUG_PRINT_FUNC("Suspended\n"); // Make sure to block in case of suspend
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("path [%s]\n", _path.c_str());
|
||||
|
||||
ret = access(_path.c_str(), F_OK);
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
bool PSPFilesystemNode::isReadable() const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
int ret = 0;
|
||||
|
||||
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
|
||||
PSP_DEBUG_PRINT_FUNC("Suspended\n"); // Make sure to block in case of suspend
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("path [%s]\n", _path.c_str());
|
||||
|
||||
ret = access(_path.c_str(), R_OK);
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
bool PSPFilesystemNode::isWritable() const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
int ret = 0;
|
||||
|
||||
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
|
||||
PSP_DEBUG_PRINT_FUNC("Suspended\n"); // Make sure to block in case of suspend
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("path [%s]\n", _path.c_str());
|
||||
|
||||
ret = access(_path.c_str(), W_OK);
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
|
||||
AbstractFSNode *PSPFilesystemNode::getChild(const Common::String &n) const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
// FIXME: Pretty lame implementation! We do no error checking to speak
|
||||
// of, do not check if this is a special node, etc.
|
||||
assert(_isDirectory);
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("child [%s]\n", newPath.c_str());
|
||||
|
||||
AbstractFSNode *node = new PSPFilesystemNode(newPath, true);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool PSPFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
assert(_isDirectory);
|
||||
|
||||
//TODO: honor the hidden flag
|
||||
|
||||
bool ret = true;
|
||||
|
||||
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
|
||||
PSP_DEBUG_PRINT_FUNC("Suspended\n"); // Make sure to block in case of suspend
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("Current path[%s]\n", _path.c_str());
|
||||
|
||||
int dfd = sceIoDopen(_path.c_str());
|
||||
if (dfd > 0) {
|
||||
SceIoDirent dir;
|
||||
memset(&dir, 0, sizeof(dir));
|
||||
|
||||
while (sceIoDread(dfd, &dir) > 0) {
|
||||
// Skip 'invisible files
|
||||
if (dir.d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
PSPFilesystemNode entry;
|
||||
|
||||
entry._isValid = true;
|
||||
entry._displayName = dir.d_name;
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (newPath.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += dir.d_name;
|
||||
|
||||
entry._path = newPath;
|
||||
entry._isDirectory = dir.d_stat.st_attr & FIO_SO_IFDIR;
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("Child[%s], %s\n", entry._path.c_str(), entry._isDirectory ? "dir" : "file");
|
||||
|
||||
// Honor the chosen mode
|
||||
if ((mode == Common::FSNode::kListFilesOnly && entry._isDirectory) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !entry._isDirectory))
|
||||
continue;
|
||||
|
||||
myList.push_back(new PSPFilesystemNode(entry));
|
||||
}
|
||||
|
||||
sceIoDclose(dfd);
|
||||
ret = true;
|
||||
} else { // dfd <= 0
|
||||
ret = false;
|
||||
}
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AbstractFSNode *PSPFilesystemNode::getParent() const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
if (_path == ROOT_PATH)
|
||||
return 0;
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("current[%s]\n", _path.c_str());
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = lastPathComponent(_path, '/');
|
||||
|
||||
AbstractFSNode *node = new PSPFilesystemNode(Common::String(start, end - start), false);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *PSPFilesystemNode::createReadStream() {
|
||||
const uint32 READ_BUFFER_SIZE = 1024;
|
||||
|
||||
Common::SeekableReadStream *stream = PspIoStream::makeFromPath(getPath(), false);
|
||||
|
||||
return Common::wrapBufferedSeekableReadStream(stream, READ_BUFFER_SIZE, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *PSPFilesystemNode::createWriteStream(bool atomic) {
|
||||
const uint32 WRITE_BUFFER_SIZE = 1024;
|
||||
|
||||
// TODO: Add atomic support if possible
|
||||
Common::SeekableWriteStream *stream = PspIoStream::makeFromPath(getPath(), true);
|
||||
|
||||
return Common::wrapBufferedWriteStream(stream, WRITE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
bool PSPFilesystemNode::createDirectory() {
|
||||
DEBUG_ENTER_FUNC();
|
||||
|
||||
if (PowerMan.beginCriticalSection() == PowerManager::Blocked)
|
||||
PSP_DEBUG_PRINT_FUNC("Suspended\n"); // Make sure to block in case of suspend
|
||||
|
||||
PSP_DEBUG_PRINT_FUNC("path [%s]\n", _path.c_str());
|
||||
|
||||
if (sceIoMkdir(_path.c_str(), 0777) == 0) {
|
||||
struct stat st;
|
||||
_isValid = (0 == stat(_path.c_str(), &st));
|
||||
_isDirectory = S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return _isValid && _isDirectory;
|
||||
}
|
||||
|
||||
#endif //#ifdef __PSP__
|
||||
70
backends/fs/psp/psp-fs.h
Normal file
70
backends/fs/psp/psp-fs.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PSP_FILESYSTEM_H
|
||||
#define PSP_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on PSPSDK API.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class PSPFilesystemNode : public AbstractFSNode {
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
bool _isDirectory;
|
||||
bool _isValid;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a PSPFilesystemNode with the root node as path.
|
||||
*/
|
||||
PSPFilesystemNode();
|
||||
|
||||
/**
|
||||
* Creates a PSPFilesystemNode for a given path.
|
||||
*
|
||||
* @param path Common::String with the path the new node should point to.
|
||||
* @param verify true if the isValid and isDirectory flags should be verified during the construction.
|
||||
*/
|
||||
PSPFilesystemNode(const Common::String &p, bool verify = true);
|
||||
|
||||
virtual bool exists() const;
|
||||
virtual Common::U32String getDisplayName() const { return _displayName; }
|
||||
virtual Common::String getName() const { return _displayName; }
|
||||
virtual Common::String getPath() const { return _path; }
|
||||
virtual bool isDirectory() const { return _isDirectory; }
|
||||
virtual bool isReadable() const;
|
||||
virtual bool isWritable() const;
|
||||
|
||||
virtual AbstractFSNode *getChild(const Common::String &n) const;
|
||||
virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
|
||||
virtual AbstractFSNode *getParent() const;
|
||||
|
||||
virtual Common::SeekableReadStream *createReadStream();
|
||||
virtual Common::SeekableWriteStream *createWriteStream(bool atomic);
|
||||
virtual bool createDirectory();
|
||||
};
|
||||
|
||||
#endif
|
||||
335
backends/fs/psp/psp-stream.cpp
Normal file
335
backends/fs/psp/psp-stream.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
#ifdef __PSP__
|
||||
|
||||
#include <pspiofilemgr.h>
|
||||
|
||||
#include "backends/platform/psp/powerman.h"
|
||||
#include "backends/fs/psp/psp-stream.h"
|
||||
|
||||
#define MIN2(a,b) ((a < b) ? a : b)
|
||||
#define MIN3(a,b,c) ( (a < b) ? (a < c ? a : c) : (b < c ? b : c) )
|
||||
|
||||
//#define __PSP_PRINT_TO_FILE__ /* For debugging suspend stuff, we have no screen output */
|
||||
//#define __PSP_DEBUG_FUNCS__ /* For debugging function calls */
|
||||
//#define __PSP_DEBUG_PRINT__ /* For debug printouts */
|
||||
|
||||
#include "backends/platform/psp/trace.h"
|
||||
|
||||
//#define DEBUG_BUFFERS /* to see the contents of the buffers being read */
|
||||
|
||||
#ifdef DEBUG_BUFFERS
|
||||
void printBuffer(byte *ptr, uint32 len) {
|
||||
uint32 printLen = len <= 10 ? len : 10;
|
||||
|
||||
for (int i = 0; i < printLen; i++) {
|
||||
PSP_INFO_PRINT("%x ", ptr[i]);
|
||||
}
|
||||
|
||||
if (len > 10) {
|
||||
PSP_INFO_PRINT("... ");
|
||||
for (int i = len - 10; i < len; i++)
|
||||
PSP_INFO_PRINT("%x ", ptr[i]);
|
||||
}
|
||||
|
||||
PSP_INFO_PRINT("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Class PspIoStream ------------------------------------------------
|
||||
|
||||
PspIoStream::PspIoStream(const Common::String &path, bool writeMode)
|
||||
: _handle(0), _path(path), _fileSize(0), _writeMode(writeMode),
|
||||
_physicalPos(0), _pos(0), _eos(false), _error(false),
|
||||
_errorSuspend(0), _errorSource(0), _errorPos(0), _errorHandle(0), _suspendCount(0) {
|
||||
DEBUG_ENTER_FUNC();
|
||||
|
||||
//assert(!path.empty()); // do we need this?
|
||||
}
|
||||
|
||||
PspIoStream::~PspIoStream() {
|
||||
DEBUG_ENTER_FUNC();
|
||||
|
||||
if (PowerMan.beginCriticalSection())
|
||||
PSP_DEBUG_PRINT_FUNC("suspended\n");
|
||||
|
||||
PowerMan.unregisterForSuspend(this); // Unregister with powermanager to be suspended
|
||||
// Must do this before fclose() or resume() will reopen.
|
||||
sceIoClose(_handle);
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
}
|
||||
|
||||
/* Function to open the file pointed to by the path.
|
||||
*
|
||||
*/
|
||||
SceUID PspIoStream::open() {
|
||||
DEBUG_ENTER_FUNC();
|
||||
|
||||
if (PowerMan.beginCriticalSection()) {
|
||||
// No need to open? Just return the _handle resume() already opened
|
||||
PSP_DEBUG_PRINT_FUNC("suspended\n");
|
||||
}
|
||||
|
||||
_handle = sceIoOpen(_path.c_str(), _writeMode ? PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC : PSP_O_RDONLY, 0777);
|
||||
if (_handle <= 0) {
|
||||
_error = true;
|
||||
_handle = 0;
|
||||
}
|
||||
|
||||
// Get the file size. This way is much faster than going to the end of the file and back
|
||||
SceIoStat stat;
|
||||
sceIoGetstat(_path.c_str(), &stat);
|
||||
_fileSize = stat.st_size; // 4GB file (32 bits) is big enough for us
|
||||
|
||||
PSP_DEBUG_PRINT("%s filesize[%d]\n", _path.c_str(), _fileSize);
|
||||
|
||||
PowerMan.registerForSuspend(this); // Register with the powermanager to be suspended
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
return _handle;
|
||||
}
|
||||
|
||||
bool PspIoStream::err() const {
|
||||
DEBUG_ENTER_FUNC();
|
||||
|
||||
if (_error) // We dump since no printing to screen with suspend callback
|
||||
PSP_ERROR("mem_error[%d], source[%d], suspend error[%d], pos[%d],"
|
||||
"_errorPos[%d], _errorHandle[%p], suspendCount[%d]\n",
|
||||
_error, _errorSource, _errorSuspend, _pos,
|
||||
_errorPos, _errorHandle, _suspendCount);
|
||||
|
||||
return _error;
|
||||
}
|
||||
|
||||
void PspIoStream::clearErr() {
|
||||
_error = false;
|
||||
}
|
||||
|
||||
bool PspIoStream::eos() const {
|
||||
return _eos;
|
||||
}
|
||||
|
||||
int64 PspIoStream::pos() const {
|
||||
return _pos;
|
||||
}
|
||||
|
||||
int64 PspIoStream::size() const {
|
||||
return _fileSize;
|
||||
}
|
||||
|
||||
bool PspIoStream::physicalSeekFromCur(int32 offset) {
|
||||
|
||||
int ret = sceIoLseek32(_handle, offset, PSP_SEEK_CUR);
|
||||
|
||||
if (ret < 0) {
|
||||
_error = true;
|
||||
PSP_ERROR("failed to seek in file[%s] to [%x]. Error[%x]\n", _path.c_str(), offset, ret);
|
||||
return false;
|
||||
}
|
||||
_physicalPos += offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PspIoStream::seek(int64 offs, int whence) {
|
||||
DEBUG_ENTER_FUNC();
|
||||
PSP_DEBUG_PRINT_FUNC("offset[0x%x], whence[%d], _pos[0x%x], _physPos[0x%x]\n", offs, whence, _pos, _physicalPos);
|
||||
_eos = false;
|
||||
|
||||
int32 posToSearchFor = 0;
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
posToSearchFor = _pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
posToSearchFor = _fileSize;
|
||||
break;
|
||||
}
|
||||
posToSearchFor += offs;
|
||||
|
||||
// Check for bad values
|
||||
if (posToSearchFor < 0) {
|
||||
_error = true;
|
||||
return false;
|
||||
} else if (posToSearchFor > _fileSize) {
|
||||
_error = true;
|
||||
_eos = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
_pos = posToSearchFor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 PspIoStream::read(void *ptr, uint32 len) {
|
||||
DEBUG_ENTER_FUNC();
|
||||
PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x], ptr[%p], _pos[%x], _physPos[%x]\n", _path.c_str(), len, ptr, _pos, _physicalPos);
|
||||
|
||||
if (_error || _eos || len <= 0)
|
||||
return 0;
|
||||
|
||||
uint32 lenRemainingInFile = _fileSize - _pos;
|
||||
|
||||
// check for getting EOS
|
||||
if (len > lenRemainingInFile) {
|
||||
len = lenRemainingInFile;
|
||||
_eos = true;
|
||||
}
|
||||
|
||||
if (PowerMan.beginCriticalSection())
|
||||
PSP_DEBUG_PRINT_FUNC("suspended\n");
|
||||
|
||||
// check if we need to seek
|
||||
if (_pos != _physicalPos) {
|
||||
PSP_DEBUG_PRINT("seeking from %x to %x\n", _physicalPos, _pos);
|
||||
if (!physicalSeekFromCur(_pos - _physicalPos)) {
|
||||
_error = true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ret = sceIoRead(_handle, ptr, len);
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
_physicalPos += ret; // Update position
|
||||
_pos = _physicalPos;
|
||||
|
||||
if (ret != (int)len) { // error
|
||||
PSP_ERROR("sceIoRead returned [0x%x] instead of len[0x%x]\n", ret, len);
|
||||
_error = true;
|
||||
_errorSource = 4;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32 PspIoStream::write(const void *ptr, uint32 len) {
|
||||
DEBUG_ENTER_FUNC();
|
||||
PSP_DEBUG_PRINT_FUNC("filename[%s], len[0x%x], ptr[%p], _pos[%x], _physPos[%x]\n", _path.c_str(), len, ptr, _pos, _physicalPos);
|
||||
|
||||
if (!len || _error) // we actually get some calls with len == 0!
|
||||
return 0;
|
||||
|
||||
_eos = false; // we can't have eos with write
|
||||
|
||||
if (PowerMan.beginCriticalSection())
|
||||
PSP_DEBUG_PRINT_FUNC("suspended\n");
|
||||
|
||||
// check if we need to seek
|
||||
if (_pos != _physicalPos)
|
||||
if (!physicalSeekFromCur(_pos - _physicalPos)) {
|
||||
_error = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = sceIoWrite(_handle, ptr, len);
|
||||
|
||||
PowerMan.endCriticalSection();
|
||||
|
||||
if (ret != (int)len) {
|
||||
_error = true;
|
||||
_errorSource = 5;
|
||||
PSP_ERROR("sceIoWrite returned[0x%x] instead of len[0x%x]\n", ret, len);
|
||||
}
|
||||
|
||||
_physicalPos += ret;
|
||||
_pos = _physicalPos;
|
||||
|
||||
if (_pos > _fileSize)
|
||||
_fileSize = _pos;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool PspIoStream::flush() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// For the PSP, since we're building in suspend support, we moved opening
|
||||
// the actual file to an open function since we need an actual PspIoStream object to suspend.
|
||||
//
|
||||
PspIoStream *PspIoStream::makeFromPath(const Common::String &path, bool writeMode) {
|
||||
DEBUG_ENTER_FUNC();
|
||||
PspIoStream *stream = new PspIoStream(path, writeMode);
|
||||
|
||||
if (stream->open() <= 0) {
|
||||
delete stream;
|
||||
stream = 0;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to suspend the IO stream (called by PowerManager)
|
||||
* we can have no output here
|
||||
*/
|
||||
int PspIoStream::suspend() {
|
||||
DEBUG_ENTER_FUNC();
|
||||
_suspendCount++;
|
||||
|
||||
if (_handle > 0 && _pos < 0) { /* check for error */
|
||||
_errorSuspend = SuspendError;
|
||||
_errorPos = _pos;
|
||||
_errorHandle = _handle;
|
||||
}
|
||||
|
||||
if (_handle > 0) {
|
||||
sceIoClose(_handle); // close our file descriptor
|
||||
_handle = 0xFFFFFFFF; // Set handle to non-null invalid value so makeFromPath doesn't return error
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to resume the IO stream (called by Power Manager)
|
||||
*/
|
||||
int PspIoStream::resume() {
|
||||
DEBUG_ENTER_FUNC();
|
||||
int ret = 0;
|
||||
_suspendCount--;
|
||||
|
||||
// We reopen our file descriptor
|
||||
_handle = sceIoOpen(_path.c_str(), _writeMode ? PSP_O_RDWR | PSP_O_CREAT : PSP_O_RDONLY, 0777); // open
|
||||
if (_handle <= 0) {
|
||||
_errorSuspend = ResumeError;
|
||||
_errorPos = _pos;
|
||||
}
|
||||
|
||||
// Resume our previous position if needed
|
||||
if (_handle > 0 && _pos > 0) {
|
||||
ret = sceIoLseek32(_handle, _pos, PSP_SEEK_SET);
|
||||
|
||||
_physicalPos = _pos;
|
||||
|
||||
if (ret < 0) { // Check for problem
|
||||
_errorSuspend = ResumeError;
|
||||
_errorPos = _pos;
|
||||
_errorHandle = _handle;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __PSP__ */
|
||||
90
backends/fs/psp/psp-stream.h
Normal file
90
backends/fs/psp/psp-stream.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PSPSTREAM_H_
|
||||
#define PSPSTREAM_H_
|
||||
|
||||
#include <pspkerneltypes.h>
|
||||
#include "backends/platform/psp/powerman.h"
|
||||
//#include "common/list.h"
|
||||
#include "common/noncopyable.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/str.h"
|
||||
|
||||
/**
|
||||
* Class to handle special suspend/resume needs of PSP IO Streams
|
||||
*/
|
||||
class PspIoStream final : public Common::SeekableReadStream, public Common::SeekableWriteStream, public Common::NonCopyable, public Suspendable {
|
||||
protected:
|
||||
SceUID _handle; // file handle
|
||||
Common::String _path;
|
||||
int _fileSize;
|
||||
bool _writeMode; // for resuming in the right mode
|
||||
int _physicalPos; // physical position in file
|
||||
int _pos; // position. Sometimes virtual
|
||||
bool _eos; // EOS flag
|
||||
|
||||
enum {
|
||||
SuspendError = 2,
|
||||
ResumeError = 3
|
||||
};
|
||||
|
||||
// debug stuff
|
||||
mutable int _error; // file error state
|
||||
int _errorSuspend; // for debugging
|
||||
mutable int _errorSource;
|
||||
int _errorPos;
|
||||
SceUID _errorHandle;
|
||||
int _suspendCount;
|
||||
|
||||
bool physicalSeekFromCur(int32 offset);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Given a path, invoke fopen on that path and wrap the result in a
|
||||
* PspIoStream instance.
|
||||
*/
|
||||
static PspIoStream *makeFromPath(const Common::String &path, bool writeMode);
|
||||
|
||||
PspIoStream(const Common::String &path, bool writeMode);
|
||||
~PspIoStream() override;
|
||||
|
||||
SceUID open(); // open the file pointed to by the file path
|
||||
|
||||
bool err() const override;
|
||||
void clearErr() override;
|
||||
bool eos() const override;
|
||||
|
||||
uint32 write(const void *dataPtr, uint32 dataSize) override;
|
||||
bool flush() override;
|
||||
|
||||
int64 pos() const override;
|
||||
int64 size() const override;
|
||||
bool seek(int64 offs, int whence = SEEK_SET) override;
|
||||
uint32 read(void *dataPtr, uint32 dataSize) override;
|
||||
|
||||
// for suspending
|
||||
int suspend() override; /* Suspendable interface (power manager) */
|
||||
int resume() override; /* " " */
|
||||
};
|
||||
|
||||
#endif /* PSPSTREAM_H_ */
|
||||
47
backends/fs/riscos/riscos-fs-factory.cpp
Normal file
47
backends/fs/riscos/riscos-fs-factory.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#if defined(RISCOS)
|
||||
|
||||
#include "backends/fs/riscos/riscos-fs-factory.h"
|
||||
#include "backends/fs/riscos/riscos-fs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
AbstractFSNode *RISCOSFilesystemFactory::makeRootFileNode() const {
|
||||
return new RISCOSFilesystemNode("/");
|
||||
}
|
||||
|
||||
AbstractFSNode *RISCOSFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
return getcwd(buf, MAXPATHLEN) ? new RISCOSFilesystemNode(buf) : NULL;
|
||||
}
|
||||
|
||||
AbstractFSNode *RISCOSFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
assert(!path.empty());
|
||||
return new RISCOSFilesystemNode(path);
|
||||
}
|
||||
#endif
|
||||
39
backends/fs/riscos/riscos-fs-factory.h
Normal file
39
backends/fs/riscos/riscos-fs-factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RISCOS_FILESYSTEM_FACTORY_H
|
||||
#define RISCOS_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates RISCOSFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class RISCOSFilesystemFactory final : public FilesystemFactory {
|
||||
protected:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*RISCOS_FILESYSTEM_FACTORY_H*/
|
||||
288
backends/fs/riscos/riscos-fs.cpp
Normal file
288
backends/fs/riscos/riscos-fs.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h.
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
|
||||
#include "common/scummsys.h"
|
||||
|
||||
#if defined(RISCOS)
|
||||
|
||||
#include "backends/platform/sdl/riscos/riscos-utils.h"
|
||||
#include "backends/fs/riscos/riscos-fs.h"
|
||||
#include "backends/fs/stdiostream.h"
|
||||
#include "common/algorithm.h"
|
||||
|
||||
// TODO: Replace use of access()
|
||||
#include <unistd.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <swis.h>
|
||||
|
||||
bool RISCOSFilesystemNode::exists() const {
|
||||
return access(_path.c_str(), F_OK) == 0;
|
||||
}
|
||||
|
||||
bool RISCOSFilesystemNode::isReadable() const {
|
||||
return access(_path.c_str(), R_OK) == 0;
|
||||
}
|
||||
|
||||
bool RISCOSFilesystemNode::isWritable() const {
|
||||
return access(_path.c_str(), W_OK) == 0;
|
||||
}
|
||||
|
||||
void RISCOSFilesystemNode::setFlags() {
|
||||
_kernel_swi_regs regs;
|
||||
regs.r[0] = 23;
|
||||
regs.r[1] = (int)_nativePath.c_str();
|
||||
_kernel_swi(OS_File, ®s, ®s);
|
||||
|
||||
if (regs.r[0] == 0) {
|
||||
_isDirectory = false;
|
||||
_isValid = false;
|
||||
} else if (regs.r[0] == 2) {
|
||||
_isDirectory = true;
|
||||
_isValid = true;
|
||||
} else {
|
||||
_isDirectory = false;
|
||||
_isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
RISCOSFilesystemNode::RISCOSFilesystemNode(const Common::String &p) {
|
||||
_path = p;
|
||||
if (p == "/") {
|
||||
_nativePath = "";
|
||||
_isDirectory = true;
|
||||
_isValid = true;
|
||||
} else {
|
||||
_nativePath = RISCOS_Utils::toRISCOS(p);
|
||||
setFlags();
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *RISCOSFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(!_path.empty());
|
||||
assert(_isDirectory);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
// We assume here that _path is already normalized (hence don't bother to call
|
||||
// Common::normalizePath on the final path).
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return makeNode(newPath);
|
||||
}
|
||||
|
||||
bool RISCOSFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
if (_path == "/") {
|
||||
// Special case for the root dir: List all drives
|
||||
char fsname[MAXPATHLEN] = "";
|
||||
for (int fsNum = 0; fsNum < 256; fsNum += 1) {
|
||||
if (fsNum == 33 || fsNum == 46 || fsNum == 53 || fsNum == 99)
|
||||
continue;
|
||||
|
||||
_kernel_swi_regs regs;
|
||||
regs.r[0] = 33;
|
||||
regs.r[1] = fsNum;
|
||||
regs.r[2] = (int)fsname;
|
||||
regs.r[3] = sizeof(fsname);
|
||||
_kernel_swi(OS_FSControl, ®s, ®s);
|
||||
if (fsname[0] == 0)
|
||||
continue;
|
||||
|
||||
int drives = (fsNum == 193) ? 23 : 9;
|
||||
|
||||
for (int discnum = 0; discnum <= drives; discnum += 1) {
|
||||
const Common::String path = Common::String::format("%s::%d.$", fsname, discnum);
|
||||
char outpath[MAXPATHLEN] = "";
|
||||
regs.r[0] = 37;
|
||||
regs.r[1] = (int)path.c_str();
|
||||
regs.r[2] = (int)outpath;
|
||||
regs.r[3] = 0;
|
||||
regs.r[4] = 0;
|
||||
regs.r[5] = sizeof(outpath);
|
||||
if (_kernel_swi(OS_FSControl, ®s, ®s) != NULL)
|
||||
continue;
|
||||
|
||||
RISCOSFilesystemNode *entry = new RISCOSFilesystemNode();
|
||||
entry->_nativePath = outpath;
|
||||
entry->_path = Common::String('/') + outpath;
|
||||
entry->_displayName = outpath;
|
||||
entry->setFlags();
|
||||
if (entry->_isDirectory)
|
||||
myList.push_back(entry);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char file[MAXPATHLEN];
|
||||
_kernel_swi_regs regs;
|
||||
regs.r[0] = 9;
|
||||
regs.r[1] = (int)_nativePath.c_str();
|
||||
regs.r[2] = (int)file;
|
||||
regs.r[3] = 1;
|
||||
regs.r[4] = 0;
|
||||
regs.r[5] = sizeof(file);
|
||||
regs.r[6] = 0;
|
||||
while (regs.r[4] != -1) {
|
||||
_kernel_swi(OS_GBPB, ®s, ®s);
|
||||
|
||||
if (regs.r[4] == -1)
|
||||
break;
|
||||
|
||||
// Start with a clone of this node, with the correct path set
|
||||
RISCOSFilesystemNode entry(*this);
|
||||
entry._displayName = file;
|
||||
entry._displayName = RISCOS_Utils::toUnix(entry._displayName);
|
||||
if (_path.lastChar() != '/')
|
||||
entry._path += '/';
|
||||
entry._path += entry._displayName;
|
||||
entry._nativePath = RISCOS_Utils::toRISCOS(entry._path);
|
||||
entry.setFlags();
|
||||
if (!entry._isValid)
|
||||
continue;
|
||||
|
||||
// Honor the chosen mode
|
||||
if ((mode == Common::FSNode::kListFilesOnly && entry._isDirectory) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !entry._isDirectory))
|
||||
continue;
|
||||
|
||||
myList.push_back(new RISCOSFilesystemNode(entry));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *RISCOSFilesystemNode::getParent() const {
|
||||
if (_path == "/")
|
||||
return 0; // The filesystem root has no parent
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = start + _path.size();
|
||||
|
||||
// Strip of the last component. We make use of the fact that at this
|
||||
// point, _path is guaranteed to be normalized
|
||||
while (end > start && *(end-1) != '/')
|
||||
end--;
|
||||
|
||||
if (end == start) {
|
||||
// This only happens if we were called with a relative path, for which
|
||||
// there simply is no parent.
|
||||
// TODO: We could also resolve this by assuming that the parent is the
|
||||
// current working directory, and returning a node referring to that.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*(end-1) == '/' && end != start + 1)
|
||||
end--;
|
||||
|
||||
return makeNode(Common::String(start, end));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *RISCOSFilesystemNode::createReadStream() {
|
||||
return StdioStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *RISCOSFilesystemNode::createWriteStream(bool atomic) {
|
||||
return StdioStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
}
|
||||
|
||||
bool RISCOSFilesystemNode::createDirectory() {
|
||||
_kernel_swi_regs regs;
|
||||
regs.r[0] = 8;
|
||||
regs.r[1] = (int)_nativePath.c_str();
|
||||
if (_kernel_swi(OS_File, ®s, ®s) == NULL)
|
||||
setFlags();
|
||||
|
||||
return _isValid && _isDirectory;
|
||||
}
|
||||
|
||||
namespace Riscos {
|
||||
|
||||
bool assureDirectoryExists(const Common::String &dir, const char *prefix) {
|
||||
AbstractFSNode *node;
|
||||
|
||||
// Check whether the prefix exists if one is supplied.
|
||||
if (prefix) {
|
||||
node = new RISCOSFilesystemNode(prefix);
|
||||
if (!node->isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain absolute path.
|
||||
Common::String path;
|
||||
if (prefix) {
|
||||
path = prefix;
|
||||
path += '/';
|
||||
path += dir;
|
||||
} else {
|
||||
path = dir;
|
||||
}
|
||||
|
||||
path = Common::normalizePath(path, '/');
|
||||
|
||||
const Common::String::iterator end = path.end();
|
||||
Common::String::iterator cur = path.begin();
|
||||
if (*cur == '/')
|
||||
++cur;
|
||||
|
||||
do {
|
||||
if (cur + 1 != end) {
|
||||
if (*cur != '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is kind of ugly and against the purpose of Common::String to
|
||||
// insert 0s inside, but this is just for a local string and
|
||||
// simplifies the code a lot.
|
||||
*cur = '\0';
|
||||
}
|
||||
|
||||
node = new RISCOSFilesystemNode(path);
|
||||
if (!node->createDirectory()) {
|
||||
if (node->exists()) {
|
||||
if (!node->isDirectory()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*cur = '/';
|
||||
} while (cur++ != end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace RISCOS
|
||||
|
||||
#endif //#if defined(RISCOS)
|
||||
92
backends/fs/riscos/riscos-fs.h
Normal file
92
backends/fs/riscos/riscos-fs.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RISCOS_FILESYSTEM_H
|
||||
#define RISCOS_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class RISCOSFilesystemNode final : public AbstractFSNode {
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _nativePath;
|
||||
Common::String _path;
|
||||
bool _isDirectory;
|
||||
bool _isValid;
|
||||
|
||||
virtual AbstractFSNode *makeNode(const Common::String &path) const {
|
||||
return new RISCOSFilesystemNode(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain constructor, for internal use only (hence protected).
|
||||
*/
|
||||
RISCOSFilesystemNode() : _isDirectory(false), _isValid(false) {}
|
||||
public:
|
||||
/**
|
||||
* Creates a RISCOSFilesystemNode for a given path.
|
||||
*
|
||||
* @param path the path the new node should point to.
|
||||
*/
|
||||
RISCOSFilesystemNode(const Common::String &path);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
private:
|
||||
/**
|
||||
* Tests and sets the _isValid and _isDirectory flags, using OS_File 20.
|
||||
*/
|
||||
virtual void setFlags();
|
||||
};
|
||||
|
||||
namespace Riscos {
|
||||
|
||||
/**
|
||||
* Assure that a directory path exists.
|
||||
*
|
||||
* @param dir The path which is required to exist.
|
||||
* @param prefix An (optional) prefix which should not be created if non existent.
|
||||
* prefix is prepended to dir if supplied.
|
||||
* @return true in case the directoy exists (or was created), false otherwise.
|
||||
*/
|
||||
bool assureDirectoryExists(const Common::String &dir, const char *prefix = nullptr);
|
||||
|
||||
} // End of namespace RISCOS
|
||||
|
||||
#endif
|
||||
216
backends/fs/stdiostream.cpp
Normal file
216
backends/fs/stdiostream.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if !defined(DISABLE_STDIO_FILESTREAM)
|
||||
|
||||
// Disable symbol overrides so that we can use FILE, fopen etc.
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
// for Windows unicode fopen(): _wfopen() and for Win32::moveFile()
|
||||
#if defined(WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include "backends/platform/sdl/win32/win32_wrapper.h"
|
||||
#endif
|
||||
|
||||
// Include this after windows.h so we don't get a warning for redefining ARRAYSIZE
|
||||
#include "backends/fs/stdiostream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#if defined(__DC__)
|
||||
// libronin doesn't support rename
|
||||
#define STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
#endif
|
||||
#if defined(ATARI)
|
||||
// Atari file names must have a 8.3 format, atomic breaks this
|
||||
#define STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
#endif
|
||||
#if defined(RISCOS)
|
||||
// RISC OS file names are expected to be 10 characters or less, atomic makes this hard to guarantee
|
||||
#define STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
#endif
|
||||
|
||||
StdioStream::StdioStream(void *handle) : _handle(handle), _path(nullptr) {
|
||||
assert(handle);
|
||||
}
|
||||
|
||||
StdioStream::~StdioStream() {
|
||||
fclose((FILE *)_handle);
|
||||
|
||||
if (!_path) {
|
||||
return;
|
||||
}
|
||||
|
||||
// _path is set: recreate the temporary file name and rename the file to
|
||||
// its real name
|
||||
Common::String tmpPath(*_path);
|
||||
tmpPath += ".tmp";
|
||||
|
||||
if (!moveFile(tmpPath, *_path)) {
|
||||
warning("Couldn't save file %s", _path->c_str());
|
||||
}
|
||||
|
||||
delete _path;
|
||||
}
|
||||
|
||||
bool StdioStream::moveFile(const Common::String &src, const Common::String &dst) {
|
||||
#ifndef STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
// This piece of code can't be in a subclass override, as moveFile is called from the destructor.
|
||||
// In this case, the vtable is reset to the StdioStream one before calling moveFile.
|
||||
#if defined(WIN32)
|
||||
return Win32::moveFile(src, dst);
|
||||
#else
|
||||
if (!rename(src.c_str(), dst.c_str())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Error: try to delete the file first
|
||||
(void)remove(dst.c_str());
|
||||
return !rename(src.c_str(), dst.c_str());
|
||||
#endif
|
||||
#else // STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool StdioStream::err() const {
|
||||
return ferror((FILE *)_handle) != 0;
|
||||
}
|
||||
|
||||
void StdioStream::clearErr() {
|
||||
clearerr((FILE *)_handle);
|
||||
}
|
||||
|
||||
bool StdioStream::eos() const {
|
||||
return feof((FILE *)_handle) != 0;
|
||||
}
|
||||
|
||||
int64 StdioStream::pos() const {
|
||||
#if defined(WIN32)
|
||||
return _ftelli64((FILE *)_handle);
|
||||
#elif defined(HAS_FSEEKO_OFFT_64)
|
||||
return ftello((FILE *)_handle);
|
||||
#elif defined(HAS_FSEEKO64)
|
||||
return ftello64((FILE *)_handle);
|
||||
#else
|
||||
return ftell((FILE *)_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
int64 StdioStream::size() const {
|
||||
#if defined(WIN32)
|
||||
int64 oldPos = _ftelli64((FILE *)_handle);
|
||||
_fseeki64((FILE *)_handle, 0, SEEK_END);
|
||||
int64 length = _ftelli64((FILE *)_handle);
|
||||
_fseeki64((FILE *)_handle, oldPos, SEEK_SET);
|
||||
#elif defined(HAS_FSEEKO_OFFT_64)
|
||||
int64 oldPos = ftello((FILE *)_handle);
|
||||
fseeko((FILE *)_handle, 0, SEEK_END);
|
||||
int64 length = ftello((FILE *)_handle);
|
||||
fseeko((FILE *)_handle, oldPos, SEEK_SET);
|
||||
#elif defined(HAS_FSEEKO64)
|
||||
int64 oldPos = ftello64((FILE *)_handle);
|
||||
fseeko64((FILE *)_handle, 0, SEEK_END);
|
||||
int64 length = ftello64((FILE *)_handle);
|
||||
fseeko64((FILE *)_handle, oldPos, SEEK_SET);
|
||||
#else
|
||||
int64 oldPos = ftell((FILE *)_handle);
|
||||
fseek((FILE *)_handle, 0, SEEK_END);
|
||||
int64 length = ftell((FILE *)_handle);
|
||||
fseek((FILE *)_handle, oldPos, SEEK_SET);
|
||||
#endif
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
bool StdioStream::seek(int64 offs, int whence) {
|
||||
#if defined(WIN32)
|
||||
return _fseeki64((FILE *)_handle, offs, whence) == 0;
|
||||
#elif defined(HAS_FSEEKO_OFFT_64)
|
||||
return fseeko((FILE *)_handle, offs, whence) == 0;
|
||||
#elif defined(HAS_FSEEKO64)
|
||||
return fseeko64((FILE *)_handle, offs, whence) == 0;
|
||||
#else
|
||||
return fseek((FILE *)_handle, offs, whence) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32 StdioStream::read(void *ptr, uint32 len) {
|
||||
return fread((byte *)ptr, 1, len, (FILE *)_handle);
|
||||
}
|
||||
|
||||
bool StdioStream::setBufferSize(uint32 bufferSize) {
|
||||
if (bufferSize != 0) {
|
||||
return setvbuf((FILE *)_handle, nullptr, _IOFBF, bufferSize) == 0;
|
||||
} else {
|
||||
return setvbuf((FILE *)_handle, nullptr, _IONBF, 0) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 StdioStream::write(const void *ptr, uint32 len) {
|
||||
return fwrite(ptr, 1, len, (FILE *)_handle);
|
||||
}
|
||||
|
||||
bool StdioStream::flush() {
|
||||
return fflush((FILE *)_handle) == 0;
|
||||
}
|
||||
|
||||
StdioStream *StdioStream::makeFromPathHelper(const Common::String &path, WriteMode writeMode,
|
||||
StdioStream *(*factory)(void *handle)) {
|
||||
Common::String tmpPath(path);
|
||||
|
||||
// If no atmoic support is compiled in, WriteMode_WriteAtomic must behave like WriteMode_Write
|
||||
#ifndef STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
// In atomic mode we create a temporary file and rename it when closing the file descriptor
|
||||
if (writeMode == WriteMode_WriteAtomic) {
|
||||
tmpPath += ".tmp";
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
wchar_t *wPath = Win32::stringToTchar(tmpPath);
|
||||
FILE *handle = _wfopen(wPath, writeMode == WriteMode_Read ? L"rb" : L"wb");
|
||||
free(wPath);
|
||||
#elif defined(HAS_FOPEN64)
|
||||
FILE *handle = fopen64(tmpPath.c_str(), writeMode == WriteMode_Read ? "rb" : "wb");
|
||||
#else
|
||||
FILE *handle = fopen(tmpPath.c_str(), writeMode == WriteMode_Read ? "rb" : "wb");
|
||||
#endif
|
||||
|
||||
if (!handle) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StdioStream *stream = factory(handle);
|
||||
|
||||
#ifndef STDIOSTREAM_NO_ATOMIC_SUPPORT
|
||||
// Store the final path alongside the stream
|
||||
// If _path is not nullptr, it will be used to rename the file
|
||||
// when closing it
|
||||
if (writeMode == WriteMode_WriteAtomic) {
|
||||
stream->_path = new Common::String(path);
|
||||
}
|
||||
#endif
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
#endif
|
||||
98
backends/fs/stdiostream.h
Normal file
98
backends/fs/stdiostream.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BACKENDS_FS_STDIOSTREAM_H
|
||||
#define BACKENDS_FS_STDIOSTREAM_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/noncopyable.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/str.h"
|
||||
|
||||
class StdioStream : public Common::SeekableReadStream, public Common::SeekableWriteStream, public Common::NonCopyable {
|
||||
public:
|
||||
enum WriteMode {
|
||||
WriteMode_Read = 0,
|
||||
WriteMode_Write = 1,
|
||||
WriteMode_WriteAtomic = 2,
|
||||
};
|
||||
|
||||
protected:
|
||||
/** File handle to the actual file. */
|
||||
void *_handle;
|
||||
Common::String *_path;
|
||||
|
||||
static StdioStream *makeFromPathHelper(const Common::String &path, WriteMode writeMode,
|
||||
StdioStream *(*factory)(void *handle));
|
||||
|
||||
public:
|
||||
/**
|
||||
* Given a path, invokes fopen on that path and wrap the result in a
|
||||
* StdioStream instance.
|
||||
*/
|
||||
static StdioStream *makeFromPath(const Common::String &path, WriteMode writeMode) {
|
||||
return makeFromPathHelper(path, writeMode, [](void *handle) {
|
||||
return new StdioStream(handle);
|
||||
});
|
||||
}
|
||||
|
||||
StdioStream(void *handle);
|
||||
~StdioStream() override;
|
||||
|
||||
bool err() const override;
|
||||
void clearErr() override;
|
||||
bool eos() const override;
|
||||
|
||||
uint32 write(const void *dataPtr, uint32 dataSize) override;
|
||||
bool flush() override;
|
||||
|
||||
int64 pos() const override;
|
||||
int64 size() const override;
|
||||
bool seek(int64 offs, int whence = SEEK_SET) override;
|
||||
uint32 read(void *dataPtr, uint32 dataSize) override;
|
||||
|
||||
/**
|
||||
* Configure buffered IO
|
||||
*
|
||||
* Must be called immediately after opening the file.
|
||||
* A buffer size of 0 disables buffering.
|
||||
*
|
||||
* @param bufferSize the size of the Stdio read / write buffer
|
||||
* @return success or failure
|
||||
*/
|
||||
bool setBufferSize(uint32 bufferSize);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Move the file from src to dst.
|
||||
* This must succeed even if the destination file already exists.
|
||||
*
|
||||
* This function cannot be overridden as it's called from the destructor.
|
||||
*
|
||||
* @param src The file to move
|
||||
* @param dst The path where the file is to be moved.
|
||||
*
|
||||
* @returns Whether the renaming succeeded or not.
|
||||
*/
|
||||
bool moveFile(const Common::String &src, const Common::String &dst);
|
||||
};
|
||||
|
||||
#endif
|
||||
231
backends/fs/wii/wii-fs-factory.cpp
Normal file
231
backends/fs/wii/wii-fs-factory.cpp
Normal file
@@ -0,0 +1,231 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__WII__)
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_printf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getcwd
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "backends/fs/wii/wii-fs-factory.h"
|
||||
#include "backends/fs/wii/wii-fs.h"
|
||||
|
||||
#ifdef USE_WII_DI
|
||||
#include <di/di.h>
|
||||
#include <iso9660.h>
|
||||
#ifdef GAMECUBE
|
||||
#include <ogc/dvd.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef USE_WII_SMB
|
||||
#include <network.h>
|
||||
#include <smb.h>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
DECLARE_SINGLETON(WiiFilesystemFactory);
|
||||
}
|
||||
|
||||
WiiFilesystemFactory::WiiFilesystemFactory() :
|
||||
_dvdMounted(false),
|
||||
_smbMounted(false),
|
||||
_dvdError(false),
|
||||
_smbError(false) {
|
||||
}
|
||||
|
||||
AbstractFSNode *WiiFilesystemFactory::makeRootFileNode() const {
|
||||
return new WiiFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *WiiFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
char buf[MAXPATHLEN];
|
||||
|
||||
if (getcwd(buf, MAXPATHLEN))
|
||||
return new WiiFilesystemNode(buf);
|
||||
else
|
||||
return new WiiFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *WiiFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
return new WiiFilesystemNode(path);
|
||||
}
|
||||
|
||||
void WiiFilesystemFactory::asyncInit() {
|
||||
#ifdef USE_WII_SMB
|
||||
asyncInitNetwork();
|
||||
#endif
|
||||
}
|
||||
|
||||
void WiiFilesystemFactory::asyncDeinit() {
|
||||
#ifdef USE_WII_DI
|
||||
umount(kDVD);
|
||||
#ifndef GAMECUBE
|
||||
DI_Close();
|
||||
#endif
|
||||
#endif
|
||||
#ifdef USE_WII_SMB
|
||||
umount(kSMB);
|
||||
net_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_WII_SMB
|
||||
void WiiFilesystemFactory::asyncInitNetwork() {
|
||||
net_init_async(NULL, NULL);
|
||||
}
|
||||
|
||||
void WiiFilesystemFactory::setSMBLoginData(const String &server,
|
||||
const String &share,
|
||||
const String &username,
|
||||
const String &password) {
|
||||
_smbServer = server;
|
||||
_smbShare = share;
|
||||
_smbUsername = username;
|
||||
_smbPassword = password;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool WiiFilesystemFactory::isMounted(FileSystemType type) {
|
||||
switch (type) {
|
||||
case kDVD:
|
||||
return _dvdMounted;
|
||||
case kSMB:
|
||||
return _smbMounted;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WiiFilesystemFactory::failedToMount(FileSystemType type) {
|
||||
switch (type) {
|
||||
case kDVD:
|
||||
return _dvdError;
|
||||
case kSMB:
|
||||
return _smbError;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_WII_DI
|
||||
#ifndef GAMECUBE
|
||||
const DISC_INTERFACE* dvd = &__io_wiidvd;
|
||||
#else
|
||||
const DISC_INTERFACE* dvd = &__io_gcdvd;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void WiiFilesystemFactory::mount(FileSystemType type) {
|
||||
switch (type) {
|
||||
case kDVD:
|
||||
#ifdef USE_WII_DI
|
||||
if (_dvdMounted)
|
||||
break;
|
||||
|
||||
printf("mount dvd\n");
|
||||
if (ISO9660_Mount("dvd", dvd)) {
|
||||
_dvdMounted = true;
|
||||
_dvdError = false;
|
||||
printf("ISO9660 mounted\n");
|
||||
} else {
|
||||
_dvdError = true;
|
||||
printf("ISO9660 mount failed\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
case kSMB:
|
||||
#ifdef USE_WII_SMB
|
||||
if (_smbMounted)
|
||||
break;
|
||||
|
||||
printf("mount smb\n");
|
||||
|
||||
if (net_get_status()) {
|
||||
printf("network not inited\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (smbInit(_smbUsername.c_str(), _smbPassword.c_str(),
|
||||
_smbShare.c_str(), _smbServer.c_str())) {
|
||||
_smbMounted = true;
|
||||
_smbError = false;
|
||||
printf("smb mounted\n");
|
||||
} else {
|
||||
_smbError = true;
|
||||
printf("error mounting smb\n");
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WiiFilesystemFactory::umount(FileSystemType type) {
|
||||
switch (type) {
|
||||
case kDVD:
|
||||
#ifdef USE_WII_DI
|
||||
if (!_dvdMounted)
|
||||
break;
|
||||
|
||||
printf("umount dvd\n");
|
||||
|
||||
ISO9660_Unmount("dvd:");
|
||||
|
||||
_dvdMounted = false;
|
||||
_dvdError = false;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case kSMB:
|
||||
#ifdef USE_WII_SMB
|
||||
if (!_smbMounted)
|
||||
break;
|
||||
|
||||
printf("umount smb\n");
|
||||
|
||||
smbClose("smb:");
|
||||
|
||||
_smbMounted = false;
|
||||
_smbError = false;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WiiFilesystemFactory::mountByPath(const String &path) {
|
||||
if (path.hasPrefix("dvd:/"))
|
||||
mount(kDVD);
|
||||
else if (path.hasPrefix("smb:/"))
|
||||
mount(kSMB);
|
||||
}
|
||||
|
||||
void WiiFilesystemFactory::umountUnused(const String &path) {
|
||||
if (!path.hasPrefix("dvd:/"))
|
||||
umount(kDVD);
|
||||
|
||||
if (!path.hasPrefix("smb:/"))
|
||||
umount(kSMB);
|
||||
}
|
||||
|
||||
#endif
|
||||
86
backends/fs/wii/wii-fs-factory.h
Normal file
86
backends/fs/wii/wii-fs-factory.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _WII_FILESYSTEM_FACTORY_H_
|
||||
#define _WII_FILESYSTEM_FACTORY_H_
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/singleton.h"
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
#include <gctypes.h>
|
||||
|
||||
/**
|
||||
* Creates WiiFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class WiiFilesystemFactory final : public FilesystemFactory, public Common::Singleton<WiiFilesystemFactory> {
|
||||
public:
|
||||
typedef Common::String String;
|
||||
|
||||
enum FileSystemType {
|
||||
kDVD,
|
||||
kSMB
|
||||
};
|
||||
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
|
||||
void asyncInit();
|
||||
void asyncDeinit();
|
||||
|
||||
#ifdef USE_WII_SMB
|
||||
void asyncInitNetwork();
|
||||
void setSMBLoginData(const String &server, const String &share,
|
||||
const String &username, const String &password);
|
||||
#endif
|
||||
|
||||
bool isMounted(FileSystemType type);
|
||||
bool failedToMount(FileSystemType type);
|
||||
|
||||
void mount(FileSystemType type);
|
||||
void umount(FileSystemType type);
|
||||
|
||||
void mountByPath(const String &path);
|
||||
void umountUnused(const String &path);
|
||||
|
||||
protected:
|
||||
WiiFilesystemFactory();
|
||||
|
||||
private:
|
||||
friend class Common::Singleton<SingletonBaseType>;
|
||||
|
||||
bool _dvdMounted;
|
||||
bool _smbMounted;
|
||||
bool _dvdError;
|
||||
bool _smbError;
|
||||
|
||||
#ifdef USE_WII_SMB
|
||||
String _smbServer;
|
||||
String _smbShare;
|
||||
String _smbUsername;
|
||||
String _smbPassword;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /*Wii_FILESYSTEM_FACTORY_H*/
|
||||
236
backends/fs/wii/wii-fs.cpp
Normal file
236
backends/fs/wii/wii-fs.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(__WII__)
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h
|
||||
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_mkdir
|
||||
|
||||
#include "backends/fs/wii/wii-fs.h"
|
||||
#include "backends/fs/wii/wii-fs-factory.h"
|
||||
#include "backends/fs/stdiostream.h"
|
||||
|
||||
#include <sys/iosupport.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gctypes.h>
|
||||
|
||||
// gets all registered devoptab devices
|
||||
bool WiiFilesystemNode::getDevopChildren(AbstractFSList &list, ListMode mode, bool hidden) const {
|
||||
u8 i;
|
||||
const devoptab_t* dt;
|
||||
|
||||
if (mode == Common::FSNode::kListFilesOnly)
|
||||
return true;
|
||||
|
||||
// skip in, out and err
|
||||
for (i = 3; i < STD_MAX; ++i) {
|
||||
dt = devoptab_list[i];
|
||||
|
||||
if (!dt || !dt->name || !dt->open_r || !dt->diropen_r)
|
||||
continue;
|
||||
|
||||
list.push_back(new WiiFilesystemNode(Common::String(dt->name) + ":/"));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WiiFilesystemNode::initRootNode() {
|
||||
_path.clear();
|
||||
_displayName = "<devices>";
|
||||
|
||||
_exists = true;
|
||||
_isDirectory = true;
|
||||
_isReadable = false;
|
||||
_isWritable = false;
|
||||
}
|
||||
|
||||
void WiiFilesystemNode::clearFlags() {
|
||||
_exists = false;
|
||||
_isDirectory = false;
|
||||
_isReadable = false;
|
||||
_isWritable = false;
|
||||
}
|
||||
|
||||
void WiiFilesystemNode::setFlags(const struct stat *st) {
|
||||
_exists = true;
|
||||
_isDirectory = ( (st->st_mode & S_IFDIR) != 0 );
|
||||
_isReadable = ( (st->st_mode & S_IRUSR) != 0 );
|
||||
_isWritable = ( (st->st_mode & S_IWUSR) != 0 );
|
||||
}
|
||||
|
||||
WiiFilesystemNode::WiiFilesystemNode() {
|
||||
initRootNode();
|
||||
}
|
||||
|
||||
WiiFilesystemNode::WiiFilesystemNode(const Common::String &p) {
|
||||
if (p.empty()) {
|
||||
initRootNode();
|
||||
return;
|
||||
}
|
||||
|
||||
_path = Common::normalizePath(p, '/');
|
||||
|
||||
WiiFilesystemFactory::instance().mountByPath(_path);
|
||||
|
||||
// "sd:" is not a valid directory, but "sd:/" is
|
||||
if (_path.lastChar() == ':')
|
||||
_path += '/';
|
||||
|
||||
_displayName = lastPathComponent(_path, '/');
|
||||
|
||||
struct stat st;
|
||||
if(stat(_path.c_str(), &st) != -1)
|
||||
setFlags(&st);
|
||||
else
|
||||
clearFlags();
|
||||
}
|
||||
|
||||
WiiFilesystemNode::WiiFilesystemNode(const Common::String &p, const struct stat *st) {
|
||||
if (p.empty()) {
|
||||
initRootNode();
|
||||
return;
|
||||
}
|
||||
|
||||
_path = Common::normalizePath(p, '/');
|
||||
|
||||
// "sd:" is not a valid directory, but "sd:/" is
|
||||
if (_path.lastChar() == ':')
|
||||
_path += '/';
|
||||
|
||||
_displayName = lastPathComponent(_path, '/');
|
||||
|
||||
setFlags(st);
|
||||
}
|
||||
|
||||
bool WiiFilesystemNode::exists() const {
|
||||
return _exists;
|
||||
}
|
||||
|
||||
AbstractFSNode *WiiFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
assert(!n.contains('/'));
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (newPath.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += n;
|
||||
|
||||
return new WiiFilesystemNode(newPath);
|
||||
}
|
||||
|
||||
bool WiiFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
if (_path.empty())
|
||||
return getDevopChildren(list, mode, hidden);
|
||||
|
||||
DIR *dp = opendir (_path.c_str());
|
||||
|
||||
if (dp == NULL)
|
||||
return false;
|
||||
|
||||
struct dirent *pent;
|
||||
|
||||
while ((pent = readdir(dp)) != NULL) {
|
||||
if (strcmp(pent->d_name, ".") == 0 || strcmp(pent->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (newPath.lastChar() != '/')
|
||||
newPath += '/';
|
||||
newPath += pent->d_name;
|
||||
|
||||
bool isDir = ( pent->d_type == DT_DIR );
|
||||
|
||||
if ((mode == Common::FSNode::kListFilesOnly && isDir) ||
|
||||
(mode == Common::FSNode::kListDirectoriesOnly && !isDir))
|
||||
continue;
|
||||
|
||||
struct stat st;
|
||||
st.st_mode = 0;
|
||||
st.st_mode |= ( isDir ? S_IFDIR : 0 );
|
||||
st.st_mode |= S_IRUSR;
|
||||
st.st_mode |= S_IWUSR;
|
||||
|
||||
list.push_back(new WiiFilesystemNode(newPath, &st));
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *WiiFilesystemNode::getParent() const {
|
||||
if (_path.empty())
|
||||
return NULL;
|
||||
|
||||
const char *start = _path.c_str();
|
||||
const char *end = lastPathComponent(_path, '/');
|
||||
|
||||
return new WiiFilesystemNode(Common::String(start, end - start));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *WiiFilesystemNode::createReadStream() {
|
||||
StdioStream *readStream = StdioStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
|
||||
// disable newlib's buffering, the device libraries handle caching
|
||||
if (readStream) {
|
||||
readStream->setBufferSize(0);
|
||||
}
|
||||
|
||||
return readStream;
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *WiiFilesystemNode::createWriteStream(bool atomic) {
|
||||
StdioStream *writeStream = StdioStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
|
||||
// disable newlib's buffering, the device libraries handle caching
|
||||
if (writeStream) {
|
||||
writeStream->setBufferSize(0);
|
||||
}
|
||||
|
||||
return writeStream;
|
||||
}
|
||||
|
||||
bool WiiFilesystemNode::createDirectory() {
|
||||
if(!_exists) {
|
||||
if (mkdir(_path.c_str(), 0755) == 0) {
|
||||
_exists = true;
|
||||
_isDirectory = true;
|
||||
_isReadable = true;
|
||||
_isWritable = true;
|
||||
}
|
||||
}
|
||||
|
||||
return _exists && _isDirectory;
|
||||
}
|
||||
|
||||
#endif //#if defined(__WII__)
|
||||
74
backends/fs/wii/wii-fs.h
Normal file
74
backends/fs/wii/wii-fs.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WII_FILESYSTEM_H
|
||||
#define WII_FILESYSTEM_H
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on Wii.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class WiiFilesystemNode final : public AbstractFSNode {
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
bool _exists, _isDirectory, _isReadable, _isWritable;
|
||||
|
||||
virtual void initRootNode();
|
||||
virtual bool getDevopChildren(AbstractFSList &list, ListMode mode, bool hidden) const;
|
||||
virtual void setFlags(const struct stat *st);
|
||||
virtual void clearFlags();
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a WiiFilesystemNode with the root node as path.
|
||||
*/
|
||||
WiiFilesystemNode();
|
||||
|
||||
/**
|
||||
* Creates a WiiFilesystemNode for a given path.
|
||||
*
|
||||
* @param path Common::String with the path the new node should point to.
|
||||
*/
|
||||
WiiFilesystemNode(const Common::String &p);
|
||||
WiiFilesystemNode(const Common::String &p, const struct stat *st);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isReadable() const override { return _isReadable; }
|
||||
bool isWritable() const override { return _isWritable; }
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
41
backends/fs/windows/windows-fs-factory.cpp
Normal file
41
backends/fs/windows/windows-fs-factory.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
// Disable symbol overrides so that we can use system headers.
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/windows/windows-fs.h"
|
||||
#include "backends/fs/windows/windows-fs-factory.h"
|
||||
|
||||
AbstractFSNode *WindowsFilesystemFactory::makeRootFileNode() const {
|
||||
return new WindowsFilesystemNode();
|
||||
}
|
||||
|
||||
AbstractFSNode *WindowsFilesystemFactory::makeCurrentDirectoryFileNode() const {
|
||||
return new WindowsFilesystemNode("", true);
|
||||
}
|
||||
|
||||
AbstractFSNode *WindowsFilesystemFactory::makeFileNodePath(const Common::String &path) const {
|
||||
return new WindowsFilesystemNode(path, false);
|
||||
}
|
||||
#endif
|
||||
39
backends/fs/windows/windows-fs-factory.h
Normal file
39
backends/fs/windows/windows-fs-factory.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WINDOWS_FILESYSTEM_FACTORY_H
|
||||
#define WINDOWS_FILESYSTEM_FACTORY_H
|
||||
|
||||
#include "backends/fs/fs-factory.h"
|
||||
|
||||
/**
|
||||
* Creates WindowsFilesystemNode objects.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, FilesystemFactory.
|
||||
*/
|
||||
class WindowsFilesystemFactory final : public FilesystemFactory {
|
||||
public:
|
||||
AbstractFSNode *makeRootFileNode() const override;
|
||||
AbstractFSNode *makeCurrentDirectoryFileNode() const override;
|
||||
AbstractFSNode *makeFileNodePath(const Common::String &path) const override;
|
||||
};
|
||||
|
||||
#endif /*WINDOWS_FILESYSTEM_FACTORY_H*/
|
||||
241
backends/fs/windows/windows-fs.cpp
Normal file
241
backends/fs/windows/windows-fs.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
// Disable symbol overrides so that we can use system headers.
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "backends/fs/windows/windows-fs.h"
|
||||
#include "backends/fs/stdiostream.h"
|
||||
|
||||
bool WindowsFilesystemNode::exists() const {
|
||||
// Check whether the file actually exists
|
||||
return (GetFileAttributes(charToTchar(_path.c_str())) != INVALID_FILE_ATTRIBUTES);
|
||||
}
|
||||
|
||||
bool WindowsFilesystemNode::isReadable() const {
|
||||
// Since all files are always readable and it is not possible to give
|
||||
// write-only permission, this is equivalent to ::exists().
|
||||
return (GetFileAttributes(charToTchar(_path.c_str())) != INVALID_FILE_ATTRIBUTES);
|
||||
}
|
||||
|
||||
bool WindowsFilesystemNode::isWritable() const {
|
||||
// Check whether the file exists and it can be written.
|
||||
DWORD fileAttribs = GetFileAttributes(charToTchar(_path.c_str()));
|
||||
return ((fileAttribs != INVALID_FILE_ATTRIBUTES) && (!(fileAttribs & FILE_ATTRIBUTE_READONLY)));
|
||||
}
|
||||
|
||||
void WindowsFilesystemNode::addFile(AbstractFSList &list, ListMode mode, const char *base, bool hidden, WIN32_FIND_DATA* find_data) {
|
||||
// Skip local directory (.) and parent (..)
|
||||
if (!_tcscmp(find_data->cFileName, TEXT(".")) ||
|
||||
!_tcscmp(find_data->cFileName, TEXT("..")))
|
||||
return;
|
||||
|
||||
// Skip hidden files if asked
|
||||
if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) && !hidden)
|
||||
return;
|
||||
|
||||
bool isDirectory = ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false);
|
||||
|
||||
if ((!isDirectory && mode == Common::FSNode::kListDirectoriesOnly) ||
|
||||
(isDirectory && mode == Common::FSNode::kListFilesOnly))
|
||||
return;
|
||||
|
||||
const char *fileName = tcharToChar(find_data->cFileName);
|
||||
|
||||
WindowsFilesystemNode entry;
|
||||
entry._isDirectory = isDirectory;
|
||||
entry._displayName = fileName;
|
||||
entry._path = base;
|
||||
entry._path += fileName;
|
||||
if (entry._isDirectory)
|
||||
entry._path += "\\";
|
||||
entry._isValid = true;
|
||||
entry._isPseudoRoot = false;
|
||||
|
||||
list.push_back(new WindowsFilesystemNode(entry));
|
||||
}
|
||||
|
||||
const char* WindowsFilesystemNode::tcharToChar(const TCHAR *str) {
|
||||
#ifndef UNICODE
|
||||
return str;
|
||||
#else
|
||||
static char multiByteString[MAX_PATH];
|
||||
WideCharToMultiByte(CP_UTF8, 0, str, _tcslen(str) + 1, multiByteString, MAX_PATH, nullptr, nullptr);
|
||||
return multiByteString;
|
||||
#endif
|
||||
}
|
||||
|
||||
const TCHAR* WindowsFilesystemNode::charToTchar(const char *str) {
|
||||
#ifndef UNICODE
|
||||
return str;
|
||||
#else
|
||||
static wchar_t wideCharString[MAX_PATH];
|
||||
MultiByteToWideChar(CP_UTF8, 0, str, strlen(str) + 1, wideCharString, MAX_PATH);
|
||||
return wideCharString;
|
||||
#endif
|
||||
}
|
||||
|
||||
WindowsFilesystemNode::WindowsFilesystemNode() {
|
||||
// Create a virtual root directory for standard Windows system
|
||||
_isDirectory = true;
|
||||
_isValid = false;
|
||||
_path = "";
|
||||
_isPseudoRoot = true;
|
||||
}
|
||||
|
||||
WindowsFilesystemNode::WindowsFilesystemNode(const Common::String &p, const bool currentDir) {
|
||||
if (currentDir) {
|
||||
TCHAR path[MAX_PATH];
|
||||
GetCurrentDirectory(MAX_PATH, path);
|
||||
_path = tcharToChar(path);
|
||||
} else {
|
||||
assert(p.size() > 0);
|
||||
_path = p;
|
||||
}
|
||||
|
||||
_displayName = lastPathComponent(_path, '\\');
|
||||
|
||||
setFlags();
|
||||
|
||||
_isPseudoRoot = false;
|
||||
}
|
||||
|
||||
void WindowsFilesystemNode::setFlags() {
|
||||
// Check whether it is a directory, and whether the file actually exists
|
||||
DWORD fileAttribs = GetFileAttributes(charToTchar(_path.c_str()));
|
||||
|
||||
if (fileAttribs == INVALID_FILE_ATTRIBUTES) {
|
||||
_isDirectory = false;
|
||||
_isValid = false;
|
||||
} else {
|
||||
_isDirectory = ((fileAttribs & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||
_isValid = true;
|
||||
// Add a trailing slash, if necessary.
|
||||
if (_isDirectory && _path.lastChar() != '\\') {
|
||||
_path += '\\';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AbstractFSNode *WindowsFilesystemNode::getChild(const Common::String &n) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
// Make sure the string contains no slashes
|
||||
assert(!n.contains('/'));
|
||||
|
||||
Common::String newPath(_path);
|
||||
if (_path.lastChar() != '\\')
|
||||
newPath += '\\';
|
||||
newPath += n;
|
||||
|
||||
return new WindowsFilesystemNode(newPath, false);
|
||||
}
|
||||
|
||||
bool WindowsFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
|
||||
assert(_isDirectory);
|
||||
|
||||
if (_isPseudoRoot) {
|
||||
// Drives enumeration
|
||||
TCHAR drive_buffer[100];
|
||||
GetLogicalDriveStrings(sizeof(drive_buffer) / sizeof(TCHAR), drive_buffer);
|
||||
|
||||
for (TCHAR *current_drive = drive_buffer; *current_drive;
|
||||
current_drive += _tcslen(current_drive) + 1) {
|
||||
WindowsFilesystemNode entry;
|
||||
char drive_name[2];
|
||||
|
||||
drive_name[0] = tcharToChar(current_drive)[0];
|
||||
drive_name[1] = '\0';
|
||||
entry._displayName = drive_name;
|
||||
entry._isDirectory = true;
|
||||
entry._isValid = true;
|
||||
entry._isPseudoRoot = false;
|
||||
entry._path = tcharToChar(current_drive);
|
||||
myList.push_back(new WindowsFilesystemNode(entry));
|
||||
}
|
||||
} else {
|
||||
// Files enumeration
|
||||
WIN32_FIND_DATA desc;
|
||||
HANDLE handle;
|
||||
char searchPath[MAX_PATH + 10];
|
||||
|
||||
Common::sprintf_s(searchPath, "%s*", _path.c_str());
|
||||
|
||||
handle = FindFirstFile(charToTchar(searchPath), &desc);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
addFile(myList, mode, _path.c_str(), hidden, &desc);
|
||||
|
||||
while (FindNextFile(handle, &desc))
|
||||
addFile(myList, mode, _path.c_str(), hidden, &desc);
|
||||
|
||||
FindClose(handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AbstractFSNode *WindowsFilesystemNode::getParent() const {
|
||||
assert(_isValid || _isPseudoRoot);
|
||||
|
||||
if (_isPseudoRoot)
|
||||
return nullptr;
|
||||
|
||||
WindowsFilesystemNode *p;
|
||||
if (_path.size() > 3) {
|
||||
const char *start = _path.c_str();
|
||||
const char *end = lastPathComponent(_path, '\\');
|
||||
|
||||
p = new WindowsFilesystemNode();
|
||||
p->_path = Common::String(start, end - start);
|
||||
p->_isValid = true;
|
||||
p->_isDirectory = true;
|
||||
p->_displayName = lastPathComponent(p->_path, '\\');
|
||||
p->_isPseudoRoot = false;
|
||||
} else {
|
||||
// pseudo root
|
||||
p = new WindowsFilesystemNode();
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *WindowsFilesystemNode::createReadStream() {
|
||||
return StdioStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
|
||||
}
|
||||
|
||||
Common::SeekableWriteStream *WindowsFilesystemNode::createWriteStream(bool atomic) {
|
||||
return StdioStream::makeFromPath(getPath(), atomic ?
|
||||
StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
|
||||
}
|
||||
|
||||
bool WindowsFilesystemNode::createDirectory() {
|
||||
if (CreateDirectory(charToTchar(_path.c_str()), nullptr) != 0)
|
||||
setFlags();
|
||||
|
||||
return _isValid && _isDirectory;
|
||||
}
|
||||
|
||||
#endif //#ifdef WIN32
|
||||
125
backends/fs/windows/windows-fs.h
Normal file
125
backends/fs/windows/windows-fs.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/* 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 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WINDOWS_FILESYSTEM_H
|
||||
#define WINDOWS_FILESYSTEM_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "backends/fs/abstract-fs.h"
|
||||
|
||||
#include <io.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <tchar.h>
|
||||
|
||||
/**
|
||||
* Implementation of the ScummVM file system API based on Windows API.
|
||||
*
|
||||
* Parts of this class are documented in the base interface class, AbstractFSNode.
|
||||
*/
|
||||
class WindowsFilesystemNode final : public AbstractFSNode {
|
||||
protected:
|
||||
Common::String _displayName;
|
||||
Common::String _path;
|
||||
bool _isDirectory;
|
||||
bool _isPseudoRoot;
|
||||
bool _isValid;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a WindowsFilesystemNode with the root node as path.
|
||||
*
|
||||
* In regular windows systems, a virtual root path is used "".
|
||||
*/
|
||||
WindowsFilesystemNode();
|
||||
|
||||
/**
|
||||
* Creates a WindowsFilesystemNode for a given path.
|
||||
*
|
||||
* Examples:
|
||||
* path=c:\foo\bar.txt, currentDir=false -> c:\foo\bar.txt
|
||||
* path=c:\foo\bar.txt, currentDir=true -> current directory
|
||||
* path=NULL, currentDir=true -> current directory
|
||||
*
|
||||
* @param path Common::String with the path the new node should point to.
|
||||
* @param currentDir if true, the path parameter will be ignored and the resulting node will point to the current directory.
|
||||
*/
|
||||
WindowsFilesystemNode(const Common::String &path, const bool currentDir);
|
||||
|
||||
bool exists() const override;
|
||||
Common::U32String getDisplayName() const override { return _displayName; }
|
||||
Common::String getName() const override { return _displayName; }
|
||||
Common::String getPath() const override { return _path; }
|
||||
bool isDirectory() const override { return _isDirectory; }
|
||||
bool isReadable() const override;
|
||||
bool isWritable() const override;
|
||||
|
||||
AbstractFSNode *getChild(const Common::String &n) const override;
|
||||
bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const override;
|
||||
AbstractFSNode *getParent() const override;
|
||||
|
||||
Common::SeekableReadStream *createReadStream() override;
|
||||
Common::SeekableWriteStream *createWriteStream(bool atomic) override;
|
||||
bool createDirectory() override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Adds a single WindowsFilesystemNode to a given list.
|
||||
* This method is used by getChildren() to populate the directory entries list.
|
||||
*
|
||||
* @param list List to put the file entry node in.
|
||||
* @param mode Mode to use while adding the file entry to the list.
|
||||
* @param base Common::String with the directory being listed.
|
||||
* @param hidden true if hidden files should be added, false otherwise
|
||||
* @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find.
|
||||
*/
|
||||
static void addFile(AbstractFSList &list, ListMode mode, const char *base, bool hidden, WIN32_FIND_DATA* find_data);
|
||||
|
||||
/**
|
||||
* Converts a string of TCHARs returned from a Windows API function to
|
||||
* a character string. If UNICODE is defined then the incoming string
|
||||
* is wide characters and is converted to UTF8, otherwise the incoming
|
||||
* string is returned with no conversion.
|
||||
*
|
||||
* @param str String to convert if UNICODE is defined
|
||||
* @return str in UTF8 format if UNICODE is defined, otherwise just str
|
||||
*/
|
||||
static const char *tcharToChar(const TCHAR *str);
|
||||
|
||||
/**
|
||||
* Converts a character string to a string of TCHARs for passing
|
||||
* to a Windows API function. If UNICODE is defined then the incoming
|
||||
* string is converted from UTF8 to wide characters, otherwise the incoming
|
||||
* string is returned with no conversion.
|
||||
*
|
||||
* @param str String to convert if UNICODE is defined
|
||||
* @return str in wide character format if UNICODE is defined, otherwise just str
|
||||
*/
|
||||
static const TCHAR* charToTchar(const char *str);
|
||||
|
||||
/**
|
||||
* Tests and sets the _isValid and _isDirectory flags, using the GetFileAttributes() function.
|
||||
*/
|
||||
virtual void setFlags();
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user