FileSys: Added preliminary support for applications reading the RomFS archive.

Archive: Fixed brace ugliness for neobrain :)

FS: Commented out unused local variables to prevent warnings.

...But keeping them here for future use.

archive_romfs: Removed unused #include.
master
bunnei 2014-06-27 16:18:56 +07:00 committed by bunnei
parent 82702fedb8
commit 17a6148f9d
11 changed files with 311 additions and 160 deletions

@ -8,6 +8,7 @@ set(SRCS core.cpp
system.cpp
arm/disassembler/arm_disasm.cpp
arm/disassembler/load_symbol_map.cpp
file_sys/archive_romfs.cpp
arm/interpreter/arm_interpreter.cpp
arm/interpreter/armcopro.cpp
arm/interpreter/armemu.cpp
@ -75,7 +76,8 @@ set(HEADERS core.h
arm/interpreter/vfp/asm_vfp.h
arm/interpreter/vfp/vfp.h
arm/interpreter/vfp/vfp_helper.h
file_sys/file_sys.h
file_sys/archive.h
file_sys/archive_romfs.h
hle/config_mem.h
hle/coprocessor.h
hle/hle.h

@ -162,6 +162,7 @@
<ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" />
<ClCompile Include="core.cpp" />
<ClCompile Include="core_timing.cpp" />
<ClCompile Include="file_sys\archive_romfs.cpp" />
<ClCompile Include="hle\config_mem.cpp" />
<ClCompile Include="hle\coprocessor.cpp" />
<ClCompile Include="hle\hle.cpp" />
@ -211,7 +212,8 @@
<ClInclude Include="arm\interpreter\vfp\vfp_helper.h" />
<ClInclude Include="core.h" />
<ClInclude Include="core_timing.h" />
<ClInclude Include="file_sys\file_sys.h" />
<ClInclude Include="file_sys\archive.h" />
<ClInclude Include="file_sys\archive_romfs.h" />
<ClInclude Include="hle\config_mem.h" />
<ClInclude Include="hle\coprocessor.h" />
<ClInclude Include="hle\function_wrappers.h" />

@ -176,6 +176,9 @@
<ClCompile Include="hle\service\fs.cpp">
<Filter>hle\service</Filter>
</ClCompile>
<ClCompile Include="file_sys\archive_romfs.cpp">
<Filter>file_sys</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="arm\disassembler\arm_disasm.h">
@ -205,9 +208,6 @@
<ClInclude Include="arm\interpreter\skyeye_defs.h">
<Filter>arm\interpreter</Filter>
</ClInclude>
<ClInclude Include="file_sys\file_sys.h">
<Filter>file_sys</Filter>
</ClInclude>
<ClInclude Include="hw\hw.h">
<Filter>hw</Filter>
</ClInclude>
@ -314,6 +314,12 @@
<ClInclude Include="hle\service\fs.h">
<Filter>hle\service</Filter>
</ClInclude>
<ClInclude Include="file_sys\archive.h">
<Filter>file_sys</Filter>
</ClInclude>
<ClInclude Include="file_sys\archive_romfs.h">
<Filter>file_sys</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

@ -0,0 +1,54 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
class Archive : NonCopyable {
public:
/// Supported archive types
enum class IdCode : u32 {
RomFS = 0x00000003,
SaveData = 0x00000004,
ExtSaveData = 0x00000006,
SharedExtSaveData = 0x00000007,
SystemSaveData = 0x00000008,
SDMC = 0x00000009,
SDMCWriteOnly = 0x0000000A,
};
Archive() { }
virtual ~Archive() { }
/**
* Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
* @return IdCode of the archive
*/
virtual IdCode GetIdCode() const = 0;
/**
* Read data from the archive
* @param offset Offset in bytes to start reading archive from
* @param length Length in bytes to read data from archive
* @param buffer Buffer to read data into
* @return Number of bytes read
*/
virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0;
/**
* Get the size of the archive in bytes
* @return Size of the archive in bytes
*/
virtual size_t GetSize() const = 0;
};
} // namespace FileSys

@ -0,0 +1,46 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "common/common_types.h"
#include "core/file_sys/archive_romfs.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
Archive_RomFS::Archive_RomFS(Loader::AppLoader& app_loader) {
// Load the RomFS from the app
if (Loader::ResultStatus::Success != app_loader.ReadRomFS(raw_data)) {
WARN_LOG(FILESYS, "Unable to read RomFS!");
}
}
Archive_RomFS::~Archive_RomFS() {
}
/**
* Read data from the archive
* @param offset Offset in bytes to start reading archive from
* @param length Length in bytes to read data from archive
* @param buffer Buffer to read data into
* @return Number of bytes read
*/
size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length);
memcpy(buffer, &raw_data[(u32)offset], length);
return length;
}
/**
* Get the size of the archive in bytes
* @return Size of the archive in bytes
*/
size_t Archive_RomFS::GetSize() const {
ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
return 0;
}
} // namespace FileSys

