diff --git a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp index 5194f68f6de..7a1dfbdac8f 100644 --- a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +++ b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp @@ -54,7 +54,29 @@ std::string GetBundleFromEmbeddedResource(const winrt::Windows::Foundation::Uri return std::string(start, start + size); } -std::future LocalBundleReader::LoadBundleAsync(const std::wstring bundleUri) { +namespace { + +std::string BufferToString(const winrt::Windows::Storage::Streams::IBuffer &buffer) { + std::string result(buffer.Length(), '\0'); + if (!result.empty()) { + auto reader = winrt::Windows::Storage::Streams::DataReader::FromBuffer(buffer); + reader.ReadBytes(winrt::array_view{ + reinterpret_cast(&result[0]), reinterpret_cast(&result[result.length()])}); + } + return result; +} + +winrt::Windows::Storage::Streams::IBuffer BytesToBuffer(const void *data, uint32_t size) { + winrt::Windows::Storage::Streams::DataWriter writer; + auto bytes = static_cast(data); + writer.WriteBytes(winrt::array_view(bytes, bytes + size)); + return writer.DetachBuffer(); +} + +} // namespace + +winrt::Windows::Foundation::IAsyncOperation +LocalBundleReader::LoadBundleAsync(const std::wstring bundleUri) { try { co_await winrt::resume_background(); @@ -66,41 +88,25 @@ std::future LocalBundleReader::LoadBundleAsync(const std::wstring b file = co_await winrt::Windows::Storage::StorageFile::GetFileFromApplicationUriAsync(uri); } else if (bundleUri.starts_with(L"resource://")) { winrt::Windows::Foundation::Uri uri(bundleUri); - co_return GetBundleFromEmbeddedResource(uri); + auto bytes = GetBundleFromEmbeddedResource(uri); + co_return BytesToBuffer(bytes.data(), static_cast(bytes.size())); } else { file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(bundleUri); } - // Read the buffer manually to avoid a Utf8 -> Utf16 -> Utf8 encoding - // roundtrip. - auto fileBuffer{co_await winrt::Windows::Storage::FileIO::ReadBufferAsync(file)}; - auto dataReader{winrt::Windows::Storage::Streams::DataReader::FromBuffer(fileBuffer)}; - - // No need to use length + 1, STL guarantees that string storage is null-terminated. - std::string script(fileBuffer.Length(), '\0'); - - // Construct the array_view to slice into the first fileBuffer.Length bytes. - // DataReader.ReadBytes will read as many bytes as are present in the - // array_view. The backing string has fileBuffer.Length() + 1 bytes, without - // an explicit end it will read 1 byte to many and throw. - dataReader.ReadBytes(winrt::array_view{ - reinterpret_cast(&script[0]), reinterpret_cast(&script[script.length()])}); - dataReader.Close(); - - co_return script; + co_return co_await winrt::Windows::Storage::FileIO::ReadBufferAsync(file); } - // RuntimeScheduler only handles std::exception or jsi::JSError - catch (winrt::hresult_error const &e) { - throw std::exception(winrt::to_string(e.message()).c_str()); + catch (winrt::hresult_error const &) { + throw; } } std::string LocalBundleReader::LoadBundle(const std::wstring &bundlePath) { - return LoadBundleAsync(bundlePath).get(); + return BufferToString(LoadBundleAsync(bundlePath).get()); } StorageFileBigString::StorageFileBigString(const std::wstring &path) { - m_futureBuffer = LocalBundleReader::LoadBundleAsync(path); + m_pendingLoad = LocalBundleReader::LoadBundleAsync(path); } bool StorageFileBigString::isAscii() const { @@ -118,8 +124,9 @@ size_t StorageFileBigString::size() const { } void StorageFileBigString::ensure() const { - if (m_string.empty()) { - m_string = m_futureBuffer.get(); + if (m_pendingLoad) { + m_string = BufferToString(m_pendingLoad.get()); + m_pendingLoad = nullptr; } } diff --git a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h index 8671ebf59ee..4286189b94d 100644 --- a/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h +++ b/vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h @@ -3,14 +3,16 @@ #pragma once #include -#include +#include +#include #include namespace Microsoft::ReactNative { class LocalBundleReader { public: - static std::future LoadBundleAsync(const std::wstring bundlePath); + static winrt::Windows::Foundation::IAsyncOperation LoadBundleAsync( + const std::wstring bundlePath); static std::string LoadBundle(const std::wstring &bundlePath); }; @@ -24,7 +26,7 @@ class StorageFileBigString : public facebook::react::JSBigString { void ensure() const; private: - mutable std::future m_futureBuffer; + mutable winrt::Windows::Foundation::IAsyncOperation m_pendingLoad; mutable std::string m_string; };