diff options
Diffstat (limited to 'src/core/file_sys/archive_other_savedata.cpp')
-rw-r--r-- | src/core/file_sys/archive_other_savedata.cpp | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/core/file_sys/archive_other_savedata.cpp b/src/core/file_sys/archive_other_savedata.cpp new file mode 100644 index 000000000..d3cf080da --- /dev/null +++ b/src/core/file_sys/archive_other_savedata.cpp @@ -0,0 +1,145 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <tuple> +#include "core/file_sys/archive_other_savedata.h" +#include "core/file_sys/errors.h" +#include "core/hle/kernel/process.h" +#include "core/hle/service/fs/archive.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +// TODO(wwylele): The storage info in exheader should be checked before accessing these archives + +using Service::FS::MediaType; + +namespace { + +template <typename T> +ResultVal<std::tuple<MediaType, u64>> ParsePath(const Path& path, T program_id_reader) { + if (path.GetType() != Binary) { + LOG_ERROR(Service_FS, "Wrong path type %d", static_cast<int>(path.GetType())); + return ERROR_INVALID_PATH; + } + + std::vector<u8> vec_data = path.AsBinary(); + + if (vec_data.size() != 12) { + LOG_ERROR(Service_FS, "Wrong path length %zu", vec_data.size()); + return ERROR_INVALID_PATH; + } + + const u32* data = reinterpret_cast<const u32*>(vec_data.data()); + auto media_type = static_cast<MediaType>(data[0]); + + if (media_type != MediaType::SDMC && media_type != MediaType::GameCard) { + LOG_ERROR(Service_FS, "Unsupported media type %u", static_cast<u32>(media_type)); + + // Note: this is strange, but the error code was verified with a real 3DS + return ERROR_UNSUPPORTED_OPEN_FLAGS; + } + + return MakeResult<std::tuple<MediaType, u64>>(media_type, program_id_reader(data)); +} + +ResultVal<std::tuple<MediaType, u64>> ParsePathPermitted(const Path& path) { + return ParsePath(path, + [](const u32* data) -> u64 { return (data[1] << 8) | 0x0004000000000000ULL; }); +} + +ResultVal<std::tuple<MediaType, u64>> ParsePathGeneral(const Path& path) { + return ParsePath( + path, [](const u32* data) -> u64 { return data[1] | (static_cast<u64>(data[2]) << 32); }); +} + +} // namespace + +ArchiveFactory_OtherSaveDataPermitted::ArchiveFactory_OtherSaveDataPermitted( + std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata) + : sd_savedata_source(sd_savedata) {} + +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataPermitted::Open( + const Path& path) { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->Open(program_id); +} + +ResultCode ArchiveFactory_OtherSaveDataPermitted::Format( + const Path& path, const FileSys::ArchiveFormatInfo& format_info) { + LOG_ERROR(Service_FS, "Attempted to format a OtherSaveDataPermitted archive."); + return ERROR_INVALID_PATH; +} + +ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataPermitted::GetFormatInfo( + const Path& path) const { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathPermitted(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->GetFormatInfo(program_id); +} + +ArchiveFactory_OtherSaveDataGeneral::ArchiveFactory_OtherSaveDataGeneral( + std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata) + : sd_savedata_source(sd_savedata) {} + +ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_OtherSaveDataGeneral::Open( + const Path& path) { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->Open(program_id); +} + +ResultCode ArchiveFactory_OtherSaveDataGeneral::Format( + const Path& path, const FileSys::ArchiveFormatInfo& format_info) { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->Format(program_id, format_info); +} + +ResultVal<ArchiveFormatInfo> ArchiveFactory_OtherSaveDataGeneral::GetFormatInfo( + const Path& path) const { + MediaType media_type; + u64 program_id; + CASCADE_RESULT(std::tie(media_type, program_id), ParsePathGeneral(path)); + + if (media_type == MediaType::GameCard) { + LOG_WARNING(Service_FS, "(stubbed) Unimplemented media type GameCard"); + return ERROR_GAMECARD_NOT_INSERTED; + } + + return sd_savedata_source->GetFormatInfo(program_id); +} + +} // namespace FileSys |