@ -0,0 +1,50 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/archive.h"
#include "core/loader/loader.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
/// File system interface to the RomFS archive
class Archive_RomFS : public Archive {
public:
Archive_RomFS(Loader::AppLoader& app_loader);
~Archive_RomFS();
/**
* Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
* @return IdCode of the archive
*/
IdCode GetIdCode() const { return IdCode::RomFS; };
/**
* Read data from the archive
* @param offset Offset in bytes to start reading archive from
* @param length Length in bytes to read data from archive
* @param buffer Buffer to read data into
* @return Number of bytes read
*/
size_t Read(const u64 offset, const u32 length, u8* buffer) const;
/**
* Get the size of the archive in bytes
* @return Size of the archive in bytes
*/
size_t GetSize() const;
private:
std::vector<u8> raw_data;
};
} // namespace FileSys

@ -1,138 +0,0 @@
// Copyright (c) 2012- PPSSPP Project.
// 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, version 2.0 or later versions.
// 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 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
#include "common/common.h"
#include "common/chunk_file.h"
enum FileAccess {
FILEACCESS_NONE=0,
FILEACCESS_READ=1,
FILEACCESS_WRITE=2,
FILEACCESS_APPEND=4,
FILEACCESS_CREATE=8
};
enum FileMove {
FILEMOVE_BEGIN=0,
FILEMOVE_CURRENT=1,
FILEMOVE_END=2
};
enum FileType {
FILETYPE_NORMAL=1,
FILETYPE_DIRECTORY=2
};
class IHandleAllocator {
public:
virtual ~IHandleAllocator() {}
virtual u32 GetNewHandle() = 0;
virtual void FreeHandle(u32 handle) = 0;
};
class SequentialHandleAllocator : public IHandleAllocator {
public:
SequentialHandleAllocator() : handle_(1) {}
virtual u32 GetNewHandle() { return handle_++; }
virtual void FreeHandle(u32 handle) {}
private:
int handle_;
};
struct FileInfo {
FileInfo()
: size(0), access(0), exists(false), type(FILETYPE_NORMAL), isOnSectorSystem(false), startSector(0), numSectors(0) {}
void DoState(PointerWrap &p) {
auto s = p.Section("FileInfo", 1);
if (!s)
return;
p.Do(name);
p.Do(size);
p.Do(access);
p.Do(exists);
p.Do(type);
p.Do(atime);
p.Do(ctime);
p.Do(mtime);
p.Do(isOnSectorSystem);
p.Do(startSector);
p.Do(numSectors);
p.Do(sectorSize);
}
std::string name;
s64 size;
u32 access; //unix 777
bool exists;
FileType type;
tm atime;
tm ctime;
tm mtime;
bool isOnSectorSystem;
u32 startSector;
u32 numSectors;
u32 sectorSize;
};
class IFileSystem {
public:
virtual ~IFileSystem() {}
virtual void DoState(PointerWrap &p) = 0;
virtual std::vector<FileInfo> GetDirListing(std::string path) = 0;
virtual u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) = 0;
virtual void CloseFile(u32 handle) = 0;
virtual size_t ReadFile(u32 handle, u8 *pointer, s64 size) = 0;
virtual size_t WriteFile(u32 handle, const u8 *pointer, s64 size) = 0;
virtual size_t SeekFile(u32 handle, s32 position, FileMove type) = 0;
virtual FileInfo GetFileInfo(std::string filename) = 0;
virtual bool OwnsHandle(u32 handle) = 0;
virtual bool MkDir(const std::string &dirname) = 0;
virtual bool RmDir(const std::string &dirname) = 0;
virtual int RenameFile(const std::string &from, const std::string &to) = 0;
virtual bool RemoveFile(const std::string &filename) = 0;
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0;
};
class EmptyFileSystem : public IFileSystem {
public:
virtual void DoState(PointerWrap &p) {}
std::vector<FileInfo> GetDirListing(std::string path) {std::vector<FileInfo> vec; return vec;}
u32 OpenFile(std::string filename, FileAccess access, const char *devicename=NULL) {return 0;}
void CloseFile(u32 handle) {}
size_t ReadFile(u32 handle, u8 *pointer, s64 size) {return 0;}
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) {return 0;}
size_t SeekFile(u32 handle, s32 position, FileMove type) {return 0;}
FileInfo GetFileInfo(std::string filename) {FileInfo f; return f;}
bool OwnsHandle(u32 handle) {return false;}
virtual bool MkDir(const std::string &dirname) {return false;}
virtual bool RmDir(const std::string &dirname) {return false;}
virtual int RenameFile(const std::string &from, const std::string &to) {return -1;}
virtual bool RemoveFile(const std::string &filename) {return false;}
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
};

