diff --git a/libraries/libstratosphere/include/stratosphere/ncm.hpp b/libraries/libstratosphere/include/stratosphere/ncm.hpp
index 343073124..38811eaec 100644
--- a/libraries/libstratosphere/include/stratosphere/ncm.hpp
+++ b/libraries/libstratosphere/include/stratosphere/ncm.hpp
@@ -18,5 +18,6 @@
#include "ncm/ncm_types.hpp"
#include "ncm/ncm_content_meta.hpp"
-#include "ncm/ncm_i_content_meta_database.hpp"
-#include "ncm/ncm_i_content_storage.hpp"
+#include "ncm/ncm_content_meta_database.hpp"
+#include "ncm/ncm_content_storage.hpp"
+#include "ncm/ncm_api.hpp"
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp
new file mode 100644
index 000000000..4d42dd3b9
--- /dev/null
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_api.hpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace ams::ncm {
+
+ /* Management. */
+ void Initialize();
+ void Finalize();
+
+ void InitializeWithObject(std::shared_ptr manager_object);
+
+ /* Service API. */
+ Result CreateContentStorage(StorageId storage_id);
+ Result CreateContentMetaDatabase(StorageId storage_id);
+
+ Result VerifyContentStorage(StorageId storage_id);
+ Result VerifyContentMetaDatabase(StorageId storage_id);
+
+ Result OpenContentStorage(ContentStorage *out, StorageId storage_id);
+ Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id);
+
+ Result CleanupContentMetaDatabase(StorageId storage_id);
+
+ Result ActivateContentStorage(StorageId storage_id);
+ Result InactivateContentStorage(StorageId storage_id);
+
+ Result ActivateContentMetaDatabase(StorageId storage_id);
+ Result InactivateContentMetaDatabase(StorageId storage_id);
+
+ Result InvalidateRightsIdCache();
+
+ /* Deprecated API. */
+ Result CloseContentStorageForcibly(StorageId storage_id);
+ Result CloseContentMetaDatabaseForcibly(StorageId storage_id);
+
+}
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp
new file mode 100644
index 000000000..b3c9e3e20
--- /dev/null
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_meta_database.hpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+
+#pragma once
+#include
+#include
+
+namespace ams::ncm {
+
+ class ContentMetaDatabase {
+ NON_COPYABLE(ContentMetaDatabase);
+ public:
+ struct ListCount {
+ u32 written;
+ u32 total;
+ };
+ private:
+ std::shared_ptr interface;
+ public:
+ ContentMetaDatabase() { /* ... */ }
+ explicit ContentMetaDatabase(std::shared_ptr intf) : interface(std::move(intf)) { /* ... */ }
+
+ ContentMetaDatabase(ContentMetaDatabase &&rhs) {
+ this->interface = std::move(rhs.interface);
+ }
+
+ ContentMetaDatabase &operator=(ContentMetaDatabase &&rhs) {
+ ContentMetaDatabase(std::move(rhs)).Swap(*this);
+ return *this;
+ }
+
+ void Swap(ContentMetaDatabase &rhs) {
+ std::swap(this->interface, rhs.interface);
+ }
+ public:
+ Result Set(const ContentMetaKey &key, const void *buf, size_t size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Set(key, sf::InBuffer(buf, size));
+ }
+
+ Result Get(size_t *out_size, void *dst, size_t dst_size, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ u64 size;
+ R_TRY(this->interface->Get(std::addressof(size), key, sf::OutBuffer(dst, dst_size)));
+
+ *out_size = size;
+ return ResultSuccess();
+ }
+
+ /* TODO: Proper ProgramId vs DataId vs ApplicationId for Get */
+ #define AMS_NCM_DEFINE_GETTERS(Kind) \
+ Result Get##Kind(ContentId *out, ProgramId id, u32 version) { \
+ return this->interface->GetContentIdByType(out, ContentMetaKey::MakeUnknownType(id, version), ContentType::Kind); \
+ } \
+ \
+ Result GetLatest##Kind(ContentId *out, ProgramId id) { \
+ ContentMetaKey latest_key; \
+ R_TRY(this->interface->GetLatestContentMetaKey(std::addressof(latest_key), id)); \
+ return this->interface->GetContentIdByType(out, latest_key, ContentType::Kind); \
+ }
+
+ AMS_NCM_DEFINE_GETTERS(Program)
+ AMS_NCM_DEFINE_GETTERS(Data)
+ AMS_NCM_DEFINE_GETTERS(Control)
+ AMS_NCM_DEFINE_GETTERS(HtmlDocument)
+ AMS_NCM_DEFINE_GETTERS(LegalInformation)
+
+ #undef AMS_NCM_DEFINE_GETTERS
+
+ /* TODO: Remove(SystemProgramId) Remove(SystemDataId) Remove(ProgramId) */
+
+ Result Remove(const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Remove(key);
+ }
+
+ Result GetContentIdByType(ContentId *out_content_id, const ContentMetaKey &key, ContentType type) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetContentIdByType(out_content_id, key, type);
+ }
+
+ Result GetContentIdByTypeAndIdOffset(ContentId *out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetContentIdByTypeAndIdOffset(out_content_id, key, type, id_offset);
+ }
+
+ ListCount ListApplication(ApplicationContentMetaKey *dst, size_t dst_size) {
+ ListCount lc = {};
+ R_ABORT_UNLESS(this->interface->ListApplication(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray(dst, dst_size), ContentMetaType::Unknown));
+ return lc;
+ }
+
+ ListCount ListContentMeta(ContentMetaKey *dst, size_t dst_size, ContentMetaType type, ProgramId app_id, ProgramId min, ProgramId max, ContentInstallType install_type) {
+ ListCount lc = {};
+ R_ABORT_UNLESS(this->interface->List(std::addressof(lc.total), std::addressof(lc.written), sf::OutArray(dst, dst_size), type, app_id, min, max, install_type));
+ return lc;
+ }
+
+ Result GetLatest(ContentMetaKey *out_key, ProgramId id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetLatestContentMetaKey(out_key, id);
+ }
+
+ Result ListContentInfo(u32 *out_count, ContentInfo *dst, size_t dst_size, const ContentMetaKey &key, u32 offset) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->ListContentInfo(out_count, sf::OutArray(dst, dst_size), key, offset);
+ }
+
+ Result ListContentMetaInfo(u32 *out_count, ContentMetaInfo *dst, size_t dst_size, const ContentMetaKey &key, u32 offset) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->ListContentMetaInfo(out_count, sf::OutArray(dst, dst_size), key, offset);
+ }
+
+ Result Has(bool *out, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Has(out, key);
+ }
+
+ Result HasAll(bool *out, const ContentMetaKey *keys, size_t num_keys) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->HasAll(out, sf::InArray(keys, num_keys));
+ }
+
+ Result HasContent(bool *out, const ContentMetaKey &key, const ContentId &content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->HasContent(out, key, content_id);
+ }
+
+ Result GetSize(size_t *out_size, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ u64 size;
+ R_TRY(this->interface->GetSize(std::addressof(size), key));
+
+ *out_size = size;
+ return ResultSuccess();
+ }
+
+ Result GetRequiredSystemVersion(u32 *out_version, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetRequiredSystemVersion(out_version, key);
+ }
+
+ Result GetPatchId(ProgramId *out_patch_id, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetPatchId(out_patch_id, key);
+ }
+
+ Result DisableForcibly() {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->DisableForcibly();
+ }
+
+ Result LookupOrphanContent(bool *out_orphaned, ContentId *content_list, size_t count) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->LookupOrphanContent(sf::OutArray(out_orphaned, count), sf::InArray(content_list, count));
+ }
+
+ Result Commit() {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Commit();
+ }
+
+ Result GetAttributes(ContentMetaAttribute *out_attributes, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetAttributes(out_attributes, key);
+ }
+
+ Result GetRequiredApplicationVersion(u32 *out_version, const ContentMetaKey &key) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetRequiredApplicationVersion(out_version, key);
+ }
+ };
+
+}
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp
new file mode 100644
index 000000000..15821f6f2
--- /dev/null
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_content_storage.hpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+
+#pragma once
+#include
+#include
+
+namespace ams::ncm {
+
+ class ContentStorage {
+ NON_COPYABLE(ContentStorage);
+ private:
+ std::shared_ptr interface;
+ public:
+ ContentStorage() { /* ... */ }
+ explicit ContentStorage(std::shared_ptr intf) : interface(std::move(intf)) { /* ... */ }
+
+ ContentStorage(ContentStorage &&rhs) {
+ this->interface = std::move(rhs.interface);
+ }
+
+ ContentStorage &operator=(ContentStorage &&rhs) {
+ ContentStorage(std::move(rhs)).Swap(*this);
+ return *this;
+ }
+
+ void Swap(ContentStorage &rhs) {
+ std::swap(this->interface, rhs.interface);
+ }
+ public:
+ PlaceHolderId GeneratePlaceHolderId() {
+ AMS_ASSERT(this->interface != nullptr);
+
+ PlaceHolderId id;
+ R_ABORT_UNLESS(this->interface->GeneratePlaceHolderId(std::addressof(id)));
+ return id;
+ }
+
+ Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->CreatePlaceHolder(placeholder_id, content_id, size);
+ }
+
+ Result DeletePlaceHolder(PlaceHolderId placeholder_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->DeletePlaceHolder(placeholder_id);
+ }
+
+ Result HasPlaceHolder(bool *out, PlaceHolderId placeholder_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->HasPlaceHolder(out, placeholder_id);
+ }
+
+ Result WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, const void *buf, size_t size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->WritePlaceHolder(placeholder_id, offset, sf::InBuffer(buf, size));
+ }
+
+ Result Register(PlaceHolderId placeholder_id, ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Register(placeholder_id, content_id);
+ }
+
+ Result Delete(ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Delete(content_id);
+ }
+
+ Result Has(bool *out, ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->Has(out, content_id);
+ }
+
+ void GetPath(Path *out, ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ R_ABORT_UNLESS(this->interface->GetPath(out, content_id));
+ }
+
+ void GetPlaceHolderPath(Path *out, PlaceHolderId placeholder_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ R_ABORT_UNLESS(this->interface->GetPlaceHolderPath(out, placeholder_id));
+ }
+
+ Result CleanupAllPlaceHolder() {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->CleanupAllPlaceHolder();
+ }
+
+ Result ListPlaceHolder(u32 *out_count, PlaceHolderId *out_list, size_t out_list_size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->ListPlaceHolder(out_count, sf::OutArray(out_list, out_list_size));
+ }
+
+ Result GetContentCount(u32 *out_count) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetContentCount(out_count);
+ }
+
+ Result ListContentId(u32 *out_count, ContentId *out_list, size_t out_list_size, u32 offset) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->ListContentId(out_count, sf::OutArray(out_list, out_list_size), offset);
+ }
+
+ Result GetSize(u64 *out_size, ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetSizeFromContentId(out_size, content_id);
+ }
+
+ Result GetSize(u64 *out_size, PlaceHolderId placeholder_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetSizeFromPlaceHolderId(out_size, placeholder_id);
+ }
+
+ Result DisableForcibly() {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->DisableForcibly();
+ }
+
+ Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->RevertToPlaceHolder(placeholder_id, old_content_id, new_content_id);
+ }
+
+ Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->SetPlaceHolderSize(placeholder_id, size);
+ }
+
+ Result ReadContentIdFile(void *dst, size_t size, ContentId content_id, u64 offset) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->ReadContentIdFile(sf::OutBuffer(dst, size), content_id, offset);
+ }
+
+ Result GetRightsId(ams::fs::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300);
+ return this->interface->GetRightsIdFromPlaceHolderIdDeprecated(out_rights_id, placeholder_id);
+ }
+
+ Result GetRightsId(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300);
+ return this->interface->GetRightsIdFromPlaceHolderId(out_rights_id, placeholder_id);
+ }
+
+ Result GetRightsId(ams::fs::RightsId *out_rights_id, ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ AMS_ABORT_UNLESS(hos::GetVersion() < hos::Version_300);
+ return this->interface->GetRightsIdFromContentIdDeprecated(out_rights_id, content_id);
+ }
+
+ Result GetRightsId(ncm::RightsId *out_rights_id, ContentId content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ AMS_ABORT_UNLESS(hos::GetVersion() >= hos::Version_300);
+ return this->interface->GetRightsIdFromContentId(out_rights_id, content_id);
+ }
+
+ Result WriteContentForDebug(ContentId content_id, u64 offset, const void *buf, size_t size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->WriteContentForDebug(content_id, offset, sf::InBuffer(buf, size));
+ }
+
+ Result GetFreeSpaceSize(u64 *out_size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetFreeSpaceSize(out_size);
+ }
+
+ Result GetTotalSpaceSize(u64 *out_size) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetTotalSpaceSize(out_size);
+ }
+
+ Result FlushPlaceHolder() {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->FlushPlaceHolder();
+ }
+
+ Result RepairInvalidFileAttribute() {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->RepairInvalidFileAttribute();
+ }
+
+ Result GetRightsIdFromPlaceHolderIdWithCache(ncm::RightsId *out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
+ AMS_ASSERT(this->interface != nullptr);
+ return this->interface->GetRightsIdFromPlaceHolderIdWithCache(out_rights_id, placeholder_id, cache_content_id);
+ }
+ };
+
+}
diff --git a/stratosphere/ncm/source/ncm_content_manager_service.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp
similarity index 67%
rename from stratosphere/ncm/source/ncm_content_manager_service.hpp
rename to libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp
index f855b8259..43071f864 100644
--- a/stratosphere/ncm/source/ncm_content_manager_service.hpp
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_manager.hpp
@@ -15,12 +15,12 @@
*/
#pragma once
-#include
-#include
+#include
+#include
namespace ams::ncm {
- class ContentManagerService final : public sf::IServiceObject {
+ class IContentManager : public sf::IServiceObject {
protected:
enum class CommandId {
CreateContentStorage = 0,
@@ -39,20 +39,20 @@ namespace ams::ncm {
InvalidateRightsIdCache = 13,
};
public:
- Result CreateContentStorage(StorageId storage_id);
- Result CreateContentMetaDatabase(StorageId storage_id);
- Result VerifyContentStorage(StorageId storage_id);
- Result VerifyContentMetaDatabase(StorageId storage_id);
- Result OpenContentStorage(sf::Out> out, StorageId storage_id);
- Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id);
- Result CloseContentStorageForcibly(StorageId storage_id);
- Result CloseContentMetaDatabaseForcibly(StorageId storage_id);
- Result CleanupContentMetaDatabase(StorageId storage_id);
- Result ActivateContentStorage(StorageId storage_id);
- Result InactivateContentStorage(StorageId storage_id);
- Result ActivateContentMetaDatabase(StorageId storage_id);
- Result InactivateContentMetaDatabase(StorageId storage_id);
- Result InvalidateRightsIdCache();
+ virtual Result CreateContentStorage(StorageId storage_id) = 0;
+ virtual Result CreateContentMetaDatabase(StorageId storage_id) = 0;
+ virtual Result VerifyContentStorage(StorageId storage_id) = 0;
+ virtual Result VerifyContentMetaDatabase(StorageId storage_id) = 0;
+ virtual Result OpenContentStorage(sf::Out> out, StorageId storage_id) = 0;
+ virtual Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) = 0;
+ virtual Result CloseContentStorageForcibly(StorageId storage_id) = 0;
+ virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) = 0;
+ virtual Result CleanupContentMetaDatabase(StorageId storage_id) = 0;
+ virtual Result ActivateContentStorage(StorageId storage_id) = 0;
+ virtual Result InactivateContentStorage(StorageId storage_id) = 0;
+ virtual Result ActivateContentMetaDatabase(StorageId storage_id) = 0;
+ virtual Result InactivateContentMetaDatabase(StorageId storage_id) = 0;
+ virtual Result InvalidateRightsIdCache() = 0;
public:
DEFINE_SERVICE_DISPATCH_TABLE {
MAKE_SERVICE_COMMAND_META(CreateContentStorage),
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp
index f09c7a244..fee22c2fc 100644
--- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_meta_database.hpp
@@ -64,7 +64,7 @@ namespace ams::ncm {
virtual Result DisableForcibly() = 0;
virtual Result LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) = 0;
virtual Result Commit() = 0;
- virtual Result HasContent(sf::Out out, const ContentMetaKey &key, ContentId content_id) = 0;
+ virtual Result HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) = 0;
virtual Result ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, u32 start_index) = 0;
virtual Result GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) = 0;
virtual Result GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) = 0;
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp
index 29fb5dc4b..19896cb05 100644
--- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_i_content_storage.hpp
@@ -16,6 +16,7 @@
#pragma once
#include
+#include
#include
#include
@@ -68,8 +69,8 @@ namespace ams::ncm {
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) = 0;
virtual Result Delete(ContentId content_id) = 0;
virtual Result Has(sf::Out out, ContentId content_id) = 0;
- virtual Result GetPath(sf::Out out, ContentId content_id) = 0;
- virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) = 0;
+ virtual Result GetPath(sf::Out out, ContentId content_id) = 0;
+ virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) = 0;
virtual Result CleanupAllPlaceHolder() = 0;
virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) = 0;
virtual Result GetContentCount(sf::Out out_count) = 0;
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp
new file mode 100644
index 000000000..a0d1cd1fb
--- /dev/null
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_path.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+#pragma once
+#include
+#include
+#include
+#include
+
+namespace ams::ncm {
+
+ struct alignas(4) Path : ams::sf::LargeData {
+ char str[fs::EntryNameLengthMax];
+
+ static constexpr Path Encode(const char *p) {
+ Path path = {};
+ /* Copy C string to path, terminating when a null byte is found. */
+ for (size_t i = 0; i < sizeof(path) - 1; i++) {
+ path.str[i] = p[i];
+ if (p[i] == '\x00') {
+ break;
+ }
+ }
+ return path;
+ }
+ };
+
+}
diff --git a/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp b/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp
index feb560361..7927e8561 100644
--- a/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp
+++ b/libraries/libstratosphere/include/stratosphere/ncm/ncm_types.hpp
@@ -621,6 +621,10 @@ namespace ams::ncm {
return !(*this == other);
}
+ static constexpr ContentMetaKey MakeUnknownType(ProgramId program_id, u32 version) {
+ return { .id = program_id, .version = version, .type = ContentMetaType::Unknown };
+ }
+
static constexpr ContentMetaKey Make(ProgramId program_id, u32 version, ContentMetaType type) {
return { .id = program_id, .version = version, .type = type };
}
diff --git a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp
index 1f347ca40..3ceb664d8 100644
--- a/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp
+++ b/libraries/libstratosphere/include/stratosphere/sf/impl/sf_impl_command_serialization.hpp
@@ -86,11 +86,13 @@ namespace ams::sf {
cmif::ServiceObjectHolder *srv;
cmif::DomainObjectId *object_id;
public:
+ Out(cmif::ServiceObjectHolder *s) : srv(s), object_id(nullptr) { /* ... */ }
Out(cmif::ServiceObjectHolder *s, cmif::DomainObjectId *o) : srv(s), object_id(o) { /* ... */ }
void SetValue(std::shared_ptr &&s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) {
*this->srv = cmif::ServiceObjectHolder(std::move(s));
if (new_object_id != cmif::InvalidDomainObjectId) {
+ AMS_ABORT_UNLESS(object_id != nullptr);
*this->object_id = new_object_id;
}
}
diff --git a/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp b/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp
index 79d939945..66299f35d 100644
--- a/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp
+++ b/libraries/libstratosphere/source/lr/lr_add_on_content_location_resolver_impl.cpp
@@ -16,14 +16,6 @@
#include
#include "lr_add_on_content_location_resolver_impl.hpp"
-/* TODO: Properly integrate NCM api into libstratosphere to avoid linker hack. */
-namespace ams::ncm::impl {
-
- Result OpenContentMetaDatabase(std::shared_ptr *, ncm::StorageId);
- Result OpenContentStorage(std::shared_ptr *, ncm::StorageId);
-
-}
-
namespace ams::lr {
Result AddOnContentLocationResolverImpl::ResolveAddOnContentPath(sf::Out out, ncm::ProgramId id) {
@@ -32,19 +24,20 @@ namespace ams::lr {
R_UNLESS(this->registered_storages.Find(&storage_id, id), lr::ResultAddOnContentNotFound());
/* Obtain a Content Meta Database for the storage id. */
- std::shared_ptr content_meta_database;
- R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, storage_id));
+ ncm::ContentMetaDatabase content_meta_database;
+ R_TRY(ncm::OpenContentMetaDatabase(&content_meta_database, storage_id));
/* Find the latest data content id for the given program id. */
ncm::ContentId data_content_id;
- R_TRY(content_meta_database->GetLatestData(&data_content_id, id));
+ R_TRY(content_meta_database.GetLatestData(&data_content_id, id));
/* Obtain a Content Storage for the storage id. */
- std::shared_ptr content_storage;
- R_TRY(ncm::impl::OpenContentStorage(&content_storage, storage_id));
+ ncm::ContentStorage content_storage;
+ R_TRY(ncm::OpenContentStorage(&content_storage, storage_id));
/* Get the path of the data content. */
- R_ABORT_UNLESS(content_storage->GetPath(out.GetPointer(), data_content_id));
+ static_assert(sizeof(lr::Path) == sizeof(ncm::Path));
+ content_storage.GetPath(reinterpret_cast(out.GetPointer()), data_content_id);
return ResultSuccess();
}
diff --git a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp
index 9398ff327..64ca4e920 100644
--- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp
+++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.cpp
@@ -16,14 +16,6 @@
#include
#include "lr_content_location_resolver_impl.hpp"
-/* TODO: Properly integrate NCM api into libstratosphere to avoid linker hack. */
-namespace ams::ncm::impl {
-
- Result OpenContentMetaDatabase(std::shared_ptr *, ncm::StorageId);
- Result OpenContentStorage(std::shared_ptr *, ncm::StorageId);
-
-}
-
namespace ams::lr {
ContentLocationResolverImpl::~ContentLocationResolverImpl() {
@@ -32,7 +24,8 @@ namespace ams::lr {
/* Helper function. */
void ContentLocationResolverImpl::GetContentStoragePath(Path *out, ncm::ContentId content_id) {
- R_ABORT_UNLESS(this->content_storage->GetPath(out, content_id));
+ static_assert(sizeof(lr::Path) == sizeof(ncm::Path));
+ this->content_storage.GetPath(reinterpret_cast(out), content_id);
}
Result ContentLocationResolverImpl::ResolveProgramPath(sf::Out out, ncm::ProgramId id) {
@@ -41,7 +34,7 @@ namespace ams::lr {
/* Find the latest program content for the program id. */
ncm::ContentId program_content_id;
- R_TRY_CATCH(this->content_meta_database->GetLatestProgram(&program_content_id, id)) {
+ R_TRY_CATCH(this->content_meta_database.GetLatestProgram(&program_content_id, id)) {
R_CONVERT(ncm::ResultContentMetaNotFound, lr::ResultProgramNotFound())
} R_END_TRY_CATCH;
@@ -69,7 +62,7 @@ namespace ams::lr {
Result ContentLocationResolverImpl::ResolveDataPath(sf::Out out, ncm::ProgramId id) {
/* Find the latest data content for the program id. */
ncm::ContentId data_content_id;
- R_TRY(this->content_meta_database->GetLatestData(&data_content_id, id));
+ R_TRY(this->content_meta_database.GetLatestData(&data_content_id, id));
/* Obtain the content path. */
this->GetContentStoragePath(out.GetPointer(), data_content_id);
@@ -114,14 +107,14 @@ namespace ams::lr {
Result ContentLocationResolverImpl::Refresh() {
/* Obtain Content Meta Database and Content Storage objects for this resolver's storage. */
- std::shared_ptr content_meta_database;
- std::shared_ptr content_storage;
- R_TRY(ncm::impl::OpenContentMetaDatabase(&content_meta_database, this->storage_id));
- R_TRY(ncm::impl::OpenContentStorage(&content_storage, this->storage_id));
+ ncm::ContentMetaDatabase meta_db;
+ ncm::ContentStorage storage;
+ R_TRY(ncm::OpenContentMetaDatabase(&meta_db, this->storage_id));
+ R_TRY(ncm::OpenContentStorage(&storage, this->storage_id));
/* Store the acquired objects. */
- this->content_meta_database = std::move(content_meta_database);
- this->content_storage = std::move(content_storage);
+ this->content_meta_database = std::move(meta_db);
+ this->content_storage = std::move(storage);
/* Remove any existing redirections. */
this->ClearRedirections();
diff --git a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp
index e25af0050..04a8c55a7 100644
--- a/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp
+++ b/libraries/libstratosphere/source/lr/lr_content_location_resolver_impl.hpp
@@ -24,8 +24,8 @@ namespace ams::lr {
ncm::StorageId storage_id;
/* Objects for this storage type. */
- std::shared_ptr content_meta_database;
- std::shared_ptr content_storage;
+ ncm::ContentMetaDatabase content_meta_database;
+ ncm::ContentStorage content_storage;
public:
ContentLocationResolverImpl(ncm::StorageId storage_id) : storage_id(storage_id) { /* ... */ }
diff --git a/libraries/libstratosphere/source/ncm/ncm_api.cpp b/libraries/libstratosphere/source/ncm/ncm_api.cpp
new file mode 100644
index 000000000..7dbed826c
--- /dev/null
+++ b/libraries/libstratosphere/source/ncm/ncm_api.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+#include
+#include "ncm_remote_content_manager_impl.hpp"
+
+namespace ams::ncm {
+
+ namespace {
+
+ std::shared_ptr g_content_manager;
+
+ }
+
+ void Initialize() {
+ AMS_ASSERT(g_content_manager == nullptr);
+ R_ABORT_UNLESS(ncmInitialize());
+ g_content_manager = std::make_shared();
+ }
+
+ void Finalize() {
+ AMS_ASSERT(g_content_manager != nullptr);
+ g_content_manager.reset();
+ ncmExit();
+ }
+
+ void InitializeWithObject(std::shared_ptr manager_object) {
+ AMS_ASSERT(g_content_manager == nullptr);
+ g_content_manager = manager_object;
+ AMS_ASSERT(g_content_manager != nullptr);
+ }
+
+ /* Service API. */
+ Result CreateContentStorage(StorageId storage_id) {
+ return g_content_manager->CreateContentStorage(storage_id);
+ }
+
+ Result CreateContentMetaDatabase(StorageId storage_id) {
+ return g_content_manager->CreateContentMetaDatabase(storage_id);
+ }
+
+ Result VerifyContentStorage(StorageId storage_id) {
+ return g_content_manager->VerifyContentStorage(storage_id);
+ }
+
+ Result VerifyContentMetaDatabase(StorageId storage_id) {
+ return g_content_manager->VerifyContentMetaDatabase(storage_id);
+ }
+
+ Result OpenContentStorage(ContentStorage *out, StorageId storage_id) {
+ sf::cmif::ServiceObjectHolder object_holder;
+ R_TRY(g_content_manager->OpenContentStorage(std::addressof(object_holder), storage_id));
+
+ *out = ContentStorage(object_holder.GetServiceObject());
+ return ResultSuccess();
+ }
+
+ Result OpenContentMetaDatabase(ContentMetaDatabase *out, StorageId storage_id) {
+ sf::cmif::ServiceObjectHolder object_holder;
+ R_TRY(g_content_manager->OpenContentMetaDatabase(std::addressof(object_holder), storage_id));
+
+ *out = ContentMetaDatabase(object_holder.GetServiceObject());
+ return ResultSuccess();
+ }
+
+ Result CleanupContentMetaDatabase(StorageId storage_id) {
+ return g_content_manager->CleanupContentMetaDatabase(storage_id);
+ }
+
+ Result ActivateContentStorage(StorageId storage_id) {
+ return g_content_manager->ActivateContentStorage(storage_id);
+ }
+
+ Result InactivateContentStorage(StorageId storage_id) {
+ return g_content_manager->InactivateContentStorage(storage_id);
+ }
+
+ Result ActivateContentMetaDatabase(StorageId storage_id) {
+ return g_content_manager->ActivateContentMetaDatabase(storage_id);
+ }
+
+ Result InactivateContentMetaDatabase(StorageId storage_id) {
+ return g_content_manager->InactivateContentMetaDatabase(storage_id);
+ }
+
+ Result InvalidateRightsIdCache() {
+ return g_content_manager->InvalidateRightsIdCache();
+ }
+
+ /* Deprecated API. */
+ Result CloseContentStorageForcibly(StorageId storage_id) {
+ AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100);
+ return g_content_manager->CloseContentStorageForcibly(storage_id);
+ }
+
+ Result CloseContentMetaDatabaseForcibly(StorageId storage_id) {
+ AMS_ABORT_UNLESS(hos::GetVersion() == hos::Version_100);
+ return g_content_manager->CloseContentMetaDatabaseForcibly(storage_id);
+ }
+}
diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp
new file mode 100644
index 000000000..2baf990fd
--- /dev/null
+++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_manager_impl.hpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+
+#pragma once
+#include
+#include "ncm_remote_content_storage_impl.hpp"
+#include "ncm_remote_content_meta_database_impl.hpp"
+
+namespace ams::ncm {
+
+ class RemoteContentManagerImpl final : public IContentManager {
+ public:
+ RemoteContentManagerImpl() { /* ... */ }
+
+ ~RemoteContentManagerImpl() { /* ... */ }
+ public:
+ virtual Result CreateContentStorage(StorageId storage_id) override {
+ return ::ncmCreateContentStorage(static_cast(storage_id));
+ }
+
+ virtual Result CreateContentMetaDatabase(StorageId storage_id) override {
+ return ::ncmCreateContentMetaDatabase(static_cast(storage_id));
+ }
+
+ virtual Result VerifyContentStorage(StorageId storage_id) override {
+ return ::ncmVerifyContentStorage(static_cast(storage_id));
+ }
+
+ virtual Result VerifyContentMetaDatabase(StorageId storage_id) override {
+ return ::ncmVerifyContentMetaDatabase(static_cast(storage_id));
+ }
+
+ virtual Result OpenContentStorage(sf::Out> out, StorageId storage_id) override {
+ NcmContentStorage cs;
+ R_TRY(::ncmOpenContentStorage(std::addressof(cs), static_cast(storage_id)));
+
+ out.SetValue(std::make_shared(cs));
+ return ResultSuccess();
+ }
+
+ virtual Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) override {
+ NcmContentMetaDatabase db;
+ R_TRY(::ncmOpenContentMetaDatabase(std::addressof(db), static_cast(storage_id)));
+
+ out.SetValue(std::make_shared(db));
+ return ResultSuccess();
+ }
+
+ virtual Result CloseContentStorageForcibly(StorageId storage_id) override {
+ return ::ncmCloseContentStorageForcibly(static_cast(storage_id));
+ }
+
+ virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) override {
+ return ::ncmCloseContentMetaDatabaseForcibly(static_cast(storage_id));
+ }
+
+ virtual Result CleanupContentMetaDatabase(StorageId storage_id) override {
+ return ::ncmCleanupContentMetaDatabase(static_cast(storage_id));
+ }
+
+ virtual Result ActivateContentStorage(StorageId storage_id) override {
+ return ::ncmActivateContentStorage(static_cast(storage_id));
+ }
+
+ virtual Result InactivateContentStorage(StorageId storage_id) override {
+ return ::ncmInactivateContentStorage(static_cast(storage_id));
+ }
+
+ virtual Result ActivateContentMetaDatabase(StorageId storage_id) override {
+ return ::ncmActivateContentMetaDatabase(static_cast(storage_id));
+ }
+
+ virtual Result InactivateContentMetaDatabase(StorageId storage_id) override {
+ return ::ncmInactivateContentMetaDatabase(static_cast(storage_id));
+ }
+
+ virtual Result InvalidateRightsIdCache() override {
+ return ::ncmInvalidateRightsIdCache();
+ }
+ };
+
+}
diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp
new file mode 100644
index 000000000..ccbb0ada8
--- /dev/null
+++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_meta_database_impl.hpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+
+#pragma once
+#include
+
+namespace ams::ncm {
+
+ class RemoteContentMetaDatabaseImpl final : public IContentMetaDatabase {
+ private:
+ ::NcmContentMetaDatabase srv;
+ public:
+ RemoteContentMetaDatabaseImpl(::NcmContentMetaDatabase &db) : srv(db) { /* ... */ }
+
+ ~RemoteContentMetaDatabaseImpl() { ::ncmContentMetaDatabaseClose(std::addressof(srv)); }
+ private:
+ ALWAYS_INLINE ::NcmContentMetaKey *Convert(ContentMetaKey *k) {
+ static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey));
+ return reinterpret_cast<::NcmContentMetaKey *>(k);
+ }
+ ALWAYS_INLINE const ::NcmContentMetaKey *Convert(const ContentMetaKey *k) {
+ static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey));
+ return reinterpret_cast(k);
+ }
+
+ ALWAYS_INLINE const ::NcmContentMetaKey *Convert(const ContentMetaKey &k) {
+ static_assert(sizeof(ContentMetaKey) == sizeof(::NcmContentMetaKey));
+ return reinterpret_cast(std::addressof(k));
+ }
+
+ ALWAYS_INLINE ::NcmApplicationContentMetaKey *Convert(ApplicationContentMetaKey *k) {
+ static_assert(sizeof(ApplicationContentMetaKey) == sizeof(::NcmApplicationContentMetaKey));
+ return reinterpret_cast<::NcmApplicationContentMetaKey *>(k);
+ }
+
+ ALWAYS_INLINE ::NcmContentInfo *Convert(ContentInfo *c) {
+ static_assert(sizeof(ContentInfo) == sizeof(::NcmContentInfo));
+ return reinterpret_cast<::NcmContentInfo *>(c);
+ }
+
+ ALWAYS_INLINE ::NcmContentId *Convert(ContentId *c) {
+ static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
+ return reinterpret_cast<::NcmContentId *>(c);
+ }
+
+ ALWAYS_INLINE ::NcmContentId *Convert(ContentId &c) {
+ static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
+ return reinterpret_cast<::NcmContentId *>(std::addressof(c));
+ }
+
+ ALWAYS_INLINE const ::NcmContentId *Convert(const ContentId *c) {
+ static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
+ return reinterpret_cast(c);
+ }
+
+
+ ALWAYS_INLINE const ::NcmContentId *Convert(const ContentId &c) {
+ static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
+ return reinterpret_cast(std::addressof(c));
+ }
+ public:
+ virtual Result Set(const ContentMetaKey &key, sf::InBuffer value) override {
+ return ncmContentMetaDatabaseSet(std::addressof(this->srv), Convert(key), value.GetPointer(), value.GetSize());
+ }
+
+ virtual Result Get(sf::Out out_size, const ContentMetaKey &key, sf::OutBuffer out_value) override {
+ return ncmContentMetaDatabaseGet(std::addressof(this->srv), Convert(key), out_size.GetPointer(), out_value.GetPointer(), out_value.GetSize());
+ }
+
+ virtual Result Remove(const ContentMetaKey &key) override {
+ return ncmContentMetaDatabaseRemove(std::addressof(this->srv), Convert(key));
+ }
+
+ virtual Result GetContentIdByType(sf::Out out_content_id, const ContentMetaKey &key, ContentType type) override {
+ return ncmContentMetaDatabaseGetContentIdByType(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type));
+ }
+
+ virtual Result ListContentInfo(sf::Out out_entries_written, const sf::OutArray &out_info, const ContentMetaKey &key, u32 start_index) override {
+ return ncmContentMetaDatabaseListContentInfo(std::addressof(this->srv), reinterpret_cast(out_entries_written.GetPointer()), Convert(out_info.GetPointer()), out_info.GetSize(), Convert(key), start_index);
+ }
+
+ virtual Result List(sf::Out out_entries_total, sf::Out out_entries_written, const sf::OutArray &out, ContentMetaType meta_type, ProgramId application_program_id, ProgramId program_id_min, ProgramId program_id_max, ContentInstallType install_type) override {
+ return ncmContentMetaDatabaseList(std::addressof(this->srv), reinterpret_cast(out_entries_total.GetPointer()), reinterpret_cast(out_entries_written.GetPointer()), Convert(out.GetPointer()), out.GetSize(), static_cast<::NcmContentMetaType>(meta_type), static_cast(application_program_id), static_cast(program_id_min), static_cast(program_id_max), static_cast<::NcmContentInstallType>(install_type));
+ }
+
+ virtual Result GetLatestContentMetaKey(sf::Out out_key, ProgramId id) override {
+ return ncmContentMetaDatabaseGetLatestContentMetaKey(std::addressof(this->srv), Convert(out_key.GetPointer()), static_cast(id));
+ }
+
+ virtual Result ListApplication(sf::Out out_entries_total, sf::Out out_entries_written, const sf::OutArray &out_keys, ContentMetaType meta_type) override {
+ return ncmContentMetaDatabaseListApplication(std::addressof(this->srv), reinterpret_cast(out_entries_total.GetPointer()), reinterpret_cast(out_entries_written.GetPointer()), Convert(out_keys.GetPointer()), out_keys.GetSize(), static_cast<::NcmContentMetaType>(meta_type));
+ }
+
+ virtual Result Has(sf::Out out, const ContentMetaKey &key) override {
+ return ncmContentMetaDatabaseHas(std::addressof(this->srv), out.GetPointer(), Convert(key));
+ }
+
+ virtual Result HasAll(sf::Out out, const sf::InArray &keys) override {
+ return ncmContentMetaDatabaseHasAll(std::addressof(this->srv), out.GetPointer(), Convert(keys.GetPointer()), keys.GetSize());
+ }
+
+ virtual Result GetSize(sf::Out out_size, const ContentMetaKey &key) override {
+ return ncmContentMetaDatabaseGetSize(std::addressof(this->srv), out_size.GetPointer(), Convert(key));
+ }
+
+ virtual Result GetRequiredSystemVersion(sf::Out out_version, const ContentMetaKey &key) override {
+ return ncmContentMetaDatabaseGetRequiredSystemVersion(std::addressof(this->srv), out_version.GetPointer(), Convert(key));
+ }
+
+ virtual Result GetPatchId(sf::Out out_patch_id, const ContentMetaKey &key) override {
+ return ncmContentMetaDatabaseGetPatchId(std::addressof(this->srv), reinterpret_cast(out_patch_id.GetPointer()), Convert(key));
+ }
+
+ virtual Result DisableForcibly() override {
+ return ncmContentMetaDatabaseDisableForcibly(std::addressof(this->srv));
+ }
+
+ virtual Result LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) override {
+ return ncmContentMetaDatabaseLookupOrphanContent(std::addressof(this->srv), out_orphaned.GetPointer(), Convert(content_ids.GetPointer()), std::min(out_orphaned.GetSize(), content_ids.GetSize()));
+ }
+
+ virtual Result Commit() override {
+ return ncmContentMetaDatabaseCommit(std::addressof(this->srv));
+ }
+
+ virtual Result HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) override {
+ return ncmContentMetaDatabaseHasContent(std::addressof(this->srv), out.GetPointer(), Convert(key), Convert(content_id));
+ }
+
+ virtual Result ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, u32 start_index) override {
+ return ncmContentMetaDatabaseListContentMetaInfo(std::addressof(this->srv), reinterpret_cast(out_entries_written.GetPointer()), out_meta_info.GetPointer(), out_meta_info.GetSize(), Convert(key), start_index);
+ }
+
+ virtual Result GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) override {
+ static_assert(sizeof(ContentMetaAttribute) == sizeof(u8));
+ return ncmContentMetaDatabaseGetAttributes(std::addressof(this->srv), Convert(key), reinterpret_cast(out_attributes.GetPointer()));
+ }
+
+ virtual Result GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) override {
+ return ncmContentMetaDatabaseGetRequiredApplicationVersion(std::addressof(this->srv), out_version.GetPointer(), Convert(key));
+ }
+
+ virtual Result GetContentIdByTypeAndIdOffset(sf::Out out_content_id, const ContentMetaKey &key, ContentType type, u8 id_offset) override {
+ return ncmContentMetaDatabaseGetContentIdByTypeAndIdOffset(std::addressof(this->srv), Convert(out_content_id.GetPointer()), Convert(key), static_cast<::NcmContentType>(type), id_offset);
+ }
+
+ };
+
+}
diff --git a/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp b/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp
new file mode 100644
index 000000000..f11e1b4d9
--- /dev/null
+++ b/libraries/libstratosphere/source/ncm/ncm_remote_content_storage_impl.hpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+
+#pragma once
+#include
+
+namespace ams::ncm {
+
+ class RemoteContentStorageImpl final : public IContentStorage {
+ private:
+ ::NcmContentStorage srv;
+ public:
+ RemoteContentStorageImpl(::NcmContentStorage &cs) : srv(cs) { /* ... */ }
+
+ ~RemoteContentStorageImpl() { ::ncmContentStorageClose(std::addressof(srv)); }
+ private:
+ ALWAYS_INLINE ::NcmPlaceHolderId *Convert(PlaceHolderId *p) {
+ static_assert(sizeof(PlaceHolderId) == sizeof(::NcmPlaceHolderId));
+ return reinterpret_cast<::NcmPlaceHolderId *>(p);
+ }
+
+ ALWAYS_INLINE ::NcmPlaceHolderId *Convert(PlaceHolderId &p) {
+ static_assert(sizeof(PlaceHolderId) == sizeof(::NcmPlaceHolderId));
+ return reinterpret_cast<::NcmPlaceHolderId *>(std::addressof(p));
+ }
+
+ ALWAYS_INLINE ::NcmContentId *Convert(ContentId *c) {
+ static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
+ return reinterpret_cast<::NcmContentId *>(c);
+ }
+
+ ALWAYS_INLINE ::NcmContentId *Convert(ContentId &c) {
+ static_assert(sizeof(ContentId) == sizeof(::NcmContentId));
+ return reinterpret_cast<::NcmContentId *>(std::addressof(c));
+ }
+ public:
+ virtual Result GeneratePlaceHolderId(sf::Out out) override {
+ return ncmContentStorageGeneratePlaceHolderId(std::addressof(this->srv), Convert(out.GetPointer()));
+ }
+
+ virtual Result CreatePlaceHolder(PlaceHolderId placeholder_id, ContentId content_id, u64 size) override {
+ static_assert(alignof(ContentId) < alignof(PlaceHolderId));
+ return ncmContentStorageCreatePlaceHolder(std::addressof(this->srv), Convert(content_id), Convert(placeholder_id), static_cast(size));
+ }
+
+ virtual Result DeletePlaceHolder(PlaceHolderId placeholder_id) override {
+ return ncmContentStorageDeletePlaceHolder(std::addressof(this->srv), Convert(placeholder_id));
+ }
+
+ virtual Result HasPlaceHolder(sf::Out out, PlaceHolderId placeholder_id) override {
+ return ncmContentStorageHasPlaceHolder(std::addressof(this->srv), out.GetPointer(), Convert(placeholder_id));
+ }
+
+ virtual Result WritePlaceHolder(PlaceHolderId placeholder_id, u64 offset, sf::InBuffer data) override {
+ return ncmContentStorageWritePlaceHolder(std::addressof(this->srv), Convert(placeholder_id), offset, data.GetPointer(), data.GetSize());
+ }
+
+ virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override {
+ static_assert(alignof(ContentId) < alignof(PlaceHolderId));
+ return ncmContentStorageRegister(std::addressof(this->srv), Convert(content_id), Convert(placeholder_id));
+ }
+
+ virtual Result Delete(ContentId content_id) override {
+ return ncmContentStorageDelete(std::addressof(this->srv), Convert(content_id));
+ }
+
+ virtual Result Has(sf::Out out, ContentId content_id) override {
+ return ncmContentStorageHas(std::addressof(this->srv), out.GetPointer(), Convert(content_id));
+ }
+
+ virtual Result GetPath(sf::Out out, ContentId content_id) override {
+ return ncmContentStorageGetPath(std::addressof(this->srv), out.GetPointer()->str, sizeof(out.GetPointer()->str), Convert(content_id));
+ }
+
+ virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override {
+ return ncmContentStorageGetPlaceHolderPath(std::addressof(this->srv), out.GetPointer()->str, sizeof(out.GetPointer()->str), Convert(placeholder_id));
+ }
+
+ virtual Result CleanupAllPlaceHolder() override {
+ return ncmContentStorageCleanupAllPlaceHolder(std::addressof(this->srv));
+ }
+
+ virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) override {
+ return ncmContentStorageListPlaceHolder(std::addressof(this->srv), Convert(out_buf.GetPointer()), out_buf.GetSize(), reinterpret_cast(out_count.GetPointer()));
+ }
+
+ virtual Result GetContentCount(sf::Out out_count) override {
+ return ncmContentStorageGetContentCount(std::addressof(this->srv), reinterpret_cast(out_count.GetPointer()));
+ }
+
+ virtual Result ListContentId(sf::Out out_count, const sf::OutArray &out_buf, u32 offset) override {
+ return ncmContentStorageListContentId(std::addressof(this->srv), Convert(out_buf.GetPointer()), out_buf.GetSize(), reinterpret_cast(out_count.GetPointer()), static_cast(offset));
+ }
+
+ virtual Result GetSizeFromContentId(sf::Out out_size, ContentId content_id) override {
+ return ncmContentStorageGetSizeFromContentId(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer()), Convert(content_id));
+ }
+
+ virtual Result DisableForcibly() override {
+ return ncmContentStorageDisableForcibly(std::addressof(this->srv));
+ }
+
+ virtual Result RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) override {
+ return ncmContentStorageRevertToPlaceHolder(std::addressof(this->srv), Convert(placeholder_id), Convert(old_content_id), Convert(new_content_id));
+ }
+
+ virtual Result SetPlaceHolderSize(PlaceHolderId placeholder_id, u64 size) override {
+ return ncmContentStorageSetPlaceHolderSize(std::addressof(this->srv), Convert(placeholder_id), static_cast(size));
+ }
+
+ virtual Result ReadContentIdFile(sf::OutBuffer buf, ContentId content_id, u64 offset) override {
+ return ncmContentStorageReadContentIdFile(std::addressof(this->srv), buf.GetPointer(), buf.GetSize(), Convert(content_id), static_cast(offset));
+ }
+
+ virtual Result GetRightsIdFromPlaceHolderIdDeprecated(sf::Out out_rights_id, PlaceHolderId placeholder_id) override {
+ ::NcmRightsId rights_id;
+ R_TRY(ncmContentStorageGetRightsIdFromPlaceHolderId(std::addressof(this->srv), std::addressof(rights_id), Convert(placeholder_id)));
+
+ static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
+ std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
+ return ResultSuccess();
+ }
+
+ virtual Result GetRightsIdFromPlaceHolderId(sf::Out out_rights_id, PlaceHolderId placeholder_id) override {
+ ::NcmRightsId rights_id;
+ R_TRY(ncmContentStorageGetRightsIdFromPlaceHolderId(std::addressof(this->srv), std::addressof(rights_id), Convert(placeholder_id)));
+
+ static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
+ std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
+ return ResultSuccess();
+ }
+
+ virtual Result GetRightsIdFromContentIdDeprecated(sf::Out out_rights_id, ContentId content_id) override {
+ ::NcmRightsId rights_id;
+ R_TRY(ncmContentStorageGetRightsIdFromContentId(std::addressof(this->srv), std::addressof(rights_id), Convert(content_id)));
+
+ static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
+ std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
+ return ResultSuccess();
+ }
+
+ virtual Result GetRightsIdFromContentId(sf::Out out_rights_id, ContentId content_id) override {
+ ::NcmRightsId rights_id;
+ R_TRY(ncmContentStorageGetRightsIdFromContentId(std::addressof(this->srv), std::addressof(rights_id), Convert(content_id)));
+
+ static_assert(sizeof(*out_rights_id.GetPointer()) <= sizeof(rights_id));
+ std::memcpy(out_rights_id.GetPointer(), std::addressof(rights_id), sizeof(*out_rights_id.GetPointer()));
+ return ResultSuccess();
+ }
+
+ virtual Result WriteContentForDebug(ContentId content_id, u64 offset, sf::InBuffer data) override {
+ return ncmContentStorageWriteContentForDebug(std::addressof(this->srv), Convert(content_id), static_cast(offset), data.GetPointer(), data.GetSize());
+ }
+
+ virtual Result GetFreeSpaceSize(sf::Out out_size) override {
+ return ncmContentStorageGetFreeSpaceSize(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer()));
+ }
+
+ virtual Result GetTotalSpaceSize(sf::Out out_size) override {
+ return ncmContentStorageGetTotalSpaceSize(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer()));
+ }
+
+ virtual Result FlushPlaceHolder() override {
+ return ncmContentStorageFlushPlaceHolder(std::addressof(this->srv));
+ }
+
+ virtual Result GetSizeFromPlaceHolderId(sf::Out out_size, PlaceHolderId placeholder_id) override {
+ return ncmContentStorageGetSizeFromPlaceHolderId(std::addressof(this->srv), reinterpret_cast(out_size.GetPointer()), Convert(placeholder_id));
+ }
+
+ virtual Result RepairInvalidFileAttribute() override {
+ return ncmContentStorageRepairInvalidFileAttribute(std::addressof(this->srv));
+ }
+
+ virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) override {
+ static_assert(sizeof(::NcmRightsId) == sizeof(ncm::RightsId));
+ ::NcmRightsId *out = reinterpret_cast<::NcmRightsId *>(out_rights_id.GetPointer());
+ return ncmContentStorageGetRightsIdFromPlaceHolderIdWithCache(std::addressof(this->srv), out, Convert(placeholder_id), Convert(cache_content_id));
+ }
+ };
+
+}
diff --git a/stratosphere/ncm/source/impl/ncm_content_manager.cpp b/stratosphere/ncm/source/impl/ncm_content_manager.cpp
index 342ef813e..fce9ad590 100644
--- a/stratosphere/ncm/source/impl/ncm_content_manager.cpp
+++ b/stratosphere/ncm/source/impl/ncm_content_manager.cpp
@@ -72,7 +72,7 @@ namespace ams::ncm::impl {
constexpr u64 BuiltInSystemSaveDataSize = 0x6c000;
constexpr u64 BuiltInSystemSaveDataJournalSize = 0x6c000;
constexpr u32 BuiltInSystemSaveDataFlags = FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment;
-
+
constexpr SaveDataMeta BuiltInSystemSaveDataMeta = {
.id = BuiltInSystemSaveDataId,
.size = BuiltInSystemSaveDataSize,
@@ -119,7 +119,7 @@ namespace ams::ncm::impl {
std::optional> kvs;
u32 max_content_metas;
- inline ContentMetaDatabaseEntry() : storage_id(StorageId::None), save_meta({0}),
+ inline ContentMetaDatabaseEntry() : storage_id(StorageId::None), save_meta({0}),
content_meta_database(nullptr), kvs(std::nullopt), max_content_metas(0) {
mount_point[0] = '\0';
meta_path[0] = '\0';
@@ -268,17 +268,17 @@ namespace ams::ncm::impl {
/* First, setup the BuiltInSystem storage entry. */
g_content_storage_roots[g_num_content_storage_entries++].Initialize(StorageId::BuiltInSystem, FsContentStorageId_System);
- if (R_FAILED(VerifyContentStorage(StorageId::BuiltInSystem))) {
- R_TRY(CreateContentStorage(StorageId::BuiltInSystem));
+ if (R_FAILED(impl::VerifyContentStorage(StorageId::BuiltInSystem))) {
+ R_TRY(impl::CreateContentStorage(StorageId::BuiltInSystem));
}
- R_TRY(ActivateContentStorage(StorageId::BuiltInSystem));
+ R_TRY(impl::ActivateContentStorage(StorageId::BuiltInSystem));
/* Next, the BuiltInSystem content meta entry. */
R_TRY(g_content_meta_entries[g_num_content_meta_entries++].Initialize(StorageId::BuiltInSystem, BuiltInSystemSaveDataMeta, MaxBuiltInSystemContentMetaCount));
- if (R_FAILED(VerifyContentMetaDatabase(StorageId::BuiltInSystem))) {
- R_TRY(CreateContentMetaDatabase(StorageId::BuiltInSystem));
+ if (R_FAILED(impl::VerifyContentMetaDatabase(StorageId::BuiltInSystem))) {
+ R_TRY(impl::CreateContentMetaDatabase(StorageId::BuiltInSystem));
/* TODO: N supports a number of unused modes here, we don't bother implementing them currently. */
}
@@ -287,8 +287,8 @@ namespace ams::ncm::impl {
if (hos::GetVersion() >= hos::Version_200 && R_SUCCEEDED(fs::GetSaveDataFlags(¤t_flags, BuiltInSystemSaveDataId)) && current_flags != (FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment)) {
fs::SetSaveDataFlags(BuiltInSystemSaveDataId, FsSaveDataSpaceId_System, FsSaveDataFlags_KeepAfterResettingSystemSaveData | FsSaveDataFlags_KeepAfterRefurbishment);
}
-
- R_TRY(ActivateContentMetaDatabase(StorageId::BuiltInSystem));
+
+ R_TRY(impl::ActivateContentMetaDatabase(StorageId::BuiltInSystem));
/* Now for BuiltInUser's content storage and content meta entries. */
g_content_storage_roots[g_num_content_storage_entries++].Initialize(StorageId::BuiltInUser, FsContentStorageId_User);
@@ -316,12 +316,12 @@ namespace ams::ncm::impl {
for (size_t i = 0; i < MaxContentStorageEntries; i++) {
ContentStorageRoot *entry = &g_content_storage_roots[i];
- InactivateContentStorage(entry->storage_id);
+ impl::InactivateContentStorage(entry->storage_id);
}
for (size_t i = 0; i < MaxContentMetaDatabaseEntries; i++) {
ContentMetaDatabaseEntry *entry = &g_content_meta_entries[i];
- InactivateContentMetaDatabase(entry->storage_id);
+ impl::InactivateContentMetaDatabase(entry->storage_id);
}
}
@@ -374,7 +374,7 @@ namespace ams::ncm::impl {
ContentStorageRoot *root;
R_TRY(GetUniqueContentStorageRoot(std::addressof(root), storage_id));
-
+
auto content_storage = root->content_storage;
if (hos::GetVersion() >= hos::Version_200) {
@@ -382,7 +382,7 @@ namespace ams::ncm::impl {
} else {
/* 1.0.0 activates content storages as soon as they are opened. */
if (!content_storage) {
- R_TRY(ActivateContentStorage(storage_id));
+ R_TRY(impl::ActivateContentStorage(storage_id));
content_storage = root->content_storage;
}
}
@@ -518,7 +518,7 @@ namespace ams::ncm::impl {
ContentMetaDatabaseEntry *entry;
R_TRY(GetUniqueContentMetaDatabaseEntry(&entry, storage_id));
-
+
auto content_meta_db = entry->content_meta_database;
if (hos::GetVersion() >= hos::Version_200) {
@@ -526,7 +526,7 @@ namespace ams::ncm::impl {
} else {
/* 1.0.0 activates content meta databases as soon as they are opened. */
if (!content_meta_db) {
- R_TRY(ActivateContentMetaDatabase(storage_id));
+ R_TRY(impl::ActivateContentMetaDatabase(storage_id));
content_meta_db = entry->content_meta_database;
}
}
@@ -541,7 +541,7 @@ namespace ams::ncm::impl {
R_UNLESS(storage_id != StorageId::None, ncm::ResultUnknownStorage());
ContentMetaDatabaseEntry *entry;
R_TRY(FindContentMetaDatabaseEntry(&entry, storage_id));
-
+
auto content_meta_db = entry->content_meta_database;
if (content_meta_db) {
diff --git a/stratosphere/ncm/source/ncm_content_manager_service.cpp b/stratosphere/ncm/source/ncm_content_manager_impl.cpp
similarity index 63%
rename from stratosphere/ncm/source/ncm_content_manager_service.cpp
rename to stratosphere/ncm/source/ncm_content_manager_impl.cpp
index 82e6aff44..1f9708df1 100644
--- a/stratosphere/ncm/source/ncm_content_manager_service.cpp
+++ b/stratosphere/ncm/source/ncm_content_manager_impl.cpp
@@ -14,70 +14,70 @@
* along with this program. If not, see .
*/
+#include "ncm_content_manager_impl.hpp"
#include "impl/ncm_content_manager.hpp"
-#include "ncm_content_manager_service.hpp"
namespace ams::ncm {
- Result ContentManagerService::CreateContentStorage(StorageId storage_id) {
+ Result ContentManagerImpl::CreateContentStorage(StorageId storage_id) {
return impl::CreateContentStorage(storage_id);
}
- Result ContentManagerService::CreateContentMetaDatabase(StorageId storage_id) {
+ Result ContentManagerImpl::CreateContentMetaDatabase(StorageId storage_id) {
return impl::CreateContentMetaDatabase(storage_id);
}
- Result ContentManagerService::VerifyContentStorage(StorageId storage_id) {
+ Result ContentManagerImpl::VerifyContentStorage(StorageId storage_id) {
return impl::VerifyContentStorage(storage_id);
}
- Result ContentManagerService::VerifyContentMetaDatabase(StorageId storage_id) {
+ Result ContentManagerImpl::VerifyContentMetaDatabase(StorageId storage_id) {
return impl::VerifyContentMetaDatabase(storage_id);
}
- Result ContentManagerService::OpenContentStorage(sf::Out> out, StorageId storage_id) {
+ Result ContentManagerImpl::OpenContentStorage(sf::Out> out, StorageId storage_id) {
std::shared_ptr content_storage;
R_TRY(impl::OpenContentStorage(&content_storage, storage_id));
out.SetValue(std::move(content_storage));
return ResultSuccess();
}
- Result ContentManagerService::OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) {
+ Result ContentManagerImpl::OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) {
std::shared_ptr content_meta_database;
R_TRY(impl::OpenContentMetaDatabase(&content_meta_database, storage_id));
out.SetValue(std::move(content_meta_database));
return ResultSuccess();
}
- Result ContentManagerService::CloseContentStorageForcibly(StorageId storage_id) {
+ Result ContentManagerImpl::CloseContentStorageForcibly(StorageId storage_id) {
return impl::CloseContentStorageForcibly(storage_id);
}
- Result ContentManagerService::CloseContentMetaDatabaseForcibly(StorageId storage_id) {
+ Result ContentManagerImpl::CloseContentMetaDatabaseForcibly(StorageId storage_id) {
return impl::CloseContentMetaDatabaseForcibly(storage_id);
}
- Result ContentManagerService::CleanupContentMetaDatabase(StorageId storage_id) {
+ Result ContentManagerImpl::CleanupContentMetaDatabase(StorageId storage_id) {
return impl::CleanupContentMetaDatabase(storage_id);
}
- Result ContentManagerService::ActivateContentStorage(StorageId storage_id) {
+ Result ContentManagerImpl::ActivateContentStorage(StorageId storage_id) {
return impl::ActivateContentStorage(storage_id);
}
- Result ContentManagerService::InactivateContentStorage(StorageId storage_id) {
+ Result ContentManagerImpl::InactivateContentStorage(StorageId storage_id) {
return impl::InactivateContentStorage(storage_id);
}
- Result ContentManagerService::ActivateContentMetaDatabase(StorageId storage_id) {
+ Result ContentManagerImpl::ActivateContentMetaDatabase(StorageId storage_id) {
return impl::ActivateContentMetaDatabase(storage_id);
}
- Result ContentManagerService::InactivateContentMetaDatabase(StorageId storage_id) {
+ Result ContentManagerImpl::InactivateContentMetaDatabase(StorageId storage_id) {
return impl::InactivateContentMetaDatabase(storage_id);
}
- Result ContentManagerService::InvalidateRightsIdCache() {
+ Result ContentManagerImpl::InvalidateRightsIdCache() {
return impl::InvalidateRightsIdCache();
}
diff --git a/stratosphere/ncm/source/ncm_content_manager_impl.hpp b/stratosphere/ncm/source/ncm_content_manager_impl.hpp
new file mode 100644
index 000000000..7cbef9c85
--- /dev/null
+++ b/stratosphere/ncm/source/ncm_content_manager_impl.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019-2020 Adubbz, Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see .
+ */
+
+#pragma once
+#include
+
+namespace ams::ncm {
+
+ class ContentManagerImpl final : public IContentManager {
+ public:
+ virtual Result CreateContentStorage(StorageId storage_id) override;
+ virtual Result CreateContentMetaDatabase(StorageId storage_id) override;
+ virtual Result VerifyContentStorage(StorageId storage_id) override;
+ virtual Result VerifyContentMetaDatabase(StorageId storage_id) override;
+ virtual Result OpenContentStorage(sf::Out> out, StorageId storage_id) override;
+ virtual Result OpenContentMetaDatabase(sf::Out> out, StorageId storage_id) override;
+ virtual Result CloseContentStorageForcibly(StorageId storage_id) override;
+ virtual Result CloseContentMetaDatabaseForcibly(StorageId storage_id) override;
+ virtual Result CleanupContentMetaDatabase(StorageId storage_id) override;
+ virtual Result ActivateContentStorage(StorageId storage_id) override;
+ virtual Result InactivateContentStorage(StorageId storage_id) override;
+ virtual Result ActivateContentMetaDatabase(StorageId storage_id) override;
+ virtual Result InactivateContentMetaDatabase(StorageId storage_id) override;
+ virtual Result InvalidateRightsIdCache() override;
+ };
+
+}
diff --git a/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp b/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp
index 0612cafbe..3c8989980 100644
--- a/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp
+++ b/stratosphere/ncm/source/ncm_content_meta_database_impl.cpp
@@ -297,7 +297,7 @@ namespace ams::ncm {
return fsdevCommitDevice(this->mount_name);
}
- Result ContentMetaDatabaseImpl::HasContent(sf::Out out, const ContentMetaKey &key, ContentId content_id) {
+ Result ContentMetaDatabaseImpl::HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) {
const void *meta;
size_t meta_size;
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, key));
diff --git a/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp b/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp
index e3eb9b884..f6c3499fe 100644
--- a/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp
+++ b/stratosphere/ncm/source/ncm_content_meta_database_impl.hpp
@@ -45,7 +45,7 @@ namespace ams::ncm {
virtual Result DisableForcibly() override;
virtual Result LookupOrphanContent(const sf::OutArray &out_orphaned, const sf::InArray &content_ids) override;
virtual Result Commit() override;
- virtual Result HasContent(sf::Out out, const ContentMetaKey &key, ContentId content_id) override;
+ virtual Result HasContent(sf::Out out, const ContentMetaKey &key, const ContentId &content_id) override;
virtual Result ListContentMetaInfo(sf::Out out_entries_written, const sf::OutArray &out_meta_info, const ContentMetaKey &key, u32 start_index) override;
virtual Result GetAttributes(sf::Out out_attributes, const ContentMetaKey &key) override;
virtual Result GetRequiredApplicationVersion(sf::Out out_version, const ContentMetaKey &key) override;
diff --git a/stratosphere/ncm/source/ncm_content_storage_impl.cpp b/stratosphere/ncm/source/ncm_content_storage_impl.cpp
index b4b9fa39c..08d75840f 100644
--- a/stratosphere/ncm/source/ncm_content_storage_impl.cpp
+++ b/stratosphere/ncm/source/ncm_content_storage_impl.cpp
@@ -108,7 +108,7 @@ namespace ams::ncm {
char placeholder_path[FS_MAX_PATH] = {0};
this->placeholder_accessor.MakePath(placeholder_path, placeholder_id);
-
+
bool has = false;
R_TRY(fs::HasFile(&has, placeholder_path));
out.SetValue(has);
@@ -173,25 +173,25 @@ namespace ams::ncm {
return ResultSuccess();
}
- Result ContentStorageImpl::GetPath(sf::Out out, ContentId content_id) {
+ Result ContentStorageImpl::GetPath(sf::Out out, ContentId content_id) {
R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0};
this->GetContentPath(content_path, content_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
- out.SetValue(lr::Path::Encode(common_path));
+ out.SetValue(Path::Encode(common_path));
return ResultSuccess();
}
- Result ContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) {
+ Result ContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) {
R_TRY(this->EnsureEnabled());
char placeholder_path[FS_MAX_PATH] = {0};
char common_path[FS_MAX_PATH] = {0};
this->placeholder_accessor.GetPath(placeholder_path, placeholder_id);
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, placeholder_path));
- out.SetValue(lr::Path::Encode(common_path));
+ out.SetValue(Path::Encode(common_path));
return ResultSuccess();
}
@@ -202,7 +202,7 @@ namespace ams::ncm {
this->placeholder_accessor.InvalidateAll();
this->placeholder_accessor.MakeRootPath(placeholder_root_path);
- /* Nintendo uses CleanDirectoryRecursively which is 3.0.0+.
+ /* Nintendo uses CleanDirectoryRecursively which is 3.0.0+.
We'll just delete the directory and recreate it to support all firmwares. */
R_TRY(fsdevDeleteDirectoryRecursively(placeholder_root_path));
R_UNLESS(mkdir(placeholder_root_path, S_IRWXU) != -1, fsdevGetLastResult());
@@ -220,15 +220,15 @@ namespace ams::ncm {
R_TRY(fs::TraverseDirectory(placeholder_root_path, dir_depth, [&](bool *should_continue, bool *should_retry_dir_read, const char *current_path, struct dirent *dir_entry) -> Result {
*should_continue = true;
*should_retry_dir_read = false;
-
+
if (dir_entry->d_type == DT_REG) {
R_UNLESS(entry_count <= out_buf.GetSize(), ncm::ResultBufferInsufficient());
-
+
PlaceHolderId cur_entry_placeholder_id = {0};
R_TRY(GetPlaceHolderIdFromDirEntry(&cur_entry_placeholder_id, dir_entry));
out_buf[entry_count++] = cur_entry_placeholder_id;
}
-
+
return ResultSuccess();
}));
@@ -329,7 +329,7 @@ namespace ams::ncm {
Result ContentStorageImpl::RevertToPlaceHolder(PlaceHolderId placeholder_id, ContentId old_content_id, ContentId new_content_id) {
R_TRY(this->EnsureEnabled());
-
+
char old_content_path[FS_MAX_PATH] = {0};
char new_content_path[FS_MAX_PATH] = {0};
char placeholder_path[FS_MAX_PATH] = {0};
@@ -401,7 +401,7 @@ namespace ams::ncm {
Result ContentStorageImpl::GetRightsIdFromContentId(sf::Out out_rights_id, ContentId content_id) {
R_TRY(this->EnsureEnabled());
-
+
if (this->rights_id_cache->Find(out_rights_id.GetPointer(), content_id)) {
return ResultSuccess();
}
@@ -437,7 +437,7 @@ namespace ams::ncm {
FILE *f = nullptr;
R_TRY(fs::OpenFile(&f, content_path, FsOpenMode_Write));
-
+
ON_SCOPE_EXIT {
fclose(f);
};
@@ -522,7 +522,7 @@ namespace ams::ncm {
Result ContentStorageImpl::GetRightsIdFromPlaceHolderIdWithCache(sf::Out out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id) {
R_TRY(this->EnsureEnabled());
-
+
if (this->rights_id_cache->Find(out_rights_id.GetPointer(), cache_content_id)) {
return ResultSuccess();
}
diff --git a/stratosphere/ncm/source/ncm_content_storage_impl.hpp b/stratosphere/ncm/source/ncm_content_storage_impl.hpp
index 7ca658c34..c273fdf7a 100644
--- a/stratosphere/ncm/source/ncm_content_storage_impl.hpp
+++ b/stratosphere/ncm/source/ncm_content_storage_impl.hpp
@@ -60,8 +60,8 @@ namespace ams::ncm {
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override;
virtual Result Delete(ContentId content_id) override;
virtual Result Has(sf::Out out, ContentId content_id) override;
- virtual Result GetPath(sf::Out out, ContentId content_id) override;
- virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override;
+ virtual Result GetPath(sf::Out out, ContentId content_id) override;
+ virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override;
virtual Result CleanupAllPlaceHolder() override;
virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) override;
virtual Result GetContentCount(sf::Out out_count) override;
diff --git a/stratosphere/ncm/source/ncm_main.cpp b/stratosphere/ncm/source/ncm_main.cpp
index 237726111..4b5b66289 100644
--- a/stratosphere/ncm/source/ncm_main.cpp
+++ b/stratosphere/ncm/source/ncm_main.cpp
@@ -18,7 +18,7 @@
#include
#include "impl/ncm_content_manager.hpp"
-#include "ncm_content_manager_service.hpp"
+#include "ncm_content_manager_impl.hpp"
extern "C" {
extern u32 __start__;
@@ -100,6 +100,39 @@ namespace {
constexpr inline sm::ServiceName ContentManagerServiceName = sm::ServiceName::Encode("ncm");
+ class ContentManagerServerManager : public sf::hipc::ServerManager {
+ private:
+ static constexpr size_t ThreadStackSize = 0x4000;
+ static constexpr int ThreadPriority = 0x15;
+
+ using ServiceType = ncm::ContentManagerImpl;
+ private:
+ os::StaticThread thread;
+ std::shared_ptr ncm_manager;
+ private:
+ static void ThreadFunction(void *_this) {
+ reinterpret_cast(_this)->LoopProcess();
+ }
+ public:
+ ContentManagerServerManager(ServiceType *m)
+ : thread(ThreadFunction, this, ThreadPriority), ncm_manager(sf::ServiceObjectTraits::SharedPointerHelper::GetEmptyDeleteSharedPointer(m))
+ {
+ /* ... */
+ }
+
+ ams::Result Initialize() {
+ return this->RegisterServer(ContentManagerServiceName, ContentManagerManagerSessions, this->ncm_manager);
+ }
+
+ ams::Result StartThreads() {
+ return this->thread.Start();
+ }
+
+ void Wait() {
+ this->thread.Join();
+ }
+ };
+
struct LocationResolverServerOptions {
static constexpr size_t PointerBufferSize = 0x400;
static constexpr size_t MaxDomains = 0;
@@ -146,7 +179,8 @@ namespace {
}
};
- sf::hipc::ServerManager g_ncm_server_manager;
+ ncm::ContentManagerImpl g_ncm_manager_service_object;
+ ContentManagerServerManager g_ncm_server_manager(std::addressof(g_ncm_manager_service_object));
lr::LocationResolverManagerImpl g_lr_manager_service_object;
LocationResolverServerManager g_lr_server_manager(std::addressof(g_lr_manager_service_object));
@@ -155,7 +189,7 @@ namespace {
void ContentManagerServerMain(void *arg) {
/* Create services. */
- R_ABORT_UNLESS(g_ncm_server_manager.RegisterServer(ContentManagerServiceName, ContentManagerManagerSessions));
+ R_ABORT_UNLESS(g_ncm_server_manager.RegisterServer(ContentManagerServiceName, ContentManagerManagerSessions));
/* Loop forever, servicing our services. */
g_ncm_server_manager.LoopProcess();
@@ -164,19 +198,19 @@ void ContentManagerServerMain(void *arg) {
int main(int argc, char **argv)
{
/* Initialize content manager implementation. */
+ /* TODO: Move Initialize/Finalize into ContentManagerImpl ctor/dtor, initialize client library with static object. */
R_ABORT_UNLESS(ams::ncm::impl::InitializeContentManager());
- static os::Thread s_content_manager_thread;
-
- R_ABORT_UNLESS(s_content_manager_thread.Initialize(&ContentManagerServerMain, nullptr, 0x4000, 0x15));
- R_ABORT_UNLESS(s_content_manager_thread.Start());
+ R_ABORT_UNLESS(g_ncm_server_manager.Initialize());
+ R_ABORT_UNLESS(g_ncm_server_manager.StartThreads());
R_ABORT_UNLESS(g_lr_server_manager.Initialize());
R_ABORT_UNLESS(g_lr_server_manager.StartThreads());
- s_content_manager_thread.Join();
+ g_ncm_server_manager.Wait();
g_lr_server_manager.Wait();
+ /* TODO: This call is eventually automatic at scope exit. */
ams::ncm::impl::FinalizeContentManager();
return 0;
diff --git a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp
index 3118fb2a8..a99176d65 100644
--- a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp
+++ b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.cpp
@@ -66,7 +66,7 @@ namespace ams::ncm {
bool has = false;
R_TRY(fs::HasFile(&has, content_path));
-
+
if (!has) {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
R_TRY(fs::HasFile(&has, content_path));
@@ -76,7 +76,7 @@ namespace ams::ncm {
return ResultSuccess();
}
- Result ReadOnlyContentStorageImpl::GetPath(sf::Out out, ContentId content_id) {
+ Result ReadOnlyContentStorageImpl::GetPath(sf::Out out, ContentId content_id) {
R_TRY(this->EnsureEnabled());
char content_path[FS_MAX_PATH] = {0};
@@ -85,18 +85,18 @@ namespace ams::ncm {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
R_TRY(fs::HasFile(&is_content_meta_file, content_path));
-
+
if (!is_content_meta_file) {
this->make_content_path_func(content_path, content_id, this->root_path);
}
-
+
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
- out.SetValue(lr::Path::Encode(common_path));
+ out.SetValue(Path::Encode(common_path));
return ResultSuccess();
}
- Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) {
+ Result ReadOnlyContentStorageImpl::GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) {
return ResultInvalidContentStorageOperation();
}
@@ -124,7 +124,7 @@ namespace ams::ncm {
this->make_content_path_func(content_path, content_id, this->root_path);
R_TRY(fs::HasFile(&is_content_file, content_path));
-
+
if (!is_content_file) {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
}
@@ -158,18 +158,18 @@ namespace ams::ncm {
this->make_content_path_func(content_path, content_id, this->root_path);
R_TRY(fs::HasFile(&is_content_file, content_path));
-
+
if (!is_content_file) {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
}
-
+
FILE *f = nullptr;
R_TRY(fs::OpenFile(&f, content_path, FsOpenMode_Read));
-
+
ON_SCOPE_EXIT {
fclose(f);
};
-
+
R_TRY(fs::ReadFile(f, offset, buf.GetPointer(), buf.GetSize()));
return ResultSuccess();
}
@@ -198,13 +198,13 @@ namespace ams::ncm {
path::GetContentMetaPath(content_path, content_id, this->make_content_path_func, this->root_path);
R_TRY(fs::HasFile(&is_content_meta_file, content_path));
-
+
if (!is_content_meta_file) {
this->make_content_path_func(content_path, content_id, this->root_path);
}
R_TRY(fs::ConvertToFsCommonPath(common_path, FS_MAX_PATH-1, content_path));
-
+
ncm::RightsId rights_id;
R_TRY(GetRightsId(&rights_id, common_path));
out_rights_id.SetValue(rights_id);
diff --git a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp
index f69cd0a17..3869dac01 100644
--- a/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp
+++ b/stratosphere/ncm/source/ncm_read_only_content_storage_impl.hpp
@@ -33,8 +33,8 @@ namespace ams::ncm {
virtual Result Register(PlaceHolderId placeholder_id, ContentId content_id) override;
virtual Result Delete(ContentId content_id) override;
virtual Result Has(sf::Out out, ContentId content_id) override;
- virtual Result GetPath(sf::Out out, ContentId content_id) override;
- virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override;
+ virtual Result GetPath(sf::Out out, ContentId content_id) override;
+ virtual Result GetPlaceHolderPath(sf::Out out, PlaceHolderId placeholder_id) override;
virtual Result CleanupAllPlaceHolder() override;
virtual Result ListPlaceHolder(sf::Out out_count, const sf::OutArray &out_buf) override;
virtual Result GetContentCount(sf::Out out_count) override;