From 9c335c2026b94298a77a8ccda7d76988461d8400 Mon Sep 17 00:00:00 2001 From: dslatt Date: Sat, 26 Oct 2024 11:28:26 -0500 Subject: [PATCH] reworked extract & address some thread safety (#25) * moved to libarchive * slowed down ui refresh & moved to async * used atomic types for shared progress * update Image to use unique_ptr --- CMakeLists.txt | 6 +- include/util/extract.hpp | 4 +- include/util/image.hpp | 10 +- include/util/progress_event.hpp | 22 ++- include/view/download_view.hpp | 11 +- readme.md | 2 +- source/util/extract.cpp | 208 +++++++++++++++----------- source/util/image.cpp | 54 +++---- source/view/collection_grid.cpp | 10 +- source/view/download_view.cpp | 34 +++-- source/view/icon_part_select.cpp | 2 +- source/view/icon_part_select_grid.cpp | 4 +- source/view/main_view.cpp | 14 +- 13 files changed, 210 insertions(+), 171 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8fe162..e1b5e2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ include(${BOREALIS_LIBRARY}/cmake/toolchain.cmake) project(nso-icon-tool) set(VERSION_MAJOR "0") set(VERSION_MINOR "4") -set(VERSION_ALTER "2") +set(VERSION_ALTER "3") set(VERSION_BUILD "0") set(PROJECT_AUTHOR "dslatt") set(PROJECT_ICON ${CMAKE_CURRENT_SOURCE_DIR}/resources/img/dev.jpg) @@ -49,10 +49,10 @@ if (PLATFORM_SWITCH) glfw3 EGL glapi drm_nouveau # base lib nx m + # extract + archive # curl curl z bz2 zstd lzma lz4 - # extract - minizip # hash xxhash ) diff --git a/include/util/extract.hpp b/include/util/extract.hpp index d9d759e..3bfadd3 100644 --- a/include/util/extract.hpp +++ b/include/util/extract.hpp @@ -5,7 +5,5 @@ namespace extract { - void extract( - const std::string &filename, const std::string &workingPath, bool overwriteExisting, std::function func = []() - { return; }); + void extract(const std::string &filename, const std::string &workingPath, bool overwriteExisting); } \ No newline at end of file diff --git a/include/util/image.hpp b/include/util/image.hpp index 0780b14..55167cb 100644 --- a/include/util/image.hpp +++ b/include/util/image.hpp @@ -5,12 +5,18 @@ struct Image { - unsigned char* img = nullptr; + struct HandleDeleter + { + void operator()(unsigned char *p) const { if (p) std::free(p); } + }; + + using Handle = std::unique_ptr; + Handle data; int size = 0; // raw size in bytes int pixels = 0; // pixel count int x = 0, y = 0, n = 0; - ~Image(); + ~Image() = default; Image(const Image &other); Image(Image &&other) noexcept; diff --git a/include/util/progress_event.hpp b/include/util/progress_event.hpp index 4d8e19b..3b57fe1 100644 --- a/include/util/progress_event.hpp +++ b/include/util/progress_event.hpp @@ -1,18 +1,19 @@ #pragma once +#include + class ProgressEvent { private: ProgressEvent() {} - int _current = 0; - int _max = 60; - double _now = 0; - double _total = 0; - double _speed = 0; - long _status_code = 0; - bool _interupt = false; - double _timeStep = 0; - std::string _msg = ""; + std::atomic_int _current = 0; + std::atomic_int _max = 60; + std::atomic _now = 0; + std::atomic _total = 0; + std::atomic _speed = 0; + std::atomic _status_code = 0; + std::atomic _interupt = false; + std::atomic _timeStep = 0; public: ProgressEvent(const ProgressEvent &) = delete; @@ -36,11 +37,8 @@ class ProgressEvent _status_code = 0; _interupt = false; _timeStep = 0; - _msg = ""; } - inline void setMsg(std::string msg) { _msg = std::move(msg); } - inline const std::string &getMsg() { return _msg; } inline void setTotalSteps(int steps) { _max = steps; } inline void setTotalCount(double total) { _total = total; } inline void setSpeed(double speed) { _speed = speed; } diff --git a/include/view/download_view.hpp b/include/view/download_view.hpp index 9e26b2b..938bfe0 100644 --- a/include/view/download_view.hpp +++ b/include/view/download_view.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include typedef brls::Event DownloadDoneEvent; @@ -31,14 +32,14 @@ class DownloadView : public brls::Box void downloadFile(); void updateProgress(); - std::thread updateThread; - std::thread downloadThread; + std::jthread updateThread; + std::jthread downloadThread; std::mutex threadMutex; std::condition_variable threadCondition; DownloadDoneEvent::Callback cb; - bool downloadFinished = false; - bool extractFinished = false; - bool overwriteExisting = false; + std::atomic_flag downloadFinished; + std::atomic_flag extractFinished; + bool overwriteExisting; }; \ No newline at end of file diff --git a/readme.md b/readme.md index af3eb11..de3ab2d 100644 --- a/readme.md +++ b/readme.md @@ -8,7 +8,7 @@ License - Version + Version Build diff --git a/source/util/extract.cpp b/source/util/extract.cpp index b3d728c..5995f7a 100644 --- a/source/util/extract.cpp +++ b/source/util/extract.cpp @@ -1,126 +1,166 @@ #include "util/extract.hpp" -#include -#include - #include -#include #include #include #include +#include +#include +#include #include +#include #include "util/progress_event.hpp" using namespace brls::literals; // for _i18n namespace fs = std::filesystem; - -constexpr size_t WRITE_BUFFER_SIZE = 0x10000; +using ArchivePtr = std::unique_ptr; namespace extract { - namespace + std::tuple getFileStats(const std::string &archivePath) { - bool caselessCompare(const std::string &a, const std::string &b) - { - return strcasecmp(a.c_str(), b.c_str()) == 0; + std::tuple stats{0, 0}; + ArchivePtr archive(archive_read_new(), archive_read_free); + struct archive_entry* entry; + + archive_read_support_format_all(archive.get()); + archive_read_support_filter_all(archive.get()); + + if(archive_read_open_filename(archive.get(), archivePath.c_str(), 10240) == ARCHIVE_OK) { + while(archive_read_next_header(archive.get(), &entry) == ARCHIVE_OK) { + std::get<0>(stats) += 1; + std::get<1>(stats) += archive_entry_size(entry); + } } - s64 getUncompressedSize(const std::string &archivePath) + return stats; + } + + void ensureAvailableStorage(size_t uncompressedSize) + { + s64 freeStorage; + + if (R_SUCCEEDED(nsGetFreeSpaceSize(NcmStorageId_SdCard, &freeStorage))) { - s64 size = 0; - unzFile zfile = unzOpen(archivePath.c_str()); - unz_global_info gi; - unzGetGlobalInfo(zfile, &gi); - for (uLong i = 0; i < gi.number_entry; ++i) + brls::Logger::info("Uncompressed size of archive: {}. Available: {}", uncompressedSize, freeStorage); + if (uncompressedSize * 1.1 > freeStorage) { - unz_file_info fi; - unzOpenCurrentFile(zfile); - unzGetCurrentFileInfo(zfile, &fi, NULL, 0, NULL, 0, NULL, 0); - size += fi.uncompressed_size; - unzCloseCurrentFile(zfile); - unzGoToNextFile(zfile); + brls::Application::crash("app/errors/insufficient_storage"_i18n); + std::this_thread::sleep_for(std::chrono::microseconds(2000000)); + brls::Application::quit(); } - unzClose(zfile); - return size; // in B } + } - void ensureAvailableStorage(const std::string &archivePath) - { - s64 uncompressedSize = getUncompressedSize(archivePath); - s64 freeStorage; + void extract(const std::string &archivePath, const std::string &workingPath, bool overwriteExisting) { + auto start = std::chrono::high_resolution_clock::now(); + int count = 0; - if (R_SUCCEEDED(nsGetFreeSpaceSize(NcmStorageId_SdCard, &freeStorage))) - { - brls::Logger::info("Uncompressed size of archive {}: {}. Available: {}", archivePath, uncompressedSize, freeStorage); - if (uncompressedSize * 1.1 > freeStorage) - { - brls::Application::crash("app/errors/insufficient_storage"_i18n); - std::this_thread::sleep_for(std::chrono::microseconds(2000000)); - brls::Application::quit(); - } - } + try { + + auto [totalFiles, totalSize] = getFileStats(archivePath); + ensureAvailableStorage(totalSize); + + brls::sync([totalFiles, totalSize]() { + brls::Logger::info("Extracting {} entries of size {} bytes", totalFiles, totalSize); + }); + + ProgressEvent::instance().setTotalSteps(totalFiles); + ProgressEvent::instance().setStep(0); + + ArchivePtr archive(archive_read_new(), archive_read_free); + struct archive_entry *entry; + int err = 0, i = 0; + + archive_read_support_format_all(archive.get()); + archive_read_support_filter_all(archive.get()); + + if ((err = archive_read_open_filename(archive.get(), archivePath.c_str(), 10240))) { + brls::sync([err = std::string(archive_error_string(archive.get()))]() { + brls::Logger::error("Error opening archive: {}", err); + }); + return; } - void extractEntry(std::string filename, unzFile &zfile, bool forceCreateTree = false) - { - if (filename.back() == '/') - { - fs::create_directories(filename); - return; + for (;;) { + if (ProgressEvent::instance().getInterupt()) { + ProgressEvent::instance().setStep(ProgressEvent::instance().getMax()); + break; } - if (forceCreateTree) - { - fs::create_directories(filename); + + err = archive_read_next_header(archive.get(), &entry); + if (err == ARCHIVE_EOF) { + ProgressEvent::instance().setStep(ProgressEvent::instance().getMax()); + break; } - void *buf = malloc(WRITE_BUFFER_SIZE); - FILE *outfile; - outfile = fopen(filename.c_str(), "wb"); - for (int j = unzReadCurrentFile(zfile, buf, WRITE_BUFFER_SIZE); j > 0; j = unzReadCurrentFile(zfile, buf, WRITE_BUFFER_SIZE)) - { - fwrite(buf, 1, j, outfile); + if (err < ARCHIVE_OK) + brls::sync([archivePath, err = std::string(archive_error_string(archive.get()))]() { + brls::Logger::error("Error reading archive entry: {}", err); + }); + if (err < ARCHIVE_WARN) { + break; } - free(buf); - fclose(outfile); - } - } - - void extract(const std::string &archivePath, const std::string &workingPath, bool overwriteExisting, std::function func) - { - ensureAvailableStorage(archivePath); - unzFile zfile = unzOpen(archivePath.c_str()); - unz_global_info gi; - unzGetGlobalInfo(zfile, &gi); + auto filepath = fs::path(workingPath) / archive_entry_pathname(entry); - ProgressEvent::instance().setTotalSteps(gi.number_entry); - ProgressEvent::instance().setStep(0); + if (archive_entry_filetype(entry) == AE_IFDIR) { + fs::create_directories(filepath); + ProgressEvent::instance().setStep(++i); + continue; + } - for (uLong i = 0; i < gi.number_entry; ++i) - { - char szFilename[0x301] = ""; - unzOpenCurrentFile(zfile); - unzGetCurrentFileInfo(zfile, NULL, szFilename, sizeof(szFilename), NULL, 0, NULL, 0); - std::string filename = workingPath + szFilename; + if (fs::exists(filepath) && !overwriteExisting) { + ProgressEvent::instance().setStep(++i); + continue; + } - if (ProgressEvent::instance().getInterupt()) - { - unzCloseCurrentFile(zfile); + std::ofstream outfile(filepath.string(), std::ios::binary | std::ios::trunc); + if (!outfile.is_open()) { + brls::sync([path = filepath.string()]() { + brls::Logger::error("Error opening write file for archive entry: {}", path); + }); break; } - if (overwriteExisting || !fs::exists(filename)) - { - ProgressEvent::instance().setMsg(filename); - extractEntry(filename, zfile); + const void* buff = nullptr; + size_t size = 0; + int64_t offset = 0; + int res = -1; + while ((res = archive_read_data_block(archive.get(), &buff, &size, &offset)) == ARCHIVE_OK) { + try { + outfile.write(static_cast(buff), size); + } catch(const std::exception& e) { + res = ARCHIVE_FATAL; + break; + } + } + + if (res != ARCHIVE_EOF) { + brls::sync([res = std::string(archive_error_string(archive.get()))]() { + brls::Logger::error("Error writing out archive entry: {}", res); + }); + outfile.close(); + fs::remove(filepath); + break; } - ProgressEvent::instance().setStep(i); - unzCloseCurrentFile(zfile); - unzGoToNextFile(zfile); + count++; + ProgressEvent::instance().setStep(++i); + } + + } catch(const std::exception& e) { + brls::sync([e = std::string(e.what())]() { + brls::Logger::error("Unexpected error extracting archive: {}", e); + }); } - unzClose(zfile); - ProgressEvent::instance().setStep(ProgressEvent::instance().getMax()); + + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration_cast(end - start).count(); + + brls::sync([elapsed, count]() { + brls::Logger::info("Total extraction time: {}s for {} files", elapsed, count); + }); } } \ No newline at end of file diff --git a/source/util/image.cpp b/source/util/image.cpp index 9cfccb0..9cb1914 100644 --- a/source/util/image.cpp +++ b/source/util/image.cpp @@ -15,19 +15,11 @@ #include -Image::~Image() { - if (img) { - free(img); // free() and stbi_image_free() are the same. be sure to only use malloc() or stbi* managed memory for img - img = nullptr; - } -} - Image::Image(const Image &other) { - auto* data = static_cast(malloc(other.size)); - if (data && other.img) { - std::memcpy(data, other.img, other.size); - img = data; + data.reset(static_cast(malloc(other.size))); + if (data && other.data) { + std::memcpy(data.get(), other.data.get(), other.size); size = other.size; pixels = other.pixels; x = other.x; @@ -35,23 +27,24 @@ Image::Image(const Image &other) n = other.n; } } + Image::Image(Image &&other) noexcept { - if (img) { free(img); } - img = std::exchange(other.img, nullptr); + data = std::exchange(other.data, nullptr); size = std::exchange(other.size, 0); x = std::exchange(other.x, 0); y = std::exchange(other.y, 0); n = std::exchange(other.n, 0); } + Image &Image::operator=(const Image &other) { return *this = Image(other); } + Image &Image::operator=(Image &&other) { - if (img) { free(img); } - img = std::exchange(other.img, nullptr); + data = std::exchange(other.data, nullptr); size = std::exchange(other.size, 0); x = std::exchange(other.x, 0); y = std::exchange(other.y, 0); @@ -65,15 +58,14 @@ Image::Image(int x, int y) : Image(nullptr, x, y, 4) { allocate(); } bool Image::allocate() { - if (img) { free(img); } - img = static_cast(calloc(size / sizeof(char), sizeof(char))); + data.reset(static_cast(calloc(size / sizeof(char), sizeof(char)))); - return img != 0; + return (bool)data; } Image::Image(unsigned char *buffer, size_t size) { - this->img = stbi_load_from_memory(buffer, size, &x, &y, &n, 4); + this->data.reset(stbi_load_from_memory(buffer, size, &x, &y, &n, 4)); this->n = 4; this->pixels = x * y; this->size = pixels * 4 * sizeof(char); @@ -83,14 +75,14 @@ Image::Image(std::string file) { stbi_set_unpremultiply_on_load(1); stbi_convert_iphone_png_to_rgb(1); - this->img = stbi_load(file.c_str(), &x, &y, &n, 4); + this->data.reset(stbi_load(file.c_str(), &x, &y, &n, 4)); this->pixels = x * y; this->size = pixels * 4 * sizeof(char); } Image::Image(unsigned char *img, int x, int y, int n) { - this->img = img; + this->data.reset(img); this->x = x; this->y = y; this->n = n; @@ -102,7 +94,7 @@ void Image::resize(int x, int y) { if (this->x != x || this->y != y) { - auto *resized = stbir_resize_uint8_linear(img, this->x, this->y, 0, nullptr, x, y, 0, stbir_pixel_layout::STBIR_RGBA); + auto *resized = stbir_resize_uint8_linear(data.get(), this->x, this->y, 0, nullptr, x, y, 0, stbir_pixel_layout::STBIR_RGBA); if (resized) { *this = Image(resized, x, y, 4); @@ -113,13 +105,13 @@ void Image::resize(int x, int y) bool Image::writeJpg(std::filesystem::path path) { if (path.extension() != ".jpg") path.replace_extension(".jpg"); - return stbi_write_jpg(path.c_str(), x, y, 4, img, 90) != 0; + return stbi_write_jpg(path.c_str(), x, y, 4, data.get(), 90) != 0; } bool Image::writePng(std::filesystem::path path) { if (path.extension() != ".png") path.replace_extension(".png"); - return stbi_write_png(path.c_str(), x, y, 4, img, 0) != 0; + return stbi_write_png(path.c_str(), x, y, 4, data.get(), 0) != 0; } void Image::applyAlpha(float alpha) { @@ -128,9 +120,9 @@ void Image::applyAlpha(float alpha) { std::string Image::hash() { - if (img) + if (data) { - auto xxh = XXH3_64bits(img, pixels * 4 * sizeof(char)); + auto xxh = XXH3_64bits(data.get(), pixels * 4 * sizeof(char)); return fmt::format("{}", xxh); } @@ -162,10 +154,10 @@ void Image::merge(Image &frame, Image &character, Image &background, Image &outp { auto total = frame.x * frame.y; - std::span frameRef{reinterpret_cast(frame.img), frame.size / sizeof(Pixel)}; - std::span characterRef{reinterpret_cast(character.img), character.size / sizeof(Pixel)}; - std::span backgroundRef{reinterpret_cast(background.img), background.size / sizeof(Pixel)}; - std::span outputRef{reinterpret_cast(output.img), output.size / sizeof(Pixel)}; + std::span frameRef{reinterpret_cast(frame.data.get()), frame.size / sizeof(Pixel)}; + std::span characterRef{reinterpret_cast(character.data.get()), character.size / sizeof(Pixel)}; + std::span backgroundRef{reinterpret_cast(background.data.get()), background.size / sizeof(Pixel)}; + std::span outputRef{reinterpret_cast(output.data.get()), output.size / sizeof(Pixel)}; for (auto i = 0; i < total; i++) { @@ -195,7 +187,7 @@ void Image::merge(Image &frame, Image &character, Image &background, Image &outp void Image::applyAlpha(Image& image, float alpha) { auto total = image.x * image.y; - auto ref = std::span(reinterpret_cast(image.img), image.size / sizeof(Pixel)); + auto ref = std::span(reinterpret_cast(image.data.get()), image.size / sizeof(Pixel)); for (auto i = 0; i < total; i++) { ref[i] = Pixel{ diff --git a/source/view/collection_grid.cpp b/source/view/collection_grid.cpp index 3ade4a5..ecceb56 100644 --- a/source/view/collection_grid.cpp +++ b/source/view/collection_grid.cpp @@ -43,11 +43,11 @@ RecyclingGridItem *DataSource::cellForRow(RecyclingGrid *recycler, size_t index) RecyclerCell *item = (RecyclerCell *)recycler->dequeueReusableCell("Cell"); brls::Logger::debug("image: {}", items[index].file); - if (items[index].image.img == nullptr) { + if (items[index].image.data.get() == nullptr) { items[index].image = Image(items[index].file); } - item->image->setImageFromMemRGBA(items[index].image.img, items[index].image.x, items[index].image.y); + item->image->setImageFromMemRGBA(items[index].image.data.get(), items[index].image.x, items[index].image.y); item->img = items[index].file; return item; } @@ -69,7 +69,7 @@ void DataSource::updateCell(RecyclingGridItem* item, size_t index) { auto cell = dynamic_cast(item); if (cell) { - cell->image->setImageFromMemRGBA(items[index].image.img, items[index].image.x, items[index].image.y); + cell->image->setImageFromMemRGBA(items[index].image.data.get(), items[index].image.x, items[index].image.y); } } @@ -132,12 +132,12 @@ CollectionGrid::CollectionGrid(const std::vector &files, std::strin items.push_back(CollectionItem{file, Image{}, false}); } - workingImage->setImageFromMemRGBA(state.working.img, state.working.x, state.working.y); + workingImage->setImageFromMemRGBA(state.working.data.get(), state.working.x, state.working.y); recycler->registerCell("Cell", [view = workingImage.getView(), &state, onFocused]() { return RecyclerCell::create([view, &state, onFocused](std::string path) { onFocused(path, state); - view->setImageFromMemRGBA(state.working.img, state.working.x, state.working.y); }); }); + view->setImageFromMemRGBA(state.working.data.get(), state.working.x, state.working.y); }); }); auto* data = new collection::DataSource(std::move(items), onSelected, this); recycler->setDataSource(data); diff --git a/source/view/download_view.cpp b/source/view/download_view.cpp index 404b83c..974e2b0 100644 --- a/source/view/download_view.cpp +++ b/source/view/download_view.cpp @@ -27,8 +27,8 @@ DownloadView::DownloadView(std::string url, std::string downloadPath, std::strin this->setHideHighlightBackground(true); this->setHideHighlightBorder(true); - downloadThread = std::thread(&DownloadView::downloadFile, this); - updateThread = std::thread(&DownloadView::updateProgress, this); + downloadThread = std::jthread(&DownloadView::downloadFile, this); + updateThread = std::jthread(&DownloadView::updateProgress, this); brls::sync([this]() { getAppletFrame()->setActionAvailable(brls::ControllerButton::BUTTON_B, false); }); @@ -42,16 +42,17 @@ void DownloadView::downloadFile() brls::Logger::info("Download started: {} to {}", url, downloadPath); ProgressEvent::instance().reset(); + std::filesystem::remove(downloadPath); download::downloadFile(url, downloadPath); brls::Logger::info("Download complete"); - this->downloadFinished = true; + downloadFinished.test_and_set(); ProgressEvent::instance().reset(); brls::Logger::info("Extract started: {} to {}", downloadPath, extractPath); extract::extract(downloadPath, extractPath, overwriteExisting); brls::Logger::info("Extract complete"); - this->extractFinished = true; + extractFinished.test_and_set(); cb(""); } @@ -72,11 +73,11 @@ void DownloadView::updateProgress() while (ProgressEvent::instance().getTotal() == 0) { - if (downloadFinished) + if (downloadFinished.test()) break; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - while (!downloadFinished) + while (!downloadFinished.test()) { ASYNC_RETAIN brls::sync([ASYNC_TOKEN]() @@ -85,7 +86,7 @@ void DownloadView::updateProgress() this->status_current->setText(fmt::format("{:.0f}MB ({:.1f}MB/s)", ProgressEvent::instance().getNow() / 1000000.0, ProgressEvent::instance().getSpeed() / 1000000.0)); }); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } } // EXTRACT @@ -95,23 +96,26 @@ void DownloadView::updateProgress() { ASYNC_RELEASE download_status->setText("app/download/downloaded"_i18n); - extract_status->setText("app/download/extracting"_i18n); }); + extract_status->setText("app/download/extracting"_i18n); + status_current->setText(""); + }); while (ProgressEvent::instance().getMax() == 0) { - if (extractFinished) + if (extractFinished.test()) break; - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - while (ProgressEvent::instance().getStep() < ProgressEvent::instance().getMax() && !extractFinished) + while (ProgressEvent::instance().getStep() < ProgressEvent::instance().getMax() && !extractFinished.test()) { ASYNC_RETAIN brls::sync([ASYNC_TOKEN]() { ASYNC_RELEASE - this->status_current->setText(ProgressEvent::instance().getMsg()); - this->status_percent->setText(fmt::format("{}%", (int)((ProgressEvent::instance().getStep() * 100 / ProgressEvent::instance().getMax())))); }); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + this->status_current->setText(fmt::format("{}/{}", ProgressEvent::instance().getStep(), ProgressEvent::instance().getMax())); + this->status_percent->setText(fmt::format("({}%)", (int)((ProgressEvent::instance().getStep() * 100 / ProgressEvent::instance().getMax())))); }); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); } { ASYNC_RETAIN diff --git a/source/view/icon_part_select.cpp b/source/view/icon_part_select.cpp index 2bc283f..f6f1685 100644 --- a/source/view/icon_part_select.cpp +++ b/source/view/icon_part_select.cpp @@ -126,7 +126,7 @@ DataSource::DataSource(std::vector parts, std::function &files, std::string subcategory, const ImageState &state, std::function onSelected, std::function onFocused) : workingState(state) { this->inflateFromXMLRes("xml/views/icon_part_select.xml"); - image->setImageFromMemRGBA(workingState.working.img, workingState.working.x, workingState.working.y); + image->setImageFromMemRGBA(workingState.working.data.get(), workingState.working.x, workingState.working.y); recycler->registerCell("Cell", []() { return RecyclerCell::create(); }); recycler->setDataSource(new DataSource(files, onSelected, onFocused, this, subcategory, workingState)); diff --git a/source/view/icon_part_select_grid.cpp b/source/view/icon_part_select_grid.cpp index bf89d9c..a706bdb 100644 --- a/source/view/icon_part_select_grid.cpp +++ b/source/view/icon_part_select_grid.cpp @@ -59,13 +59,13 @@ IconPartSelectGrid::IconPartSelectGrid(const std::vector &files, st { this->inflateFromXMLRes("xml/views/icon_part_select_grid.xml"); - workingImage->setImageFromMemRGBA(state.working.img, state.working.x, state.working.y); + workingImage->setImageFromMemRGBA(state.working.data.get(), state.working.x, state.working.y); auto view = workingImage.getView(); recycler->registerCell("Cell", [view, &state, onFocused]() { return RecyclerCell::create([view, &state, onFocused](std::string path) { onFocused(path, state); - view->setImageFromMemRGBA(state.working.img, state.working.x, state.working.y); + view->setImageFromMemRGBA(state.working.data.get(), state.working.x, state.working.y); }); }); recycler->setDataSource(new DataSource(files, onSelected, this)); diff --git a/source/view/main_view.cpp b/source/view/main_view.cpp index 83c06fb..fb54d10 100644 --- a/source/view/main_view.cpp +++ b/source/view/main_view.cpp @@ -101,7 +101,7 @@ MainView::MainView() this->present(static_cast(new IconPartSelect(files.value(), "frames", imageState, [this](std::string path) { brls::Logger::info("Recieved {} from selection.", path); imageState.updateFrame(path); - image->setImageFromMemRGBA(imageState.working.img, imageState.working.x, imageState.working.y); + image->setImageFromMemRGBA(imageState.working.data.get(), imageState.working.x, imageState.working.y); }, [](std::string path, ImageState& state){ state.updateFrame(path); }))); @@ -121,7 +121,7 @@ MainView::MainView() this->present(static_cast(new IconPartSelect(files.value(), "characters", imageState, [this](std::string path) { brls::Logger::info("Recieved {} from selection.", path); imageState.updateCharacter(path); - image->setImageFromMemRGBA(imageState.working.img, imageState.working.x, imageState.working.y); + image->setImageFromMemRGBA(imageState.working.data.get(), imageState.working.x, imageState.working.y); }, [](std::string path, ImageState& state){ state.updateCharacter(path); }))); @@ -141,7 +141,7 @@ MainView::MainView() this->present(static_cast(new IconPartSelect(files.value(), "backgrounds", imageState, [this](std::string path) { brls::Logger::info("Recieved {} from selection.", path); imageState.updateBackground(path); - image->setImageFromMemRGBA(imageState.working.img, imageState.working.x, imageState.working.y); + image->setImageFromMemRGBA(imageState.working.data.get(), imageState.working.x, imageState.working.y); }, [](std::string path, ImageState& state){ state.updateBackground(path); }))); @@ -156,7 +156,7 @@ MainView::MainView() auto res = account::setUserIcon(user, imageState.working); brls::Logger::info("Icon set for user {}: {}", user.base.nickname, res); if (res) { - currentImage->setImageFromMemRGBA(imageState.working.img, imageState.working.x, imageState.working.y); + currentImage->setImageFromMemRGBA(imageState.working.data.get(), imageState.working.x, imageState.working.y); // save to collection; hash beforehand to avoid duplicate copies auto path = fs::path(paths::CollectionPath) / (imageState.working.hash() + ".png"); @@ -178,7 +178,7 @@ MainView::MainView() this->present(static_cast(new grid::IconPartSelectGrid(files.value(), "app/main/available_images"_i18n, tempState, [this](std::string path) { brls::Logger::info("Recieved {} from selection.", path); imageState.updateWorking(path); - image->setImageFromMemRGBA(imageState.working.img, imageState.working.x, imageState.working.y); + image->setImageFromMemRGBA(imageState.working.data.get(), imageState.working.x, imageState.working.y); }, [](std::string path, ImageState &state){ state.updateWorking(path); }))); @@ -200,7 +200,7 @@ MainView::MainView() this->present(static_cast(new collection::CollectionGrid(files.value(), "app/main/available_images"_i18n, tempState, [this](std::string path) { brls::Logger::info("Recieved {} from selection.", path); imageState.updateWorking(path); - image->setImageFromMemRGBA(imageState.working.img, imageState.working.x, imageState.working.y); + image->setImageFromMemRGBA(imageState.working.data.get(), imageState.working.x, imageState.working.y); }, [](std::string path, ImageState &state){ state.updateWorking(path); }))); @@ -242,7 +242,7 @@ void MainView::handleUserSelection() auto image = account::getProfileImage(user); brls::Logger::info("Loaded User is {}", user.base.nickname); currentUser->setText(user.base.nickname); - currentImage->setImageFromMemRGBA(image.img, image.x, image.y); + currentImage->setImageFromMemRGBA(image.data.get(), image.x, image.y); } }