@ -4,6 +4,8 @@
#include "common/common_types.h"
#include "core/file_sys/archive.h"
#include "core/hle/service/service.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/archive.h"
@ -12,6 +14,21 @@
namespace Kernel {
// Command to access archive file
enum class FileCommand : u32 {
Dummy1 = 0x000100C6,
Control = 0x040100C4,
OpenSubFile = 0x08010100,
Read = 0x080200C2,
Write = 0x08030102,
GetSize = 0x08040000,
SetSize = 0x08050080,
GetAttributes = 0x08060000,
SetAttributes = 0x08070040,
Close = 0x08080000,
Flush = 0x08090000,
};
class Archive : public Object {
public:
const char* GetTypeName() const { return "Archive"; }
@ -21,6 +38,36 @@ public:
Kernel::HandleType GetHandleType() const { return HandleType::Archive; }
std::string name; ///< Name of archive (optional)
FileSys::Archive* backend; ///< Archive backend interface
/**
* Synchronize kernel object
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
Result SyncRequest(bool* wait) {
u32* cmd_buff = Service::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
switch (cmd) {
// Read from archive...
case FileCommand::Read:
{
u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
u32 length = cmd_buff[3];
u32 address = cmd_buff[5];
cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
break;
}
// Unknown command...
default:
ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
return -1;
}
cmd_buff[1] = 0; // No error
return 0;
}
/**
* Wait for kernel object to synchronize
@ -29,32 +76,71 @@ public:
*/
Result WaitSynchronization(bool* wait) {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "unimplemented function");
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
/**
* Opens an archive
* @param id_code IdCode of the archive to open
* @return Handle to archive if it exists, otherwise a null handle (0)
*/
Handle OpenArchive(FileSys::Archive::IdCode id_code) {
auto itr = g_archive_map.find(id_code);
if (itr == g_archive_map.end()) {
return 0;
}
return itr->second;
}
/**
* Mounts an archive
* @param archive Pointer to the archive to mount
* @return Result of operation, 0 on success, otherwise error code
*/
Result MountArchive(Archive* archive) {
FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
if (0 != OpenArchive(id_code)) {
ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
return -1;
}
g_archive_map[id_code] = archive->GetHandle();
INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName());
return 0;
}
/**
* Creates an Archive
* @param name Optional name of Archive
* @param handle Handle to newly created archive object
* @param backend File system backend interface to the archive
* @param name Optional name of Archive
* @return Newly created Archive object
*/
Archive* CreateArchive(Handle& handle, const std::string& name) {
Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) {
Archive* archive = new Archive;
handle = Kernel::g_object_pool.Create(archive);
archive->name = name;
archive->backend = backend;
MountArchive(archive);
return archive;
}
/**
* Creates an Archive
* @param backend File system backend interface to the archive
* @param name Optional name of Archive
* @return Handle to newly created Archive object
*/
Handle CreateArchive(const std::string& name) {
Handle CreateArchive(FileSys::Archive* backend, const std::string& name) {
Handle handle;
Archive* archive = CreateArchive(handle, name);
Archive* archive = CreateArchive(handle, backend, name);
return handle;
}

@ -7,6 +7,7 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/file_sys/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Kernel namespace
@ -14,10 +15,18 @@
namespace Kernel {
/**
* Creates an archive
* @param name Optional name of archive
* @return Handle to newly created archive object
* Opens an archive
* @param id_code IdCode of the archive to open
* @return Handle to archive if it exists, otherwise a null handle (0)
*/
Handle CreateArchive(const std::string& name="Unknown");
Handle OpenArchive(FileSys::Archive::IdCode id_code);
/**
* Creates an Archive
* @param backend File system backend interface to the archive
* @param name Optional name of Archive
* @return Handle to newly created Archive object
*/
Handle CreateArchive(FileSys::Archive* backend, const std::string& name);
} // namespace FileSys

@ -2,11 +2,12 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "common/common.h"
#include "core/loader/loader.h"
#include "core/hle/hle.h"
#include "core/hle/service/fs.h"
#include "core/hle/kernel/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace FS_User
@ -15,8 +16,34 @@ namespace FS_User {
void Initialize(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
DEBUG_LOG(KERNEL, "called");
cmd_buff[1] = 0; // No error
DEBUG_LOG(KERNEL, "called");
}
void OpenFileDirectly(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
FileSys::Archive::IdCode arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
// TODO(bunnei): Properly implement use of these...
//u32 transaction = cmd_buff[1];
//u32 arch_lowpath_type = cmd_buff[3];
//u32 arch_lowpath_sz = cmd_buff[4];
//u32 file_lowpath_type = cmd_buff[5];
//u32 file_lowpath_sz = cmd_buff[6];
//u32 flags = cmd_buff[7];
//u32 attr = cmd_buff[8];
//u32 arch_lowpath_desc = cmd_buff[9];
//u32 arch_lowpath_ptr = cmd_buff[10];
//u32 file_lowpath_desc = cmd_buff[11];
//u32 file_lowpath_ptr = cmd_buff[12];
Handle handle = Kernel::OpenArchive(arch_id);
if (0 != handle) {
cmd_buff[1] = 0; // No error
cmd_buff[3] = handle;
}
DEBUG_LOG(KERNEL, "called");
}
const Interface::FunctionInfo FunctionTable[] = {
@ -24,7 +51,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x040100C4, nullptr, "Control"},
{0x08010002, Initialize, "Initialize"},
{0x080201C2, nullptr, "OpenFile"},
{0x08030204, nullptr, "OpenFileDirectly"},
{0x08030204, OpenFileDirectly, "OpenFileDirectly"},
{0x08040142, nullptr, "DeleteFile"},
{0x08050244, nullptr, "RenameFile"},
{0x08060142, nullptr, "DeleteDirectory"},

@ -4,9 +4,11 @@
#include <memory>
#include "core/file_sys/archive_romfs.h"
#include "core/loader/loader.h"
#include "core/loader/elf.h"
#include "core/loader/ncch.h"
#include "core/hle/kernel/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -51,14 +53,20 @@ ResultStatus LoadFile(const std::string& filename) {
switch (IdentifyFile(filename)) {
// Standard ELF file format...
case FileType::ELF: {
case FileType::ELF:
return AppLoader_ELF(filename).Load();
}
// NCCH/NCSD container formats...
case FileType::CXI:
case FileType::CCI: {
return AppLoader_NCCH(filename).Load();
AppLoader_NCCH app_loader(filename);
// Load application and RomFS
if (ResultStatus::Success == app_loader.Load()) {
Kernel::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS");
return ResultStatus::Success;
}
break;
}
// Error occurred durring IdentifyFile...
@ -70,7 +78,6 @@ ResultStatus LoadFile(const std::string& filename) {
default:
return ResultStatus::ErrorInvalidFormat;
}
return ResultStatus::Error;
}