Skip to content

Commit

Permalink
Switch from cpp-subprocess to boost::process
Browse files Browse the repository at this point in the history
subprocess had issues with special characters in  paths and file names.
  • Loading branch information
pivotiiii committed Apr 26, 2024
1 parent 0049045 commit cbe8d22
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 89 deletions.
3 changes: 0 additions & 3 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ Copyright (c) 2003 Michael E. Smoot
Copyright (c) 2004 Daniel Aarno
Copyright (c) 2017 Google Inc.

--- cpp-subprocess ---
Copyright (c) 2016-2018 Arun Muralidharan

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
Expand Down
18 changes: 11 additions & 7 deletions dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,19 @@ FetchContent_Declare(
PATCH_COMMAND git apply "${CMAKE_SOURCE_DIR}/patches/tclap.patch"
UPDATE_DISCONNECTED 1
)
FetchContent_MakeAvailable(tclap)

#----------------------------------------------------------------------------------------

FetchContent_Declare(
subprocess
GIT_REPOSITORY https://github.com/arun11299/cpp-subprocess.git
GIT_TAG 40cd59c0970960a0ef41365ae9d96c6a72ee6922 #
PATCH_COMMAND git apply "${CMAKE_SOURCE_DIR}/patches/subprocess.patch"
UPDATE_DISCONNECTED 1
Boost
URL https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz
URL_MD5 893b5203b862eb9bbd08553e24ff146a
DOWNLOAD_EXTRACT_TIMESTAMP ON
EXCLUDE_FROM_ALL
)

FetchContent_MakeAvailable(tclap subprocess)
set(BOOST_INCLUDE_LIBRARIES process)
FetchContent_MakeAvailable(Boost)

