[libromdata/tests] GcnFstPrint, WiiUFstPrint: Use libgsvt.
Some checks are pending
Codecov / run (push) Waiting to run
CodeQL / Analyze (cpp) (push) Waiting to run

The Unicode text printing on Windows via _fputts() was causing the
console output to lock up on Windows 7. Switching to libgsvt fixes it.

Code size difference: (64-bit Gentoo Linux, gcc-15.1.0, release build, no LTO)

   text    data     bss     dec     hex filename
  16247    1032      48   17327    43af GcnFstPrint [before]
  19006    1160      80   20246    4f16 GcnFstPrint [after]
  +2759    +128     +32   +2919    +b67 Difference

   text    data     bss     dec     hex filename
  15417    1016      48   16481    4061 WiiUFstPrint [before]
  18210    1144      80   19434    4bea WiiUFstPrint [after]
  +2793    +128     +32   +2953    +b89 Difference
This commit is contained in:
David Korth 2025-05-11 04:13:24 -04:00
parent 665a9f878c
commit 43a7bd4a49
3 changed files with 54 additions and 65 deletions

View File

@ -40,6 +40,7 @@ ADD_EXECUTABLE(GcnFstPrint
disc/FstPrint.hpp
)
TARGET_LINK_LIBRARIES(GcnFstPrint PRIVATE rpsecure romdata)
TARGET_LINK_LIBRARIES(GcnFstPrint PRIVATE gsvt)
IF(ENABLE_NLS)
TARGET_LINK_LIBRARIES(GcnFstPrint PRIVATE i18n)
ENDIF(ENABLE_NLS)
@ -87,6 +88,7 @@ ADD_EXECUTABLE(WiiUFstPrint
disc/FstPrint.hpp
)
TARGET_LINK_LIBRARIES(WiiUFstPrint PRIVATE rpsecure romdata)
TARGET_LINK_LIBRARIES(WiiUFstPrint PRIVATE gsvt)
IF(ENABLE_NLS)
TARGET_LINK_LIBRARIES(WiiUFstPrint PRIVATE i18n)
ENDIF(ENABLE_NLS)

View File

