diff options
Diffstat (limited to 'backends/platform/tizen/fs.cpp')
-rw-r--r-- | backends/platform/tizen/fs.cpp | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/backends/platform/tizen/fs.cpp b/backends/platform/tizen/fs.cpp new file mode 100644 index 0000000000..f8b32f4239 --- /dev/null +++ b/backends/platform/tizen/fs.cpp @@ -0,0 +1,441 @@ +/* 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. + */ + +#include "config.h" +#include "common/translation.h" +#include "backends/platform/tizen/system.h" +#include "backends/platform/tizen/fs.h" + +#include <FAppApp.h> + +#define BUFFER_SIZE 1024 + +using namespace Tizen::App; + +// +// converts a Tizen (wchar) String into a scummVM (char) string +// +Common::String fromString(const Tizen::Base::String &in) { + ByteBuffer *buf = StringUtil::StringToUtf8N(in); + Common::String result((const char*)buf->GetPointer()); + delete buf; + return result; +} + +// +// TizenFileStream +// +class TizenFileStream : + public Common::SeekableReadStream, + public Common::WriteStream, + public Common::NonCopyable { +public: + static TizenFileStream *makeFromPath(const String &path, bool writeMode); + + TizenFileStream(File *file, bool writeMode); + ~TizenFileStream(); + + bool err() const; + void clearErr(); + bool eos() const; + + uint32 write(const void *dataPtr, uint32 dataSize); + bool flush(); + + int32 pos() const; + int32 size() const; + bool seek(int32 offs, int whence = SEEK_SET); + uint32 read(void *dataPtr, uint32 dataSize); + +private: + byte _buffer[BUFFER_SIZE]; + uint32 _bufferIndex; + uint32 _bufferLength; + bool _writeMode; + File *_file; +}; + +TizenFileStream::TizenFileStream(File *ioFile, bool writeMode) : + _bufferIndex(0), + _bufferLength(0), + _writeMode(writeMode), + _file(ioFile) { + AppAssert(ioFile != 0); +} + +TizenFileStream::~TizenFileStream() { + if (_file) { + if (_writeMode) { + flush(); + } + delete _file; + } +} + +bool TizenFileStream::err() const { + result r = GetLastResult(); + return (r != E_SUCCESS && r != E_END_OF_FILE); +} + +void TizenFileStream::clearErr() { + SetLastResult(E_SUCCESS); +} + +bool TizenFileStream::eos() const { + return (_bufferLength - _bufferIndex == 0) && (GetLastResult() == E_END_OF_FILE); +} + +int32 TizenFileStream::pos() const { + return _file->Tell() - (_bufferLength - _bufferIndex); +} + +int32 TizenFileStream::size() const { + int32 oldPos = _file->Tell(); + _file->Seek(FILESEEKPOSITION_END, 0); + + int32 length = _file->Tell(); + SetLastResult(_file->Seek(FILESEEKPOSITION_BEGIN, oldPos)); + + return length; +} + +bool TizenFileStream::seek(int32 offs, int whence) { + bool result = false; + switch (whence) { + case SEEK_SET: + // set from start of file + SetLastResult(_file->Seek(FILESEEKPOSITION_BEGIN, offs)); + result = (E_SUCCESS == GetLastResult()); + break; + + case SEEK_CUR: + // set relative to offs + if (_bufferIndex < _bufferLength && _bufferIndex > (uint32)-offs) { + // re-position within the buffer + SetLastResult(E_SUCCESS); + _bufferIndex += offs; + return true; + } else { + offs -= (_bufferLength - _bufferIndex); + if (offs < 0 && _file->Tell() + offs < 0) { + // avoid negative positioning + offs = 0; + } + if (offs != 0) { + SetLastResult(_file->Seek(FILESEEKPOSITION_CURRENT, offs)); + result = (E_SUCCESS == GetLastResult()); + } else { + result = true; + } + } + break; + + case SEEK_END: + // set relative to end - positive will increase the file size + SetLastResult(_file->Seek(FILESEEKPOSITION_END, offs)); + result = (E_SUCCESS == GetLastResult()); + break; + + default: + AppLog("Invalid whence %d", whence); + return false; + } + + if (!result) { + AppLog("seek failed"); + } + + _bufferIndex = _bufferLength = 0; + return result; +} + +uint32 TizenFileStream::read(void *ptr, uint32 len) { + uint32 result = 0; + if (!eos()) { + if (_bufferIndex < _bufferLength) { + // use existing buffer + uint32 available = _bufferLength - _bufferIndex; + if (len <= available) { + // use allocation + memcpy((byte *)ptr, &_buffer[_bufferIndex], len); + _bufferIndex += len; + result = len; + } else { + // use remaining allocation + memcpy((byte *)ptr, &_buffer[_bufferIndex], available); + uint32 remaining = len - available; + result = available; + + if (remaining) { + result += _file->Read(((byte *)ptr) + available, remaining); + } + _bufferIndex = _bufferLength = 0; + } + } else if (len < BUFFER_SIZE) { + // allocate and use buffer + _bufferIndex = 0; + _bufferLength = _file->Read(_buffer, BUFFER_SIZE); + if (_bufferLength) { + if (_bufferLength < len) { + len = _bufferLength; + } + memcpy((byte *)ptr, _buffer, len); + result = _bufferIndex = len; + } + } else { + result = _file->Read((byte *)ptr, len); + _bufferIndex = _bufferLength = 0; + } + } else { + AppLog("Attempted to read past EOS"); + } + return result; +} + +uint32 TizenFileStream::write(const void *ptr, uint32 len) { + result r = _file->Write(ptr, len); + SetLastResult(r); + return (r == E_SUCCESS ? len : 0); +} + +bool TizenFileStream::flush() { + logEntered(); + SetLastResult(_file->Flush()); + return (E_SUCCESS == GetLastResult()); +} + +TizenFileStream *TizenFileStream::makeFromPath(const String &path, bool writeMode) { + File *ioFile = new File(); + + String filePath = path; + if (writeMode && (path[0] != '.' && path[0] != '/')) { + filePath.Insert(App::GetInstance()->GetAppDataPath() + L"/", 0); + } + + AppLog("Open file %S", filePath.GetPointer()); + TizenFileStream *stream; + result r = ioFile->Construct(filePath, writeMode ? L"w" : L"r", writeMode); + if (r == E_SUCCESS) { + stream = new TizenFileStream(ioFile, writeMode); + } else { + AppLog("Failed to open file"); + delete ioFile; + stream = NULL; + } + return stream; +} + +// +// TizenFilesystemNode +// +TizenFilesystemNode::TizenFilesystemNode(const Common::String &nodePath) { + AppAssert(nodePath.size() > 0); + init(nodePath); +} + +TizenFilesystemNode::TizenFilesystemNode(SystemPath systemPath) { + switch (systemPath) { + case kData: + _unicodePath = App::GetInstance()->GetAppDataPath(); + _displayName = _s("[ Data ]"); + break; + case kResource: + _unicodePath = App::GetInstance()->GetAppResourcePath(); + _displayName = _s("[ Resources ]"); + break; + case kSdCard: + _unicodePath = Tizen::System::Environment::GetExternalStoragePath(); + _displayName = _s("[ SDCard ]"); + break; + case kMedia: + _unicodePath = Tizen::System::Environment::GetMediaPath(); + _displayName = _s("[ Media ]"); + break; + case kShared: + _unicodePath = App::GetInstance()->GetAppSharedPath(); + _displayName = _s("[ Shared ]"); + break; + } + _path = ::fromString(_unicodePath); + _isValid = _isVirtualDir = !IsFailed(File::GetAttributes(_unicodePath, _attr)); +} + +TizenFilesystemNode::TizenFilesystemNode(const Common::String &root, const Common::String &nodePath) { + AppLog("TizenFilesystemNode '%s' '%s'", root.c_str(), nodePath.c_str()); + + // Make sure the string contains no slashes + AppAssert(!nodePath.contains('/')); + + // We assume here that path is already normalized (hence don't bother to + // call Common::normalizePath on the final path). + Common::String newPath(root); + if (root.lastChar() != '/') { + newPath += '/'; + } + newPath += nodePath; + + init(newPath); +} + +void TizenFilesystemNode::init(const Common::String &nodePath) { + // Normalize the path (that is, remove unneeded slashes etc.) + _path = Common::normalizePath(nodePath, '/'); + _displayName = Common::lastPathComponent(_path, '/'); + + StringUtil::Utf8ToString(_path.c_str(), _unicodePath); + _isVirtualDir = (_path == "/"); + _isValid = _isVirtualDir || !IsFailed(File::GetAttributes(_unicodePath, _attr)); +} + +bool TizenFilesystemNode::exists() const { + return _isValid; +} + +bool TizenFilesystemNode::isReadable() const { + return _isVirtualDir || _isValid; +} + +bool TizenFilesystemNode::isDirectory() const { + return _isVirtualDir || (_isValid && _attr.IsDirectory()); +} + +bool TizenFilesystemNode::isWritable() const { + bool result = (_isValid && !_attr.IsReadOnly()); + if (_unicodePath == App::GetInstance()->GetAppResourcePath()) { + result = false; + } + return result; +} + +AbstractFSNode *TizenFilesystemNode::getChild(const Common::String &n) const { + AppAssert(!_path.empty()); + AppAssert(isDirectory()); + return new TizenFilesystemNode(_path, n); +} + +bool TizenFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { + AppAssert(isDirectory()); + + bool result = false; + + if (_isVirtualDir && mode != Common::FSNode::kListFilesOnly && _path == "/") { + // present well known TIZEN file system areas + myList.push_back(new TizenFilesystemNode(kData)); + myList.push_back(new TizenFilesystemNode(kResource)); + myList.push_back(new TizenFilesystemNode(kSdCard)); + myList.push_back(new TizenFilesystemNode(kMedia)); + myList.push_back(new TizenFilesystemNode(kShared)); + } + + if (!result) { + DirEnumerator *pDirEnum = 0; + Directory *pDir = new Directory(); + + // open directory + if (IsFailed(pDir->Construct(_unicodePath))) { + AppLog("Failed to open directory: %S", _unicodePath.GetPointer()); + } else { + // read all directory entries + pDirEnum = pDir->ReadN(); + if (pDirEnum) { + result = true; + } + + // loop through all directory entries + while (pDirEnum && pDirEnum->MoveNext() == E_SUCCESS) { + DirEntry dirEntry = pDirEnum->GetCurrentDirEntry(); + + // skip 'invisible' files if necessary + Tizen::Base::String fileName = dirEntry.GetName(); + + if (fileName[0] == '.' && !hidden) { + continue; + } + + // skip '.' and '..' to avoid cycles + if (fileName == L"." || fileName == L"..") { + continue; + } + + // Honor the chosen mode + if ((mode == Common::FSNode::kListFilesOnly && dirEntry.IsDirectory()) || + (mode == Common::FSNode::kListDirectoriesOnly && !dirEntry.IsDirectory())) { + continue; + } + myList.push_back(new TizenFilesystemNode(_path, ::fromString(fileName))); + } + } + + // cleanup + if (pDirEnum) { + delete pDirEnum; + } + + // close the opened directory + if (pDir) { + delete pDir; + } + } + + return result; +} + +AbstractFSNode *TizenFilesystemNode::getParent() const { + logEntered(); + 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 NULL; + } + + return new TizenFilesystemNode(Common::String(start, end)); +} + +Common::SeekableReadStream *TizenFilesystemNode::createReadStream() { + Common::SeekableReadStream *result = TizenFileStream::makeFromPath(_unicodePath, false); + if (result != NULL) { + _isValid = !IsFailed(File::GetAttributes(_unicodePath, _attr)); + } + return result; +} + +Common::WriteStream *TizenFilesystemNode::createWriteStream() { + Common::WriteStream *result = TizenFileStream::makeFromPath(_unicodePath, true); + if (result != NULL) { + _isValid = !IsFailed(File::GetAttributes(_unicodePath, _attr)); + } + return result; +} |