diff options
| author | EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com> | 2021-11-27 20:06:29 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-27 15:06:29 -0500 |
| commit | 0966109a1402ac4a070345f9e151b93064d09fc9 (patch) | |
| tree | 58043fa7bd894bb57a61d843bca9e99492387df4 | |
| parent | 6948306d97a8d87c5ecae23c409894383badfe67 (diff) | |
Warning system (#189)
* first draft
* take vt.h from mm repo
* Colors
* Fix argument types
* Add argument parser to errorhandler
* Rename ErrorHandler to WarningHandler
* Add -Wno- and more warning types
* header and body in warnings
* Small cleanup
* Replace a bunch of warnings with the new system
Co-authored-by: EllipticEllipsis <EllipticEllipsis@users.noreply.github.com>
* Move stuff around
* Move stuff to header
* Make some more VT macros, new Warning_Build function + macro, ZBackground
* Add remaining warnings
* Add ZResource* param to Warning_Resource
* Add warning help message
* Simplify help message a bit
* Refactor warnings into lots of helper functions
* Fix HANG_INDT in the wild
* Builds now
* Update macros to use bold
* Fix body printing and error colour
* Add -Werror=
* Add warningType to HANDLE_ERROR
* Change some throws into HANDLE_ERROR
* Create init and main maps and write new help printer
* Changed ZTextureAnimation to new w/e
* Typo
* Delete build warnings list file
* Use ERROR in ZResource and ZPath
* Remove extra structs
* Move ifdef into the InitMap, add descriptions
* Actually move into initMap and add descriptions...
* Remove Everything from the WarningType enum
* Make more of the handler arguments const for compatibility
* Fix warning
* Document macros a bit
* Add ImageBackend ERRRORs
* Note on Weverything, rename InvalidData to InvalidExtractedData
* add texture and mesh warnings/errors
* InvalidExtractedData
* Add description for InvalidPNG
* print which warnings are enabled by using debug verbosity
* Fix everything
* Fix some newlines
* Move help to the end, start some documentation
* Remove unnecessary `WarningHandler::`s
* Remove commented code
* Some more documentation
* Make first letters consistenty lowercase, more docs
* Consistently use lowercase, more docs
* Format consistently, more detail in documentation
* Simplify enabled warnings checks
* Rename HANDLE_WARNING_BUILD and add HANDLE_ERROR_PROCESS
* Delete BuildInfo.cpp
* Use PROCESS where possible, bit more documentation
* Add documenation to README, sort when printing help
* Add an example, escalate the rest of the invalids by default
* Format warning names in table
* format readme
* Remove old flags info
* Remove obsolete variables
* Format
* assert.h -> cassert
* Replace some asserts in ZTexture
* Remove test file
* Minor cleanup
* Bit more in the help
* Fix header includes
* Format
* One character in readme
* Update README.md
Co-authored-by: Anghelo Carvajal <angheloalf95@gmail.com>
* Some Morita inspiration
* Convert new errors
* Static warnings/errors
* Merge remote-tracking branch 'upstream/master' into errorlib
* Add explanation for switch control flow
* format
* whooops
* Fix segment warning that doesn't apply now we assume no segment means use VRAM
* Comment out MM in Jenkinsfile
Co-authored-by: Angie <angheloalf95@gmail.com>
Co-authored-by: EllipticEllipsis <EllipticEllipsis@users.noreply.github.com>
53 files changed, 1124 insertions, 452 deletions
diff --git a/ExporterTest/Main.cpp b/ExporterTest/Main.cpp index 4f683a1..07fdbee 100644 --- a/ExporterTest/Main.cpp +++ b/ExporterTest/Main.cpp @@ -1,7 +1,7 @@ -#include <CollisionExporter.h> -#include <Globals.h> -#include <RoomExporter.h> -#include <TextureExporter.h> +#include "CollisionExporter.h" +#include "Globals.h" +#include "RoomExporter.h" +#include "TextureExporter.h" enum class ExporterFileMode { diff --git a/ExporterTest/RoomExporter.cpp b/ExporterTest/RoomExporter.cpp index c4a6844..6c5552d 100644 --- a/ExporterTest/RoomExporter.cpp +++ b/ExporterTest/RoomExporter.cpp @@ -1,24 +1,24 @@ #include "RoomExporter.h" -#include <CollisionExporter.h> -#include <Utils/BinaryWriter.h> -#include <Utils/File.h> -#include <Utils/MemoryStream.h> -#include <ZRoom/Commands/SetCameraSettings.h> -#include <ZRoom/Commands/SetCollisionHeader.h> -#include <ZRoom/Commands/SetCsCamera.h> -#include <ZRoom/Commands/SetEchoSettings.h> -#include <ZRoom/Commands/SetEntranceList.h> -#include <ZRoom/Commands/SetLightingSettings.h> -#include <ZRoom/Commands/SetMesh.h> -#include <ZRoom/Commands/SetRoomBehavior.h> -#include <ZRoom/Commands/SetRoomList.h> -#include <ZRoom/Commands/SetSkyboxModifier.h> -#include <ZRoom/Commands/SetSkyboxSettings.h> -#include <ZRoom/Commands/SetSoundSettings.h> -#include <ZRoom/Commands/SetSpecialObjects.h> -#include <ZRoom/Commands/SetStartPositionList.h> -#include <ZRoom/Commands/SetTimeSettings.h> -#include <ZRoom/Commands/SetWind.h> +#include "CollisionExporter.h" +#include "Utils/BinaryWriter.h" +#include "Utils/File.h" +#include "Utils/MemoryStream.h" +#include "ZRoom/Commands/SetCameraSettings.h" +#include "ZRoom/Commands/SetCollisionHeader.h" +#include "ZRoom/Commands/SetCsCamera.h" +#include "ZRoom/Commands/SetEchoSettings.h" +#include "ZRoom/Commands/SetEntranceList.h" +#include "ZRoom/Commands/SetLightingSettings.h" +#include "ZRoom/Commands/SetMesh.h" +#include "ZRoom/Commands/SetRoomBehavior.h" +#include "ZRoom/Commands/SetRoomList.h" +#include "ZRoom/Commands/SetSkyboxModifier.h" +#include "ZRoom/Commands/SetSkyboxSettings.h" +#include "ZRoom/Commands/SetSoundSettings.h" +#include "ZRoom/Commands/SetSpecialObjects.h" +#include "ZRoom/Commands/SetStartPositionList.h" +#include "ZRoom/Commands/SetTimeSettings.h" +#include "ZRoom/Commands/SetWind.h" void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter* writer) { diff --git a/ExporterTest/TextureExporter.h b/ExporterTest/TextureExporter.h index ffe6001..41c4e79 100644 --- a/ExporterTest/TextureExporter.h +++ b/ExporterTest/TextureExporter.h @@ -1,6 +1,6 @@ #pragma once -#include <Utils/BinaryWriter.h> +#include "Utils/BinaryWriter.h" #include "ZResource.h" #include "ZTexture.h" diff --git a/Jenkinsfile b/Jenkinsfile index 051e5f9..a12f30a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,13 +22,13 @@ pipeline { } } - stage('Checkout mm') { - steps{ - dir('mm') { - git url: 'https://github.com/zeldaret/mm.git' - } - } - } + // stage('Checkout mm') { + // steps{ + // dir('mm') { + // git url: 'https://github.com/zeldaret/mm.git' + // } + // } + // } } } @@ -51,20 +51,20 @@ pipeline { } } - stage('Setup MM') { - steps { - dir('mm') { - sh 'cp /usr/local/etc/roms/mm.us.rev1.z64 baserom.mm.us.rev1.z64' + // stage('Setup MM') { + // steps { + // dir('mm') { + // sh 'cp /usr/local/etc/roms/mm.us.rev1.z64 baserom.mm.us.rev1.z64' - // Identical to `make setup` except for copying our newer ZAPD.out into mm - sh 'make -C tools' - sh 'cp ../ZAPD.out tools/ZAPD/' - sh 'python3 tools/fixbaserom.py' - sh 'python3 tools/extract_baserom.py' - sh 'python3 extract_assets.py -t 4' - } - } - } + // // Identical to `make setup` except for copying our newer ZAPD.out into mm + // sh 'make -C tools' + // sh 'cp ../ZAPD.out tools/ZAPD/' + // sh 'python3 tools/fixbaserom.py' + // sh 'python3 tools/extract_baserom.py' + // sh 'python3 extract_assets.py -t 4' + // } + // } + // } } } @@ -78,14 +78,14 @@ pipeline { } } } - stage('Build mm') { - steps { - dir('mm') { - sh 'make -j disasm' - sh 'make -j all' - } - } - } + // stage('Build mm') { + // steps { + // dir('mm') { + // sh 'make -j disasm' + // sh 'make -j all' + // } + // } + // } } } } @@ -109,11 +109,51 @@ ZAPD also accepts the following list of extra parameters: - Could be useful for looking at raw data or testing. - Can be used only in `e` or `bsf` modes. - `-tm MODE`: Test Mode (enables certain experimental features). To enable it, set `MODE` to `1`. -- `-wno` / `--warn-no-offsets` : Enable warnings for nodes that dont have offsets specified. Takes priority over `-eno`/ `--error-no-offsets`. -- `-eno` / `--error-no-offsets` : Enable errors for nodes that dont have offsets specified. - `-se` / `--set-exporter` : Sets which exporter to use. -- `--gcc-compat` : Enables GCC compatible mode. Slower. +- `--gcc-compat` : Enables GCC compatibly mode. Slower. - `-s` / `--static` : Mark every asset as `static`. - This behaviour can be overridden per asset using `Static=` in the respective XML node. +- `-W...`: warning flags, see below Additionally, you can pass the flag `--version` to see the current ZAPD version. If that flag is passed, ZAPD will ignore any other parameter passed. + +### Warning flags + +ZAPD contains a variety of warning types, with similar syntax to GCC or Clang's compiler warnings. Warnings can have three levels: + +- Off (does not display anything) +- Warn (print a warning but continue processing) +- Err (behave like an error, i.e. print and throw an exception to crash ZAPD when occurs) + +Each warning type uses one of these by default, but can be modified with flags, similarly to GCC or Clang: + +- `-Wfoo` enables warnings of type `foo` +- `-Wno-foo` disables warnings of type `foo` +- `-Werror=foo` escalates `foo` to behave like an error +- `-Weverything` enables all warnings (they may be turned off using `-Wno-` flags afterwards) +- `-Werror` escalates all enabled warnings to errors + +All warning types currently implemented, with their default levels: + +| Warning type | Default level | Description | +| --------------------------- | ------------- | ------------------------------------------------------------------------ | +| `-Wdeprecated` | Warn | Deprecated features | +| `-Whardcoded-pointer` | Warn | ZAPD lacks the info to make a symbol, so must output a hardcoded pointer | +| `-Wintersection` | Warn | Two assets intersect | +| `-Winvalid-attribute-value` | Err | Attribute declared in XML is wrong | +| `-Winvalid-extracted-data` | Err | Extracted data does not have correct form | +| `-Winvalid-jpeg` | Err | JPEG file does not conform to the game's format requirements | +| `-Winvalid-png` | Err | Issues arising when processing PNG data | +| `-Winvalid-xml` | Err | XML has syntax errors | +| `-Wmissing-attribute` | Warn | Required attribute missing in XML tag | +| `-Wmissing-offsets` | Warn | Offset attribute missing in XML tag | +| `-Wmissing-segment` | Warn | Segment not given in File tag in XML | +| `-Wnot-implemented` | Warn | ZAPD does not currently support this feature | +| `-Wunaccounted` | Off | Large blocks of unaccounted | +| `-Wunknown-attribute` | Warn | Unknown attribute in XML entry tag | + +There are also errors that do not have a type, and cannot be disabled. + +For example, here we have invoked ZAPD in the usual way to extract using a (rather badly-written) XML, but escalating `-Wintersection` to an error: + + diff --git a/ZAPD/Declaration.h b/ZAPD/Declaration.h index bc8b694..b7bb0d3 100644 --- a/ZAPD/Declaration.h +++ b/ZAPD/Declaration.h @@ -43,7 +43,7 @@ public: bool isArray = false; bool forceArrayCnt = false; size_t arrayItemCnt = 0; - std::string arrayItemCntStr; + std::string arrayItemCntStr = ""; std::vector<segptr_t> references; bool isUnaccounted = false; bool isPlaceholder = false; diff --git a/ZAPD/Globals.cpp b/ZAPD/Globals.cpp index 036e4a5..528a09d 100644 --- a/ZAPD/Globals.cpp +++ b/ZAPD/Globals.cpp @@ -3,8 +3,9 @@ #include <algorithm> #include <string_view> -#include <Utils/File.h> -#include <Utils/Path.h> +#include "Utils/File.h" +#include "Utils/Path.h" +#include "WarningHandler.h" #include "tinyxml2.h" Globals* Globals::Instance; diff --git a/ZAPD/Globals.h b/ZAPD/Globals.h index 265f1af..31c9d6a 100644 --- a/ZAPD/Globals.h +++ b/ZAPD/Globals.h @@ -53,9 +53,6 @@ public: TextureType texType; ZGame game; GameConfig cfg; - bool warnUnaccounted = false; - bool warnNoOffset = false; - bool errorNoOffset = false; bool verboseUnaccounted = false; bool gccCompat = false; bool forceStatic = false; diff --git a/ZAPD/ImageBackend.cpp b/ZAPD/ImageBackend.cpp index 137e326..8accb6b 100644 --- a/ZAPD/ImageBackend.cpp +++ b/ZAPD/ImageBackend.cpp @@ -6,6 +6,7 @@ #include <stdexcept> #include "Utils/StringHelper.h" +#include "WarningHandler.h" /* ImageBackend */ @@ -20,19 +21,28 @@ void ImageBackend::ReadPng(const char* filename) FILE* fp = fopen(filename, "rb"); if (fp == nullptr) - throw std::runtime_error(StringHelper::Sprintf( - "ImageBackend::ReadPng: Error.\n\t Couldn't open file '%s'.", filename)); + { + std::string errorHeader = StringHelper::Sprintf("could not open file '%s'", filename); + HANDLE_ERROR(WarningType::InvalidPNG, errorHeader, ""); + } png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png) - throw std::runtime_error("ImageBackend::ReadPng: Error.\n\t Couldn't create png struct."); + if (png == nullptr) + { + HANDLE_ERROR(WarningType::InvalidPNG, "could not create png struct", ""); + } png_infop info = png_create_info_struct(png); - if (!info) - throw std::runtime_error("ImageBackend::ReadPng: Error.\n\t Couldn't create png info."); + if (info == nullptr) + { + HANDLE_ERROR(WarningType::InvalidPNG, "could not create png info", ""); + } if (setjmp(png_jmpbuf(png))) - throw std::runtime_error("ImageBackend::ReadPng: Error.\n\t setjmp(png_jmpbuf(png))."); + { + // TODO: better warning explanation + HANDLE_ERROR(WarningType::InvalidPNG, "setjmp(png_jmpbuf(png))", ""); + } png_init_io(png, fp); @@ -145,20 +155,30 @@ void ImageBackend::WritePng(const char* filename) assert(hasImageData); FILE* fp = fopen(filename, "wb"); - if (!fp) - throw std::runtime_error(StringHelper::Sprintf( - "ImageBackend::WritePng: Error.\n\t Couldn't open file '%s' in write mode.", filename)); + if (fp == nullptr) + { + std::string errorHeader = + StringHelper::Sprintf("could not open file '%s' in write mode", filename); + HANDLE_ERROR(WarningType::InvalidPNG, errorHeader, ""); + } png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png) - throw std::runtime_error("ImageBackend::WritePng: Error.\n\t Couldn't create png struct."); + if (png == nullptr) + { + HANDLE_ERROR(WarningType::InvalidPNG, "could not create png struct", ""); + } png_infop info = png_create_info_struct(png); - if (!info) - throw std::runtime_error("ImageBackend::WritePng: Error.\n\t Couldn't create png info."); + if (info == nullptr) + { + HANDLE_ERROR(WarningType::InvalidPNG, "could not create png info", ""); + } if (setjmp(png_jmpbuf(png))) - throw std::runtime_error("ImageBackend::WritePng: Error.\n\t setjmp(png_jmpbuf(png))."); + { + // TODO: better warning description + HANDLE_ERROR(WarningType::InvalidPNG, "setjmp(png_jmpbuf(png))", ""); + } png_init_io(png, fp); @@ -441,7 +461,7 @@ double ImageBackend::GetBytesPerPixel() const return 1 * bitDepth / 8; default: - throw std::invalid_argument("ImageBackend::GetBytesPerPixel():\n\t Invalid color type."); + HANDLE_ERROR(WarningType::InvalidPNG, "invalid color type", ""); } } diff --git a/ZAPD/Main.cpp b/ZAPD/Main.cpp index 298ca02..7f2854a 100644 --- a/ZAPD/Main.cpp +++ b/ZAPD/Main.cpp @@ -1,8 +1,9 @@ -#include <Utils/Directory.h> -#include <Utils/File.h> -#include <Utils/Path.h> #include "Globals.h" #include "Overlays/ZOverlay.h" +#include "Utils/Directory.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "WarningHandler.h" #include "ZAnimation.h" #include "ZBackground.h" #include "ZBlob.h" @@ -12,10 +13,10 @@ #if !defined(_MSC_VER) && !defined(__CYGWIN__) #include <csignal> #include <cstdlib> +#include <ctime> #include <cxxabi.h> // for __cxa_demangle #include <dlfcn.h> // for dladdr #include <execinfo.h> -#include <time.h> #include <unistd.h> #endif @@ -97,6 +98,9 @@ int main(int argc, char* argv[]) return 1; } + Globals* g = new Globals(); + WarningHandler::Init(argc, argv); + for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--version")) @@ -109,12 +113,12 @@ int main(int argc, char* argv[]) printf("Congratulations!\n"); printf("You just found the (unimplemented and undocumented) ZAPD's help message.\n"); printf("Feel free to implement it if you want :D\n"); + + WarningHandler::PrintHelp(); return 0; } } - Globals* g = new Globals; - // Parse other "commands" for (int32_t i = 2; i < argc; i++) { @@ -186,26 +190,15 @@ int main(int argc, char* argv[]) signal(SIGSEGV, ErrorHandler); signal(SIGABRT, ErrorHandler); #else - fprintf(stderr, - "Warning: Tried to set error handler, but this build lacks support for one.\n"); + HANDLE_WARNING(WarningType::Always, + "tried to set error handler, but this ZAPD build lacks support for one", + ""); #endif } else if (arg == "-v") // Verbose { Globals::Instance->verbosity = static_cast<VerbosityLevel>(strtol(argv[++i], NULL, 16)); } - else if (arg == "-wu" || arg == "--warn-unaccounted") // Warn unaccounted - { - Globals::Instance->warnUnaccounted = true; - } - else if (arg == "-wno" || arg == "--warn-no-offset") - { - Globals::Instance->warnNoOffset = true; - } - else if (arg == "-eno" || arg == "--error-no-offset") - { - Globals::Instance->errorNoOffset = true; - } else if (arg == "-vu" || arg == "--verbose-unaccounted") // Verbose unaccounted { Globals::Instance->verboseUnaccounted = true; @@ -262,6 +255,11 @@ int main(int argc, char* argv[]) if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) printf("ZAPD: Zelda Asset Processor For Decomp: %s\n", gBuildHash); + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) + { + WarningHandler::PrintWarningsDebugInfo(); + } + // TODO: switch if (fileMode == ZFileMode::Extract || fileMode == ZFileMode::BuildSourceFile) { @@ -334,7 +332,9 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path if (eResult != tinyxml2::XML_SUCCESS) { - fprintf(stderr, "Invalid xml file: '%s'\n", xmlFilePath.c_str()); + // TODO: use XMLDocument::ErrorIDToName to get more specific error messages here + HANDLE_ERROR(WarningType::InvalidXML, + StringHelper::Sprintf("invalid XML file: '%s'", xmlFilePath.c_str()), ""); return false; } @@ -342,7 +342,9 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path if (root == nullptr) { - fprintf(stderr, "Missing Root tag in xml file: '%s'\n", xmlFilePath.c_str()); + HANDLE_WARNING( + WarningType::InvalidXML, + StringHelper::Sprintf("missing Root tag in xml file: '%s'", xmlFilePath.c_str()), ""); return false; } @@ -392,10 +394,11 @@ bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path } else { - throw std::runtime_error(StringHelper::Sprintf( - "Parse: Fatal error in '%s'.\n\t A resource was found outside of " - "a File element: '%s'\n", - xmlFilePath.c_str(), child->Name())); + std::string errorHeader = + StringHelper::Sprintf("when parsing file '%s'", xmlFilePath.c_str()); + std::string errorBody = StringHelper::Sprintf( + "Found a resource outside a File element: '%s'", child->Name()); + HANDLE_ERROR(WarningType::InvalidXML, errorHeader, errorBody); } } diff --git a/ZAPD/Overlays/ZOverlay.cpp b/ZAPD/Overlays/ZOverlay.cpp index a842a7e..e5e795e 100644 --- a/ZAPD/Overlays/ZOverlay.cpp +++ b/ZAPD/Overlays/ZOverlay.cpp @@ -1,13 +1,13 @@ #include "ZOverlay.h" -#include <assert.h> +#include <cassert> #include <unordered_set> - -#include <Utils/Directory.h> -#include <Utils/File.h> -#include <Utils/Path.h> -#include <Utils/StringHelper.h> #include "Globals.h" +#include "Utils/Directory.h" +#include "Utils/File.h" +#include "Utils/Path.h" +#include "Utils/StringHelper.h" +#include "WarningHandler.h" using namespace ELFIO; @@ -128,7 +128,9 @@ ZOverlay* ZOverlay::FromBuild(fs::path buildPath, fs::path cfgFolderPath) SectionType sectionType = GetSectionTypeFromStr(pSec->get_name()); if (sectionType == SectionType::ERROR) - fprintf(stderr, "WARNING: One of the section types returned ERROR\n"); + { + HANDLE_WARNING(WarningType::Always, "one of the section types returned ERROR", ""); + } relocation_section_accessor relocs(*curReader, pSec); for (Elf_Xword j = 0; j < relocs.get_entries_num(); j++) diff --git a/ZAPD/WarningHandler.cpp b/ZAPD/WarningHandler.cpp new file mode 100644 index 0000000..f672600 --- /dev/null +++ b/ZAPD/WarningHandler.cpp @@ -0,0 +1,443 @@ +/** + * ZAPD Warning- and Error-handling system + * ======================================= + * + * This provides a common standard way to write ZAPD warnings/errors, which should be used for all + * such. It will pretty-print them in a uniform way, with styles defined in the header. + * + * Warnings/errors should be constructed using the macros given in the header; there are now plenty + * of examples in the codebase of how to do this. Their purposes are noted above each category in + * the header. Each warning has a type, one of the ones in warningStringToInitMap, or + * WarningType::Always, which is used for warnings that cannot be disabled and do not display a + * type. + * + * Currently there are three levels of alert a warning can have: + * - Off (does not display anything) + * - Warn (print a warning but continue processing) + * - Err (behave like an error, i.e. print and throw an exception to crash ZAPD when occurs) + * + * Flag use: + * - -Wfoo enables warnings of type foo + * - -Wno-foo disables warnings of type foo + * - -Werror=foo escalates foo to behave like an error + * - -Weverything enables all warnings + * - -Werror escalates all enabled warnings to errors + * + * Errors do not have types, and will always throw an exception; they cannot be disabled. + * + * Format + * === + * Each printed warning/error contains the same three sections: + * - Preamble: automatically generated; the content varies depending on category. It will print the + * file and function that the warning is from, and information about the files being processed + * or extracted. + * - Header: begins with 'warning: ' or 'error:', should contain essential information about the + * warning/error, ends with the warning type if applicable. Printed with emphasis to make it + * stand out. Does not start with a capital letter or end with a '.' + * - Body (optional): indented, should contain further diagnostic information useful for identifying + * and fixing the warning/error. Can be a sentence with captialisation and '.' on the end. + * + * Please think of what the end user will find most useful when writing the header and body, and try + * to keep it brief without sacrificing important information! Also remember that if the user is + * only looking at stderr, they will normally have no other context. + * + * Warning vs error + * === + * The principle that we have operated on so far is + * - issue a warning if ZAPD will still be able to produce a valid, compilable C file that will + * match + * - if this cannot happen, use an error. + * but at the end of the day, it is up to the programmer's discretion what it should be possible to + * disable. + * + * Documentation + * === + * Remember that all warnings also need to be documented in the README.md. The help is generated + * automatically. + */ +#include "WarningHandler.h" + +#include <cassert> +#include "Globals.h" +#include "Utils/StringHelper.h" + +typedef struct +{ + WarningType type; + WarningLevel defaultLevel; + std::string description; +} WarningInfoInit; + +typedef struct +{ + WarningLevel level; + std::string name; + std::string description; +} WarningInfo; + +/** + * Master list of all default warning types and features + * + * To add a warning type, fill in a new row of this map. Think carefully about what its default + * level should be, and try and make the description both brief and informative: it is used in the + * help message, so again, think about what the end user needs to know. + */ +// clang-format off +static const std::unordered_map<std::string, WarningInfoInit> warningStringToInitMap = { + {"deprecated", {WarningType::Deprecated, +#ifdef DEPRECATION_ON + WarningLevel::Warn, +#else + WarningLevel::Off, +#endif + "Deprecated features"}}, + {"unaccounted", {WarningType::Unaccounted, WarningLevel::Off, "Large blocks of unaccounted"}}, + {"missing-offsets", {WarningType::MissingOffsets, WarningLevel::Warn, "Offset attribute missing in XML tag"}}, + {"intersection", {WarningType::Intersection, WarningLevel::Warn, "Two assets intersect"}}, + {"missing-attribute", {WarningType::MissingAttribute, WarningLevel::Warn, "Required attribute missing in XML tag"}}, + {"invalid-attribute-value", {WarningType::InvalidAttributeValue, WarningLevel::Err, "Attribute declared in XML is wrong"}}, + {"unknown-attribute", {WarningType::UnknownAttribute, WarningLevel::Warn, "Unknown attribute in XML entry tag"}}, + {"invalid-xml", {WarningType::InvalidXML, WarningLevel::Err, "XML has syntax errors"}}, + {"invalid-jpeg", {WarningType::InvalidJPEG, WarningLevel::Err, "JPEG file does not conform to the game's format requirements"}}, + {"invalid-png", {WarningType::InvalidPNG, WarningLevel::Err, "Issues arising when processing PNG data"}}, + {"invalid-extracted-data", {WarningType::InvalidExtractedData, WarningLevel::Err, "Extracted data does not have correct form"}}, + {"missing-segment", {WarningType::MissingSegment, WarningLevel::Warn, "Segment not given in File tag in XML"}}, + {"hardcoded-pointer", {WarningType::HardcodedPointer, WarningLevel::Warn, "ZAPD lacks the info to make a symbol, so must output a hardcoded pointer"}}, + {"not-implemented", {WarningType::NotImplemented, WarningLevel::Warn, "ZAPD does not currently support this feature"}}, +}; + +/** + * Map constructed at runtime to contain the warning features as set by the user using -W flags. + */ +static std::unordered_map<WarningType, WarningInfo> warningTypeToInfoMap; + +void WarningHandler::ConstructTypeToInfoMap() { + for (auto& entry : warningStringToInitMap) { + warningTypeToInfoMap[entry.second.type] = {entry.second.defaultLevel, entry.first, entry.second.description}; + } + warningTypeToInfoMap[WarningType::Always] = {WarningLevel::Warn, "always", "you shouldn't be reading this"}; + assert(warningTypeToInfoMap.size() == static_cast<size_t>(WarningType::Max)); +} + +/** + * Initialises the main warning type map and reads flags passed to set each warning type's level. + */ +void WarningHandler::Init(int argc, char* argv[]) { + ConstructTypeToInfoMap(); + + bool werror = false; + for (int i = 1; i < argc; i++) { + // If it doesn't start with "-W" skip it. + if (argv[i][0] != '-' || argv[i][1] != 'W' || argv[i][2] == '\0') { + continue; + } + + WarningLevel warningTypeOn = WarningLevel::Warn; + size_t startingIndex = 2; + + // "-Wno-" + if (argv[i][2] == 'n' && argv[i][3] == 'o' && argv[i][4] == '-' && argv[i][5] != '\0') { + warningTypeOn = WarningLevel::Off; + startingIndex = 5; + } + + // Read starting after the "-W" or "-Wno-" + std::string_view currentArgv = &argv[i][startingIndex]; + + if (currentArgv == "error") { + werror = warningTypeOn != WarningLevel::Off; + } else if (currentArgv == "everything") { + for (auto& it: warningTypeToInfoMap) { + if (it.second.level <= WarningLevel::Warn) { + it.second.level = warningTypeOn; + } + } + } else { + // "-Werror=" / "-Wno-error=" parser + if (currentArgv.rfind("error=", 0) == 0) { + // Read starting after the "error=" part + currentArgv = &argv[i][startingIndex + 6]; + warningTypeOn = warningTypeOn != WarningLevel::Off ? WarningLevel::Err : WarningLevel::Warn; + } + + auto it = warningStringToInitMap.find(std::string(currentArgv)); + if (it != warningStringToInitMap.end()) { + warningTypeToInfoMap[it->second.type].level = warningTypeOn; + } + else { + HANDLE_WARNING(WarningType::Always, StringHelper::Sprintf("unknown warning flag '%s'", argv[i]), ""); + } + } + } + + if (werror) { + for (auto& it: warningTypeToInfoMap) { + if (it.second.level >= WarningLevel::Warn) { + it.second.level = WarningLevel::Err; + } + } + } +} + +bool WarningHandler::IsWarningEnabled(WarningType warnType) { + assert(static_cast<size_t>(warnType) >= 0 && warnType < WarningType::Max); + + return warningTypeToInfoMap.at(warnType).level != WarningLevel::Off; +} + +bool WarningHandler::WasElevatedToError(WarningType warnType) { + assert(static_cast<size_t>(warnType) >= 0 && warnType < WarningType::Max); + + if (!IsWarningEnabled(warnType)) { + return false; + } + + return warningTypeToInfoMap.at(warnType).level >= WarningLevel::Err; +} + +/** + * Print file/line/function info for debugging + */ +void WarningHandler::FunctionPreamble(const char* filename, int32_t line, const char* function) { + if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) { + fprintf(stderr, "%s:%i: in function %s:\n", filename, line, function); + } +} + +/** + * Print the information about the file(s) being processed (XML for extraction, png etc. for building) + */ +void WarningHandler::ProcessedFilePreamble() { + if (Globals::Instance->inputPath != "") { + fprintf(stderr, "When processing file %s: ", Globals::Instance->inputPath.c_str()); + } +} + +/** + * Print information about the binary file being extracted + */ +void WarningHandler::ExtractedFilePreamble(const ZFile *parent, const ZResource* res, const uint32_t offset) { + fprintf(stderr, "in input binary file %s, ", parent->GetName().c_str()); + if (res != nullptr) { + fprintf(stderr, "resource '%s' at ", res->GetName().c_str()); + } + fprintf(stderr, "offset 0x%06X: \n\t", offset); +} + +/** + * Construct the rest of the message, after warning:/error. The message is filled in one character at a time, with indents added after newlines + */ +std::string WarningHandler::ConstructMessage(std::string message, const std::string& header, const std::string& body) { + message.reserve(message.size() + header.size() + body.size() + 10 * (sizeof(HANG_INDT) - 1)); + message += StringHelper::Sprintf(HILITE("%s"), header.c_str()); + message += "\n"; + + if (body == "") { + return message; + } + + message += HANG_INDT; + for (const char* ptr = body.c_str(); *ptr != '\0'; ptr++) { + message += *ptr; + if (*ptr == '\n') { + message += HANG_INDT; + } + } + message += "\n"; + + return message; +} + +/* Error module functions */ + +void WarningHandler::PrintErrorAndThrow(const std::string& header, const std::string& body) { + std::string errorMsg = ERR_FMT("error: "); + throw std::runtime_error(ConstructMessage(errorMsg, header, body)); +} + +/* Error types, to be used via the macros */ + +void WarningHandler::ErrorType(WarningType warnType, const std::string& header, const std::string& body) { + std::string headerMsg = header; + + for (const auto& iter: warningStringToInitMap) { + if (iter.second.type == warnType) { + headerMsg += StringHelper::Sprintf(" [%s]", iter.first.c_str()); + } + } + + PrintErrorAndThrow(headerMsg, body); +} + +void WarningHandler::Error_Plain(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) { + FunctionPreamble(filename, line, function); + + ErrorType(warnType, header, body); +} + +void WarningHandler::Error_Process(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) { + FunctionPreamble(filename, line, function); + ProcessedFilePreamble(); + + ErrorType(warnType, header, body); +} + +void WarningHandler::Error_Resource(const char* filename, int32_t line, const char* function, WarningType warnType, const ZFile *parent, const ZResource* res, const uint32_t offset, const std::string& header, const std::string& body) { + assert(parent != nullptr); + + FunctionPreamble(filename, line, function); + ProcessedFilePreamble(); + ExtractedFilePreamble(parent, res, offset); + + ErrorType(warnType, header, body); +} + +/* Warning module functions */ + +void WarningHandler::PrintWarningBody(const std::string& header, const std::string& body) { + std::string errorMsg = WARN_FMT("warning: "); + fprintf(stderr, "%s", ConstructMessage(errorMsg, header, body).c_str()); +} + +void WarningHandler::WarningTypeAndChooseEscalate(WarningType warnType, const std::string& header, const std::string& body) { + std::string headerMsg = header; + + for (const auto& iter: warningStringToInitMap) { + if (iter.second.type == warnType) { + headerMsg += StringHelper::Sprintf(" [-W%s]", iter.first.c_str()); + } + } + + if (WasElevatedToError(warnType)) { + PrintErrorAndThrow(headerMsg, body); + } else { + PrintWarningBody(headerMsg, body); + } +} + + +/* Warning types, to be used via the macros */ + +void WarningHandler::Warning_Plain(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) { + if (!IsWarningEnabled(warnType)) { + return; + } + + FunctionPreamble(filename, line, function); + + WarningTypeAndChooseEscalate(warnType, header, body); +} + +void WarningHandler::Warning_Process(const char* filename, int32_t line, const char* function, WarningType warnType, const std::string& header, const std::string& body) { + if (!IsWarningEnabled(warnType)) { + return; + } + + FunctionPreamble(filename, line, function); + ProcessedFilePreamble(); + + WarningTypeAndChooseEscalate(warnType, header, body); +} + +void WarningHandler::Warning_Resource(const char* filename, int32_t line, const char* function, WarningType warnType, const ZFile *parent, const ZResource* res, const uint32_t offset, const std::string& header, const std::string& body) { + assert(parent != nullptr); + + if (!IsWarningEnabled(warnType)) { + return; + } + + FunctionPreamble(filename, line, function); + ProcessedFilePreamble(); + ExtractedFilePreamble(parent, res, offset); + + WarningTypeAndChooseEscalate(warnType, header, body); +} + + +/* Help-related functions */ + +#include <set> + +/** + * Print each warning name, default status, and description using the init map + */ +void WarningHandler::PrintHelp() { + std::set<std::string> sortedKeys; + WarningInfoInit warningInfo; + uint columnWidth = 25; + std::string dt; + + // Sort keys through the magic of `set`, to print in alphabetical order + for (auto& it : warningStringToInitMap) { + sortedKeys.insert(it.first); + } + + printf("\nWarning types ( * means enabled by default)\n"); + for (auto& key : sortedKeys) { + warningInfo = warningStringToInitMap.at(key); + if (warningInfo.defaultLevel <= WarningLevel::Warn) { + dt = "-W"; + dt += key; + if (warningInfo.defaultLevel == WarningLevel::Warn) { + dt += " *"; + } + printf(HELP_DT_INDT "%-*s", columnWidth, dt.c_str()); + + if (dt.length() + 2 > columnWidth) { + printf("\n" HELP_DT_INDT "%-*s", columnWidth, ""); + } + printf("%s\n", warningInfo.description.c_str()); + } + } + + printf("\nDefault errors\n"); + for (auto& key : sortedKeys) { + if (warningInfo.defaultLevel > WarningLevel::Warn) { + dt = "-W"; + dt += key; + printf(HELP_DT_INDT "%-*s", columnWidth, dt.c_str()); + + if (dt.length() + 2 > columnWidth) { + printf("\n" HELP_DT_INDT "%*s", columnWidth, ""); + } + printf("%s\n", warningInfo.description.c_str()); + } + } + + printf("\n"); + printf("Other\n" HELP_DT_INDT "-Weverything will enable all existing warnings.\n" HELP_DT_INDT "-Werror will promote all warnings to errors.\n"); + + printf("\n"); + printf("Warnings can be disabled using -Wno-... instead of -W...; -Weverything will override any -Wno-... flags passed before it.\n"); +} + +/** + * Print which warnings are currently enabled + */ +void WarningHandler::PrintWarningsDebugInfo() +{ + std::string dt; + + printf("Warnings status:\n"); + for (auto& it: warningTypeToInfoMap) { + dt = it.second.name; + dt += ": "; + + printf(HELP_DT_INDT "%-25s", dt.c_str()); + switch (it.second.level) + { + case WarningLevel::Off: + printf(VT_FGCOL(LIGHTGRAY) "Off" VT_RST); + break; + case WarningLevel::Warn: + printf(VT_FGCOL(YELLOW) "Warn" VT_RST); + break; + case WarningLevel::Err: + printf(VT_FGCOL(RED) "Err" VT_RST); + break; + + } + printf("\n"); + } + printf("\n"); +} diff --git a/ZAPD/WarningHandler.h b/ZAPD/WarningHandler.h new file mode 100644 index 0000000..bb0360a --- /dev/null +++ b/ZAPD/WarningHandler.h @@ -0,0 +1,145 @@ +#pragma once + +#include <array> +#include <string> +#include <string_view> +#include <unordered_map> + +#include "Utils/vt.h" +#include "ZFile.h" + +#ifdef _MSC_VER +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#elif not defined(__GNUC__) +#define __PRETTY_FUNCTION__ __func__ +#endif + +// ======================================= +/* Formatting macros */ + +// TODO: move this somewhere else so it can be used by other help +#define HELP_DT_INDT " " + +/* Macros for formatting warnings/errors */ +#define VT_HILITE VT_BOLD_FGCOL(WHITE) +#define VT_WARN VT_BOLD_FGCOL(PURPLE) +#define VT_ERR VT_BOLD_FGCOL(RED) + +#define HILITE(string) (VT_HILITE string VT_RST) +#define WARN_FMT(string) (VT_WARN string VT_RST) +#define ERR_FMT(string) (VT_ERR string VT_RST) + +// Maybe make WARN_LF instead +// Currently 8 spaces +#define WARN_INDT " " +// Currently 16 spaces +#define HANG_INDT " " + +// ======================================= +/* Warning and error macros */ +// TODO: better names + +// General-purpose, plain style (only prints function,file,line in the preamble) +#define HANDLE_ERROR(warningType, header, body) \ + WarningHandler::Error_Plain(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, body) +#define HANDLE_WARNING(warningType, header, body) \ + WarningHandler::Warning_Plain(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, \ + body) + +// For processing XMLs or textures/blobs (preamble contains function,file,line; processed file) +#define HANDLE_ERROR_PROCESS(warningType, header, body) \ + WarningHandler::Error_Process(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, \ + body) +#define HANDLE_WARNING_PROCESS(warningType, header, body) \ + WarningHandler::Warning_Process(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, header, \ + body) + +// For ZResource-related stuff (preamble contains function,file,line; processed file; extracted file +// and offset) +#define HANDLE_ERROR_RESOURCE(warningType, parent, resource, offset, header, body) \ + WarningHandler::Error_Resource(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, parent, \ + resource, offset, header, body) +#define HANDLE_WARNING_RESOURCE(warningType, parent, resource, offset, header, body) \ + WarningHandler::Warning_Resource(__FILE__, __LINE__, __PRETTY_FUNCTION__, warningType, parent, \ + resource, offset, header, body) + +// ======================================= + +enum class WarningType +{ + Always, // Warnings of this type are always printed, cannot be disabled. + Deprecated, + Unaccounted, + MissingOffsets, + Intersection, + MissingAttribute, + InvalidAttributeValue, + UnknownAttribute, + InvalidXML, + InvalidJPEG, + InvalidPNG, + InvalidExtractedData, + MissingSegment, + HardcodedPointer, + NotImplemented, + Max, +}; + +enum class WarningLevel +{ + Off, + Warn, + Err, +}; + +class WarningHandler +{ +public: + static void ConstructTypeToInfoMap(); + + static void Init(int argc, char* argv[]); + + static bool IsWarningEnabled(WarningType warnType); + static bool WasElevatedToError(WarningType warnType); + + static void FunctionPreamble(const char* filename, int32_t line, const char* function); + static void ProcessedFilePreamble(); + static void ExtractedFilePreamble(const ZFile* parent, const ZResource* res, + const uint32_t offset); + static std::string ConstructMessage(std::string message, const std::string& header, + const std::string& body); + + [[noreturn]] static void PrintErrorAndThrow(const std::string& header, const std::string& body); + static void PrintWarningBody(const std::string& header, const std::string& body); + + [[noreturn]] static void ErrorType(WarningType warnType, const std::string& header, + const std::string& body); + [[noreturn]] static void Error_Plain(const char* filename, int32_t line, const char* function, + WarningType warnType, const std::string& header, + const std::string& body); + [[noreturn]] static void Error_Process(const char* filename, int32_t line, const char* function, + WarningType warnType, const std::string& header, + const std::string& body); + [[noreturn]] static void Error_Resource(const char* filename, int32_t line, + const char* function, WarningType warnType, + const ZFile* parent, const ZResource* res, + const uint32_t offset, const std::string& header, + const std::string& body); + + static void WarningTypeAndChooseEscalate(WarningType warnType, const std::string& header, + const std::string& body); + + static void Warning_Plain(const char* filename, int32_t line, const char* function, + WarningType warnType, const std::string& header, + const std::string& body); + static void Warning_Process(const char* filename, int32_t line, const char* function, + WarningType warnType, const std::string& header, + const std::string& body); + static void Warning_Resource(const char* filename, int32_t line, const char* function, + WarningType warnType, const ZFile* parent, const ZResource* res, + const uint32_t offset, const std::string& header, + const std::string& body); + + static void PrintHelp(); + static void PrintWarningsDebugInfo(); +}; diff --git a/ZAPD/ZAnimation.cpp b/ZAPD/ZAnimation.cpp index 9242f65..adb0ae7 100644 --- a/ZAPD/ZAnimation.cpp +++ b/ZAPD/ZAnimation.cpp @@ -6,6 +6,7 @@ #include "Utils/BitConverter.h" #include "Utils/File.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Animation, ZNormalAnimation); @@ -218,11 +219,9 @@ void ZCurveAnimation::ParseXML(tinyxml2::XMLElement* reader) std::string skelOffsetXml = registeredAttributes.at("SkelOffset").value; if (skelOffsetXml == "") { - throw std::runtime_error( - StringHelper::Sprintf("ZCurveAnimation::ParseXML: Fatal error in '%s'.\n" - "\t Missing 'SkelOffset' attribute in ZCurveAnimation.\n" - "\t You need to provide the offset of the curve skeleton.", - name.c_str())); + HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'SkelOffset' attribute in <ZCurveAnimation>", + "You need to provide the offset of the curve skeleton."); } skelOffset = StringHelper::StrToL(skelOffsetXml, 0); } diff --git a/ZAPD/ZAnimation.h b/ZAPD/ZAnimation.h index e5b69d3..2c04b4f 100644 --- a/ZAPD/ZAnimation.h +++ b/ZAPD/ZAnimation.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "Vec3s.h" diff --git a/ZAPD/ZArray.cpp b/ZAPD/ZArray.cpp index b1ba3a6..ebfb13e 100644 --- a/ZAPD/ZArray.cpp +++ b/ZAPD/ZArray.cpp @@ -4,6 +4,7 @@ #include "Globals.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Array, ZArray); @@ -25,13 +26,18 @@ void ZArray::ParseXML(tinyxml2::XMLElement* reader) ZResource::ParseXML(reader); arrayCnt = reader->IntAttribute("Count", 0); - // TODO: do a better check. - assert(arrayCnt > 0); + if (arrayCnt <= 0) + { + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Count' attribute", ""); + } tinyxml2::XMLElement* child = reader->FirstChildElement(); if (child == nullptr) - throw std::runtime_error( - StringHelper::Sprintf("Error! Array needs at least one sub-element.\n")); + { + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, + "<Array> needs one sub-element", ""); + } childName = child->Name(); @@ -42,9 +48,10 @@ void ZArray::ParseXML(tinyxml2::XMLElement* reader) ZResource* res = nodeMap->at(childName)(parent); if (!res->DoesSupportArray()) { - throw std::runtime_error(StringHelper::Sprintf( - "Error! Resource %s does not support being wrapped in an array!\n", - childName.c_str())); + std::string errorHeader = StringHelper::Sprintf( + "resource <%s> does not support being wrapped in an <Array>", childName.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, errorHeader, + ""); } res->parent = parent; res->SetInnerNode(true); @@ -87,7 +94,7 @@ Declaration* ZArray::DeclareVar(const std::string& prefix, const std::string& bo std::string ZArray::GetBodySourceCode() const { - std::string output; + std::string output = ""; for (size_t i = 0; i < arrayCnt; i++) { diff --git a/ZAPD/ZArray.h b/ZAPD/ZArray.h index 46a04d7..b78a8ed 100644 --- a/ZAPD/ZArray.h +++ b/ZAPD/ZArray.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "ZResource.h" diff --git a/ZAPD/ZBackground.cpp b/ZAPD/ZBackground.cpp index 0b35109..0ed1eb7 100644 --- a/ZAPD/ZBackground.cpp +++ b/ZAPD/ZBackground.cpp @@ -5,6 +5,7 @@ #include "Utils/File.h" #include "Utils/Path.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Background, ZBackground); @@ -63,52 +64,46 @@ void ZBackground::CheckValidJpeg(const std::string& filepath) uint32_t jpegMarker = BitConverter::ToUInt32BE(data, 0); if (jpegMarker != JPEG_MARKER) { - fprintf(stderr, - "ZBackground::CheckValidJpeg: Warning.\n" - "\t Missing jpeg marker at the beginning of file: '%s'.\n" - "\t The game will skip this jpeg.\n", - filename.c_str()); + HANDLE_WARNING_PROCESS( + WarningType::InvalidJPEG, + StringHelper::Sprintf("missing jpeg marker at beginning of file: '%s'", + filename.c_str()), + "The game will skip this jpeg."); } if (data.at(6) != 'J' || data.at(7) != 'F' || data.at(8) != 'I' || data.at(9) != 'F' || data.at(10) != '\0') { std::string jfifIdentifier(data.begin() + 6, data.begin() + 6 + 5); - fprintf(stderr, - "ZBackground::CheckValidJpeg: Warning.\n" - "\t Missing 'JFIF' identifier. File: '%s'.\n" - "\t This image may be corrupted or not be a jpeg iamge.\n" - "\t The identifier found was '%s'.\n", - filename.c_str(), jfifIdentifier.c_str()); + HANDLE_WARNING_PROCESS( + WarningType::InvalidJPEG, "missing 'JFIF' identifier", + StringHelper::Sprintf( + "This image may be corrupted, or not a jpeg. The identifier found was: '%s'", + jfifIdentifier.c_str())); } uint8_t majorVersion = data.at(11); uint8_t minorVersion = data.at(12); if (majorVersion != 0x01 || minorVersion != 0x01) { - fprintf(stderr, - "ZBackground::CheckValidJpeg: Warning.\n" - "\t Wrong JFIF version '%i.%02i'. File: '%s'.\n" - "\t The expected version is '1.01'. The game may not be able to decode this image " - "properly.\n", - majorVersion, minorVersion, filename.c_str()); + HANDLE_WARNING_PROCESS( + WarningType::InvalidJPEG, + StringHelper::Sprintf("wrong JFIF version '%i.%02i'", majorVersion, minorVersion), + "The expected version is '1.01'. The game may be unable to decode this image " + "correctly."); } if (BitConverter::ToUInt16BE(data, 20) != MARKER_DQT) { // This may happen when creating a custom image with Exif, XMP, thumbnail, progressive, etc. // enabled. - fprintf(stderr, - "ZBackground::CheckValidJpeg: Warning.\n" - "\t There seems to be extra data before the image data in file: '%s'.\n" - "\t The game may not be able to decode this image properly.\n", - filename.c_str()); + HANDLE_WARNING_PROCESS(WarningType::InvalidJPEG, + "there seems to be extra data before the image data in this file", + "The game may not be able to decode this image correctly."); } if (data.size() > GetRawDataSize()) { - fprintf(stderr, - "ZBackground::CheckValidJpeg: Warning.\n" - "\t The image is bigger than the screen buffer. File: '%s'.\n" - "\t Image size: %zu bytes.\n" - "\t Screen buffer size: %zu bytes.\n", - filename.c_str(), data.size(), GetRawDataSize()); + HANDLE_WARNING_PROCESS( + WarningType::InvalidJPEG, "the image is bigger than the screen buffer", + StringHelper::Sprintf("Image size: %zu bytes\nScreen buffer size: %zu bytes", + data.size(), GetRawDataSize())); } } diff --git a/ZAPD/ZCollision.cpp b/ZAPD/ZCollision.cpp index f9c0bf7..1dfa46b 100644 --- a/ZAPD/ZCollision.cpp +++ b/ZAPD/ZCollision.cpp @@ -88,7 +88,7 @@ void ZCollisionHeader::ParseRawData() void ZCollisionHeader::DeclareReferences(const std::string& prefix) { - std::string declaration; + std::string declaration = ""; std::string auxName = name; if (name == "") @@ -174,7 +174,7 @@ void ZCollisionHeader::DeclareReferences(const std::string& prefix) std::string ZCollisionHeader::GetBodySourceCode() const { - std::string declaration; + std::string declaration = ""; declaration += "\n"; diff --git a/ZAPD/ZCutscene.cpp b/ZAPD/ZCutscene.cpp index 2374810..ba8fe89 100644 --- a/ZAPD/ZCutscene.cpp +++ b/ZAPD/ZCutscene.cpp @@ -2,6 +2,7 @@ #include "Utils/BitConverter.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZResource.h" REGISTER_ZFILENODE(Cutscene, ZCutscene); @@ -87,7 +88,7 @@ CutsceneCommandSceneTransFX::~CutsceneCommandSceneTransFX() std::string ZCutscene::GetBodySourceCode() const { - std::string output; + std::string output = ""; uint32_t curPtr = 0; output += StringHelper::Sprintf(" CS_BEGIN_CUTSCENE(%i, %i),\n", commands.size(), endFrame); @@ -225,8 +226,9 @@ void ZCutscene::ParseRawData() cmd = new CutsceneCommandEnd(rawData, currentPtr); break; case CutsceneCommands::Error: - fprintf(stderr, "Cutscene command error %d %s %d\n", (int32_t)cmdID, __FILE__, - __LINE__); + HANDLE_WARNING_RESOURCE(WarningType::NotImplemented, parent, this, rawDataIndex, + StringHelper::Sprintf("cutscene command error %d", cmdID), + ""); break; } @@ -404,7 +406,9 @@ CutsceneCommands ZCutscene::GetCommandFromID(int32_t id) return CutsceneCommands::Unknown; } - fprintf(stderr, "WARNING: Could not identify cutscene command ID 0x%04X\n", id); + HANDLE_WARNING_RESOURCE( + WarningType::NotImplemented, parent, this, rawDataIndex, + StringHelper::Sprintf("could not identify cutscene command. ID 0x%04X", id), ""); return CutsceneCommands::Error; } diff --git a/ZAPD/ZCutscene.h b/ZAPD/ZCutscene.h index cbb6a78..8e901e3 100644 --- a/ZAPD/ZCutscene.h +++ b/ZAPD/ZCutscene.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "ZFile.h" diff --git a/ZAPD/ZCutsceneMM.h b/ZAPD/ZCutsceneMM.h index 41b7de3..44b108d 100644 --- a/ZAPD/ZCutsceneMM.h +++ b/ZAPD/ZCutsceneMM.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "ZCutscene.h" diff --git a/ZAPD/ZDisplayList.cpp b/ZAPD/ZDisplayList.cpp index 63c5684..d2defb1 100644 --- a/ZAPD/ZDisplayList.cpp +++ b/ZAPD/ZDisplayList.cpp @@ -11,6 +11,7 @@ #include "Utils/File.h" #include "Utils/Path.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "gfxd.h" REGISTER_ZFILENODE(DList, ZDisplayList); @@ -445,11 +446,12 @@ int32_t ZDisplayList::GetDListLength(const std::vector<uint8_t>& rawData, uint32 { if (ptr >= rawDataSize) { - throw std::runtime_error(StringHelper::Sprintf( - "%s: Fatal error.\n" - "\t End of file found when trying to find the end of the " - "DisplayList at offset: '0x%X'.\n", - "Raw data size: 0x%zX.\n", __PRETTY_FUNCTION__, rawDataIndex, rawDataSize)); + std::string errorHeader = + StringHelper::Sprintf("reached end of file when trying to find the end of the " + "DisplayList starting at offset 0x%X", + rawDataIndex); + std::string errorBody = StringHelper::Sprintf("Raw data size: 0x%zX.", rawDataSize); + HANDLE_ERROR_PROCESS(WarningType::Always, errorHeader, errorBody); } uint8_t opcode = rawData.at(ptr); @@ -1775,7 +1777,7 @@ std::string ZDisplayList::GetSourceOutputCode(const std::string& prefix) // Generate Vertex Declarations for (auto& item : vertices) { - std::string declaration; + std::string declaration = ""; offset_t curAddr = item.first; auto& firstVtx = item.second.at(0); diff --git a/ZAPD/ZFile.cpp b/ZAPD/ZFile.cpp index ff57778..b95671b 100644 --- a/ZAPD/ZFile.cpp +++ b/ZAPD/ZFile.cpp @@ -13,6 +13,7 @@ #include "Utils/MemoryStream.h" #include "Utils/Path.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZAnimation.h" #include "ZArray.h" #include "ZBackground.h" @@ -114,8 +115,11 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) else if (std::string_view(gameStr) == "OOT") Globals::Instance->game = ZGame::OOT_RETAIL; else - throw std::runtime_error( - StringHelper::Sprintf("Error: Game type %s not supported.", gameStr)); + { + std::string errorHeader = + StringHelper::Sprintf("'Game' type '%s' is not supported.", gameStr); + HANDLE_ERROR_PROCESS(WarningType::InvalidAttributeValue, errorHeader, ""); + } } if (reader->Attribute("BaseAddress") != nullptr) @@ -128,16 +132,22 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) rangeEnd = StringHelper::StrToL(reader->Attribute("RangeEnd"), 16); if (rangeStart > rangeEnd) - throw std::runtime_error("Error: RangeStart must be before than RangeEnd."); + HANDLE_ERROR_PROCESS( + WarningType::Always, + StringHelper::Sprintf("'RangeStart' 0x%06X must be before 'RangeEnd' 0x%06X", + rangeStart, rangeEnd), + ""); const char* segmentXml = reader->Attribute("Segment"); if (segmentXml != nullptr) { if (!StringHelper::HasOnlyDigits(segmentXml)) { - throw std::runtime_error(StringHelper::Sprintf( - "error: Invalid segment value '%s': must be a decimal between 0 and 15 inclusive", - segmentXml)); + HANDLE_ERROR_PROCESS(WarningType::Always, + StringHelper::Sprintf("error: Invalid segment value '%s': must be " + "a decimal between 0 and 15 inclusive", + segmentXml), + ""); } segment = StringHelper::StrToL(segmentXml, 10); @@ -146,16 +156,19 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) if (segment == 128) { #ifdef DEPRECATION_ON - fprintf(stderr, "warning: segment 128 is deprecated.\n\tRemove " - "'Segment=\"128\"' from the xml to use virtual addresses\n"); + HANDLE_WARNING_PROCESS( + WarningType::Always, "warning: segment 128 is deprecated.", + "Remove 'Segment=\"128\"' from the xml to use virtual addresses\n"); #endif } else { - throw std::runtime_error( + HANDLE_ERROR_PROCESS( + WarningType::Always, StringHelper::Sprintf("error: invalid segment value '%s': must be a decimal " "number between 0 and 15 inclusive", - segmentXml)); + segmentXml), + ""); } } } @@ -176,18 +189,16 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) if (mode == ZFileMode::Extract || mode == ZFileMode::ExternalFile) { if (!File::Exists((basePath / name).string())) - throw std::runtime_error( - StringHelper::Sprintf("Error! File %s does not exist.", (basePath / name).c_str())); + { + std::string errorHeader = StringHelper::Sprintf("binary file '%s' does not exist.", + (basePath / name).c_str()); + HANDLE_ERROR_PROCESS(WarningType::Always, errorHeader, ""); + } rawData = File::ReadAllBytes((basePath / name).string()); - /* - * TODO: In OoT repo ovl_Boss_Sst has a wrong RangeEnd (0xAD40 instead of 0xAD70), - * so uncommenting the following produces wrong behavior. - * If somebody fixes that in OoT repo, uncomment this. I'm too tired of fixing XMLs. - */ - // if (reader->Attribute("RangeEnd") == nullptr) - // rangeEnd = rawData.size(); + if (reader->Attribute("RangeEnd") == nullptr) + rangeEnd = rawData.size(); } std::unordered_set<std::string> nameSet; @@ -211,20 +222,17 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) if (offsetSet.find(offsetXml) != offsetSet.end()) { - throw std::runtime_error(StringHelper::Sprintf( - "ZFile::ParseXML: Error in '%s'.\n\t Repeated 'Offset' attribute: %s \n", - name.c_str(), offsetXml)); + std::string errorHeader = + StringHelper::Sprintf("repeated 'Offset' attribute: %s", offsetXml); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); } offsetSet.insert(offsetXml); } - else if (Globals::Instance->warnNoOffset) - { - fprintf(stderr, "Warning No offset specified for: %s", nameXml); - } - else if (Globals::Instance->errorNoOffset) + else { - throw std::runtime_error( - StringHelper::Sprintf("Error no offset specified for %s", nameXml)); + HANDLE_WARNING_RESOURCE(WarningType::MissingOffsets, this, nullptr, rawDataIndex, + StringHelper::Sprintf("no offset specified for %s.", nameXml), + ""); } if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO) @@ -234,9 +242,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) { if (outNameSet.find(outNameXml) != outNameSet.end()) { - throw std::runtime_error(StringHelper::Sprintf( - "ZFile::ParseXML: Error in '%s'.\n\t Repeated 'OutName' attribute: %s \n", - name.c_str(), outNameXml)); + std::string errorHeader = + StringHelper::Sprintf("repeated 'OutName' attribute: %s", outNameXml); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); } outNameSet.insert(outNameXml); } @@ -244,9 +252,9 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) { if (nameSet.find(nameXml) != nameSet.end()) { - throw std::runtime_error(StringHelper::Sprintf( - "ZFile::ParseXML: Error in '%s'.\n\t Repeated 'Name' attribute: %s \n", - name.c_str(), nameXml)); + std::string errorHeader = + StringHelper::Sprintf("repeated 'Name' attribute: %s", nameXml); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); } nameSet.insert(nameXml); } @@ -279,16 +287,14 @@ void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename) } else if (std::string_view(child->Name()) == "File") { - throw std::runtime_error(StringHelper::Sprintf( - "ZFile::ParseXML: Error in '%s'.\n\t Can't declare a File inside a File.\n", - name.c_str())); + std::string errorHeader = "Can't declare a <File> inside a <File>"; + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); } else { - throw std::runtime_error( - StringHelper::Sprintf("ZFile::ParseXML: Error in '%s'.\n\t Unknown element found " - "inside a File element: '%s'.\n", - name.c_str(), nodeName.c_str())); + std::string errorHeader = StringHelper::Sprintf( + "Unknown element found inside a <File> element: %s", nodeName.c_str()); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); } } } @@ -1232,11 +1238,12 @@ bool ZFile::HandleUnaccountedAddress(uint32_t currentAddress, uint32_t lastAddr, { Declaration* currentDecl = declarations.at(currentAddress); - fprintf(stderr, - "WARNING: Intersection detected from 0x%06X:0x%06X (%s), conflicts with " - "0x%06X (%s)\n", - lastAddr, lastAddr + lastSize, lastDecl->varName.c_str(), currentAddress, - currentDecl->varName.c_str()); + std::string intersectionInfo = StringHelper::Sprintf( + "Resource from 0x%06X:0x%06X (%s) conflicts with 0x%06X (%s).", lastAddr, + lastAddr + lastSize, lastDecl->varName.c_str(), currentAddress, + currentDecl->varName.c_str()); + HANDLE_WARNING_RESOURCE(WarningType::Intersection, this, nullptr, currentAddress, + "intersection detected", intersectionInfo); } } @@ -1307,25 +1314,17 @@ bool ZFile::HandleUnaccountedAddress(uint32_t currentAddress, uint32_t lastAddr, diff, src); decl->isUnaccounted = true; - if (Globals::Instance->warnUnaccounted) + if (nonZeroUnaccounted) { - if (nonZeroUnaccounted) - { - fprintf(stderr, - "Warning in file: %s (%s)\n" - "\t A non-zero unaccounted block was found at offset '0x%06X'.\n" - "\t Block size: '0x%X'.\n", - xmlFilePath.c_str(), name.c_str(), unaccountedAddress, diff); - } - else if (diff >= 16) - { - fprintf(stderr, - "Warning in file: %s (%s)\n" - "\t A big (size>=0x10) zero-only unaccounted block was found " - "at offset '0x%06X'.\n" - "\t Block size: '0x%X'.\n", - xmlFilePath.c_str(), name.c_str(), unaccountedAddress, diff); - } + HANDLE_WARNING_RESOURCE(WarningType::Unaccounted, this, nullptr, unaccountedAddress, + "a non-zero unaccounted block was found", + StringHelper::Sprintf("Block size: '0x%X'", diff)); + } + else if (diff >= 16) + { + HANDLE_WARNING_RESOURCE(WarningType::Unaccounted, this, nullptr, unaccountedAddress, + "a big (size>=0x10) zero-only unaccounted block was found", + StringHelper::Sprintf("Block size: '0x%X'", diff)); } } } diff --git a/ZAPD/ZFile.h b/ZAPD/ZFile.h index 9de6950..d0a3464 100644 --- a/ZAPD/ZFile.h +++ b/ZAPD/ZFile.h @@ -1,6 +1,5 @@ #pragma once -#include <Utils/Directory.h> #include <string> #include <vector> diff --git a/ZAPD/ZLimb.cpp b/ZAPD/ZLimb.cpp index 77c6687..a47615d 100644 --- a/ZAPD/ZLimb.cpp +++ b/ZAPD/ZLimb.cpp @@ -4,7 +4,7 @@ #include "Globals.h" #include "Utils/BitConverter.h" -#include "Utils/StringHelper.h" +#include "WarningHandler.h" REGISTER_ZFILENODE(Limb, ZLimb); @@ -37,17 +37,15 @@ void ZLimb::ParseXML(tinyxml2::XMLElement* reader) if (limbType == "") { - throw std::runtime_error(StringHelper::Sprintf("ZLimb::ParseXML: Error in '%s'.\n" - "\t Missing 'LimbType' attribute in xml.\n", - name.c_str())); + HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'LimbType' attribute in <Limb>", ""); } type = GetTypeByAttributeName(limbType); if (type == ZLimbType::Invalid) { - throw std::runtime_error(StringHelper::Sprintf("ZLimb::ParseXML: Error in '%s'.\n" - "\t Invalid 'LimbType' found: '%s'.\n", - name.c_str(), limbType.c_str())); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'LimbType' attribute", ""); } } @@ -109,8 +107,12 @@ void ZLimb::ParseRawData() } break; - default: - throw std::runtime_error("Invalid ZLimb type"); + case ZLimbType::Curve: + case ZLimbType::Legacy: + break; + + case ZLimbType::Invalid: + assert(!"whoops"); break; } } diff --git a/ZAPD/ZPath.cpp b/ZAPD/ZPath.cpp index 4a95c5b..e19513d 100644 --- a/ZAPD/ZPath.cpp +++ b/ZAPD/ZPath.cpp @@ -3,6 +3,7 @@ #include "Globals.h" #include "Utils/BitConverter.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Path, ZPath); @@ -20,10 +21,12 @@ void ZPath::ParseXML(tinyxml2::XMLElement* reader) numPaths = StringHelper::StrToL(registeredAttributes.at("NumPaths").value); if (numPaths < 1) - throw std::runtime_error( - StringHelper::Sprintf("ZPath::ParseXML: Fatal error in '%s'.\n" - "\t Invalid value for attribute 'NumPaths': '%i'\n", - name.c_str(), numPaths)); + { + HANDLE_ERROR_RESOURCE( + WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("invalid value '%d' found for 'NumPaths' attribute", numPaths), + "Should be at least '1'"); + } } void ZPath::ParseRawData() @@ -144,7 +147,7 @@ void PathwayEntry::DeclareReferences(const std::string& prefix) if (addressFound) return; - std::string declaration; + std::string declaration = ""; size_t index = 0; for (const auto& point : points) diff --git a/ZAPD/ZResource.cpp b/ZAPD/ZResource.cpp index cb811f4..4fd6d08 100644 --- a/ZAPD/ZResource.cpp +++ b/ZAPD/ZResource.cpp @@ -4,6 +4,7 @@ #include <regex> #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" ZResource::ZResource(ZFile* nParent) @@ -85,29 +86,33 @@ void ZResource::ParseXML(tinyxml2::XMLElement* reader) } if (!attrDeclared) - fprintf(stderr, - "ZResource::ParseXML: Warning while parsing '%s'.\n" - "\t Unexpected '%s' attribute in resource '%s'.\n", - parent->GetName().c_str(), attrName.c_str(), reader->Name()); + { + HANDLE_WARNING_RESOURCE( + WarningType::UnknownAttribute, parent, this, rawDataIndex, + StringHelper::Sprintf("unexpected '%s' attribute in resource <%s>", + attrName.c_str(), reader->Name()), + ""); + } attrs = attrs->Next(); } if (!canHaveInner && !reader->NoChildren()) { - throw std::runtime_error( - StringHelper::Sprintf("ZResource::ParseXML: Fatal error in '%s'.\n" - "\t Resource '%s' with inner element/child detected.\n", - name.c_str(), reader->Name())); + std::string errorHeader = StringHelper::Sprintf( + "resource '%s' with inner element/child detected", reader->Name()); + HANDLE_ERROR_PROCESS(WarningType::InvalidXML, errorHeader, ""); } for (const auto& attr : registeredAttributes) { if (attr.second.isRequired && attr.second.value == "") - throw std::runtime_error(StringHelper::Sprintf( - "ZResource::ParseXML: Fatal error while parsing '%s'.\n" - "\t Missing required attribute '%s' in resource '%s'.\n" - "\t Aborting...", - parent->GetName().c_str(), attr.first.c_str(), reader->Name())); + { + std::string headerMsg = + StringHelper::Sprintf("missing required attribute '%s' in resource <%s>", + attr.first.c_str(), reader->Name()); + HANDLE_ERROR_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + headerMsg, ""); + } } name = registeredAttributes.at("Name").value; @@ -118,10 +123,8 @@ void ZResource::ParseXML(tinyxml2::XMLElement* reader) { if (!std::regex_match(name, r)) { - throw std::domain_error( - StringHelper::Sprintf("ZResource::ParseXML: Fatal error in '%s'.\n" - "\t Resource with invalid 'Name' attribute.\n", - name.c_str())); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, + rawDataIndex, "invalid value found for 'Name' attribute", ""); } } @@ -146,7 +149,9 @@ void ZResource::ParseXML(tinyxml2::XMLElement* reader) } else { - throw std::runtime_error("Invalid value for 'Static' attribute."); + HANDLE_ERROR_RESOURCE( + WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("invalid value '%s' for 'Static' attribute", staticConf), ""); } declaredInXml = true; @@ -312,13 +317,13 @@ offset_t Seg2Filespace(segptr_t segmentedAddress, uint32_t parentBaseAddress) uint32_t parentBaseOffset = GETSEGOFFSET(parentBaseAddress); if (parentBaseOffset > currentPtr) { - throw std::runtime_error( - StringHelper::Sprintf("\nSeg2Filespace: Segmented address is smaller than " - "'BaseAddress'. Maybe your 'BaseAddress' is wrong?\n" - "\t SegmentedAddress: 0x%08X\n" - "\t BaseAddress: 0x%08X\n", - segmentedAddress, parentBaseAddress)); + HANDLE_ERROR(WarningType::Always, + StringHelper::Sprintf( + "resource address 0x%08X is smaller than 'BaseAddress' 0x%08X", + segmentedAddress, parentBaseAddress), + "Maybe your 'BaseAddress' is wrong?"); } + currentPtr -= parentBaseOffset; } diff --git a/ZAPD/ZResource.h b/ZAPD/ZResource.h index ff35786..b127417 100644 --- a/ZAPD/ZResource.h +++ b/ZAPD/ZResource.h @@ -1,16 +1,15 @@ #pragma once -#include <Utils/BinaryWriter.h> +#include <cstdint> #include <map> #include <stdexcept> -#include <stdint.h> #include <string> #include <vector> #include "Declaration.h" +#include "Utils/BinaryWriter.h" +#include "Utils/Directory.h" #include "tinyxml2.h" -#include <Utils/Directory.h> - #define SEGMENT_SCENE 2 #define SEGMENT_ROOM 3 #define SEGMENT_KEEP 4 diff --git a/ZAPD/ZRoom/Commands/SetMesh.cpp b/ZAPD/ZRoom/Commands/SetMesh.cpp index dae736a..5463496 100644 --- a/ZAPD/ZRoom/Commands/SetMesh.cpp +++ b/ZAPD/ZRoom/Commands/SetMesh.cpp @@ -1,8 +1,10 @@ #include "SetMesh.h" -#include <Globals.h> -#include <Utils/Path.h> + +#include "Globals.h" #include "Utils/BitConverter.h" +#include "Utils/Path.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZBackground.h" #include "ZFile.h" #include "ZRoom/ZRoom.h" @@ -34,9 +36,8 @@ void SetMesh::ParseRawData() break; default: - throw std::runtime_error(StringHelper::Sprintf("Error in SetMesh::ParseRawData\n" - "\t Unknown meshHeaderType: %i\n", - meshHeaderType)); + HANDLE_ERROR(WarningType::InvalidExtractedData, + StringHelper::Sprintf("unknown meshHeaderType: %i", meshHeaderType), ""); } polyType->ParseRawData(); @@ -472,8 +473,8 @@ void PolygonType1::DeclareReferences(const std::string& prefix) break; default: - throw std::runtime_error(StringHelper::Sprintf( - "Error in PolygonType1::PolygonType1\n\t Unknown format: %i\n", format)); + HANDLE_ERROR(WarningType::InvalidExtractedData, + StringHelper::Sprintf("unknown format: %i", format), ""); break; } } diff --git a/ZAPD/ZRoom/ZRoom.cpp b/ZAPD/ZRoom/ZRoom.cpp index edc0cad..cf9430d 100644 --- a/ZAPD/ZRoom/ZRoom.cpp +++ b/ZAPD/ZRoom/ZRoom.cpp @@ -40,6 +40,7 @@ #include "Utils/File.h" #include "Utils/Path.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZBlob.h" #include "ZCutscene.h" #include "ZFile.h" @@ -123,10 +124,12 @@ void ZRoom::ParseXML(tinyxml2::XMLElement* reader) { hackMode = std::string(reader->Attribute("HackMode")); if (hackMode != "syotes_room") - throw std::runtime_error( - StringHelper::Sprintf("ZRoom::ParseXML: Fatal error in '%s'.\n" - "\t Invalid value for attribute 'HackMode': '%s'\n", - name.c_str(), hackMode.c_str())); + { + std::string headerError = StringHelper::Sprintf( + "invalid value found for 'HackMode' attribute: '%s'", hackMode.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + headerError, ""); + } } } diff --git a/ZAPD/ZScalar.cpp b/ZAPD/ZScalar.cpp index 062fb0e..7e4be4d 100644 --- a/ZAPD/ZScalar.cpp +++ b/ZAPD/ZScalar.cpp @@ -4,6 +4,7 @@ #include "Utils/BitConverter.h" #include "Utils/File.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Scalar, ZScalar); @@ -207,8 +208,8 @@ void ZScalar::ParseRawData() scalarData.f64 = BitConverter::ToDoubleBE(rawData, rawDataIndex); break; case ZScalarType::ZSCALAR_NONE: - fprintf(stderr, "Warning in ZScalar: Invalid type. %d %s %d\n", (int32_t)scalarType, - __FILE__, __LINE__); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Type' attribute", "Defaulting to ''"); break; } } diff --git a/ZAPD/ZScalar.h b/ZAPD/ZScalar.h index d269995..8f98f26 100644 --- a/ZAPD/ZScalar.h +++ b/ZAPD/ZScalar.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "ZResource.h" diff --git a/ZAPD/ZSkeleton.cpp b/ZAPD/ZSkeleton.cpp index 84f00c8..1a2f93f 100644 --- a/ZAPD/ZSkeleton.cpp +++ b/ZAPD/ZSkeleton.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "Utils/BitConverter.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" REGISTER_ZFILENODE(Skeleton, ZSkeleton); REGISTER_ZFILENODE(LimbTable, ZLimbTable); @@ -27,18 +28,19 @@ void ZSkeleton::ParseXML(tinyxml2::XMLElement* reader) type = ZSkeletonType::Curve; else if (skelTypeXml != "Normal") { - throw std::runtime_error(StringHelper::Sprintf("ZSkeleton::ParseXML: Error in '%s'.\n" - "\t Invalid Type found: '%s'.\n", - name.c_str(), skelTypeXml.c_str())); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Type' attribute", ""); } std::string limbTypeXml = registeredAttributes.at("LimbType").value; limbType = ZLimb::GetTypeByAttributeName(limbTypeXml); if (limbType == ZLimbType::Invalid) { - throw std::runtime_error(StringHelper::Sprintf("ZSkeleton::ParseXML: Error in '%s'.\n" - "\t Invalid LimbType found: '%s'.\n", - name.c_str(), limbTypeXml.c_str())); + HANDLE_ERROR_RESOURCE( + WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("invalid value '%s' found for 'LimbType' attribute", + limbTypeXml.c_str()), + "Defaulting to 'Standard'."); } } @@ -170,11 +172,9 @@ void ZLimbTable::ParseXML(tinyxml2::XMLElement* reader) limbType = ZLimb::GetTypeByAttributeName(limbTypeXml); if (limbType == ZLimbType::Invalid) { - fprintf(stderr, - "ZLimbTable::ParseXML: Warning in '%s'.\n" - "\t Invalid LimbType found: '%s'.\n" - "\t Defaulting to 'Standard'.\n", - name.c_str(), limbTypeXml.c_str()); + HANDLE_WARNING_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'LimbType' attribute.", + "Defaulting to 'Standard'."); limbType = ZLimbType::Standard; } diff --git a/ZAPD/ZSymbol.cpp b/ZAPD/ZSymbol.cpp index b24c3de..eabfc2f 100644 --- a/ZAPD/ZSymbol.cpp +++ b/ZAPD/ZSymbol.cpp @@ -1,6 +1,7 @@ #include "ZSymbol.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Symbol, ZSymbol); @@ -20,11 +21,8 @@ void ZSymbol::ParseXML(tinyxml2::XMLElement* reader) if (typeXml == "") { - fprintf(stderr, - "ZSymbol::ParseXML: Warning in '%s'.\n" - "\t Missing 'Type' attribute in xml.\n" - "\t Defaulting to 'void*'.\n", - name.c_str()); + HANDLE_WARNING_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'Type' attribute in <Symbol>", "Defaulting to 'void*'."); type = "void*"; } else @@ -35,11 +33,8 @@ void ZSymbol::ParseXML(tinyxml2::XMLElement* reader) std::string typeSizeXml = registeredAttributes.at("TypeSize").value; if (typeSizeXml == "") { - fprintf(stderr, - "ZSymbol::ParseXML: Warning in '%s'.\n" - "\t Missing 'TypeSize' attribute in xml.\n" - "\t Defaulting to '4'.\n", - name.c_str()); + HANDLE_WARNING_RESOURCE(WarningType::MissingAttribute, parent, this, rawDataIndex, + "missing 'TypeSize' attribute in <Symbol>", "Defaulting to '4'."); typeSize = 4; // Size of a word. } else @@ -58,7 +53,9 @@ void ZSymbol::ParseXML(tinyxml2::XMLElement* reader) if (registeredAttributes.at("Static").value == "On") { - fprintf(stderr, "A <Symbol> can't be marked as static.\n\t Disabling static\n"); + HANDLE_WARNING_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "a <Symbol> cannot be marked as static", + "Disabling static for this resource."); } staticConf = StaticConfig::Off; } diff --git a/ZAPD/ZTexture.cpp b/ZAPD/ZTexture.cpp index 33ee54d..7bd3143 100644 --- a/ZAPD/ZTexture.cpp +++ b/ZAPD/ZTexture.cpp @@ -8,6 +8,7 @@ #include "Utils/Directory.h" #include "Utils/File.h" #include "Utils/Path.h" +#include "WarningHandler.h" REGISTER_ZFILENODE(Texture, ZTexture); @@ -57,17 +58,17 @@ void ZTexture::ParseXML(tinyxml2::XMLElement* reader) if (!StringHelper::HasOnlyDigits(widthXml)) { - throw std::runtime_error( - StringHelper::Sprintf("ZTexture::ParseXML: Error in %s\n" - "\t Value of 'Width' attribute has non-decimal digits: '%s'.\n", - name.c_str(), widthXml.c_str())); + std::string errorHeader = StringHelper::Sprintf( + "value of 'Width' attribute has non-decimal digits: '%s'", widthXml.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + errorHeader, ""); } if (!StringHelper::HasOnlyDigits(heightXml)) { - throw std::runtime_error( - StringHelper::Sprintf("ZTexture::ParseXML: Error in %s\n" - "\t Value of 'Height' attribute has non-decimal digits: '%s'.\n", - name.c_str(), heightXml.c_str())); + std::string errorHeader = StringHelper::Sprintf( + "value of 'Height' attribute has non-decimal digits: '%s'", heightXml.c_str()); + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + errorHeader, ""); } width = StringHelper::StrToL(widthXml); @@ -77,7 +78,10 @@ void ZTexture::ParseXML(tinyxml2::XMLElement* reader) format = GetTextureTypeFromString(formatStr); if (format == TextureType::Error) - throw std::runtime_error("Format " + formatStr + " is not supported!"); + { + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + "invalid value found for 'Format' attribute", ""); + } const auto& tlutOffsetAttr = registeredAttributes.at("TlutOffset"); if (tlutOffsetAttr.wasSet) @@ -90,10 +94,9 @@ void ZTexture::ParseXML(tinyxml2::XMLElement* reader) break; default: - throw std::runtime_error(StringHelper::Sprintf( - "ZTexture::ParseXML: Error in %s\n" - "\t 'TlutOffset' declared in non color-indexed (ci4 or ci8) texture.\n", - name.c_str())); + HANDLE_ERROR_RESOURCE(WarningType::InvalidXML, parent, this, rawDataIndex, + "'TlutOffset' declared in non color-indexed (ci4 or ci8) texture", + ""); break; } } @@ -102,10 +105,10 @@ void ZTexture::ParseXML(tinyxml2::XMLElement* reader) void ZTexture::ParseRawData() { if (rawDataIndex % 8 != 0) - fprintf(stderr, - "ZTexture::ParseXML: Warning in '%s'.\n" - "\t This texture is not 64-bit aligned.\n", - name.c_str()); + { + HANDLE_WARNING_RESOURCE(WarningType::NotImplemented, parent, this, rawDataIndex, + "this texture is not 64-bit aligned", ""); + } switch (format) { @@ -136,8 +139,11 @@ void ZTexture::ParseRawData() case TextureType::Palette8bpp: PrepareBitmapPalette8(); break; - default: - throw std::runtime_error("Format is not supported!"); + case TextureType::Error: + HANDLE_ERROR_RESOURCE(WarningType::InvalidAttributeValue, parent, this, rawDataIndex, + StringHelper::Sprintf("Invalid texture format", format), ""); + assert(!"TODO"); + break; } } @@ -375,8 +381,9 @@ void ZTexture::PrepareRawDataFromFile(const fs::path& pngFilePath) case TextureType::Palette8bpp: PrepareRawDataPalette8(pngFilePath); break; - default: - throw std::runtime_error("Format is not supported!"); + case TextureType::Error: + HANDLE_ERROR_PROCESS(WarningType::InvalidPNG, "Input PNG file has invalid format type", ""); + break; } } @@ -860,13 +867,9 @@ TextureType ZTexture::GetTextureTypeFromString(const std::string& str) else if (str == "rgb5a1") { texType = TextureType::RGBA16bpp; -#ifdef DEPRECATION_ON - fprintf(stderr, "ZTexture::GetTextureTypeFromString: Deprecation warning.\n" - "\t The texture format 'rgb5a1' is currently deprecated, and will be " - "removed in a future " - "version.\n" - "\t Use the format 'rgba16' instead.\n"); -#endif + HANDLE_WARNING(WarningType::Deprecated, + "the texture format 'rgb5a1' is currently deprecated", + "It will be removed in a future version. Use the format 'rgba16' instead."); } else if (str == "i4") texType = TextureType::Grayscale4bpp; @@ -883,7 +886,9 @@ TextureType ZTexture::GetTextureTypeFromString(const std::string& str) else if (str == "ci8") texType = TextureType::Palette8bpp; else - fprintf(stderr, "Encountered Unknown Texture format %s \n", str.c_str()); + // TODO: handle this case in a more coherent way + HANDLE_WARNING(WarningType::InvalidAttributeValue, + "invalid value found for 'Type' attribute", "Defaulting to ''."); return texType; } diff --git a/ZAPD/ZTextureAnimation.cpp b/ZAPD/ZTextureAnimation.cpp index 4332fcf..698054f 100644 --- a/ZAPD/ZTextureAnimation.cpp +++ b/ZAPD/ZTextureAnimation.cpp @@ -2,8 +2,8 @@ * File: ZTextureAnimation.cpp * ZResources defined: ZTextureAnimation, ZTextureAnimationParams (XML declaration not supported for * the latter) - * Purpose: extracting texture animating structures from asset files Note: data type is exclusive to - * Majora's Mask + * Purpose: extracting texture animating structures from asset files + * Note: data type is exclusive to Majora's Mask * * Structure of data: * A texture animation consists of a main array of data of the form @@ -82,6 +82,7 @@ #include "Globals.h" #include "Utils/BitConverter.h" +#include "WarningHandler.h" #include "ZFile.h" #include "ZResource.h" #include "tinyxml2.h" @@ -115,7 +116,7 @@ void ZTextureAnimationParams::ExtractFromBinary(uint32_t nRawDataIndex) ParseRawData(); } -// Implemented by TextureScrollingParams only[ +// Implemented by TextureScrollingParams only void ZTextureAnimationParams::ExtractFromBinary([[maybe_unused]] uint32_t nRawDataIndex, [[maybe_unused]] int count) { @@ -217,19 +218,8 @@ void TextureColorChangingParams::ParseRawData() ((type == TextureAnimationParamsType::ColorChange) ? animLength : colorListCount); if (listLength == 0) - throw std::runtime_error(StringHelper::Sprintf( - "When processing file %s: in input binary file %s, offset 0x%06X:" - "\n\t" - "\033[97m" - "TextureColorChangingParams::ParseRawData:" - "\033[0m" - "\033[91m" - " error: " - "\033[0m" - "\033[97m" - "color list length cannot be 0\n" - "\033[0m", - Globals::Instance->inputPath.c_str(), parent->GetName().c_str(), rawDataIndex)); + HANDLE_ERROR_RESOURCE(WarningType::Always, parent, this, rawDataIndex, + "color list length cannot be 0", ""); primColorListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4); envColorListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); @@ -378,20 +368,8 @@ void TextureCyclingParams::ParseRawData() cycleLength = BitConverter::ToUInt16BE(rawData, rawDataIndex); if (cycleLength == 0) - throw std::runtime_error( - StringHelper::Sprintf("When processing file %s: in input binary file %s, offset 0x%06X:" - "\n\t" - "\033[97m" - "TextureCyclingParams::ParseRawData:" - "\033[0m" - "\033[91m" - " error: " - "\033[0m" - "\033[97m" - "cycleLength cannot be 0\n" - "\033[0m", - Globals::Instance->inputPath.c_str(), parent->GetName().c_str(), - Seg2Filespace(rawDataIndex, 0))); + HANDLE_ERROR_RESOURCE(WarningType::Always, parent, this, rawDataIndex, + "cycle length cannot be 0", ""); textureListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 4); textureIndexListAddress = BitConverter::ToUInt32BE(rawData, rawDataIndex + 8); @@ -454,21 +432,12 @@ void TextureCyclingParams::DeclareReferences([[maybe_unused]] const std::string& { comment = " // Raw pointer, declare texture in XML to use proper symbol"; - fprintf(stderr, - "When processing file %s: in input binary file %s, offset 0x%06X:" - "\n\t" - "\033[97m" - "TextureCyclingParams::DeclareReferences:" - "\033[0m" - "\033[95m" - " warning: " - "\033[0m" - "\033[97m" - "TexCycle declared here points to unknown texture at address %s. " - "Please declare the texture in the XML to use the proper symbol.\n" - "\033[0m", - Globals::Instance->inputPath.c_str(), parent->GetName().c_str(), - Seg2Filespace(textureListAddress, parent->baseAddress), texName.c_str()); + auto msgHeader = StringHelper::Sprintf( + "TexCycle texture array declared here points to unknown texture at address %s", + texName.c_str()); + HANDLE_WARNING_RESOURCE( + WarningType::HardcodedPointer, parent, this, rawDataIndex, msgHeader, + "Please declare the texture in the XML to use the proper symbol."); } texturesBodyStr += StringHelper::Sprintf("\t%s,%s\n", texName.c_str(), comment.c_str()); } @@ -546,22 +515,14 @@ void ZTextureAnimation::ParseRawData() if ((type < 0) || (type > 6)) { - throw std::runtime_error(StringHelper::Sprintf( - "When processing file %s: in input binary file %s, offset 0x%06X:" - "\n\t" - "\033[97m" - "ZTextureAnimation::ParseRawData:" - "\033[0m" - "\033[91m" - " error: " - "\033[0m" - "\033[97m" - "unknown TextureAnimationParams type 0x%02X in TextureAnimation: entry reads\n\t{ " - "0x%02X, 0x%02X, 0x%08X }\n(type should be between " - "0x00 and 0x06)\n" - "\033[0m", - Globals::Instance->inputPath.c_str(), parent->GetName().c_str(), rawDataIndex, type, - currentEntry.segment, type, currentEntry.paramsPtr)); + HANDLE_ERROR_RESOURCE( + WarningType::Always, parent, this, rawDataIndex, + StringHelper::Sprintf( + "unknown TextureAnimationParams type 0x%02X in TextureAnimation", type), + StringHelper::Sprintf( + "Entry reads { 0x%02X, 0x%02X, 0x%08X } , but type should be " + "between 0x00 and 0x06 inclusive.", + currentEntry.segment, type, currentEntry.paramsPtr)); } if (currentEntry.segment <= 0) @@ -589,13 +550,24 @@ void ZTextureAnimation::DeclareReferences(const std::string& prefix) if (!parent->HasDeclaration(paramsOffset)) { ZTextureAnimationParams* params; - int count = 2; + int count; switch (entry.type) { case TextureAnimationParamsType::SingleScroll: - count = 1; - [[fallthrough]]; - case TextureAnimationParamsType::DualScroll: + if (true) + { + count = 1; + // The else now allows SingleScroll to fall through to params = ... without + // touching the code in the else block + } + else + { + // The contents of this block can only be run by jumping into it with the + // case label + [[fallthrough]]; + case TextureAnimationParamsType::DualScroll: + count = 2; + } params = new TextureScrollingParams(parent); params->ExtractFromBinary(paramsOffset, count); break; @@ -614,22 +586,12 @@ void ZTextureAnimation::DeclareReferences(const std::string& prefix) break; case TextureAnimationParamsType::Empty: - fprintf(stderr, - "When processing file %s: in input binary file %s: offset 0x%06X:" - "\n\t" - "\033[97m" - "ZTextureAnimation::DeclareReferences:" - "\033[0m" - "\033[95m" - " warning: " - "\033[0m" - "\033[97m" - "TextureAnimationParams entry has empty type (6), but params pointer " - "is not NULL. Params read\n\t\t" - "{ 0x%02X, 0x%02X, 0x%08X }\n" - "\033[0m", - Globals::Instance->inputPath.c_str(), parent->GetName().c_str(), - rawDataIndex, entry.segment, (int)entry.type, entry.paramsPtr); + HANDLE_WARNING_RESOURCE( + WarningType::InvalidExtractedData, parent, this, rawDataIndex, + "TextureAnimationParams entry has empty type (6), but params pointer is " + "not NULL", + StringHelper::Sprintf("Params read { 0x%02X, 0x%02X, 0x%08X } .", + entry.segment, (int)entry.type, entry.paramsPtr)); return; default: // Because GCC is worried this could happen diff --git a/ZAPD/ZVector.cpp b/ZAPD/ZVector.cpp index c940b0b..a5a059e 100644 --- a/ZAPD/ZVector.cpp +++ b/ZAPD/ZVector.cpp @@ -6,6 +6,7 @@ #include "Utils/BitConverter.h" #include "Utils/File.h" #include "Utils/StringHelper.h" +#include "WarningHandler.h" #include "ZFile.h" REGISTER_ZFILENODE(Vector, ZVector); @@ -86,20 +87,18 @@ std::string ZVector::GetSourceTypeName() const return "Vec3i"; else { - std::string output = StringHelper::Sprintf( - "Encountered unsupported vector type: %d dimensions, %s type", dimensions, + std::string msgHeader = StringHelper::Sprintf( + "encountered unsupported vector type: %d dimensions, %s type", dimensions, ZScalar::MapScalarTypeToOutputType(scalarType).c_str()); - if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG) - printf("%s\n", output.c_str()); - - throw std::runtime_error(output); + HANDLE_ERROR_RESOURCE(WarningType::NotImplemented, parent, this, rawDataIndex, msgHeader, + ""); } } std::string ZVector::GetBodySourceCode() const { - std::string body; + std::string body = ""; for (size_t i = 0; i < scalars.size(); i++) { diff --git a/ZAPD/ZVector.h b/ZAPD/ZVector.h index d1a7389..a50d3e8 100644 --- a/ZAPD/ZVector.h +++ b/ZAPD/ZVector.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "ZResource.h" diff --git a/ZAPD/ZVtx.h b/ZAPD/ZVtx.h index 018a1d4..5110487 100644 --- a/ZAPD/ZVtx.h +++ b/ZAPD/ZVtx.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> #include <string> #include <vector> #include "ZResource.h" diff --git a/ZAPDUtils/Color3b.h b/ZAPDUtils/Color3b.h index 7e59f6b..507c099 100644 --- a/ZAPDUtils/Color3b.h +++ b/ZAPDUtils/Color3b.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> struct Color3b { diff --git a/ZAPDUtils/StrHash.h b/ZAPDUtils/StrHash.h index 68d22b9..c611bdd 100644 --- a/ZAPDUtils/StrHash.h +++ b/ZAPDUtils/StrHash.h @@ -1,8 +1,8 @@ #pragma once -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> +#include <cstdint> +#include <cstdio> +#include <cstdlib> typedef uint32_t strhash; diff --git a/ZAPDUtils/Utils/BinaryReader.cpp b/ZAPDUtils/Utils/BinaryReader.cpp index a4cf782..3541278 100644 --- a/ZAPDUtils/Utils/BinaryReader.cpp +++ b/ZAPDUtils/Utils/BinaryReader.cpp @@ -1,5 +1,5 @@ #include "BinaryReader.h" -#include <math.h> +#include <cmath> #include <stdexcept> #include "Stream.h" @@ -89,7 +89,7 @@ float BinaryReader::ReadSingle() stream->Read((char*)&result, sizeof(float)); - if (isnan(result)) + if (std::isnan(result)) throw std::runtime_error("BinaryReader::ReadSingle(): Error reading stream"); return result; @@ -100,7 +100,7 @@ double BinaryReader::ReadDouble() double result = NAN; stream->Read((char*)&result, sizeof(double)); - if (isnan(result)) + if (std::isnan(result)) throw std::runtime_error("BinaryReader::ReadDouble(): Error reading stream"); return result; diff --git a/ZAPDUtils/Utils/BitConverter.h b/ZAPDUtils/Utils/BitConverter.h index 5cca35b..e672b97 100644 --- a/ZAPDUtils/Utils/BitConverter.h +++ b/ZAPDUtils/Utils/BitConverter.h @@ -1,7 +1,7 @@ #pragma once +#include <cstdint> #include <limits> -#include <stdint.h> #include <vector> class BitConverter diff --git a/ZAPDUtils/Utils/File.h b/ZAPDUtils/Utils/File.h index e3f8880..084152f 100644 --- a/ZAPDUtils/Utils/File.h +++ b/ZAPDUtils/Utils/File.h @@ -1,8 +1,8 @@ #pragma once +#include <cstdio> #include <fstream> #include <iostream> -#include <stdio.h> #include <string> #include <vector> #include "Directory.h" diff --git a/ZAPDUtils/Utils/MemoryStream.cpp b/ZAPDUtils/Utils/MemoryStream.cpp index 6c27399..6e85c59 100644 --- a/ZAPDUtils/Utils/MemoryStream.cpp +++ b/ZAPDUtils/Utils/MemoryStream.cpp @@ -1,5 +1,5 @@ #include "MemoryStream.h" -#include <string.h> +#include <cstring> #ifndef _MSC_VER #define memcpy_s(dest, destSize, source, sourceSize) memcpy(dest, source, destSize) diff --git a/ZAPDUtils/Utils/Stream.h b/ZAPDUtils/Utils/Stream.h index 060e23c..e73a9a7 100644 --- a/ZAPDUtils/Utils/Stream.h +++ b/ZAPDUtils/Utils/Stream.h @@ -1,7 +1,7 @@ #pragma once +#include <cstdint> #include <memory> -#include <stdint.h> enum class SeekOffsetType { diff --git a/ZAPDUtils/Utils/StringHelper.h b/ZAPDUtils/Utils/StringHelper.h index 74607ce..3335849 100644 --- a/ZAPDUtils/Utils/StringHelper.h +++ b/ZAPDUtils/Utils/StringHelper.h @@ -1,18 +1,12 @@ #pragma once #include <algorithm> +#include <cstdarg> #include <cstring> #include <numeric> -#include <stdarg.h> #include <string> #include <vector> -#ifdef _MSC_VER -#define __PRETTY_FUNCTION__ __FUNCSIG__ -#elif not defined(__GNUC__) -#define __PRETTY_FUNCTION__ __func__ -#endif - class StringHelper { public: diff --git a/ZAPDUtils/Utils/vt.h b/ZAPDUtils/Utils/vt.h new file mode 100644 index 0000000..23f4244 --- /dev/null +++ b/ZAPDUtils/Utils/vt.h @@ -0,0 +1,45 @@ +#ifndef VT_H +#define VT_H + +// clang-format off +#define VT_COLOR_BLACK 0 +#define VT_COLOR_RED 1 +#define VT_COLOR_GREEN 2 +#define VT_COLOR_YELLOW 3 +#define VT_COLOR_BLUE 4 +#define VT_COLOR_PURPLE 5 +#define VT_COLOR_CYAN 6 +#define VT_COLOR_WHITE 7 +#define VT_COLOR_LIGHTGRAY 8 +#define VT_COLOR_DARKGRAY 9 + +#define VT_COLOR_FOREGROUND 3 +#define VT_COLOR_BACKGROUND 4 +// clang-format on + +#define VT_COLOR_EXPAND0(type, color) #type #color +#define VT_COLOR_EXPAND1(type, color) VT_COLOR_EXPAND0(type, color) +#define VT_COLOR(type, color) VT_COLOR_EXPAND1(VT_COLOR_##type, VT_COLOR_##color) + +#define VT_ESC "\x1b" +#define VT_CSI "[" +#define VT_CUP(x, y) VT_ESC VT_CSI y ";" x "H" +#define VT_ED(n) VT_ESC VT_CSI #n "J" +#define VT_SGR(n) VT_ESC VT_CSI n "m" + +// Add more macros if necessary +#define VT_COL(back, fore) VT_SGR(VT_COLOR(BACKGROUND, back) ";" VT_COLOR(FOREGROUND, fore)) +#define VT_FGCOL(color) VT_SGR(VT_COLOR(FOREGROUND, color)) +#define VT_BGCOL(color) VT_SGR(VT_COLOR(BACKGROUND, color)) + +// Bold +#define VT_BOLD "1" + +// Bold color support +#define VT_BOLD_FGCOL(color) VT_SGR(VT_BOLD ";" VT_COLOR(FOREGROUND, color)) +#define VT_BOLD_BGCOL(color) VT_SGR(VT_BOLD ";" VT_COLOR(BACKGROUND, color)) + +#define VT_RST VT_SGR("") +#define VT_CLS VT_ED(2) + +#endif diff --git a/ZAPDUtils/Vec2f.h b/ZAPDUtils/Vec2f.h index 9d4beeb..73e9259 100644 --- a/ZAPDUtils/Vec2f.h +++ b/ZAPDUtils/Vec2f.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> struct Vec2f { diff --git a/ZAPDUtils/Vec3f.h b/ZAPDUtils/Vec3f.h index 4bfbb3c..d6e9c55 100644 --- a/ZAPDUtils/Vec3f.h +++ b/ZAPDUtils/Vec3f.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> struct Vec3f { diff --git a/ZAPDUtils/Vec3s.h b/ZAPDUtils/Vec3s.h index 23e4673..05816ed 100644 --- a/ZAPDUtils/Vec3s.h +++ b/ZAPDUtils/Vec3s.h @@ -1,6 +1,6 @@ #pragma once -#include <stdint.h> +#include <cstdint> struct Vec3s { diff --git a/docs/zapd_warning_example.png b/docs/zapd_warning_example.png Binary files differnew file mode 100644 index 0000000..a001c64 --- /dev/null +++ b/docs/zapd_warning_example.png |
