diff options
-rw-r--r-- | tools/knarc/Makefile | 4 | ||||
-rw-r--r-- | tools/knarc/Narc.cpp | 77 | ||||
-rw-r--r-- | tools/knarc/Narc.h | 22 | ||||
-rw-r--r-- | tools/knarc/fnmatch.c | 220 | ||||
-rw-r--r-- | tools/knarc/fnmatch.h | 70 |
5 files changed, 342 insertions, 51 deletions
diff --git a/tools/knarc/Makefile b/tools/knarc/Makefile index 62af834f..ef75789b 100644 --- a/tools/knarc/Makefile +++ b/tools/knarc/Makefile @@ -1,7 +1,7 @@ CXXFLAGS := -std=c++17 -O2 -Wall -Wno-switch -lstdc++fs -SRCS := Source.cpp Narc.cpp -HEADERS := Narc.h +SRCS := Source.cpp Narc.cpp fnmatch.c +HEADERS := Narc.h fnmatch.h .PHONY: all clean diff --git a/tools/knarc/Narc.cpp b/tools/knarc/Narc.cpp index 2faed98e..f299375f 100644 --- a/tools/knarc/Narc.cpp +++ b/tools/knarc/Narc.cpp @@ -6,6 +6,7 @@ #include <fstream> #include <iomanip> #include <ios> +#include <iostream> #include <map> #include <memory> #include <regex> @@ -13,10 +14,10 @@ #include <stack> #include <string> #include <vector> -#include <iostream> -#include <fnmatch.h> -#if __GNUC__ <= 7 +#include "fnmatch.h" + +#if (__GNUC__ <= 7) && !defined _MSC_VER #include <experimental/filesystem> namespace fs = std::experimental::filesystem; #else @@ -111,31 +112,31 @@ NarcError Narc::GetError() const class WildcardVector : public vector<string> { 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; - } + 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) @@ -158,11 +159,11 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) { ++directoryCounter; } - else if (keep_patterns.matches(de.path().filename()) || !ignore_patterns.matches(de.path().filename())) + 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 (debug) { + cerr << "DEBUG: adding file " << de.path() << endl; + } fatEntries.push_back(FileAllocationTableEntry { .Start = 0x0, @@ -198,7 +199,7 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) for (const auto& de : OrderedDirectoryIterator(directory, true)) { - if (!subTables.count(de.path().parent_path()) && (keep_patterns.matches(de.path().filename()) || !ignore_patterns.matches(de.path().filename()))) + 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()); @@ -213,7 +214,7 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) subTables[de.path().parent_path()] += (0xF000 + directoryCounter) & 0xFF; subTables[de.path().parent_path()] += (0xF000 + directoryCounter) >> 8; } - else if (keep_patterns.matches(de.path().filename()) || !ignore_patterns.matches(de.path().filename())) + else if (keep_patterns.matches(de.path().filename().string()) || !ignore_patterns.matches(de.path().filename().string())) { subTables[de.path().parent_path()] += static_cast<uint8_t>(de.path().filename().string().size()); subTables[de.path().parent_path()] += de.path().filename().string(); @@ -345,10 +346,10 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) continue; } - if (!(keep_patterns.matches(de.path().filename()) || !ignore_patterns.matches(de.path().filename()))) - { - 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); diff --git a/tools/knarc/Narc.h b/tools/knarc/Narc.h index 4516d2d5..ba97cbc9 100644 --- a/tools/knarc/Narc.h +++ b/tools/knarc/Narc.h @@ -5,7 +5,7 @@ #include <string> #include <vector> -#if __GNUC__ <= 7 +#if (__GNUC__ <= 7) && !defined _MSC_VER #include <experimental/filesystem> namespace fs = std::experimental::filesystem; #else @@ -75,19 +75,19 @@ struct FileImages class Narc { - public: - NarcError GetError() const; +public: + NarcError GetError() const; - bool Pack(const fs::path& fileName, const fs::path& directory); - bool Unpack(const fs::path& fileName, const fs::path& directory); + 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; +private: + NarcError error = NarcError::None; - void AlignDword(std::ofstream& ofs, uint8_t paddingChar); + void AlignDword(std::ofstream& ofs, uint8_t paddingChar); - bool Cleanup(std::ifstream& ifs, const NarcError& e); - bool Cleanup(std::ofstream& ofs, const NarcError& e); + bool Cleanup(std::ifstream& ifs, const NarcError& e); + bool Cleanup(std::ofstream& ofs, const NarcError& e); - std::vector<fs::directory_entry> OrderedDirectoryIterator(const fs::path& path, bool recursive) const; + std::vector<fs::directory_entry> OrderedDirectoryIterator(const fs::path& path, bool recursive) const; }; diff --git a/tools/knarc/fnmatch.c b/tools/knarc/fnmatch.c new file mode 100644 index 00000000..5ab452f0 --- /dev/null +++ b/tools/knarc/fnmatch.c @@ -0,0 +1,220 @@ +/* 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 <config.h> 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 <config.h> +#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 <ctype.h> + + /* 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 new file mode 100644 index 00000000..508c59a7 --- /dev/null +++ b/tools/knarc/fnmatch.h @@ -0,0 +1,70 @@ +/* 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 <unistd.h>. */ +#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 */ |