mirror of
https://github.com/pret/pokediamond.git
synced 2025-02-17 04:17:56 +00:00
Add nitrobanner tool
This tool was made from reverse-engineering the Nitro SDK's makebanner, and is intended to replace that program. It has been tested to match the Diamond/Pearl banners as well as the HeartGold/SoulSilver banners.
This commit is contained in:
parent
70f49f7dff
commit
352605c1b5
4
Makefile
4
Makefile
@ -90,6 +90,7 @@ KNARC = tools/knarc/knarc$(EXE)
|
||||
MSGENC = tools/msgenc/msgenc$(EXE)
|
||||
MWLDARM = tools/mwccarm/$(MWCCVERSION)/mwldarm.exe
|
||||
MWASMARM = tools/mwccarm/$(MWCCVERSION)/mwasmarm.exe
|
||||
NITROBANNER = tools/nitrobanner/nitrobanner$(EXE)
|
||||
SCANINC = tools/scaninc/scaninc$(EXE)
|
||||
|
||||
AS = $(WINE) $(MWASMARM)
|
||||
@ -119,7 +120,6 @@ JSONPROC = $(TOOLS_DIR)/jsonproc/jsonproc$(EXE)
|
||||
O2NARC = $(TOOLS_DIR)/o2narc/o2narc$(EXE)
|
||||
GFX = $(TOOLS_DIR)/nitrogfx/nitrogfx$(EXE)
|
||||
MWASMARM_PATCHER = $(TOOLS_DIR)/mwasmarm_patcher/mwasmarm_patcher$(EXE) -q
|
||||
MAKEBANNER = $(WINE) $(TOOLS_DIR)/bin/makebanner.exe
|
||||
MAKEROM = $(WINE) $(TOOLS_DIR)/bin/makerom.exe
|
||||
FIXROM = $(TOOLS_DIR)/fixrom/fixrom$(EXE)
|
||||
NTRCOMP = $(WINE) $(TOOLS_DIR)/bin/ntrcomp.exe
|
||||
@ -286,7 +286,7 @@ $(8BPP_COMP10_NOPAD_NCLR_PAL_FILES): GFX_FLAGS = -bitdepth 8 -nopad -comp 10
|
||||
######################## Misc #######################
|
||||
|
||||
$(BNR): $(TARGET).bsf $(ICON_FILE:%.png=%.gbapal) $(ICON_FILE:%.png=%.4bpp)
|
||||
$(MAKEBANNER) $< $@
|
||||
$(NITROBANNER) $< $@
|
||||
|
||||
symbols.csv: arm9 arm7
|
||||
(echo "Name,Location"; $(GREP) " *[0-9A-F]{8} [0-9A-F]{8} \S+ +\w+\t\(\w+\.o\)" arm9/$(BUILD_DIR)/arm9.elf.xMAP arm7/build/arm7.elf.xMAP | $(SED) 's/ *([0-9A-F]{8}) [0-9A-F]{8} \S+ +(\w+)\t\(\w+\.o\)/\2,\1/g' | cut -d: -f2) > $@
|
||||
|
1
tools/nitrobanner/.gitignore
vendored
Normal file
1
tools/nitrobanner/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
nitrobanner
|
21
tools/nitrobanner/LICENSE
Normal file
21
tools/nitrobanner/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021 tgsm
|
||||
|
||||
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 use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
30
tools/nitrobanner/Makefile
Normal file
30
tools/nitrobanner/Makefile
Normal file
@ -0,0 +1,30 @@
|
||||
CXXFLAGS := -std=c++17 -O3 -Wall -Wextra -Wpedantic
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
LDFLAGS += -lstdc++fs
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
LDFLAGS += -lstdc++ -lc++ -lc /usr/local/opt/llvm@8/lib/libc++fs.a
|
||||
else
|
||||
LDFLAGS += -lstdc++fs
|
||||
endif
|
||||
endif
|
||||
|
||||
OBJS = \
|
||||
banner.o \
|
||||
crc16.o \
|
||||
main.o
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: nitrobanner
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) nitrobanner nitrobanner.exe *.o
|
||||
|
||||
nitrobanner: $(OBJS)
|
||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
276
tools/nitrobanner/banner.cpp
Normal file
276
tools/nitrobanner/banner.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
#include <cstdio>
|
||||
#include <codecvt>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include "banner.h"
|
||||
#include "crc16.h"
|
||||
|
||||
template <typename T>
|
||||
void SerializeData(std::ofstream& ostream, T data) {
|
||||
for (std::size_t i = 0; i < sizeof(T); i++) {
|
||||
ostream.put(static_cast<u8>((data >> (i * 8)) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring GetTitleAndDeveloperFromSpecCommandArgument(std::wifstream& stream, const std::wstring& command_argument) {
|
||||
std::wstring title_and_developer = command_argument;
|
||||
constexpr int max_lines = 3;
|
||||
int current_line = 1;
|
||||
|
||||
while (true) {
|
||||
wchar_t first_char = stream.get();
|
||||
stream.unget();
|
||||
if (first_char != L' ') {
|
||||
return title_and_developer;
|
||||
}
|
||||
|
||||
if (current_line++ == max_lines) {
|
||||
throw std::runtime_error("Title and developer can not be more than " + std::to_string(max_lines) + " lines");
|
||||
}
|
||||
|
||||
std::wstring line;
|
||||
std::getline(stream, line);
|
||||
|
||||
title_and_developer += '\n';
|
||||
title_and_developer += line.substr(line.find_first_not_of(L' '), line.size());
|
||||
}
|
||||
}
|
||||
|
||||
SpecFileData ParseSpecFile(const filesystem::path& specfile_path) {
|
||||
std::wifstream stream(specfile_path, std::ios::binary);
|
||||
if (!stream.is_open()) {
|
||||
throw std::runtime_error("could not open specfile " + specfile_path.string() + " for parsing");
|
||||
}
|
||||
|
||||
// convert utf-16 to utf-32
|
||||
stream.imbue(std::locale(stream.getloc(), new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));
|
||||
|
||||
// first character of the file has to be U+FEFF.
|
||||
if (stream.get() != 0xFEFF) {
|
||||
throw std::runtime_error("specfile must be encoded as UTF-16");
|
||||
}
|
||||
|
||||
SpecFileData specfile_data = {};
|
||||
|
||||
for (std::wstring line; std::getline(stream, line);) {
|
||||
const std::size_t end_of_command_name = line.find(L':');
|
||||
if (end_of_command_name == std::wstring::npos) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::size_t beginning_of_command_name = line.find_first_not_of(' ');
|
||||
const std::wstring command_name = line.substr(beginning_of_command_name, end_of_command_name - beginning_of_command_name);
|
||||
|
||||
const std::size_t beginning_of_command_argument = line.find_first_of(L": ") + 2;
|
||||
const std::wstring command_argument = line.substr(beginning_of_command_argument, line.size());
|
||||
|
||||
if (command_name == L"Version") {
|
||||
printf("warning: Version command is currently unsupported, defaulting to version 1\n");
|
||||
specfile_data.version = 1;
|
||||
} else if (command_name == L"ImageFile") {
|
||||
specfile_data.icon_bitmap_filename = command_argument;
|
||||
} else if (command_name == L"PlttFile") {
|
||||
specfile_data.icon_palette_filename = command_argument;
|
||||
} else if (CommandIsForTitleAndDeveloper(command_name)) {
|
||||
const std::wstring& title_and_developer = GetTitleAndDeveloperFromSpecCommandArgument(stream, command_argument);
|
||||
|
||||
if (command_name == L"JP") {
|
||||
for (wchar_t c : title_and_developer) {
|
||||
specfile_data.japanese_title += char16_t(c);
|
||||
}
|
||||
} else if (command_name == L"EN") {
|
||||
for (wchar_t c : title_and_developer) {
|
||||
specfile_data.english_title += char16_t(c);
|
||||
}
|
||||
} else if (command_name == L"FR") {
|
||||
for (wchar_t c : title_and_developer) {
|
||||
specfile_data.french_title += char16_t(c);
|
||||
}
|
||||
} else if (command_name == L"GE") {
|
||||
for (wchar_t c : title_and_developer) {
|
||||
specfile_data.german_title += char16_t(c);
|
||||
}
|
||||
} else if (command_name == L"IT") {
|
||||
for (wchar_t c : title_and_developer) {
|
||||
specfile_data.italian_title += char16_t(c);
|
||||
}
|
||||
} else if (command_name == L"SP") {
|
||||
for (wchar_t c : title_and_developer) {
|
||||
specfile_data.spanish_title += char16_t(c);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("warning: unsupported command '%ls', ignoring...\n", command_name.data());
|
||||
}
|
||||
}
|
||||
|
||||
if (specfile_data.version == 0) {
|
||||
// no banner version provided, assuming version 1
|
||||
specfile_data.version = 1;
|
||||
}
|
||||
|
||||
if (specfile_data.icon_bitmap_filename.empty()) {
|
||||
throw std::runtime_error("missing required ImageFile command (filename of icon bitmap)");
|
||||
}
|
||||
|
||||
if (specfile_data.icon_palette_filename.empty()) {
|
||||
throw std::runtime_error("missing required PlttFile command (filename of icon palette)");
|
||||
}
|
||||
|
||||
if (specfile_data.japanese_title.empty()) {
|
||||
throw std::runtime_error("missing required JP command (Japanese title & developer)");
|
||||
}
|
||||
|
||||
if (specfile_data.english_title.empty()) {
|
||||
throw std::runtime_error("missing required EN command (English title & developer)");
|
||||
}
|
||||
|
||||
if (specfile_data.french_title.empty()) {
|
||||
throw std::runtime_error("missing required FR command (French title & developer)");
|
||||
}
|
||||
|
||||
if (specfile_data.german_title.empty()) {
|
||||
throw std::runtime_error("missing required GE command (German title & developer)");
|
||||
}
|
||||
|
||||
if (specfile_data.italian_title.empty()) {
|
||||
throw std::runtime_error("missing required IT command (Italian title & developer)");
|
||||
}
|
||||
|
||||
if (specfile_data.spanish_title.empty()) {
|
||||
throw std::runtime_error("missing required SP command (Spanish title & developer)");
|
||||
}
|
||||
|
||||
return specfile_data;
|
||||
}
|
||||
|
||||
IconBitmap GetIconBitmap(const filesystem::path& icon_bitmap_filename) {
|
||||
if (!filesystem::is_regular_file(icon_bitmap_filename)) {
|
||||
throw std::runtime_error("icon bitmap file '" + icon_bitmap_filename.string() + "' does not exist / is not a regular file");
|
||||
}
|
||||
|
||||
if (filesystem::file_size(icon_bitmap_filename) != ICON_BITMAP_SIZE) {
|
||||
throw std::runtime_error("icon bitmap is not 512 bytes");
|
||||
}
|
||||
|
||||
std::ifstream stream(icon_bitmap_filename, std::ios::binary);
|
||||
if (!stream.is_open()) {
|
||||
throw std::runtime_error("could not open icon bitmap file '" + icon_bitmap_filename.string() + "' for reading");
|
||||
}
|
||||
|
||||
IconBitmap bitmap = {};
|
||||
stream.read(reinterpret_cast<char*>(bitmap.data()), ICON_BITMAP_SIZE);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
IconPalette GetIconPalette(const filesystem::path& icon_palette_filename) {
|
||||
if (!filesystem::is_regular_file(icon_palette_filename)) {
|
||||
throw std::runtime_error("icon palette file '" + icon_palette_filename.string() + "' does not exist / is not a regular file");
|
||||
}
|
||||
|
||||
if (filesystem::file_size(icon_palette_filename) != ICON_PALETTE_SIZE) {
|
||||
throw std::runtime_error("icon palette is not 32 bytes");
|
||||
}
|
||||
|
||||
std::ifstream stream(icon_palette_filename, std::ios::binary);
|
||||
if (!stream.is_open()) {
|
||||
throw std::runtime_error("could not open icon palette file '" + icon_palette_filename.string() + "' for reading");
|
||||
}
|
||||
|
||||
IconPalette palette = {};
|
||||
stream.read(reinterpret_cast<char*>(palette.data()), ICON_PALETTE_SIZE);
|
||||
return palette;
|
||||
}
|
||||
|
||||
void OutputBanner(std::ofstream& ostream, const Banner& banner) {
|
||||
SerializeData<u16>(ostream, banner.version);
|
||||
SerializeData<u16>(ostream, banner.crc);
|
||||
|
||||
for ([[maybe_unused]] u16 i : banner.crc_padding) {
|
||||
SerializeData<u16>(ostream, 0);
|
||||
}
|
||||
|
||||
for ([[maybe_unused]] u8 i : banner.padding) {
|
||||
SerializeData<u8>(ostream, 0);
|
||||
}
|
||||
|
||||
for (u8 i : banner.bitmap) {
|
||||
SerializeData<u8>(ostream, i);
|
||||
}
|
||||
|
||||
for (u8 i : banner.palette) {
|
||||
SerializeData<u8>(ostream, i);
|
||||
}
|
||||
|
||||
for (char16_t c : banner.japanese_title) {
|
||||
SerializeData<u16>(ostream, c);
|
||||
}
|
||||
|
||||
for (char16_t c : banner.english_title) {
|
||||
SerializeData<u16>(ostream, c);
|
||||
}
|
||||
|
||||
for (char16_t c : banner.french_title) {
|
||||
SerializeData<u16>(ostream, c);
|
||||
}
|
||||
|
||||
for (char16_t c : banner.german_title) {
|
||||
SerializeData<u16>(ostream, c);
|
||||
}
|
||||
|
||||
for (char16_t c : banner.italian_title) {
|
||||
SerializeData<u16>(ostream, c);
|
||||
}
|
||||
|
||||
for (char16_t c : banner.spanish_title) {
|
||||
SerializeData<u16>(ostream, c);
|
||||
}
|
||||
}
|
||||
|
||||
bool MakeBanner(const filesystem::path& specfile_path, const filesystem::path& outfile_path) {
|
||||
std::ofstream ostream(outfile_path, std::ios::binary);
|
||||
if (!ostream.is_open()) {
|
||||
#ifdef _MSC_VER
|
||||
printf("error: could not open %ls for writing\n", outfile_path.c_str());
|
||||
#else
|
||||
printf("error: could not open %s for writing\n", outfile_path.c_str());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
SpecFileData specfile_data = {};
|
||||
try {
|
||||
specfile_data = ParseSpecFile(specfile_path);
|
||||
} catch (std::runtime_error& e) {
|
||||
printf("error: %s\n", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
Banner banner = {};
|
||||
|
||||
banner.version = specfile_data.version;
|
||||
banner.bitmap = GetIconBitmap(specfile_data.icon_bitmap_filename);
|
||||
banner.palette = GetIconPalette(specfile_data.icon_palette_filename);
|
||||
|
||||
std::copy(specfile_data.japanese_title.begin(), specfile_data.japanese_title.end(), banner.japanese_title.data());
|
||||
std::copy(specfile_data.english_title.begin(), specfile_data.english_title.end(), banner.english_title.data());
|
||||
std::copy(specfile_data.french_title.begin(), specfile_data.french_title.end(), banner.french_title.data());
|
||||
std::copy(specfile_data.german_title.begin(), specfile_data.german_title.end(), banner.german_title.data());
|
||||
std::copy(specfile_data.italian_title.begin(), specfile_data.italian_title.end(), banner.italian_title.data());
|
||||
std::copy(specfile_data.spanish_title.begin(), specfile_data.spanish_title.end(), banner.spanish_title.data());
|
||||
|
||||
// checksum the banner data, starting from the icon bitmap and ending at the end of the file.
|
||||
banner.crc = CalculateCRC16FromBannerData(banner.bitmap.data());
|
||||
|
||||
// check against diamond's icon crc
|
||||
// if (banner.crc != 0x048B) {
|
||||
// printf("CRC did not match (expected 0x048B, got 0x%04X)\n", banner.crc);
|
||||
// } else {
|
||||
// printf("CRC matched\n");
|
||||
// }
|
||||
|
||||
OutputBanner(ostream, banner);
|
||||
return true;
|
||||
}
|
61
tools/nitrobanner/banner.h
Normal file
61
tools/nitrobanner/banner.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include "types.h"
|
||||
|
||||
constexpr int TITLE_LENGTH = 0x100 / sizeof(u16); // 128 UTF-16 characters
|
||||
constexpr int ICON_BITMAP_SIZE = 0x200; // 512 bytes
|
||||
constexpr int ICON_PALETTE_SIZE = 0x20; // 32 bytes
|
||||
|
||||
struct SpecFileData {
|
||||
u16 version;
|
||||
std::wstring icon_bitmap_filename;
|
||||
std::wstring icon_palette_filename;
|
||||
std::u16string japanese_title;
|
||||
std::u16string english_title;
|
||||
std::u16string french_title;
|
||||
std::u16string german_title;
|
||||
std::u16string italian_title;
|
||||
std::u16string spanish_title;
|
||||
};
|
||||
|
||||
using IconBitmap = std::array<u8, ICON_BITMAP_SIZE>;
|
||||
using IconPalette = std::array<u8, ICON_PALETTE_SIZE>;
|
||||
|
||||
struct Banner {
|
||||
u16 version;
|
||||
u16 crc;
|
||||
const std::array<u16, 3> crc_padding {};
|
||||
const std::array<u8, 0x16> padding {};
|
||||
IconBitmap bitmap {};
|
||||
IconPalette palette {};
|
||||
std::array<u16, TITLE_LENGTH> japanese_title {};
|
||||
std::array<u16, TITLE_LENGTH> english_title {};
|
||||
std::array<u16, TITLE_LENGTH> french_title {};
|
||||
std::array<u16, TITLE_LENGTH> german_title {};
|
||||
std::array<u16, TITLE_LENGTH> italian_title {};
|
||||
std::array<u16, TITLE_LENGTH> spanish_title {};
|
||||
};
|
||||
static_assert(sizeof(Banner) == 0x840, "Size of banner struct is wrong");
|
||||
|
||||
template <typename T>
|
||||
void SerializeData(std::ofstream& ostream, T data);
|
||||
|
||||
void ProcessSpecFileCommand(SpecFileData& specfile_data, const std::wstring_view& command_name, const std::wstring_view& command_argument);
|
||||
SpecFileData ParseSpecFile(const std::filesystem::path& specfile_path);
|
||||
|
||||
IconBitmap GetIconBitmap(const std::filesystem::path& icon_bitmap_filename);
|
||||
IconPalette GetIconPalette(const std::filesystem::path& icon_palette_filename);
|
||||
|
||||
void OutputBanner(std::ofstream& ostream, const Banner& banner);
|
||||
bool MakeBanner(const std::filesystem::path& specfile_path, const std::filesystem::path& outfile_path);
|
||||
|
||||
inline bool CommandIsForTitleAndDeveloper(const std::wstring& command_name) {
|
||||
return command_name == L"JP" ||
|
||||
command_name == L"EN" ||
|
||||
command_name == L"FR" ||
|
||||
command_name == L"GE" ||
|
||||
command_name == L"IT" ||
|
||||
command_name == L"SP";
|
||||
}
|
22
tools/nitrobanner/crc16.cpp
Normal file
22
tools/nitrobanner/crc16.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <array>
|
||||
#include "banner.h"
|
||||
#include "crc16.h"
|
||||
|
||||
u16 CalculateCRC16FromBannerData(const u8* banner_data) {
|
||||
const std::array<u16, 16> crc_table = {
|
||||
0x0000, 0xCC01, 0xD801, 0x1400,
|
||||
0xF001, 0x3C00, 0x2800, 0xE401,
|
||||
0xA001, 0x6C00, 0x7800, 0xB401,
|
||||
0x5000, 0x9C01, 0x8801, 0x4400,
|
||||
};
|
||||
|
||||
u16 checksum = 0xFFFF;
|
||||
|
||||
const std::size_t data_size = sizeof(Banner) - offsetof(Banner, bitmap);
|
||||
for (std::size_t i = 0; i < data_size; i++) {
|
||||
u16 lookup_index = crc_table[banner_data[i] & 0xF] ^ (checksum >> 4) ^ crc_table[checksum & 0xF];
|
||||
checksum = crc_table[banner_data[i] >> 4] ^ (lookup_index >> 4) ^ crc_table[lookup_index & 0xF];
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
5
tools/nitrobanner/crc16.h
Normal file
5
tools/nitrobanner/crc16.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u16 CalculateCRC16FromBannerData(const u8* banner_data);
|
45
tools/nitrobanner/main.cpp
Normal file
45
tools/nitrobanner/main.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "banner.h"
|
||||
#include "types.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2 && argc != 3) {
|
||||
printf("usage: %s <specfile> [outfile]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const filesystem::path specfile_path = argv[1];
|
||||
if (!filesystem::is_regular_file(specfile_path)) {
|
||||
printf("error: provided specfile does not exist / is not a regular file. (did you put the right path?)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (specfile_path.extension() == ".bnr") {
|
||||
printf("error: can't use a bnr file as a specfile\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If the user doesn't provide a path to an outfile, or if the provided outfile is
|
||||
// identical to the provided specfile, use the specfile's name + the .bnr extension.
|
||||
filesystem::path outfile_path;
|
||||
if (argc == 2 || strcasecmp(argv[1], argv[2]) == 0) {
|
||||
outfile_path = specfile_path.stem().string() + ".bnr";
|
||||
} else {
|
||||
outfile_path = argv[2];
|
||||
}
|
||||
|
||||
// printf("debug: specfile: %s\n", specfile_path.c_str());
|
||||
// printf("debug: outfile: %s\n", outfile_path.c_str());
|
||||
|
||||
if (!MakeBanner(specfile_path, outfile_path)) {
|
||||
printf("error: failed to create banner file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
15
tools/nitrobanner/types.h
Normal file
15
tools/nitrobanner/types.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if (__GNUC__ <= 7) && !defined _MSC_VER
|
||||
#include <experimental/filesystem>
|
||||
namespace filesystem = std::experimental::filesystem;
|
||||
#else
|
||||
#include <filesystem>
|
||||
namespace filesystem = std::filesystem;
|
||||
#endif
|
||||
|
||||
using u8 = uint8_t;
|
||||
using u16 = uint16_t;
|
||||
using u32 = uint32_t;
|
Loading…
x
Reference in New Issue
Block a user