@ -14,6 +14,9 @@ using LibRomData::GcnFst;
// i18n
#include "libi18n/i18n.h"
// libgsvt for VT handling
#include "gsvtpp.hpp"
// C includes (C++ namespace)
#include <cerrno>
#include <cstdio>
@ -68,14 +71,19 @@ int RP_C_API main(int argc, char *argv[])
setlocale(LC_CTYPE, "C");
#endif /* _WIN32 */
// Detect console information.
// NOTE: Technically not needed, since Gsvt::Console access
// will call this for us...
gsvt_init();
// Initialize i18n.
rp_i18n_init();
if (argc < 2 || argc > 3) {
fmt::print(stderr, FRUN(C_("GcnFstPrint", "Syntax: {:s} fst.bin [offsetShift]")), argv[0]);
fputc('\n', stderr);
fputs(C_("GcnFstPrint", "offsetShift should be 0 for GameCube, 2 for Wii. (default is 0)"), stderr);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "Syntax: {:s} fst.bin [offsetShift]")), argv[0]));
Gsvt::StdErr.newline();
Gsvt::StdErr.fputs(C_("GcnFstPrint", "offsetShift should be 0 for GameCube, 2 for Wii. (default is 0)"));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -85,10 +93,10 @@ int RP_C_API main(int argc, char *argv[])
char *endptr = nullptr;
long ltmp = strtol(argv[2], &endptr, 10);
if (*endptr != '\0' || (ltmp != 0 && ltmp != 2)) {
fmt::print(stderr, FRUN(C_("GcnFstPrint", "Invalid offset shift '{:s}' specified.")), argv[2]);
fputc('\n', stderr);
fputs(C_("GcnFstPrint", "offsetShift should be 0 for GameCube, 2 for Wii. (default is 0)"), stderr);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "Invalid offset shift '{:s}' specified.")), argv[2]));
Gsvt::StdErr.newline();
Gsvt::StdErr.fputs(C_("GcnFstPrint", "offsetShift should be 0 for GameCube, 2 for Wii. (default is 0)"));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
offsetShift = static_cast<uint8_t>(ltmp);
@ -98,8 +106,8 @@ int RP_C_API main(int argc, char *argv[])
FILE *f = fopen(argv[1], "rb");
if (!f) {
// tr: {0:s} == filename, {1:s} == error message
fmt::print(stderr, FRUN(C_("GcnFstPrint", "Error opening '{0:s}': '{1:s}'")), argv[1], strerror(errno));
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "Error opening '{0:s}': '{1:s}'")), argv[1], strerror(errno)));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -107,8 +115,8 @@ int RP_C_API main(int argc, char *argv[])
fseeko(f, 0, SEEK_END);
const off64_t fileSize_o = ftello(f);
if (fileSize_o > (16*1024*1024)) {
fputs(C_("GcnFstPrint", "ERROR: FST is too big. (Maximum of 16 MB.)"), stderr);
fputc('\n', stderr);
Gsvt::StdErr.fputs(C_("GcnFstPrint", "ERROR: FST is too big. (Maximum of 16 MB.)"));
Gsvt::StdErr.newline();
fclose(f);
return EXIT_FAILURE;
}
@ -121,9 +129,9 @@ int RP_C_API main(int argc, char *argv[])
fclose(f);
if (rd_size != fileSize) {
// tr: {0:d} == number of bytes read, {1:d} == number of bytes expected to read
fmt::print(stderr, FRUN(C_("GcnFstPrint", "ERROR: Read {0:Ld} bytes, expected {1:Ld} bytes.")),
rd_size, fileSize);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "ERROR: Read {0:Ld} bytes, expected {1:Ld} bytes.")),
rd_size, fileSize));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -145,35 +153,20 @@ int RP_C_API main(int argc, char *argv[])
unique_ptr<IFst> fst(new GcnFst(&fstData[fst_start_offset],
static_cast<uint32_t>(fileSize - fst_start_offset), offsetShift));
if (!fst->isOpen()) {
fmt::print(stderr, FRUN(C_("GcnFstPrint", "*** ERROR: Could not parse '{:s}' as GcnFst.")), argv[1]);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "*** ERROR: Could not parse '{:s}' as GcnFst.")), argv[1]));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
// Print the FST to an ostringstream.
ostringstream oss;
LibRomData::fstPrint(fst.get(), oss);
const string fst_str = oss.str();
#ifdef _WIN32
// FIXME: isatty() might not work properly on Win8+ with MinGW.
// Reference: https://lists.gnu.org/archive/html/bug-gnulib/2013-01/msg00007.html
if (isatty(fileno(stdout))) {
// Convert to wchar_t, then print it.
_fputts(U82T_s(fst_str), stdout);
} else {
// Writing to file. Print the original UTF-8.
fputs(fst_str.c_str(), stdout);
}
#else /* !_WIN32 */
// Print the FST.
fputs(fst_str.c_str(), stdout);
#endif
Gsvt::StdOut.fputs(oss.str());
if (fst->hasErrors()) {
fputc('\n', stderr);
fputs(C_("GcnFstPrint", "*** WARNING: FST has errors and may be unusable."), stderr);
fputc('\n', stderr);
Gsvt::StdErr.newline();
Gsvt::StdErr.fputs(C_("GcnFstPrint", "*** WARNING: FST has errors and may be unusable."));
Gsvt::StdErr.newline();
}
// Cleanup.

View File

@ -16,6 +16,9 @@ using LibRomData::WiiUFst;
// i18n
#include "libi18n/i18n.h"
// libgsvt for VT handling
#include "gsvtpp.hpp"
// C includes (C++ namespace)
#include <cerrno>
#include <cstdio>
@ -69,12 +72,17 @@ int RP_C_API main(int argc, char *argv[])
setlocale(LC_CTYPE, "C");
#endif /* _WIN32 */
// Detect console information.
// NOTE: Technically not needed, since Gsvt::Console access
// will call this for us...
gsvt_init();
// Initialize i18n.
rp_i18n_init();
if (argc < 2 || argc > 3) {
fmt::print(stderr, FRUN(C_("WiiUFstPrint", "Syntax: {:s} fst.bin")), argv[0]);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("WiiUFstPrint", "Syntax: {:s} fst.bin")), argv[0]));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -82,8 +90,8 @@ int RP_C_API main(int argc, char *argv[])
FILE *f = fopen(argv[1], "rb");
if (!f) {
// tr: {0:s} == filename, {1:s} == error message
fmt::print(stderr, FRUN(C_("GcnFstPrint", "Error opening '{0:s}': '{1:s}'")), argv[1], strerror(errno));
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "Error opening '{0:s}': '{1:s}'")), argv[1], strerror(errno)));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -91,8 +99,8 @@ int RP_C_API main(int argc, char *argv[])
fseeko(f, 0, SEEK_END);
const off64_t fileSize_o = ftello(f);
if (fileSize_o > (16*1024*1024)) {
fputs(C_("GcnFstPrint", "ERROR: FST is too big. (Maximum of 16 MB.)"), stderr);
fputc('\n', stderr);
Gsvt::StdErr.fputs(C_("GcnFstPrint", "ERROR: FST is too big. (Maximum of 16 MB.)"));
Gsvt::StdErr.newline();
fclose(f);
return EXIT_FAILURE;
}
@ -105,9 +113,9 @@ int RP_C_API main(int argc, char *argv[])
fclose(f);
if (rd_size != fileSize) {
// tr: {0:Ld} == number of bytes read, {1:Ld} == number of bytes expected to read
fmt::print(stderr, FRUN(C_("GcnFstPrint", "ERROR: Read {0:Ld} bytes, expected {1:Ld} bytes.")),
rd_size, fileSize);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("GcnFstPrint", "ERROR: Read {0:Ld} bytes, expected {1:Ld} bytes.")),
rd_size, fileSize));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -116,8 +124,8 @@ int RP_C_API main(int argc, char *argv[])
// "look" like an FST?
unique_ptr<IFst> fst(new WiiUFst(fstData.get(), static_cast<uint32_t>(fileSize)));
if (!fst->isOpen()) {
fmt::print(stderr, FRUN(C_("WiiUFstPrint", "*** ERROR: Could not parse '{:s}' as WiiUFst.")), argv[1]);
fputc('\n', stderr);
Gsvt::StdErr.fputs(fmt::format(FRUN(C_("WiiUFstPrint", "*** ERROR: Could not parse '{:s}' as WiiUFst.")), argv[1]));
Gsvt::StdErr.newline();
return EXIT_FAILURE;
}
@ -125,26 +133,12 @@ int RP_C_API main(int argc, char *argv[])
ostringstream oss;
LibRomData::fstPrint(fst.get(), oss, true);
const string fst_str = oss.str();
#ifdef _WIN32
// FIXME: isatty() might not work properly on Win8+ with MinGW.
// Reference: https://lists.gnu.org/archive/html/bug-gnulib/2013-01/msg00007.html
if (isatty(fileno(stdout))) {
// Convert to wchar_t, then print it.
_fputts(U82T_s(fst_str), stdout);
} else {
// Writing to file. Print the original UTF-8.
fputs(fst_str.c_str(), stdout);
}
#else /* !_WIN32 */
// Print the FST.
fputs(fst_str.c_str(), stdout);
#endif
Gsvt::StdOut.fputs(oss.str());
if (fst->hasErrors()) {
fputc('\n', stderr);
fputs(C_("WiiUFstPrint", "*** WARNING: FST has errors and may be unusable."), stderr);
fputc('\n', stderr);
Gsvt::StdErr.newline();
Gsvt::StdErr.fputs(C_("WiiUFstPrint", "*** WARNING: FST has errors and may be unusable."));
Gsvt::StdErr.newline();
}
// Cleanup.