#----------------------------------------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion src/CMakelists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ add_library(nsui_banner_fixer_game
Settings.hpp)
target_compile_features(nsui_banner_fixer_game PRIVATE cxx_std_20)
target_include_directories(nsui_banner_fixer_game INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(nsui_banner_fixer_game PRIVATE subprocess)
target_link_libraries(nsui_banner_fixer_game PRIVATE Boost::process)

target_link_libraries(nsui_banner_fixer PRIVATE nsui_banner_fixer_game TCLAP)

Expand Down
120 changes: 60 additions & 60 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,38 @@
#include <regex>
#include <vector>

#include <subprocess.hpp>
#include <boost/process.hpp>

#include "Game.hpp"

#define run_process(name, verbose_offset, ret_code, err_msg) \
{ \
if (set.verbose) { \
name.insert(name.begin() + verbose_offset, "-v"); \
} \
\
sp::Popen process = sp::Popen(name, sp::output {sp::PIPE}); \
auto obuf = process.communicate().first; \
\
if (process.retcode() != ret_code) { \
std::cerr << obuf.buf.data() << "\n"; \
std::cerr << "ERROR: " << err_msg << " (" << process.retcode() << ")\n"; \
return false; \
} \
\
if (set.verbose) { \
std::cerr << obuf.buf.data() << "\n"; \
} \
#define run_process(exec, arg_list, verbose_offset, ret_code, err_msg) \
{ \
if (set.verbose) { \
arg_list.insert(arg_list.begin() + verbose_offset, "-v"); \
} \
bp::ipstream output_stream; \
std::string line; \
int retval = bp::system(bp::exe = exec, \
bp::args = arg_list, \
bp::std_out > output_stream); \
\
if (retval != ret_code) { \
while (std::getline(output_stream, line)) { \
std::cerr << line << "\n"; \
} \
std::cerr << "ERROR: " << err_msg << " (" << retval << ")\n"; \
return false; \
} \
\
if (set.verbose) { \
while (std::getline(output_stream, line)) { \
std::cout << line << "\n"; \
} \
} \
}

namespace fs = std::filesystem;
namespace sp = subprocess;
namespace bp = boost::process;

const std::vector<int> locale_offsets = {0x14BC, 0x14CB};

Expand Down Expand Up @@ -99,24 +105,26 @@ bool Game::fix_banner()
versionS Game::get_version()
{
versionS version;

auto output_buffer = sp::check_output({set.ctrtool.string(), "-i", this->cia_path.string()});
if (output_buffer.buf.data() != NULL) {
std::stringstream ss(output_buffer.buf.data());
std::string line;
while (std::getline(ss, line, '\n')) {
if (line.starts_with("Title version:")) {
std::regex version_regex("(\\d+).(\\d+).(\\d+)");
std::smatch matches;
if (std::regex_search(line, matches, version_regex)) {
if (matches.size() == 4) {
version.major = max(min(63, stoi(matches[1].str())), 0);
version.minor = max(min(63, stoi(matches[2].str())), 0);
version.micro = max(min(15, stoi(matches[3].str())), 0);
}
bp::ipstream output_stream;
std::string line;

bp::system(bp::exe = set.ctrtool.string(),
bp::args = {"-i",
this->cia_path.string()},
bp::std_out > output_stream);

while (std::getline(output_stream, line)) {
if (line.starts_with("Title version:")) {
std::regex version_regex("(\\d+).(\\d+).(\\d+)");
std::smatch matches;
if (std::regex_search(line, matches, version_regex)) {
if (matches.size() == 4) {
version.major = std::max(std::min(63, stoi(matches[1].str())), 0);
version.minor = std::max(std::min(63, stoi(matches[2].str())), 0);
version.micro = std::max(std::min(15, stoi(matches[3].str())), 0);
}
break;
}
break;
}
}
if (set.verbose) {
Expand All @@ -128,37 +136,33 @@ versionS Game::get_version()

bool Game::extract_cia()
{
std::vector<std::string> extract_contents = {set.ctrtool.string(),
std::string("--contents=") + (this->cwd / "contents").string(),
std::vector<std::string> extract_contents = {std::string("--contents=") + (this->cwd / "contents").string(),
this->cia_path.string()};
run_process(extract_contents, 1, 0, "Failed to extract contents from .CIA");
run_process(set.ctrtool.string(), extract_contents, 1, 0, "Failed to extract contents from .CIA");

std::vector<std::string> split_contents = {set.dstool.string(),
"-x", "-t",
std::vector<std::string> split_contents = {"-x", "-t",
"cxi", "-f", (this->cwd / "contents.0000.00000000").string(),
"--header", (this->cwd / "ncch.header").string(),
"--exh", (this->cwd / "exheader.bin").string(),
"--exefs", (this->cwd / "exefs.bin").string(),
"--romfs", (this->cwd / "romfs.bin").string()};
run_process(split_contents, 2, 0, "Failed to split contents");
run_process(set.dstool.string(), split_contents, 1, 0, "Failed to split contents");

std::vector<std::string> extract_exefs = {set.dstool.string(),
"-x", "-t",
std::vector<std::string> extract_exefs = {"-x", "-t",
"exefs", "-f", (this->cwd / "exefs.bin").string(),
"--header", (this->cwd / "exefs.header").string(),
"--exefs-dir", (this->cwd / "exefs").string()};
run_process(extract_exefs, 2, 0, "Failed to extract exefs from contents");
run_process(set.dstool.string(), extract_exefs, 1, 0, "Failed to extract exefs from contents");

fs::create_directory(this->cwd / "banner");
if (fs::exists(this->cwd / "exefs" / "banner.bnr")) {
this->banner_ext = "bnr";
}

std::vector<std::string> extract_banner = {set.dstool.string(),
"-x", "-t",
std::vector<std::string> extract_banner = {"-x", "-t",
"banner", "-f", (this->cwd / "exefs" / (std::string("banner.") + this->banner_ext)).string(),
"--banner-dir", (this->cwd / "banner").string()};
run_process(extract_banner, 2, 0, "Failed to extract banner from exefs");
run_process(set.dstool.string(), extract_banner, 1, 0, "Failed to extract banner from exefs");

return true;
}
Expand Down Expand Up @@ -206,27 +210,24 @@ bool Game::edit_bcmdl()
bool Game::repack_cia()
{
fs::remove(this->cwd / "exefs" / (std::string("banner.") + this->banner_ext));
std::vector<std::string> rebuild_banner = {set.dstool.string(),
"-c", "-t",
std::vector<std::string> rebuild_banner = {"-c", "-t",
"banner", "-f", (this->cwd / "exefs" / (std::string("banner.") + this->banner_ext)).string(),
"--banner-dir", (this->cwd / "banner").string()};
run_process(rebuild_banner, 2, 0, "Failed to rebuild banner");
run_process(set.dstool.string(), rebuild_banner, 1, 0, "Failed to rebuild banner");

std::vector<std::string> rebuild_exefs = {set.dstool.string(),
"-c", "-t",
std::vector<std::string> rebuild_exefs = {"-c", "-t",
"exefs", "-f", (this->cwd / "exefs.bin").string(),
"--header", (this->cwd / "exefs.header").string(),
"--exefs-dir", (this->cwd / "exefs").string()};
run_process(rebuild_exefs, 2, 0, "Failed to rebuild exefs");
run_process(set.dstool.string(), rebuild_exefs, 1, 0, "Failed to rebuild exefs");

std::vector<std::string> rebuild_cxi = {set.dstool.string(),
"-c", "-t",
std::vector<std::string> rebuild_cxi = {"-c", "-t",
"cxi", "-f", (this->cwd / (this->name + ".cxi")).string(),
"--header", (this->cwd / "ncch.header").string(),
"--exh", (this->cwd / "exheader.bin").string(),
"--exefs", (this->cwd / "exefs.bin").string(),
"--romfs", (this->cwd / "romfs.bin").string()};
run_process(rebuild_cxi, 2, 0, "Failed to rebuild cxi");
run_process(set.dstool.string(), rebuild_cxi, 1, 0, "Failed to rebuild cxi");

fs::path out_cia;
if (set.replace) {
Expand All @@ -238,14 +239,13 @@ bool Game::repack_cia()
}
fs::path content_path_rel = fs::relative(this->cwd / (this->name + ".cxi"), fs::current_path()); // may need checking if file on different drive

std::vector<std::string> rebuild_cia = {set.makerom.string(),
"-f", "cia",
std::vector<std::string> rebuild_cia = {"-f", "cia",
"-o", out_cia.string(),
"-content", content_path_rel.string() + ":0:0x00",
"-major", std::to_string(this->version.major),
"-minor", std::to_string(this->version.minor),
"-micro", std::to_string(this->version.micro)};
run_process(rebuild_cia, 1, 0, "Failed to rebuild CIA");
run_process(set.makerom.string(), rebuild_cia, 0, 0, "Failed to rebuild CIA");

return true;
}
1 change: 0 additions & 1 deletion src/nsui_banner_fixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ int parse_args(int argc, char** argv, std::vector<fs::path> &cias, Settings &set
"nsui_banner_fixer uses the following tools and libraries licensed under the MIT license:\n\n"
"3dstool\nCopyright (c) 2014-2020 Daowen Sun\n\n"
"TCLAP\nCopyright (c) 2003 Michael E. Smoot\nCopyright (c) 2004 Daniel Aarno\nCopyright (c) 2017 Google Inc.\n\n"
"cpp-subprocess\nCopyright (c) 2016-2018 Arun Muralidharan\n\n"
"The full MIT license text is available at https://github.com/pivotiiii/nsui_banner_fixer/blob/master/LICENSE\n";
return 2;
}
Expand Down
2 changes: 1 addition & 1 deletion test/CMakelists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set(test_files test_v28.cia test_v27.cia)
foreach(test_name IN LISTS test_names)
add_executable(${test_name} ${test_name}.cpp)
target_compile_features(${test_name} PRIVATE cxx_std_20)
target_link_libraries(${test_name} PRIVATE nsui_banner_fixer_game subprocess)
target_link_libraries(${test_name} PRIVATE nsui_banner_fixer_game Boost::process)
add_test(NAME ${test_name} COMMAND $<TARGET_FILE:${test_name}> WORKING_DIRECTORY $<TARGET_FILE_DIR:${test_name}>)
endforeach()

Expand Down
36 changes: 20 additions & 16 deletions test/test_get_version.cpp
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
#include <filesystem>
#include <regex>

#include <subprocess.hpp>
#include <Boost/process.hpp>

#include <Game.hpp>
#include <Settings.hpp>

namespace fs = std::filesystem;
namespace bp = boost::process;

versionS get_version(const fs::path &cia, const Settings set)
{
versionS version;
auto output_buffer = subprocess::check_output({set.ctrtool.string(), "-i", cia.string()});
if (output_buffer.buf.data() != NULL) {
std::stringstream ss(output_buffer.buf.data());
std::string line;
while (std::getline(ss, line, '\n')) {
if (line.starts_with("Title version:")) {
std::regex version_regex("(\\d+).(\\d+).(\\d+)");
std::smatch matches;
if (std::regex_search(line, matches, version_regex)) {
if (matches.size() == 4) {
version.major = max(min(63, stoi(matches[1].str())), 0);
version.minor = max(min(63, stoi(matches[2].str())), 0);
version.micro = max(min(15, stoi(matches[3].str())), 0);
}
bp::ipstream output_stream;
std::string line;

bp::system(bp::exe = set.ctrtool.string(),
bp::args = {"-i",
cia.string()},
bp::std_out > output_stream);

while (std::getline(output_stream, line)) {
if (line.starts_with("Title version:")) {
std::regex version_regex("(\\d+).(\\d+).(\\d+)");
std::smatch matches;
if (std::regex_search(line, matches, version_regex)) {
if (matches.size() == 4) {
version.major = std::max(std::min(63, stoi(matches[1].str())), 0);
version.minor = std::max(std::min(63, stoi(matches[2].str())), 0);
version.micro = std::max(std::min(15, stoi(matches[3].str())), 0);
}
break;
}
break;
}
}
return version;
Expand Down

0 comments on commit cbe8d22

Please sign in to comment.