diff options
| author | 2020-01-26 13:18:13 -0500 | |
|---|---|---|
| committer | 2020-02-05 23:06:52 -0500 | |
| commit | 84e895cdd64f0378f1c5bc3af3897b77068d5acf (patch) | |
| tree | 3673a1d60a718f2decdd71f7b4d5b8a9538dfc3b /src | |
| parent | applets: software_keyboard: Signal state change on end of interactive session. (diff) | |
| download | yuzu-84e895cdd64f0378f1c5bc3af3897b77068d5acf.tar.gz yuzu-84e895cdd64f0378f1c5bc3af3897b77068d5acf.tar.xz yuzu-84e895cdd64f0378f1c5bc3af3897b77068d5acf.zip | |
am: Refactor IStorage interface.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 74 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.h | 30 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/error.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/general_backend.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/profile_select.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/software_keyboard.cpp | 8 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/web_browser.cpp | 2 |
7 files changed, 81 insertions, 43 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 95aa5d23d..d1495ce18 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -709,8 +709,34 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) { | |||
| 709 | apm_sys->SetCpuBoostMode(ctx); | 709 | apm_sys->SetCpuBoostMode(ctx); |
| 710 | } | 710 | } |
| 711 | 711 | ||
| 712 | IStorage::IStorage(std::vector<u8> buffer) | 712 | IStorageImpl::~IStorageImpl() = default; |
| 713 | : ServiceFramework("IStorage"), buffer(std::move(buffer)) { | 713 | |
| 714 | class StorageDataImpl final : public IStorageImpl { | ||
| 715 | public: | ||
| 716 | explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {} | ||
| 717 | |||
| 718 | std::vector<u8>& GetData() override { | ||
| 719 | return buffer; | ||
| 720 | } | ||
| 721 | |||
| 722 | const std::vector<u8>& GetData() const override { | ||
| 723 | return buffer; | ||
| 724 | } | ||
| 725 | |||
| 726 | std::size_t GetSize() const override { | ||
| 727 | return buffer.size(); | ||
| 728 | } | ||
| 729 | |||
| 730 | private: | ||
| 731 | std::vector<u8> buffer; | ||
| 732 | }; | ||
| 733 | |||
| 734 | IStorage::IStorage(std::vector<u8>&& buffer) | ||
| 735 | : ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} { | ||
| 736 | Register(); | ||
| 737 | } | ||
| 738 | |||
| 739 | void IStorage::Register() { | ||
| 714 | // clang-format off | 740 | // clang-format off |
| 715 | static const FunctionInfo functions[] = { | 741 | static const FunctionInfo functions[] = { |
| 716 | {0, &IStorage::Open, "Open"}, | 742 | {0, &IStorage::Open, "Open"}, |
| @@ -723,8 +749,13 @@ IStorage::IStorage(std::vector<u8> buffer) | |||
| 723 | 749 | ||
| 724 | IStorage::~IStorage() = default; | 750 | IStorage::~IStorage() = default; |
| 725 | 751 | ||
| 726 | const std::vector<u8>& IStorage::GetData() const { | 752 | void IStorage::Open(Kernel::HLERequestContext& ctx) { |
| 727 | return buffer; | 753 | LOG_DEBUG(Service_AM, "called"); |
| 754 | |||
| 755 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 756 | |||
| 757 | rb.Push(RESULT_SUCCESS); | ||
| 758 | rb.PushIpcInterface<IStorageAccessor>(*this); | ||
| 728 | } | 759 | } |
| 729 | 760 | ||
| 730 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | 761 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { |
| @@ -891,15 +922,6 @@ private: | |||
| 891 | std::shared_ptr<Applets::Applet> applet; | 922 | std::shared_ptr<Applets::Applet> applet; |
| 892 | }; | 923 | }; |
| 893 | 924 | ||
| 894 | void IStorage::Open(Kernel::HLERequestContext& ctx) { | ||
| 895 | LOG_DEBUG(Service_AM, "called"); | ||
| 896 | |||
| 897 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 898 | |||
| 899 | rb.Push(RESULT_SUCCESS); | ||
| 900 | rb.PushIpcInterface<IStorageAccessor>(*this); | ||
| 901 | } | ||
| 902 | |||
| 903 | IStorageAccessor::IStorageAccessor(IStorage& storage) | 925 | IStorageAccessor::IStorageAccessor(IStorage& storage) |
| 904 | : ServiceFramework("IStorageAccessor"), backing(storage) { | 926 | : ServiceFramework("IStorageAccessor"), backing(storage) { |
| 905 | // clang-format off | 927 | // clang-format off |
| @@ -921,7 +943,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { | |||
| 921 | IPC::ResponseBuilder rb{ctx, 4}; | 943 | IPC::ResponseBuilder rb{ctx, 4}; |
| 922 | 944 | ||
| 923 | rb.Push(RESULT_SUCCESS); | 945 | rb.Push(RESULT_SUCCESS); |
| 924 | rb.Push(static_cast<u64>(backing.buffer.size())); | 946 | rb.Push(static_cast<u64>(backing.GetSize())); |
| 925 | } | 947 | } |
| 926 | 948 | ||
| 927 | void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | 949 | void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { |
| @@ -932,17 +954,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | |||
| 932 | 954 | ||
| 933 | LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); | 955 | LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size()); |
| 934 | 956 | ||
| 935 | if (data.size() > backing.buffer.size() - offset) { | 957 | if (data.size() > backing.GetSize() - offset) { |
| 936 | LOG_ERROR(Service_AM, | 958 | LOG_ERROR(Service_AM, |
| 937 | "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", | 959 | "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", |
| 938 | backing.buffer.size(), data.size(), offset); | 960 | backing.GetSize(), data.size(), offset); |
| 939 | 961 | ||
| 940 | IPC::ResponseBuilder rb{ctx, 2}; | 962 | IPC::ResponseBuilder rb{ctx, 2}; |
| 941 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | 963 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); |
| 942 | return; | 964 | return; |
| 943 | } | 965 | } |
| 944 | 966 | ||
| 945 | std::memcpy(backing.buffer.data() + offset, data.data(), data.size()); | 967 | std::memcpy(backing.GetData().data() + offset, data.data(), data.size()); |
| 946 | 968 | ||
| 947 | IPC::ResponseBuilder rb{ctx, 2}; | 969 | IPC::ResponseBuilder rb{ctx, 2}; |
| 948 | rb.Push(RESULT_SUCCESS); | 970 | rb.Push(RESULT_SUCCESS); |
| @@ -956,16 +978,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | |||
| 956 | 978 | ||
| 957 | LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); | 979 | LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); |
| 958 | 980 | ||
| 959 | if (size > backing.buffer.size() - offset) { | 981 | if (size > backing.GetSize() - offset) { |
| 960 | LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", | 982 | LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", |
| 961 | backing.buffer.size(), size, offset); | 983 | backing.GetSize(), size, offset); |
| 962 | 984 | ||
| 963 | IPC::ResponseBuilder rb{ctx, 2}; | 985 | IPC::ResponseBuilder rb{ctx, 2}; |
| 964 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | 986 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); |
| 965 | return; | 987 | return; |
| 966 | } | 988 | } |
| 967 | 989 | ||
| 968 | ctx.WriteBuffer(backing.buffer.data() + offset, size); | 990 | ctx.WriteBuffer(backing.GetData().data() + offset, size); |
| 969 | 991 | ||
| 970 | IPC::ResponseBuilder rb{ctx, 2}; | 992 | IPC::ResponseBuilder rb{ctx, 2}; |
| 971 | rb.Push(RESULT_SUCCESS); | 993 | rb.Push(RESULT_SUCCESS); |
| @@ -1031,7 +1053,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex | |||
| 1031 | rp.SetCurrentOffset(3); | 1053 | rp.SetCurrentOffset(3); |
| 1032 | const auto handle{rp.Pop<Kernel::Handle>()}; | 1054 | const auto handle{rp.Pop<Kernel::Handle>()}; |
| 1033 | 1055 | ||
| 1034 | const auto transfer_mem = | 1056 | auto transfer_mem = |
| 1035 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); | 1057 | system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); |
| 1036 | 1058 | ||
| 1037 | if (transfer_mem == nullptr) { | 1059 | if (transfer_mem == nullptr) { |
| @@ -1047,7 +1069,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex | |||
| 1047 | 1069 | ||
| 1048 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1070 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1049 | rb.Push(RESULT_SUCCESS); | 1071 | rb.Push(RESULT_SUCCESS); |
| 1050 | rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory))); | 1072 | rb.PushIpcInterface<IStorage>(std::move(memory)); |
| 1051 | } | 1073 | } |
| 1052 | 1074 | ||
| 1053 | IApplicationFunctions::IApplicationFunctions(Core::System& system_) | 1075 | IApplicationFunctions::IApplicationFunctions(Core::System& system_) |
| @@ -1189,13 +1211,11 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 1189 | u64 build_id{}; | 1211 | u64 build_id{}; |
| 1190 | std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); | 1212 | std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); |
| 1191 | 1213 | ||
| 1192 | const auto data = | 1214 | auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); |
| 1193 | backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id}); | ||
| 1194 | |||
| 1195 | if (data.has_value()) { | 1215 | if (data.has_value()) { |
| 1196 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 1216 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 1197 | rb.Push(RESULT_SUCCESS); | 1217 | rb.Push(RESULT_SUCCESS); |
| 1198 | rb.PushIpcInterface<AM::IStorage>(*data); | 1218 | rb.PushIpcInterface<IStorage>(std::move(*data)); |
| 1199 | launch_popped_application_specific = true; | 1219 | launch_popped_application_specific = true; |
| 1200 | return; | 1220 | return; |
| 1201 | } | 1221 | } |
| @@ -1218,7 +1238,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 1218 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); | 1238 | std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); |
| 1219 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | 1239 | std::memcpy(buffer.data(), ¶ms, buffer.size()); |
| 1220 | 1240 | ||
| 1221 | rb.PushIpcInterface<AM::IStorage>(buffer); | 1241 | rb.PushIpcInterface<IStorage>(std::move(buffer)); |
| 1222 | launch_popped_account_preselect = true; | 1242 | launch_popped_account_preselect = true; |
| 1223 | return; | 1243 | return; |
| 1224 | } | 1244 | } |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 448817be9..0b9a4332d 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -12,7 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | namespace Kernel { | 13 | namespace Kernel { |
| 14 | class KernelCore; | 14 | class KernelCore; |
| 15 | } | 15 | class TransferMemory; |
| 16 | } // namespace Kernel | ||
| 16 | 17 | ||
| 17 | namespace Service::NVFlinger { | 18 | namespace Service::NVFlinger { |
| 18 | class NVFlinger; | 19 | class NVFlinger; |
| @@ -188,19 +189,36 @@ private: | |||
| 188 | std::shared_ptr<AppletMessageQueue> msg_queue; | 189 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 189 | }; | 190 | }; |
| 190 | 191 | ||
| 192 | class IStorageImpl { | ||
| 193 | public: | ||
| 194 | virtual ~IStorageImpl(); | ||
| 195 | virtual std::vector<u8>& GetData() = 0; | ||
| 196 | virtual const std::vector<u8>& GetData() const = 0; | ||
| 197 | virtual std::size_t GetSize() const = 0; | ||
| 198 | }; | ||
| 199 | |||
| 191 | class IStorage final : public ServiceFramework<IStorage> { | 200 | class IStorage final : public ServiceFramework<IStorage> { |
| 192 | public: | 201 | public: |
| 193 | explicit IStorage(std::vector<u8> buffer); | 202 | explicit IStorage(std::vector<u8>&& buffer); |
| 194 | ~IStorage() override; | 203 | ~IStorage() override; |
| 195 | 204 | ||
| 196 | const std::vector<u8>& GetData() const; | 205 | std::vector<u8>& GetData() { |
| 206 | return impl->GetData(); | ||
| 207 | } | ||
| 208 | |||
| 209 | const std::vector<u8>& GetData() const { | ||
| 210 | return impl->GetData(); | ||
| 211 | } | ||
| 212 | |||
| 213 | std::size_t GetSize() const { | ||
| 214 | return impl->GetSize(); | ||
| 215 | } | ||
| 197 | 216 | ||
| 198 | private: | 217 | private: |
| 218 | void Register(); | ||
| 199 | void Open(Kernel::HLERequestContext& ctx); | 219 | void Open(Kernel::HLERequestContext& ctx); |
| 200 | 220 | ||
| 201 | std::vector<u8> buffer; | 221 | std::shared_ptr<IStorageImpl> impl; |
| 202 | |||
| 203 | friend class IStorageAccessor; | ||
| 204 | }; | 222 | }; |
| 205 | 223 | ||
| 206 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { | 224 | class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { |
diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index eab0d42c9..e6c4e8b87 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp | |||
| @@ -186,7 +186,7 @@ void Error::Execute() { | |||
| 186 | 186 | ||
| 187 | void Error::DisplayCompleted() { | 187 | void Error::DisplayCompleted() { |
| 188 | complete = true; | 188 | complete = true; |
| 189 | broker.PushNormalDataFromApplet(IStorage{{}}); | 189 | broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}}); |
| 190 | broker.SignalStateChanged(); | 190 | broker.SignalStateChanged(); |
| 191 | } | 191 | } |
| 192 | 192 | ||
diff --git a/src/core/hle/service/am/applets/general_backend.cpp b/src/core/hle/service/am/applets/general_backend.cpp index 328438a1d..fe8400a15 100644 --- a/src/core/hle/service/am/applets/general_backend.cpp +++ b/src/core/hle/service/am/applets/general_backend.cpp | |||
| @@ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) { | |||
| 148 | std::vector<u8> out(sizeof(Return)); | 148 | std::vector<u8> out(sizeof(Return)); |
| 149 | std::memcpy(out.data(), &return_, sizeof(Return)); | 149 | std::memcpy(out.data(), &return_, sizeof(Return)); |
| 150 | 150 | ||
| 151 | broker.PushNormalDataFromApplet(IStorage{out}); | 151 | broker.PushNormalDataFromApplet(IStorage{std::move(out)}); |
| 152 | broker.SignalStateChanged(); | 152 | broker.SignalStateChanged(); |
| 153 | } | 153 | } |
| 154 | 154 | ||
| @@ -198,7 +198,7 @@ void PhotoViewer::Execute() { | |||
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | void PhotoViewer::ViewFinished() { | 200 | void PhotoViewer::ViewFinished() { |
| 201 | broker.PushNormalDataFromApplet(IStorage{{}}); | 201 | broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}}); |
| 202 | broker.SignalStateChanged(); | 202 | broker.SignalStateChanged(); |
| 203 | } | 203 | } |
| 204 | 204 | ||
diff --git a/src/core/hle/service/am/applets/profile_select.cpp b/src/core/hle/service/am/applets/profile_select.cpp index 3eba696ca..91d00f72a 100644 --- a/src/core/hle/service/am/applets/profile_select.cpp +++ b/src/core/hle/service/am/applets/profile_select.cpp | |||
| @@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() { | |||
| 50 | 50 | ||
| 51 | void ProfileSelect::Execute() { | 51 | void ProfileSelect::Execute() { |
| 52 | if (complete) { | 52 | if (complete) { |
| 53 | broker.PushNormalDataFromApplet(IStorage{final_data}); | 53 | broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); |
| 54 | return; | 54 | return; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| @@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { | |||
| 71 | 71 | ||
| 72 | final_data = std::vector<u8>(sizeof(UserSelectionOutput)); | 72 | final_data = std::vector<u8>(sizeof(UserSelectionOutput)); |
| 73 | std::memcpy(final_data.data(), &output, final_data.size()); | 73 | std::memcpy(final_data.data(), &output, final_data.size()); |
| 74 | broker.PushNormalDataFromApplet(IStorage{final_data}); | 74 | broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); |
| 75 | broker.SignalStateChanged(); | 75 | broker.SignalStateChanged(); |
| 76 | } | 76 | } |
| 77 | 77 | ||
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp index 08579dea0..964c67202 100644 --- a/src/core/hle/service/am/applets/software_keyboard.cpp +++ b/src/core/hle/service/am/applets/software_keyboard.cpp | |||
| @@ -102,7 +102,7 @@ void SoftwareKeyboard::ExecuteInteractive() { | |||
| 102 | 102 | ||
| 103 | void SoftwareKeyboard::Execute() { | 103 | void SoftwareKeyboard::Execute() { |
| 104 | if (complete) { | 104 | if (complete) { |
| 105 | broker.PushNormalDataFromApplet(IStorage{final_data}); | 105 | broker.PushNormalDataFromApplet(IStorage{std::move(final_data)}); |
| 106 | broker.SignalStateChanged(); | 106 | broker.SignalStateChanged(); |
| 107 | return; | 107 | return; |
| 108 | } | 108 | } |
| @@ -145,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { | |||
| 145 | final_data = output_main; | 145 | final_data = output_main; |
| 146 | 146 | ||
| 147 | if (complete) { | 147 | if (complete) { |
| 148 | broker.PushNormalDataFromApplet(IStorage{output_main}); | 148 | broker.PushNormalDataFromApplet(IStorage{std::move(output_main)}); |
| 149 | broker.SignalStateChanged(); | 149 | broker.SignalStateChanged(); |
| 150 | } else { | 150 | } else { |
| 151 | broker.PushInteractiveDataFromApplet(IStorage{output_sub}); | 151 | broker.PushInteractiveDataFromApplet(IStorage{std::move(output_sub)}); |
| 152 | } | 152 | } |
| 153 | } else { | 153 | } else { |
| 154 | output_main[0] = 1; | 154 | output_main[0] = 1; |
| 155 | complete = true; | 155 | complete = true; |
| 156 | broker.PushNormalDataFromApplet(IStorage{output_main}); | 156 | broker.PushNormalDataFromApplet(IStorage{std::move(output_main)}); |
| 157 | broker.SignalStateChanged(); | 157 | broker.SignalStateChanged(); |
| 158 | } | 158 | } |
| 159 | } | 159 | } |
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index 5546ef6e8..05d6b3a19 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp | |||
| @@ -284,7 +284,7 @@ void WebBrowser::Finalize() { | |||
| 284 | std::vector<u8> data(sizeof(WebCommonReturnValue)); | 284 | std::vector<u8> data(sizeof(WebCommonReturnValue)); |
| 285 | std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); | 285 | std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue)); |
| 286 | 286 | ||
| 287 | broker.PushNormalDataFromApplet(IStorage{data}); | 287 | broker.PushNormalDataFromApplet(IStorage{std::move(data)}); |
| 288 | broker.SignalStateChanged(); | 288 | broker.SignalStateChanged(); |
| 289 | 289 | ||
| 290 | if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { | 290 | if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { |