/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #if defined(RISCOS) // Re-enable some forbidden symbols to avoid clashes with stat.h and unistd.h. #define FORBIDDEN_SYMBOL_EXCEPTION_unistd_h #define FORBIDDEN_SYMBOL_EXCEPTION_mkdir #include "backends/fs/riscos/riscos-fs.h" #include "backends/fs/stdiostream.h" #include "common/algorithm.h" #include #include #include #include #include #include #include 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; } RISCOSFilesystemNode::RISCOSFilesystemNode(const Common::String &p) { _path = p; if (p == "/") { _isDirectory = true; _isValid = true; } else { int type = _swi(OS_File, _INR(0,1)|_RETURN(0), 20, toRISCOS(_path).c_str()); if (type == 0) { _isDirectory = false; _isValid = false; } else if (type == 2) { _isDirectory = true; _isValid = true; } else { _isDirectory = false; _isValid = true; } } } Common::String RISCOSFilesystemNode::toRISCOS(Common::String &path) { char start[PATH_MAX]; char *end = __riscosify_std(path.c_str(), 0, start, PATH_MAX, 0); return Common::String(start, end); } Common::String RISCOSFilesystemNode::toUnix(Common::String &path) { Common::String out = Common::String(path); uint32 start = 0; if (out.contains("$")) { char *x = strstr(out.c_str(), "$"); start = x ? x - out.c_str() : -1; } else if (out.contains(":")) { char *x = strstr(out.c_str(), ":"); start = x ? x - out.c_str() : -1; } for (uint32 ptr = start; ptr < out.size(); ptr += 1) { switch (out.c_str()[ptr]) { case '.': out.setChar('/', ptr); break; case '/': out.setChar('.', ptr); break; case '\xA0': out.setChar(' ', ptr); break; default: break; } } if (out.contains("$") || out.contains(":")) out = "/" + out; return out; } 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[PATH_MAX] = ""; for (int fsNum = 0; fsNum < 256; fsNum += 1) { _swi(OS_FSControl, _INR(0,3), 33, fsNum, fsname, sizeof(fsname)); if (strcmp(fsname, "") != 0) { if (!(fsNum == 46 || fsNum == 53 || fsNum == 99)) { int drives = 9; if (fsNum == 193) drives = 23; for (int discnum = 0; discnum <= drives; discnum += 1) { const Common::String path = Common::String::format("%s::%d.$", fsname, discnum); char outpath[PATH_MAX] = ""; if(_swix(OS_FSControl, _INR(0,2)|_IN(5), 37, path.c_str(), outpath, sizeof(outpath)) == NULL) { int exist; if (_swix(OS_File, _INR(0,1)|_OUT(0), 23, outpath, &exist) != NULL || exist != 2) continue; RISCOSFilesystemNode *entry = new RISCOSFilesystemNode(); entry->_isDirectory = true; entry->_isValid = true; entry->_path = Common::String::format("/%s", outpath); entry->_displayName = outpath; myList.push_back(entry); } } } } } return true; } int count = 0; int read = 0; char file[PATH_MAX]; Common::String dir = _path; while (count != -1) { _swix(OS_GBPB, _INR(0,5)|_OUTR(3,4), 9, toRISCOS(dir).c_str(), file, 1, count, sizeof(file), &read, &count); if (count == -1) continue; // Start with a clone of this node, with the correct path set RISCOSFilesystemNode entry(*this); entry._displayName = file; entry._displayName = toUnix(entry._displayName); if (_path.lastChar() != '/') entry._path += '/'; entry._path += entry._displayName; int type = _swi(OS_File, _INR(0,1)|_RETURN(0), 20, toRISCOS(entry._path).c_str()); if (type == 0) { continue; } else if (type == 2) { entry._isDirectory = true; } else { entry._isDirectory = false; } // 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(), false); } Common::WriteStream *RISCOSFilesystemNode::createWriteStream() { return StdioStream::makeFromPath(getPath(), true); } bool RISCOSFilesystemNode::create(bool isDirectoryFlag) { bool success; if (isDirectoryFlag) { success = _swix(OS_File, _INR(0,1), 8, toRISCOS(_path).c_str()) == NULL; } else { int fd = open(_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0755); success = fd >= 0; if (fd >= 0) { close(fd); } } if (success) { if (exists()) { _isDirectory = _swi(OS_File, _INR(0,1)|_RETURN(0), 20, toRISCOS(_path).c_str()) == 2; if (_isDirectory != isDirectoryFlag) warning("failed to create %s: got %s", isDirectoryFlag ? "directory" : "file", _isDirectory ? "directory" : "file"); return _isDirectory == isDirectoryFlag; } warning("RISCOSFilesystemNode: Attempting to create a %s was a success, but access indicates there is no such %s", isDirectoryFlag ? "directory" : "file", isDirectoryFlag ? "directory" : "file"); return false; } return false; } 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->create(true)) { 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)