mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-03-21 17:24:37 -05:00
Code revisions.
This commit is contained in:
parent
cc5da07eaa
commit
b73de43c5a
|
|
@ -22,52 +22,30 @@ class BufferQueue final
|
|||
|
||||
/// @brief Creates a new BufferQueue.
|
||||
/// @param bufferLimit Number of buffers before the queue is considered full.
|
||||
BufferQueue(int bufferLimit, size_t bufferSize) noexcept
|
||||
: m_bufferLimit(bufferLimit)
|
||||
, m_bufferSize(bufferSize) {};
|
||||
BufferQueue(int bufferLimit) noexcept
|
||||
: m_bufferLimit(bufferLimit) {};
|
||||
|
||||
/// @brief Gets an returns a scoped lock_guard for the internal mutex.
|
||||
inline BufferGuard lock_queue() noexcept { return BufferGuard{m_queueMutex}; }
|
||||
|
||||
/// @brief Returns if the buffer queue is "full", or, has reached its limit.
|
||||
inline bool is_full() const noexcept
|
||||
inline bool try_push(Buffer &buffer, size_t bufferSize)
|
||||
{
|
||||
if (static_cast<int>(m_queue.size()) < m_bufferLimit) { return false; }
|
||||
std::lock_guard queueGuard{m_queueMutex};
|
||||
if (m_bufferLimit != NO_LIMIT && static_cast<int>(m_queue.size()) >= m_bufferLimit) { return false; }
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
||||
m_queue.emplace(std::move(buffer), bufferSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Returns if the buffer queue is empty.
|
||||
inline bool is_empty() const noexcept
|
||||
inline bool get_front(QueuePair &pairOut)
|
||||
{
|
||||
if (!m_queue.empty()) { return false; }
|
||||
std::lock_guard queueGuard{m_queueMutex};
|
||||
if (m_queue.empty()) { return false; }
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Creates and returns a buffer of bufferSize.
|
||||
inline Buffer allocate_buffer() { return std::make_unique<sys::Byte[]>(m_bufferSize); }
|
||||
|
||||
/// @brief Same as above, but with the size passed here.
|
||||
inline Buffer allocate_buffer(size_t bufferSize) { return std::make_unique<sys::Byte[]>(bufferSize); }
|
||||
|
||||
/// @brief Pushes a new buffer to the queue.
|
||||
inline void push_to_queue(Buffer &buffer, size_t bufferSize)
|
||||
{
|
||||
auto queuePair = std::make_pair(std::move(buffer), bufferSize);
|
||||
m_queue.push(std::move(queuePair));
|
||||
}
|
||||
|
||||
/// @brief Returns the front of the queue and pops it.
|
||||
inline QueuePair get_front()
|
||||
{
|
||||
auto front = std::move(m_queue.front());
|
||||
pairOut = std::move(m_queue.front());
|
||||
m_queue.pop();
|
||||
return front;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void default_delay() noexcept { std::this_thread::sleep_for(std::chrono::microseconds(10)); }
|
||||
|
||||
/// @brief This can be passed to the constructor to make is_full() return false all of the time.
|
||||
static inline int NO_LIMIT = -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@
|
|||
|
||||
namespace curl
|
||||
{
|
||||
inline constexpr int DOWNLOAD_QUEUE_LIMIT = 128;
|
||||
|
||||
// clang-format off
|
||||
struct DownloadStruct : sys::threadpool::DataStruct
|
||||
{
|
||||
/// @brief Buffer queue for downloads.
|
||||
BufferQueue bufferQueue{BufferQueue::NO_LIMIT, 0};
|
||||
BufferQueue bufferQueue{BufferQueue::NO_LIMIT};
|
||||
|
||||
/// @brief Destination file to write to.
|
||||
fslib::File *dest{};
|
||||
|
|
|
|||
|
|
@ -71,13 +71,10 @@ size_t curl::download_file_threaded(const char *buffer, size_t size, size_t coun
|
|||
auto &bufferQueue = download->bufferQueue;
|
||||
|
||||
const size_t downloadSize = size * count;
|
||||
auto chunkBuffer = bufferQueue.allocate_buffer(downloadSize);
|
||||
auto chunkBuffer = std::make_unique<sys::Byte[]>(downloadSize);
|
||||
std::copy(buffer, buffer + downloadSize, chunkBuffer.get());
|
||||
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
bufferQueue.push_to_queue(chunkBuffer, downloadSize);
|
||||
}
|
||||
while (!bufferQueue.try_push(chunkBuffer, downloadSize)) { std::this_thread::sleep_for(std::chrono::microseconds(10)); }
|
||||
|
||||
return downloadSize;
|
||||
}
|
||||
|
|
@ -95,17 +92,10 @@ void curl::download_write_thread_function(sys::threadpool::JobData jobData)
|
|||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
BufferQueue::QueuePair queuePair{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_empty()) { continue; }
|
||||
|
||||
queuePair = bufferQueue.get_front();
|
||||
}
|
||||
while (!bufferQueue.get_front(queuePair)) { BufferQueue::default_delay(); }
|
||||
|
||||
auto &[chunkBuffer, bufferSize] = queuePair;
|
||||
|
||||
dest.write(chunkBuffer.get(), bufferSize);
|
||||
|
||||
i += bufferSize;
|
||||
|
||||
if (task) { task->update_current(static_cast<double>(i)); }
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace
|
|||
// clang-format off
|
||||
struct FileThreadStruct : sys::threadpool::DataStruct
|
||||
{
|
||||
BufferQueue bufferQueue{SIZE_QUEUE_LIMIT, SIZE_FILE_BUFFER};
|
||||
BufferQueue bufferQueue{SIZE_QUEUE_LIMIT};
|
||||
fslib::File *source{};
|
||||
};
|
||||
// clang-format on
|
||||
|
|
@ -41,16 +41,10 @@ static void read_thread_function(sys::threadpool::JobData jobData)
|
|||
|
||||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
ssize_t readSize{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_full()) { continue; }
|
||||
|
||||
auto readBuffer = bufferQueue.allocate_buffer();
|
||||
readSize = source.read(readBuffer.get(), SIZE_FILE_BUFFER);
|
||||
bufferQueue.push_to_queue(readBuffer, readSize);
|
||||
}
|
||||
auto chunkBuffer = std::make_unique<sys::Byte[]>(SIZE_FILE_BUFFER);
|
||||
ssize_t readSize = source.read(chunkBuffer.get(), SIZE_FILE_BUFFER);
|
||||
|
||||
while (!bufferQueue.try_push(chunkBuffer, readSize)) { BufferQueue::default_delay(); }
|
||||
i += readSize;
|
||||
}
|
||||
}
|
||||
|
|
@ -80,12 +74,7 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy
|
|||
for (int64_t i = 0; i < sourceSize;)
|
||||
{
|
||||
BufferQueue::QueuePair queuePair{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_empty()) { continue; }
|
||||
|
||||
queuePair = bufferQueue.get_front();
|
||||
}
|
||||
while (!bufferQueue.get_front(queuePair)) { BufferQueue::default_delay(); }
|
||||
|
||||
auto &[buffer, bufferSize] = queuePair;
|
||||
destFile.write(buffer.get(), bufferSize);
|
||||
|
|
@ -127,12 +116,7 @@ void fs::copy_file_commit(const fslib::Path &source,
|
|||
for (int64_t i = 0; i < sourceSize;)
|
||||
{
|
||||
BufferQueue::QueuePair queuePair{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_empty()) { continue; }
|
||||
|
||||
queuePair = bufferQueue.get_front();
|
||||
}
|
||||
while (!bufferQueue.get_front(queuePair)) { BufferQueue::default_delay(); }
|
||||
|
||||
const auto &[buffer, bufferSize] = queuePair;
|
||||
const bool needsCommit = journalCount + static_cast<int64_t>(bufferSize) >= journalSize;
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ namespace
|
|||
struct ZipReadStruct : sys::threadpool::DataStruct
|
||||
{
|
||||
fslib::File *source{};
|
||||
BufferQueue bufferQueue{SIZE_BUFFER_LIMIT, SIZE_ZIP_BUFFER};
|
||||
BufferQueue bufferQueue{SIZE_BUFFER_LIMIT};
|
||||
};
|
||||
|
||||
struct UnzipReadStruct : sys::threadpool::DataStruct
|
||||
{
|
||||
fs::MiniUnzip *unzip{};
|
||||
BufferQueue bufferQueue{SIZE_BUFFER_LIMIT, SIZE_UNZIP_BUFFER};
|
||||
BufferQueue bufferQueue{SIZE_BUFFER_LIMIT};
|
||||
};
|
||||
// clang-format on
|
||||
} // namespace
|
||||
|
|
@ -51,16 +51,10 @@ static void zip_read_thread_function(sys::threadpool::JobData jobData)
|
|||
|
||||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
ssize_t readSize{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_full()) { continue; }
|
||||
|
||||
auto readBuffer = bufferQueue.allocate_buffer();
|
||||
readSize = source.read(readBuffer.get(), SIZE_ZIP_BUFFER);
|
||||
bufferQueue.push_to_queue(readBuffer, readSize);
|
||||
}
|
||||
auto chunkBuffer = std::make_unique<sys::Byte[]>(SIZE_ZIP_BUFFER);
|
||||
ssize_t readSize = source.read(chunkBuffer.get(), SIZE_ZIP_BUFFER);
|
||||
|
||||
while (!bufferQueue.try_push(chunkBuffer, readSize)) { BufferQueue::default_delay(); }
|
||||
i += readSize;
|
||||
}
|
||||
}
|
||||
|
|
@ -76,16 +70,10 @@ static void unzip_read_thread_function(sys::threadpool::JobData jobData)
|
|||
|
||||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
ssize_t readSize{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_full()) { continue; }
|
||||
|
||||
auto readBuffer = bufferQueue.allocate_buffer();
|
||||
readSize = unzip.read(readBuffer.get(), SIZE_UNZIP_BUFFER);
|
||||
bufferQueue.push_to_queue(readBuffer, readSize);
|
||||
}
|
||||
auto chunkBuffer = std::make_unique<sys::Byte[]>(SIZE_UNZIP_BUFFER);
|
||||
ssize_t readSize = unzip.read(chunkBuffer.get(), SIZE_UNZIP_BUFFER);
|
||||
|
||||
while (!bufferQueue.try_push(chunkBuffer, readSize)) { BufferQueue::default_delay(); }
|
||||
i += readSize;
|
||||
}
|
||||
}
|
||||
|
|
@ -128,12 +116,7 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys
|
|||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
BufferQueue::QueuePair queuePair{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_empty()) { continue; }
|
||||
|
||||
queuePair = bufferQueue.get_front();
|
||||
}
|
||||
while (!bufferQueue.get_front(queuePair)) { BufferQueue::default_delay(); }
|
||||
|
||||
auto &[buffer, bufferSize] = queuePair;
|
||||
dest.write(buffer.get(), bufferSize);
|
||||
|
|
@ -199,16 +182,10 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, in
|
|||
for (int64_t i = 0; i < fileSize;)
|
||||
{
|
||||
BufferQueue::QueuePair queuePair{};
|
||||
{
|
||||
auto queueGuard = bufferQueue.lock_queue();
|
||||
if (bufferQueue.is_empty()) { continue; }
|
||||
|
||||
queuePair = bufferQueue.get_front();
|
||||
}
|
||||
while (!bufferQueue.get_front(queuePair)) { BufferQueue::default_delay(); }
|
||||
|
||||
auto &[buffer, bufferSize] = queuePair;
|
||||
|
||||
const bool commitNeeded = needCommits && journalCount + static_cast<int64_t>(bufferSize) >= journalSize;
|
||||
const bool commitNeeded = needCommits && journalCount + static_cast<int64_t>(bufferSize) >= journalSize;
|
||||
if (commitNeeded)
|
||||
{
|
||||
destFile.close();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#include <ctime>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -19,8 +18,7 @@ namespace
|
|||
{L',', L'/', L'\\', L'<', L'>', L':', L'"', L'|', L'?', L'*', L'™', L'©', L'®'};
|
||||
|
||||
/// @brief This is a table for replacing accented characters and "look alike" unicode characters.
|
||||
// Note: extra outer braces required to initialize std::array of non-scalar elements (pairs)
|
||||
constexpr std::array<std::pair<uint32_t, std::string_view>, 78> REPLACEMENT_TABLE{
|
||||
constexpr std::array<std::pair<uint32_t, std::string_view>, 78> REPLACEMENT_TABLE = {
|
||||
{{L'Á', "A"}, {L'À', "A"}, {L'Â', "A"}, {L'Ä', "A"}, {L'Ã', "A"}, {L'Å', "A"}, {L'á', "a"}, {L'à', "a"},
|
||||
{L'â', "a"}, {L'ä', "a"}, {L'ã', "a"}, {L'å', "a"}, {L'É', "E"}, {L'È', "E"}, {L'Ê', "E"}, {L'Ë', "E"},
|
||||
{L'é', "e"}, {L'è', "e"}, {L'ê', "e"}, {L'ë', "e"}, {L'Í', "I"}, {L'Ì', "I"}, {L'Î', "I"}, {L'Ï', "I"},
|
||||
|
|
@ -88,7 +86,7 @@ bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut,
|
|||
// Check for replacing.
|
||||
const auto &replace = std::find_if(REPLACEMENT_TABLE.begin(),
|
||||
REPLACEMENT_TABLE.end(),
|
||||
[=](const auto &replacePair) { return replacePair.first == codepoint; });
|
||||
[codepoint](const auto &replacePair) { return replacePair.first == codepoint; });
|
||||
if (replace != REPLACEMENT_TABLE.end())
|
||||
{
|
||||
const auto &[tablePoint, replacement] = *replace;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "error.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
#include "ui/PopMessageManager.hpp"
|
||||
|
|
@ -12,35 +13,24 @@
|
|||
// Defined at bottom.
|
||||
static bool read_save_meta(const fslib::Path &path, fs::SaveMetaData &metaOut);
|
||||
static bool test_for_save(data::User *user, const fs::SaveMetaData &saveMeta);
|
||||
static bool create_save_data_from_meta(sys::ProgressTask *task, data::User *user, const fs::SaveMetaData &saveMeta);
|
||||
|
||||
void tasks::saveimport::import_save_backup(sys::threadpool::JobData taskData)
|
||||
{
|
||||
auto castData = std::static_pointer_cast<SaveImportState::DataStruct>(taskData);
|
||||
|
||||
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
|
||||
if (error::is_null(task)) { return; }
|
||||
|
||||
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(castData->task);
|
||||
data::User *user = castData->user;
|
||||
const fslib::Path &target = castData->path;
|
||||
if (error::is_null(task) || error::is_null(user)) { return; }
|
||||
|
||||
fs::SaveMetaData metaData{};
|
||||
const bool metaRead = read_save_meta(target, metaData);
|
||||
if (!metaRead || metaData.revision < 1) { TASK_FINISH_RETURN(task); }
|
||||
|
||||
const bool saveExists = test_for_save(user, metaData);
|
||||
if (!saveExists)
|
||||
{
|
||||
// Gonna borrow this.
|
||||
const char *statusFormat = strings::get_by_name(strings::names::USEROPTION_STATUS, 0);
|
||||
const std::string hexID = stringutil::get_formatted_string("%016llX", metaData.applicationID);
|
||||
std::string status = stringutil::get_formatted_string(statusFormat, hexID.c_str());
|
||||
task->set_status(status);
|
||||
|
||||
fs::create_save_data_for(user, metaData);
|
||||
user->clear_data_entries();
|
||||
user->load_user_data();
|
||||
MainMenuState::refresh_view_states();
|
||||
}
|
||||
const bool saveExists = test_for_save(user, metaData);
|
||||
const bool saveCreated = !saveExists && create_save_data_from_meta(task, user, metaData);
|
||||
if (!saveExists && !saveCreated) { TASK_FINISH_RETURN(task); }
|
||||
|
||||
const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(metaData.applicationID);
|
||||
if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); }
|
||||
|
|
@ -135,3 +125,30 @@ static bool test_for_save(data::User *user, const fs::SaveMetaData &saveMeta)
|
|||
|
||||
return mounted;
|
||||
}
|
||||
|
||||
static bool create_save_data_from_meta(sys::ProgressTask *task, data::User *user, const fs::SaveMetaData &saveMeta)
|
||||
{
|
||||
if (error::is_null(task) || error::is_null(user)) { return false; }
|
||||
|
||||
// Gonna borrow this.
|
||||
const char *statusFormat = strings::get_by_name(strings::names::USEROPTION_STATUS, 0);
|
||||
const std::string hexID = stringutil::get_formatted_string("%016llX", saveMeta.applicationID);
|
||||
std::string status = stringutil::get_formatted_string(statusFormat, hexID.c_str());
|
||||
task->set_status(status);
|
||||
|
||||
const bool saveCreated = fs::create_save_data_for(user, saveMeta);
|
||||
if (!saveCreated)
|
||||
{
|
||||
// Gonna borrow this too.
|
||||
const char *popFailed = strings::get_by_name(strings::names::SAVECREATE_POPS, 1);
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_TICKS, popFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Need to reload and refresh to reflect changes.
|
||||
user->clear_data_entries();
|
||||
user->load_user_data();
|
||||
MainMenuState::refresh_view_states();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ void tasks::useroptions::backup_all_for_user_remote(sys::threadpool::JobData tas
|
|||
}
|
||||
|
||||
data::TitleInfo *titleInfo = data::get_title_info_by_id(saveInfo->application_id);
|
||||
if (error::is_null(saveInfo)) { continue; }
|
||||
if (error::is_null(titleInfo)) { continue; }
|
||||
|
||||
backupStruct->titleInfo = titleInfo;
|
||||
const std::string_view remoteTitle =
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user