summaryrefslogtreecommitdiffstats
path: root/src/core/file_sys/archive_other_savedata.cpp
blob: d3cf080da8d2d41914541c60b2d0a45d36bfe452 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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