Просмотр исходного кода

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.
bunnei 12 лет назад
Родитель
Сommit
17a6148f9d

+ 3 - 1
src/core/CMakeLists.txt

@@ -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

+ 3 - 1
src/core/core.vcxproj

@@ -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" />

+ 9 - 3
src/core/core.vcxproj.filters

@@ -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" />

+ 54 - 0
src/core/file_sys/archive.h

@@ -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

+ 46 - 0
src/core/file_sys/archive_romfs.cpp

@@ -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

+ 50 - 0
src/core/file_sys/archive_romfs.h

@@ -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

+ 0 - 138
src/core/file_sys/file_sys.h

@@ -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;}
-};
-
-

+ 92 - 6
src/core/hle/kernel/archive.cpp

@@ -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"; }
@@ -20,7 +37,37 @@ public:
     static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; }
     Kernel::HandleType GetHandleType() const { return HandleType::Archive; }
 
-    std::string name; ///< Name of archive (optional)
+    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;
 }
 

+ 13 - 4
src/core/hle/kernel/archive.h

@@ -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

+ 30 - 3
src/core/hle/service/fs.cpp

@@ -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"},

+ 11 - 4
src/core/loader/loader.cpp

@@ -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;
 }