diff --git a/.gitignore b/.gitignore index e0ebefcd45..6e2c31d00a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ /subprojects/packagecache /subprojects/constgen/ /subprojects/SDATTool/ +/subprojects/knarc/ # CLion folders .idea/ diff --git a/subprojects/knarc.wrap b/subprojects/knarc.wrap new file mode 100644 index 0000000000..3298a6b854 --- /dev/null +++ b/subprojects/knarc.wrap @@ -0,0 +1,7 @@ +[wrap-git] +url = https://github.com/lhearachel/knarc.git +revision = head +depth = 1 + +[provide] +program_names = knarc diff --git a/tools/knarc/Narc.cpp b/tools/knarc/Narc.cpp deleted file mode 100644 index 0459409107..0000000000 --- a/tools/knarc/Narc.cpp +++ /dev/null @@ -1,720 +0,0 @@ -#include "Narc.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fnmatch.h" - -#if (__cplusplus < 201703L) -#include -namespace fs = std::experimental::filesystem; -#else -#include -namespace fs = std::filesystem; -#endif - -using namespace std; - -extern bool debug; -extern bool pack_no_fnt; -extern bool output_header; - -void Narc::AlignDword(ofstream& ofs, uint8_t paddingChar) -{ - if ((ofs.tellp() % 4) != 0) - { - for (int i = 4 - (ofs.tellp() % 4); i-- > 0; ) - { - ofs.write(reinterpret_cast(&paddingChar), sizeof(uint8_t)); - } - } -} - -bool Narc::Cleanup(ifstream& ifs, const NarcError& e) -{ - ifs.close(); - - error = e; - - return false; -} - -bool Narc::Cleanup(ofstream& ofs, const NarcError& e) -{ - ofs.close(); - - error = e; - - return false; -} - -std::vector Narc::KnarcOrderDirectoryIterator(const fs::path& path, bool recursive) const -{ - std::vector ordered_files; - std::vector unordered_files; - - // open the order file - if (fs::exists(path / ".knarcorder")) - { - std::ifstream order_file(path / ".knarcorder"); - if (order_file) - { - if (debug) - { - cerr << "DEBUG: knarcorder file exists" << endl; - } - // read the filenames in the order file and add the corresponding directory entries to the ordered files vector - std::string filename; - while (std::getline(order_file, filename)) - { - fs::path file_path = path / filename; - if (fs::exists(file_path)) - { - if (debug) - { - cerr << "DEBUG: knarcorder file: " << file_path << endl; - } - ordered_files.push_back(fs::directory_entry(file_path)); - } - } - } - } - - // if recursive flag is set, search for knarcorder files in subdirectories and process them recursively - if (recursive) - { - for (auto &entry : fs::directory_iterator(path)) - { - if (entry.is_directory()) - { - std::vector subdirectory_files = - KnarcOrderDirectoryIterator(entry.path(), true); - ordered_files.insert( - ordered_files.end(), subdirectory_files.begin(), subdirectory_files.end()); - } - } - } - - // add the remaining files in alphabetical order - for (auto& entry : fs::directory_iterator(path)) - { - if (entry.is_regular_file() && entry.path().filename() != ".knarcorder") - { - if (std::find(ordered_files.begin(), ordered_files.end(), entry) == ordered_files.end()) - { - unordered_files.push_back(entry); - } - } - } - std::sort(unordered_files.begin(), unordered_files.end(), - [](const fs::directory_entry& a, const fs::directory_entry& b) - { - // I fucking hate C++ - string aStr = a.path().filename().string(); - string bStr = b.path().filename().string(); - - for (size_t i = 0; i < aStr.size(); ++i) - { - aStr[i] = tolower(aStr[i]); - } - - for (size_t i = 0; i < bStr.size(); ++i) - { - bStr[i] = tolower(bStr[i]); - } - - return aStr < bStr; - }); - ordered_files.insert(ordered_files.end(), unordered_files.begin(), unordered_files.end()); - - return ordered_files; -} - -vector Narc::OrderedDirectoryIterator(const fs::path& path, bool recursive) const -{ - vector v; - - for (const auto& de : fs::directory_iterator(path)) - { - v.push_back(de); - } - - sort(v.begin(), v.end(), [](const fs::directory_entry& a, const fs::directory_entry& b) - { - // I fucking hate C++ - string aStr = a.path().filename().string(); - string bStr = b.path().filename().string(); - - for (size_t i = 0; i < aStr.size(); ++i) - { - aStr[i] = tolower(aStr[i]); - } - - for (size_t i = 0; i < bStr.size(); ++i) - { - bStr[i] = tolower(bStr[i]); - } - - return aStr < bStr; - }); - - if (recursive) - { - size_t vSize = v.size(); - - for (size_t i = 0; i < vSize; ++i) - { - if (is_directory(v[i])) - { - vector temp = OrderedDirectoryIterator(v[i], true); - - v.insert(v.end(), temp.begin(), temp.end()); - } - } - } - - return v; -} - -NarcError Narc::GetError() const -{ - return error; -} - -class WildcardVector : public vector { -public: - WildcardVector(fs::path fp) { - fstream infile; - if (!fs::exists(fp)) return; - infile.open(fp, ios_base::in); - string line; - while (getline(infile, line)) { - if (!line.empty()) - { - // strip CR - size_t i; - for (i = line.size() - 1; line[i] == '\r'; i--) - ; - if (i < line.size() - 1) - line.erase(i + 1); - push_back(line); - } - } - } - bool matches(string fp) { - for (string& pattern : *this) { - if (fnmatch(pattern.c_str(), fp.c_str(), FNM_PERIOD) == 0) - return true; - } - return false; - } -}; - -bool Narc::Pack(const fs::path& fileName, const fs::path& directory) -{ - ofstream ofs(fileName, ios::binary); - - if (!ofs.good()) { return Cleanup(ofs, NarcError::InvalidOutputFile); } - - ofstream ofhs; - string stem; - string stem_upper; - // Pikalax 29 May 2021 - // Output an includable header that enumerates the NARC contents - if (output_header) - { - fs::path naixfname = fileName; - naixfname.replace_extension(".naix"); - - ofhs.open(naixfname); - if (!ofhs.good()) - { - ofhs.close(); - return Cleanup(ofs, NarcError::InvalidOutputFile); - } - - stem = fileName.stem().string(); - stem_upper = stem; - for (char &c : stem_upper) - { c = toupper(c); } - - ofhs << "/*\n" - " * THIS FILE WAS AUTOMATICALLY\n" - " * GENERATED BY tools/knarc\n" - " * DO NOT MODIFY!!!\n" - " */\n" - "\n" - "#ifndef NARC_" << stem_upper << "_NAIX_\n" - "#define NARC_" << stem_upper << "_NAIX_\n" - "\n" - "enum {\n"; - } - vector fatEntries; - uint16_t directoryCounter = 1; - - WildcardVector ignore_patterns(directory / ".knarcignore"); - ignore_patterns.push_back(".*ignore"); - ignore_patterns.push_back(".*keep"); - ignore_patterns.push_back(".*order"); - WildcardVector keep_patterns(directory / ".knarckeep"); - - int memberNo = 0; - for (const auto& de : KnarcOrderDirectoryIterator(directory, true)) - { - if (is_directory(de)) - { - ++directoryCounter; - } - else if (keep_patterns.matches(de.path().filename().string()) || !ignore_patterns.matches(de.path().filename().string())) - { - if (debug) { - cerr << "DEBUG: adding file " << de.path() << endl; - } - if (output_header) - { - string de_stem = de.path().filename().string(); - std::replace(de_stem.begin(), de_stem.end(), '.', '_'); - ofhs << "\tNARC_" << stem << "_" << de_stem << " = " << (memberNo++) << ",\n"; - } - fatEntries.push_back(FileAllocationTableEntry - { - .Start = 0x0, - .End = 0x0 - }); - - if (fatEntries.size() > 1) - { - fatEntries.back().Start = fatEntries.rbegin()[1].End; - - if ((fatEntries.rbegin()[1].End % 4) != 0) - { - fatEntries.back().Start += 4 - (fatEntries.rbegin()[1].End % 4); - } - } - - fatEntries.back().End = fatEntries.back().Start + static_cast(file_size(de)); - } - } - if (output_header) - { - ofhs << "};\n\n#endif //NARC_" << stem_upper << "_NAIX_\n"; - ofhs.close(); - } - - FileAllocationTable fat - { - .Id = 0x46415442, // BTAF - .ChunkSize = static_cast(sizeof(FileAllocationTable) + ((uint32_t)fatEntries.size() * sizeof(FileAllocationTableEntry))), - .FileCount = static_cast(fatEntries.size()), - .Reserved = 0x0 - }; - - map subTables; - vector paths; - - directoryCounter = 0; - - for (const auto& de : KnarcOrderDirectoryIterator(directory, true)) - { - if (!subTables.count(de.path().parent_path()) && (keep_patterns.matches(de.path().filename().string()) || !ignore_patterns.matches(de.path().filename().string()))) - { - subTables.insert({ de.path().parent_path(), "" }); - paths.push_back(de.path().parent_path()); - } - - if (is_directory(de)) - { - ++directoryCounter; - - subTables[de.path().parent_path()] += static_cast(0x80 + de.path().filename().string().size()); - subTables[de.path().parent_path()] += de.path().filename().string(); - subTables[de.path().parent_path()] += (0xF000 + directoryCounter) & 0xFF; - subTables[de.path().parent_path()] += (0xF000 + directoryCounter) >> 8; - } - else if (keep_patterns.matches(de.path().filename().string()) || !ignore_patterns.matches(de.path().filename().string())) - { - subTables[de.path().parent_path()] += static_cast(de.path().filename().string().size()); - subTables[de.path().parent_path()] += de.path().filename().string(); - } - } - - for (auto& subTable : subTables) - { - subTable.second += '\0'; - } - - vector fntEntries; - - if (!pack_no_fnt) - { - fntEntries.push_back( - { - .Offset = static_cast((directoryCounter + 1) * sizeof(FileNameTableEntry)), - .FirstFileId = 0x0, - .Utility = static_cast(directoryCounter + 1) - }); - - for (uint16_t i = 0; i < directoryCounter; ++i) - { - fntEntries.push_back( - { - .Offset = static_cast(fntEntries.back().Offset + subTables[paths[i]].size()), - .FirstFileId = fntEntries.back().FirstFileId, - .Utility = 0x0 - }); - - for (size_t j = 0; j < (subTables[paths[i]].size() - 1); ++j) - { - if (static_cast(subTables[paths[i]][j]) <= 0x7F) - { - j += static_cast(subTables[paths[i]][j]); - ++fntEntries.back().FirstFileId; - } - else if (static_cast(subTables[paths[i]][j]) <= 0xFF) - { - j += static_cast(subTables[paths[i]][j]) - 0x80 + 0x2; - } - } - - fntEntries.back().Utility = 0xF000 + (find(paths.begin(), paths.end(), paths[i + 1].parent_path()) - paths.begin()); - } - } - else - { - fntEntries.push_back( - { - .Offset = 0x4, - .FirstFileId = 0x0, - .Utility = 0x1 - }); - } - - FileNameTable fnt - { - .Id = 0x464E5442, // BTNF - .ChunkSize = static_cast(sizeof(FileNameTable) + (fntEntries.size() * sizeof(FileNameTableEntry))) - }; - - if (!pack_no_fnt) - { - for (const auto& subTable : subTables) - { - fnt.ChunkSize += subTable.second.size(); - } - } - - if ((fnt.ChunkSize % 4) != 0) - { - fnt.ChunkSize += 4 - (fnt.ChunkSize % 4); - } - - FileImages fi - { - .Id = 0x46494D47, // GMIF - .ChunkSize = static_cast(sizeof(FileImages) + (fatEntries.empty() ? 0 : fatEntries.back().End)) - }; - - if ((fi.ChunkSize % 4) != 0) - { - fi.ChunkSize += 4 - (fi.ChunkSize % 4); - } - - Header header - { - .Id = 0x4352414E, // NARC - .ByteOrderMark = 0xFFFE, - .Version = 0x100, - .FileSize = static_cast(sizeof(Header) + fat.ChunkSize + fnt.ChunkSize + fi.ChunkSize), - .ChunkSize = sizeof(Header), - .ChunkCount = 0x3 - }; - - ofs.write(reinterpret_cast(&header), sizeof(Header)); - ofs.write(reinterpret_cast(&fat), sizeof(FileAllocationTable)); - - for (auto& entry : fatEntries) - { - ofs.write(reinterpret_cast(&entry), sizeof(FileAllocationTableEntry)); - } - - ofs.write(reinterpret_cast(&fnt), sizeof(FileNameTable)); - - for (auto& entry : fntEntries) - { - ofs.write(reinterpret_cast(&entry), sizeof(FileNameTableEntry)); - } - - if (!pack_no_fnt) - { - for (const auto& path : paths) - { - ofs << subTables[path]; - } - } - - AlignDword(ofs, 0xFF); - - ofs.write(reinterpret_cast(&fi), sizeof(FileImages)); - - for (const auto& de : KnarcOrderDirectoryIterator(directory, true)) - { - if (is_directory(de)) - { - continue; - } - - if (!(keep_patterns.matches(de.path().filename().string()) || !ignore_patterns.matches(de.path().filename().string()))) - { - continue; - } - - ifstream ifs(de.path(), ios::binary | ios::ate); - - if (!ifs.good()) - { - ifs.close(); - - return Cleanup(ofs, NarcError::InvalidInputFile); - } - - streampos length = ifs.tellg(); - unique_ptr buffer = make_unique(static_cast(length)); - - ifs.seekg(0); - ifs.read(buffer.get(), length); - ifs.close(); - - ofs.write(buffer.get(), length); - - AlignDword(ofs, 0xFF); - } - - ofs.close(); - - return error == NarcError::None ? true : false; -} - -bool Narc::Unpack(const fs::path& fileName, const fs::path& directory) -{ - ifstream ifs(fileName, ios::binary); - - if (!ifs.good()) { return Cleanup(ifs, NarcError::InvalidInputFile); } - - Header header; - ifs.read(reinterpret_cast(&header), sizeof(Header)); - - if (header.Id != 0x4352414E) { return Cleanup(ifs, NarcError::InvalidHeaderId); } - if (header.ByteOrderMark != 0xFFFE) { return Cleanup(ifs, NarcError::InvalidByteOrderMark); } - if ((header.Version != 0x0100) && (header.Version != 0x0000)) { return Cleanup(ifs, NarcError::InvalidVersion); } - if (header.ChunkSize != 0x10) { return Cleanup(ifs, NarcError::InvalidHeaderSize); } - if (header.ChunkCount != 0x3) { return Cleanup(ifs, NarcError::InvalidChunkCount); } - - FileAllocationTable fat; - ifs.read(reinterpret_cast(&fat), sizeof(FileAllocationTable)); - - if (fat.Id != 0x46415442) { return Cleanup(ifs, NarcError::InvalidFileAllocationTableId); } - if (fat.Reserved != 0x0) { return Cleanup(ifs, NarcError::InvalidFileAllocationTableReserved); } - - unique_ptr fatEntries = make_unique(fat.FileCount); - - for (uint16_t i = 0; i < fat.FileCount; ++i) - { - ifs.read(reinterpret_cast(&fatEntries.get()[i]), sizeof(FileAllocationTableEntry)); - } - - FileNameTable fnt; - vector FileNameTableEntries; - ifs.read(reinterpret_cast(&fnt), sizeof(FileNameTable)); - - if (fnt.Id != 0x464E5442) { return Cleanup(ifs, NarcError::InvalidFileNameTableId); } - - vector fntEntries; - - do - { - fntEntries.push_back(FileNameTableEntry()); - - ifs.read(reinterpret_cast(&fntEntries.back().Offset), sizeof(uint32_t)); - ifs.read(reinterpret_cast(&fntEntries.back().FirstFileId), sizeof(uint16_t)); - ifs.read(reinterpret_cast(&fntEntries.back().Utility), sizeof(uint16_t)); - } while (static_cast(ifs.tellg()) < (header.ChunkSize + fat.ChunkSize + sizeof(FileNameTable) + fntEntries[0].Offset)); - - unique_ptr fileNames = make_unique(0xFFFF); - - for (size_t i = 0; i < fntEntries.size(); ++i) - { - ifs.seekg(static_cast(header.ChunkSize) + fat.ChunkSize + sizeof(FileNameTable) + fntEntries[i].Offset); - - uint16_t fileId = 0x0000; - - for (uint8_t length = 0x80; length != 0x00; ifs.read(reinterpret_cast(&length), sizeof(uint8_t))) - { - if (length <= 0x7F) - { - for (uint8_t j = 0; j < length; ++j) - { - uint8_t c; - ifs.read(reinterpret_cast(&c), sizeof(uint8_t)); - - fileNames.get()[fntEntries[i].FirstFileId + fileId] += c; - } - - ++fileId; - } - else if (length == 0x80) - { - // Reserved - } - else if (length <= 0xFF) - { - length -= 0x80; - string directoryName; - - for (uint8_t j = 0; j < length; ++j) - { - uint8_t c; - ifs.read(reinterpret_cast(&c), sizeof(uint8_t)); - - directoryName += c; - } - - uint16_t directoryId; - ifs.read(reinterpret_cast(&directoryId), sizeof(uint16_t)); - - fileNames.get()[directoryId] = directoryName; - } - else - { - return Cleanup(ifs, NarcError::InvalidFileNameTableEntryId); - } - } - } - - if ((ifs.tellg() % 4) != 0) - { - ifs.seekg(4 - (ifs.tellg() % 4), ios::cur); - } - - FileImages fi; - ifs.read(reinterpret_cast(&fi), sizeof(FileImages)); - - if (fi.Id != 0x46494D47) { return Cleanup(ifs, NarcError::InvalidFileImagesId); } - - fs::create_directory(directory); - fs::current_path(directory); - - if (fnt.ChunkSize == 0x10) - { - for (uint16_t i = 0; i < fat.FileCount; ++i) - { - ifs.seekg(static_cast(header.ChunkSize) + fat.ChunkSize + fnt.ChunkSize + 8 + fatEntries.get()[i].Start); - - unique_ptr buffer = make_unique(fatEntries.get()[i].End - fatEntries.get()[i].Start); - ifs.read(buffer.get(), fatEntries.get()[i].End - fatEntries.get()[i].Start); - - ostringstream oss; - oss << fileName.stem().string() << "_" << setfill('0') << setw(8) << i << ".bin"; - - ofstream ofs(oss.str(), ios::binary); - - if (!ofs.good()) - { - ofs.close(); - - return Cleanup(ifs, NarcError::InvalidOutputFile); - } - - ofs.write(buffer.get(), fatEntries.get()[i].End - fatEntries.get()[i].Start); - ofs.close(); - } - } - else - { - fs::path absolutePath = fs::absolute(fs::current_path()); - - for (size_t i = 0; i < fntEntries.size(); ++i) - { - fs::current_path(absolutePath); - stack directories; - - for (uint16_t j = fntEntries[i].Utility; j > 0xF000; j = fntEntries[j - 0xF000].Utility) - { - directories.push(fileNames.get()[j]); - } - - for (; !directories.empty(); directories.pop()) - { - fs::create_directory(directories.top()); - fs::current_path(directories.top()); - } - - if (fntEntries[i].Utility >= 0xF000) - { - fs::create_directory(fileNames.get()[0xF000 + i]); - fs::current_path(fileNames.get()[0xF000 + i]); - } - - ifs.seekg(static_cast(header.ChunkSize) + fat.ChunkSize + sizeof(FileNameTable) + fntEntries[i].Offset); - - uint16_t fileId = 0x0000; - - for (uint8_t length = 0x80; length != 0x00; ifs.read(reinterpret_cast(&length), sizeof(uint8_t))) - { - if (length <= 0x7F) - { - streampos savedPosition = ifs.tellg(); - - ifs.seekg(static_cast(header.ChunkSize) + fat.ChunkSize + fnt.ChunkSize + 8 + fatEntries.get()[fntEntries[i].FirstFileId + fileId].Start); - - unique_ptr buffer = make_unique(fatEntries.get()[fntEntries[i].FirstFileId + fileId].End - fatEntries.get()[fntEntries[i].FirstFileId + fileId].Start); - ifs.read(buffer.get(), fatEntries.get()[fntEntries[i].FirstFileId + fileId].End - fatEntries.get()[fntEntries[i].FirstFileId + fileId].Start); - - ofstream ofs(fileNames.get()[fntEntries[i].FirstFileId + fileId], ios::binary); - - if (!ofs.good()) - { - ofs.close(); - - return Cleanup(ifs, NarcError::InvalidOutputFile); - } - - ofs.write(buffer.get(), fatEntries.get()[fntEntries[i].FirstFileId + fileId].End - fatEntries.get()[fntEntries[i].FirstFileId + fileId].Start); - ofs.close(); - - ifs.seekg(savedPosition); - ifs.seekg(length, ios::cur); - - ++fileId; - } - else if (length == 0x80) - { - // Reserved - } - else if (length <= 0xFF) - { - ifs.seekg(static_cast(length) - 0x80 + 0x2, ios::cur); - } - else - { - return Cleanup(ifs, NarcError::InvalidFileNameTableEntryId); - } - } - } - } - - ifs.close(); - - return error == NarcError::None ? true : false; -} diff --git a/tools/knarc/Narc.h b/tools/knarc/Narc.h deleted file mode 100644 index ed0504f90b..0000000000 --- a/tools/knarc/Narc.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#if (__cplusplus < 201703L) -#include -namespace fs = std::experimental::filesystem; -#else -#include -namespace fs = std::filesystem; -#endif - -enum class NarcError -{ - None, - InvalidInputFile, - InvalidHeaderId, - InvalidByteOrderMark, - InvalidVersion, - InvalidHeaderSize, - InvalidChunkCount, - InvalidFileAllocationTableId, - InvalidFileAllocationTableReserved, - InvalidFileNameTableId, - InvalidFileNameTableEntryId, - InvalidFileImagesId, - InvalidOutputFile -}; - -struct Header -{ - uint32_t Id; - uint16_t ByteOrderMark; - uint16_t Version; - uint32_t FileSize; - uint16_t ChunkSize; - uint16_t ChunkCount; -}; - -struct FileAllocationTable -{ - uint32_t Id; - uint32_t ChunkSize; - uint16_t FileCount; - uint16_t Reserved; -}; - -struct FileAllocationTableEntry -{ - uint32_t Start; - uint32_t End; -}; - -struct FileNameTable -{ - uint32_t Id; - uint32_t ChunkSize; -}; - -struct FileNameTableEntry -{ - uint32_t Offset; - uint16_t FirstFileId; - uint16_t Utility; -}; - -struct FileImages -{ - uint32_t Id; - uint32_t ChunkSize; -}; - -class Narc -{ -public: - NarcError GetError() const; - - bool Pack(const fs::path& fileName, const fs::path& directory); - bool Unpack(const fs::path& fileName, const fs::path& directory); - -private: - NarcError error = NarcError::None; - - void AlignDword(std::ofstream& ofs, uint8_t paddingChar); - - bool Cleanup(std::ifstream& ifs, const NarcError& e); - bool Cleanup(std::ofstream& ofs, const NarcError& e); - - std::vector KnarcOrderDirectoryIterator(const fs::path& path, bool recursive) const; - std::vector OrderedDirectoryIterator(const fs::path& path, bool recursive) const; -}; diff --git a/tools/knarc/Source.cpp b/tools/knarc/Source.cpp deleted file mode 100644 index 587c852752..0000000000 --- a/tools/knarc/Source.cpp +++ /dev/null @@ -1,150 +0,0 @@ -#include -#include -#include - -#include "Narc.h" - -using namespace std; - -bool debug = false; -bool pack_no_fnt = true; -bool output_header = false; - -void PrintError(NarcError error) -{ - switch (error) - { - case NarcError::None: cout << "ERROR: No error???" << endl; break; - case NarcError::InvalidInputFile: cout << "ERROR: Invalid input file" << endl; break; - case NarcError::InvalidHeaderId: cout << "ERROR: Invalid header ID" << endl; break; - case NarcError::InvalidByteOrderMark: cout << "ERROR: Invalid byte order mark" << endl; break; - case NarcError::InvalidVersion: cout << "ERROR: Invalid NARC version" << endl; break; - case NarcError::InvalidHeaderSize: cout << "ERROR: Invalid header size" << endl; break; - case NarcError::InvalidChunkCount: cout << "ERROR: Invalid chunk count" << endl; break; - case NarcError::InvalidFileAllocationTableId: cout << "ERROR: Invalid file allocation table ID" << endl; break; - case NarcError::InvalidFileAllocationTableReserved: cout << "ERROR: Invalid file allocation table reserved section" << endl; break; - case NarcError::InvalidFileNameTableId: cout << "ERROR: Invalid file name table ID" << endl; break; - case NarcError::InvalidFileNameTableEntryId: cout << "ERROR: Invalid file name table entry ID" << endl; break; - case NarcError::InvalidFileImagesId: cout << "ERROR: Invalid file images ID" << endl; break; - case NarcError::InvalidOutputFile: cout << "ERROR: Invalid output file" << endl; break; - default: cout << "ERROR: Unknown error???" << endl; break; - } -} - -static inline void usage() { - cout << "OVERVIEW: Knarc" << endl << endl; - cout << "USAGE: knarc [options] -d DIRECTORY [-p TARGET | -u SOURCE]" << endl << endl; - cout << "OPTIONS:" << endl; - cout << "\t-d DIRECTORY\tDirectory to pack from/unpack to" << endl; - cout << "\t-p TARGET\tPack to the target NARC" << endl; - cout << "\t-u SOURCE\tUnpack from the source NARC" << endl; - cout << "\t-n\tBuild the filename table (default: discards filenames)" << endl; - cout << "\t-D/--debug\tPrint additional debug messages" << endl; - cout << "\t-h/--help\tPrint this message and exit" << endl; - cout << "\t-i\tOutput a .naix header" << endl; -} - -int main(int argc, char* argv[]) -{ - string directory = ""; - string fileName = ""; - bool pack = false; - - for (int i = 1; i < argc; ++i) - { - if (!strcmp(argv[i], "-d")) - { - if (i == (argc - 1)) - { - cerr << "ERROR: No directory specified" << endl; - - return 1; - } - - if (!directory.empty()) { - cerr << "ERROR: Multiple directories specified" << endl; - return 1; - } - directory = argv[++i]; - } - else if (!strcmp(argv[i], "-p")) - { - if (i == (argc - 1)) - { - cerr << "ERROR: No NARC specified to pack to" << endl; - - return 1; - } - - if (!fileName.empty()) { - cerr << "ERROR: Multiple files specified" << endl; - return 1; - } - fileName = argv[++i]; - pack = true; - } - else if (!strcmp(argv[i], "-u")) - { - if (i == (argc - 1)) - { - cerr << "ERROR: No NARC specified to unpack from" << endl; - - return 1; - } - - if (!fileName.empty()) { - cerr << "ERROR: Multiple files specified" << endl; - return 1; - } - fileName = argv[++i]; - } else if (!strcmp(argv[i], "-D") || !strcmp(argv[i], "--debug")) { - debug = true; - } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - usage(); - return 0; - } - else if (!strcmp(argv[i], "-n")) { - pack_no_fnt = false; - } - else if (!strcmp(argv[i], "-i")) { - output_header = true; - } - else { - usage(); - cerr << "ERROR: Unrecognized argument: " << argv[i] << endl; - return 1; - } - } - - if (fileName.empty()) { - cerr << "ERROR: Missing -u or -p" << endl; - return 1; - } - if (directory.empty()) { - cerr << "ERROR: Missing -d" << endl; - return 1; - } - - Narc narc; - - if (pack) - { - if (!narc.Pack(fileName, directory)) - { - PrintError(narc.GetError()); - - return 1; - } - } - else - { - if (!narc.Unpack(fileName, directory)) - { - PrintError(narc.GetError()); - - return 1; - } - } - - return 0; -} diff --git a/tools/knarc/fnmatch.c b/tools/knarc/fnmatch.c deleted file mode 100644 index 6ba0a87100..0000000000 --- a/tools/knarc/fnmatch.c +++ /dev/null @@ -1,219 +0,0 @@ -/* Copyright (C) 1991-2018 Free Software Foundation, Inc. - -NOTE: This source is derived from an old version taken from the GNU C -Library (glibc). - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 51 Franklin Street - Fifth Floor, -Boston, MA 02110-1301, USA. */ - -#ifdef HAVE_CONFIG_H -#if defined (CONFIG_BROKETS) -/* We use instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ -#include -#else -#include "config.h" -#endif -#endif - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -/* This code to undef const added in libiberty. */ -#ifndef __STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - -#include "fnmatch.h" - -#include - - /* Comment out all this code if we are using the GNU C Library, and are not - actually compiling the library itself. This code is part of the GNU C - Library, but also included in many other GNU distributions. Compiling - and linking in this code is a waste when using the GNU C library - (especially if it is a shared library). Rather than having every GNU - program understand `configure --with-gnu-libc' and omit the object files, - it is simpler to just do this in the source for each such file. */ - -#if defined (_LIBC) || !defined (__GNU_LIBRARY__) - - -#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) -extern int errno; -#endif - -/* Match STRING against the filename pattern PATTERN, returning zero if - it matches, nonzero if not. */ -int -fnmatch(const char* pattern, const char* string, int flags) -{ - register const char* p = pattern, * n = string; - register unsigned char c; - -#define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) - - while ((c = *p++) != '\0') - { - c = FOLD(c); - - switch (c) - { - case '?': - if (*n == '\0') - return FNM_NOMATCH; - else if ((flags & FNM_FILE_NAME) && *n == '/') - return FNM_NOMATCH; - else if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) - return FNM_NOMATCH; - break; - - case '\\': - if (!(flags & FNM_NOESCAPE)) - { - c = *p++; - c = FOLD(c); - } - if (FOLD((unsigned char)*n) != c) - return FNM_NOMATCH; - break; - - case '*': - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) - return FNM_NOMATCH; - - for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) - if (((flags & FNM_FILE_NAME) && *n == '/') || - (c == '?' && *n == '\0')) - return FNM_NOMATCH; - - if (c == '\0') - return 0; - - { - unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; - c1 = FOLD(c1); - for (--p; *n != '\0'; ++n) - if ((c == '[' || FOLD((unsigned char)*n) == c1) && - fnmatch(p, n, flags & ~FNM_PERIOD) == 0) - return 0; - return FNM_NOMATCH; - } - - case '[': - { - /* Nonzero if the sense of the character class is inverted. */ - register int negate; - - if (*n == '\0') - return FNM_NOMATCH; - - if ((flags & FNM_PERIOD) && *n == '.' && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) - return FNM_NOMATCH; - - negate = (*p == '!' || *p == '^'); - if (negate) - ++p; - - c = *p++; - for (;;) - { - register unsigned char cstart = c, cend = c; - - if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; - - cstart = cend = FOLD(cstart); - - if (c == '\0') - /* [ (unterminated) loses. */ - return FNM_NOMATCH; - - c = *p++; - c = FOLD(c); - - if ((flags & FNM_FILE_NAME) && c == '/') - /* [/] can never match. */ - return FNM_NOMATCH; - - if (c == '-' && *p != ']') - { - cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == '\\') - cend = *p++; - if (cend == '\0') - return FNM_NOMATCH; - cend = FOLD(cend); - - c = *p++; - } - - if (FOLD((unsigned char)*n) >= cstart - && FOLD((unsigned char)*n) <= cend) - goto matched; - - if (c == ']') - break; - } - if (!negate) - return FNM_NOMATCH; - break; - - matched:; - /* Skip the rest of the [...] that already matched. */ - while (c != ']') - { - if (c == '\0') - /* [... (unterminated) loses. */ - return FNM_NOMATCH; - - c = *p++; - if (!(flags & FNM_NOESCAPE) && c == '\\') - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; - } - if (negate) - return FNM_NOMATCH; - } - break; - - default: - if (c != FOLD((unsigned char)*n)) - return FNM_NOMATCH; - } - - ++n; - } - - if (*n == '\0') - return 0; - - if ((flags & FNM_LEADING_DIR) && *n == '/') - /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ - return 0; - - return FNM_NOMATCH; -} - -#endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/tools/knarc/fnmatch.h b/tools/knarc/fnmatch.h deleted file mode 100644 index 508c59a770..0000000000 --- a/tools/knarc/fnmatch.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 1991-2020 Free Software Foundation, Inc. - -NOTE: The canonical source of this file is maintained with the GNU C Library. -Bugs can be reported to bug-glibc@prep.ai.mit.edu. - -This program is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 2, or (at your option) any -later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, 51 Franklin Street - Fifth Floor, -Boston, MA 02110-1301, USA. */ - -#ifndef _FNMATCH_H - -#define _FNMATCH_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) -#undef __P -#define __P(args) args -#else /* Not C++ or ANSI C. */ -#undef __P -#define __P(args) () - /* We can get away without defining `const' here only because in this file - it is used only inside the prototype for `fnmatch', which is elided in - non-ANSI C where `const' is problematical. */ -#endif /* C++ or ANSI C. */ - - - /* We #undef these before defining them because some losing systems - (HP-UX A.08.07 for example) define these in . */ -#undef FNM_PATHNAME -#undef FNM_NOESCAPE -#undef FNM_PERIOD - - /* Bits set in the FLAGS argument to `fnmatch'. */ -#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ -#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ -#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ - -#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) -#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ -#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ -#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ -#endif - -/* Value returned by `fnmatch' if STRING does not match PATTERN. */ -#define FNM_NOMATCH 1 - -/* Match STRING against the filename pattern PATTERN, - returning zero if it matches, FNM_NOMATCH if not. */ - extern int fnmatch __P((const char* __pattern, const char* __string, - int __flags)); - -#ifdef __cplusplus -} -#endif - -#endif /* fnmatch.h */ diff --git a/tools/knarc/meson.build b/tools/knarc/meson.build deleted file mode 100644 index c1d55c00ef..0000000000 --- a/tools/knarc/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -c_srcs = [] - -if build_machine.system() == 'windows' - c_srcs += 'fnmatch.c' -endif - -cpp_scrs = [ - 'Source.cpp', - 'Narc.cpp' -] - -knarc_exe = executable('knarc', - sources: [ - c_srcs, - cpp_scrs - ], - cpp_args: '-std=c++17', - native: true -) diff --git a/tools/meson.build b/tools/meson.build index a34dc0eb65..5e8b8b52c2 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -2,7 +2,6 @@ subdir('csv2bin') subdir('fixrom') subdir('json2bin') -subdir('knarc') subdir('msgenc') subdir('postconf') subdir('scripts') @@ -23,6 +22,8 @@ if not nitrogfx_exe.found() nitrogfx_exe = find_program('nitrogfx', native: true) endif +knarc_exe = find_program('knarc', native: true) + constgen_py = find_program('constgen_py', native: true, required: false) if not constgen_py.found() subproject('constgen')