ZAPD fixes in sys_initial_check, update subrepos (#507)

* git subrepo pull --force tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "a3363333d"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "a3363333d"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

* git subrepo pull tools/asm-differ --force

subrepo:
  subdir:   "tools/asm-differ"
  merged:   "70c33cc12"
upstream:
  origin:   "https://github.com/simonlindholm/asm-differ.git"
  branch:   "main"
  commit:   "70c33cc12"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

* git subrepo pull (merge) tools/z64compress --force

subrepo:
  subdir:   "tools/z64compress"
  merged:   "ac5b1a0d0"
upstream:
  origin:   "https://github.com/z64me/z64compress.git"
  branch:   "main"
  commit:   "ac5b1a0d0"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"

* Use defines for texture sizes in sys_initial_check

* Update extract_assets.py

* Add null check

* git subrepo pull --force tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "50242eca9"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "50242eca9"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
This commit is contained in:
EllipticEllipsis 2021-12-16 04:05:29 +00:00 committed by GitHub
parent ff231e093a
commit 9ca4ec7604
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 1646 additions and 757 deletions

View File

@ -1,8 +1,10 @@
#!/usr/bin/env python3
import argparse, json, os, signal, time
import argparse, json, os, signal, time, colorama
from multiprocessing import Pool, Event, Manager
colorama.init();
EXTRACTED_ASSETS_NAMEFILE = ".extracted-assets.json"
def SignalHandler(sig, frame):
@ -15,10 +17,10 @@ def ExtractFile(xmlPath, outputPath, outputSourcePath):
# Don't extract if another file wasn't extracted properly.
return
execStr = "tools/ZAPD/ZAPD.out e -eh -i %s -b baserom/ -o %s -osf %s -gsf 1 -rconf tools/ZAPDConfigs/MM/Config.xml" % (xmlPath, outputPath, outputSourcePath)
execStr = f"tools/ZAPD/ZAPD.out e -eh -i {xmlPath} -b baserom/ -o {outputPath} -osf {outputSourcePath} -gsf 1 -rconf tools/ZAPDConfigs/MM/Config.xml {ZAPDArgs}"
if globalUnaccounted:
execStr += " -wu"
execStr += " -Wunaccounted"
print(execStr)
exitValue = os.system(execStr)
@ -72,8 +74,27 @@ def main():
parser.add_argument("-t", "--threads", help="Number of cpu cores to extract with.")
parser.add_argument("-f", "--force", help="Force the extraction of every xml instead of checking the touched ones.", action="store_true")
parser.add_argument("-u", "--unaccounted", help="Enables ZAPD unaccounted detector warning system.", action="store_true")
parser.add_argument("-Z", help="Pass the argument on to ZAPD, e.g. `-ZWunaccounted` to warn about unaccounted blocks in XMLs. Each argument should be passed separately, *without* the leading dash.", metavar="ZAPD_ARG", action="append")
args = parser.parse_args()
global ZAPDArgs;
ZAPDArgs = "";
if args.Z is not None:
badZAPDArg = False;
for i in range(len(args.Z)):
z = args.Z[i]
if z[0] == '-':
print(f"{colorama.Fore.LIGHTRED_EX}error{colorama.Fore.RESET}: argument \"{z}\" starts with \"-\", which is not supported.", file=os.sys.stderr);
badZAPDArg = True;
else:
args.Z[i] = "-" + z;
if badZAPDArg:
exit(1);
ZAPDArgs = " ".join(args.Z);
print("Using extra ZAPD arguments: " + ZAPDArgs);
global mainAbort
mainAbort = Event()
manager = Manager()
@ -88,7 +109,7 @@ def main():
if asset_path is not None:
fullPath = os.path.join("assets", "xml", asset_path + ".xml")
if not os.path.exists(fullPath):
print(f"Error. File {fullPath} doesn't exists.", file=os.sys.stderr)
print(f"Error. File {fullPath} does not exist.", file=os.sys.stderr)
exit(1)
initializeWorker(mainAbort, args.unaccounted, extractedAssetsTracker, manager)
@ -107,7 +128,7 @@ def main():
numCores = int(args.threads or 0)
if numCores <= 0:
numCores = 1
print("Extracting assets with " + str(numCores) + " CPU cores.")
print("Extracting assets with " + str(numCores) + " CPU core" + ("s" if numCores > 1 else "") + ".")
with Pool(numCores, initializer=initializeWorker, initargs=(mainAbort, args.unaccounted, extractedAssetsTracker, manager)) as p:
p.map(ExtractFunc, xmlFiles)

View File

@ -10,8 +10,16 @@
#include "misc/locerrmsg/locerrmsg.h"
#include "misc/memerrmsg/memerrmsg.h"
#define SIZEOF_LOCERRMSG (sizeof(gNotDesignedForSystemErrorTex))
#define SIZEOF_MEMERRMSG (sizeof(gExpansionPakNotInstalledErrorTex) + sizeof(gSeeInstructionBookletErrorTex))
#define LOCERRMSG_WIDTH 208
#define LOCERRMSG_HEIGHT 16
#define NUMBEROF_LOCERRMSGS 1
#define MEMERRMSG_WIDTH 128
#define MEMERRMSG_HEIGHT 37
#define NUMBEROF_MEMERRMSGS 2
#define SIZEOF_LOCERRMSG (LOCERRMSG_WIDTH * LOCERRMSG_HEIGHT / 2 * NUMBEROF_LOCERRMSGS)
#define SIZEOF_MEMERRMSG (MEMERRMSG_WIDTH * MEMERRMSG_HEIGHT / 2 * NUMBEROF_MEMERRMSGS)
// Address with enough room after to load either of the error message image files before the fault screen buffer at the
// end of RDRAM
@ -64,9 +72,9 @@ void Check_ClearRGBA16(u16* buffer) {
void Check_DrawExpansionPakErrorMessage(void) {
DmaMgr_SendRequest0(CHECK_ERRMSG_STATIC_SEGMENT, SEGMENT_ROM_START(memerrmsg), SEGMENT_SIZE(memerrmsg));
Check_ClearRGBA16((u16*)FAULT_FB_ADDRESS);
Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 96, 71, 128, 37, CHECK_ERRMSG_STATIC_SEGMENT);
Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 96, 127, 128, 37,
CHECK_ERRMSG_STATIC_SEGMENT + sizeof(gExpansionPakNotInstalledErrorTex));
Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 96, 71, MEMERRMSG_WIDTH, MEMERRMSG_HEIGHT, CHECK_ERRMSG_STATIC_SEGMENT);
Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 96, 127, MEMERRMSG_WIDTH, MEMERRMSG_HEIGHT,
CHECK_ERRMSG_STATIC_SEGMENT + MEMERRMSG_WIDTH * MEMERRMSG_HEIGHT / 2);
osWritebackDCacheAll();
osViSwapBuffer((u16*)FAULT_FB_ADDRESS);
osViBlack(false);
@ -78,7 +86,8 @@ void Check_DrawExpansionPakErrorMessage(void) {
void Check_DrawRegionLockErrorMessage(void) {
DmaMgr_SendRequest0(CHECK_ERRMSG_STATIC_SEGMENT, SEGMENT_ROM_START(locerrmsg), SEGMENT_SIZE(locerrmsg));
Check_ClearRGBA16((u16*)FAULT_FB_ADDRESS);
Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 56, 112, 208, 16, CHECK_ERRMSG_STATIC_SEGMENT);
Check_DrawI4Texture((u16*)FAULT_FB_ADDRESS, 56, 112, LOCERRMSG_WIDTH, LOCERRMSG_HEIGHT,
CHECK_ERRMSG_STATIC_SEGMENT);
osWritebackDCacheAll();
osViSwapBuffer((u16*)FAULT_FB_ADDRESS);
osViBlack(false);

View File

@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/zeldaret/ZAPD.git
branch = master
commit = 4f7b8393ec8a3abd59649c2ba669e951fb61f3d2
parent = 346df1bbc8ca21673fe63d884b6734c23a4d9f4b
commit = 50242eca96a9c36fd84f438bab24548e73b42303
parent = 744955732b1fc9e8a835c62440aa97799cfe8940
method = merge
cmdver = 0.4.3

View File

@ -79,7 +79,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)\ZAPD\;$(SolutionDir)ZAPDUtils;$(SolutionDir)lib\tinyxml2;$(SolutionDir)lib\libgfxd;$(SolutionDir)lib\elfio;$(SolutionDir)lib\stb;$(ProjectDir);$(IncludePath)</IncludePath>
<IncludePath>$(ProjectDir)..\ZAPD\;$(ProjectDir)..\ZAPDUtils;$(ProjectDir)..\lib\tinyxml2;$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\lib\elfio;$(ProjectDir)..\lib\stb;$(ProjectDir);$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
@ -120,6 +120,7 @@
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc11</LanguageStandard_C>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -156,4 +157,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -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
{

View File

@ -1,7 +1,7 @@
# Only used for standalone compilation, usually inherits these from the main makefile
CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17
SRC_DIRS := $(shell find -type d -not -path "*build*")
SRC_DIRS := $(shell find . -type d -not -path "*build*")
CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h))

View File

@ -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)
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <Utils/BinaryWriter.h>
#include "Utils/BinaryWriter.h"
#include "ZResource.h"
#include "ZTexture.h"

View File

@ -7,7 +7,7 @@ pipeline {
// Non-parallel ZAPD stage
stage('Build ZAPD') {
steps {
sh 'make -j'
sh 'make -j WERROR=1'
}
}
@ -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'
// }
// }
// }
}
}
}

View File

@ -6,6 +6,7 @@ DEPRECATION_ON ?= 1
DEBUG ?= 0
COPYCHECK_ARGS ?=
LLD ?= 0
WERROR ?= 0
# Use clang++ if available, else use g++
ifeq ($(shell command -v clang++ >/dev/null 2>&1; echo $$?),0)
@ -23,14 +24,16 @@ ifneq ($(DEBUG),0)
CXXFLAGS += -g3 -DDEVELOPMENT -D_DEBUG
COPYCHECK_ARGS += --devel
DEPRECATION_ON = 0
else
endif
ifneq ($(WERROR),0)
CXXFLAGS += -Werror
endif
ifeq ($(OPTIMIZATION_ON),0)
OPTFLAGS := -O0
else
OPTFLAGS := -O2 -march=native -mtune=native
OPTFLAGS := -O2
endif
ifneq ($(ASAN),0)
@ -53,10 +56,23 @@ ifneq ($(LLD),0)
endif
UNAME := $(shell uname)
UNAMEM := $(shell uname -m)
ifneq ($(UNAME), Darwin)
LDFLAGS += -Wl,-export-dynamic -lstdc++fs
LDFLAGS += -Wl,-export-dynamic -lstdc++fs
EXPORTERS := -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive
else
EXPORTERS := -Wl,-force_load ExporterTest/ExporterTest.a
ifeq ($(UNAMEM),arm64)
ifeq ($(shell brew list libpng > /dev/null 2>&1; echo $$?),0)
LDFLAGS += -L $(shell brew --prefix)/lib
INC += -I $(shell brew --prefix)/include
else
$(error Please install libpng via Homebrew)
endif
endif
endif
ZAPD_SRC_DIRS := $(shell find ZAPD -type d)
SRC_DIRS = $(ZAPD_SRC_DIRS) lib/tinyxml2
@ -115,4 +131,4 @@ ZAPDUtils:
# Linking
ZAPD.out: $(O_FILES) lib/libgfxd/libgfxd.a ExporterTest ZAPDUtils
$(CXX) $(CXXFLAGS) $(O_FILES) lib/libgfxd/libgfxd.a ZAPDUtils/ZAPDUtils.a -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive $(LDFLAGS) $(OUTPUT_OPTION)
$(CXX) $(CXXFLAGS) $(O_FILES) lib/libgfxd/libgfxd.a ZAPDUtils/ZAPDUtils.a $(EXPORTERS) $(LDFLAGS) $(OUTPUT_OPTION)

View File

@ -16,6 +16,14 @@ In a Debian/Ubuntu based environment, those could be installed with the followin
sudo apt install libpng-dev
```
On a Mac, you will need to install libpng with Homebrew or MacPorts; we currently only support Homebrew. You can run
```bash
brew install libpng
```
to install it via Homebrew.
### Building
#### Linux / *nix
@ -109,11 +117,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:
![ZAPD warnings example](docs/zapd_warning_example.png?raw=true)

View File

@ -92,20 +92,20 @@ std::string Declaration::GetNormalDeclarationStr() const
if (isArray)
{
if (arrayItemCntStr != "")
if (arrayItemCntStr != "" && (IsStatic() || forceArrayCnt))
{
output += StringHelper::Sprintf("%s %s[%s];\n", varType.c_str(), varName.c_str(),
arrayItemCntStr.c_str());
}
else if (arrayItemCnt == 0)
{
output += StringHelper::Sprintf("%s %s[] = {\n", varType.c_str(), varName.c_str());
}
else
else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt))
{
output += StringHelper::Sprintf("%s %s[%i] = {\n", varType.c_str(), varName.c_str(),
arrayItemCnt);
}
else
{
output += StringHelper::Sprintf("%s %s[] = {\n", varType.c_str(), varName.c_str());
}
output += text + "\n";
}
@ -145,16 +145,16 @@ std::string Declaration::GetExternalDeclarationStr() const
output += "static ";
}
if (arrayItemCntStr != "")
if (arrayItemCntStr != "" && (IsStatic() || forceArrayCnt))
output += StringHelper::Sprintf("%s %s[%s] = ", varType.c_str(), varName.c_str(),
arrayItemCntStr.c_str());
else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt))
output +=
StringHelper::Sprintf("%s %s[%s] = {\n#include \"%s\"\n};", varType.c_str(),
varName.c_str(), arrayItemCntStr.c_str(), includePath.c_str());
else if (arrayItemCnt != 0)
output += StringHelper::Sprintf("%s %s[%i] = {\n#include \"%s\"\n};", varType.c_str(),
varName.c_str(), arrayItemCnt, includePath.c_str());
StringHelper::Sprintf("%s %s[%i] = ", varType.c_str(), varName.c_str(), arrayItemCnt);
else
output += StringHelper::Sprintf("%s %s[] = {\n#include \"%s\"\n};", varType.c_str(),
varName.c_str(), includePath.c_str());
output += StringHelper::Sprintf("%s %s[] = ", varType.c_str(), varName.c_str());
output += StringHelper::Sprintf("{\n#include \"%s\"\n};", includePath.c_str());
if (rightText != "")
output += " " + rightText + "";
@ -178,14 +178,16 @@ std::string Declaration::GetExternStr() const
if (isArray)
{
if (arrayItemCntStr != "")
if (arrayItemCntStr != "" && (IsStatic() || forceArrayCnt))
{
return StringHelper::Sprintf("extern %s %s[%s];\n", varType.c_str(), varName.c_str(),
arrayItemCntStr.c_str());
}
else if (arrayItemCnt != 0)
else if (arrayItemCnt != 0 && (IsStatic() || forceArrayCnt))
{
return StringHelper::Sprintf("extern %s %s[%i];\n", varType.c_str(), varName.c_str(),
arrayItemCnt);
}
else
return StringHelper::Sprintf("extern %s %s[];\n", varType.c_str(), varName.c_str());
}

View File

@ -38,10 +38,12 @@ public:
std::string varType;
std::string varName;
std::string includePath;
bool isExternal = false;
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;

View File

@ -25,7 +25,7 @@ GameConfig::~GameConfig()
void GameConfig::ReadTexturePool(const fs::path& texturePoolXmlPath)
{
tinyxml2::XMLDocument doc;
tinyxml2::XMLError eResult = doc.LoadFile(texturePoolXmlPath.c_str());
tinyxml2::XMLError eResult = doc.LoadFile(texturePoolXmlPath.string().c_str());
if (eResult != tinyxml2::XML_SUCCESS)
{
@ -155,7 +155,7 @@ void GameConfig::ReadConfigFile(const fs::path& argConfigFilePath)
{"ExternalFile", &GameConfig::ConfigFunc_ExternalFile},
};
configFilePath = argConfigFilePath;
configFilePath = argConfigFilePath.string();
tinyxml2::XMLDocument doc;
tinyxml2::XMLError eResult = doc.LoadFile(configFilePath.c_str());

View File

@ -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;

View File

@ -20,6 +20,7 @@ typedef bool (*ExporterSetFuncBool)(ZFileMode fileMode);
typedef void (*ExporterSetFuncVoid)(int argc, char* argv[], int& i);
typedef void (*ExporterSetFuncVoid2)(const std::string& buildMode, ZFileMode& fileMode);
typedef void (*ExporterSetFuncVoid3)();
typedef void (*ExporterSetResSave)(ZResource* res, BinaryWriter& writer);
class ExporterSet
{
@ -34,6 +35,7 @@ public:
ExporterSetFunc endFileFunc = nullptr;
ExporterSetFuncVoid3 beginXMLFunc = nullptr;
ExporterSetFuncVoid3 endXMLFunc = nullptr;
ExporterSetResSave resSaveFunc = nullptr;
};
class Globals
@ -53,9 +55,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;

View File

@ -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", "");
}
}

View File

@ -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
@ -47,6 +48,7 @@ void ErrorHandler(int sig)
const char* crashEasterEgg[] = {
"\tYou've met with a terrible fate, haven't you?",
"\tSEA BEARS FOAM. SLEEP BEARS DREAMS. \n\tBOTH END IN THE SAME WAY: CRASSSH!",
"ZAPD has fallen and cannot get up."
};
srand(time(nullptr));
@ -97,6 +99,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 +114,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 +191,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 +256,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 +333,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 +343,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 +395,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);
}
}

View File

View File

@ -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;
@ -90,7 +90,7 @@ ZOverlay* ZOverlay::FromBuild(fs::path buildPath, fs::path cfgFolderPath)
std::vector<elfio*> readers;
for (size_t i = 1; i < cfgLines.size(); i++)
{
std::string elfPath = buildPath / (cfgLines[i].substr(0, cfgLines[i].size() - 2) + ".o");
std::string elfPath = (buildPath / (cfgLines[i].substr(0, cfgLines[i].size() - 2) + ".o")).string();
elfio* reader = new elfio();
if (!reader->load(elfPath))
@ -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++)

View File

@ -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;
uint32_t 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");
}

View File

@ -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();
};

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.props" Condition="Exists('..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.props')" />
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@ -71,8 +72,8 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(SolutionDir)lib\libgfxd;$(SolutionDir)x64\Debug;$(SolutionDir)packages\libpng.1.6.28.1\build\native\lib\x64\v140\dynamic\Debug;$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)ZAPDUtils;$(SolutionDir)lib\tinyxml2;$(SolutionDir)lib\libgfxd;$(SolutionDir)lib\elfio;$(SolutionDir)lib\stb;$(ProjectDir);$(IncludePath)</IncludePath>
<LibraryPath>$(OutDir);$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\packages\libpng-v142.1.6.37.2\build\native\lib\x64\v142\Debug\;$(LibraryPath)</LibraryPath>
<IncludePath>$(ProjectDir)..\ZAPDUtils;$(ProjectDir)..\lib\tinyxml2;$(ProjectDir)..\lib\libgfxd;$(ProjectDir)..\lib\elfio;$(ProjectDir)..\lib\stb;$(ProjectDir);$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(IncludePath)</IncludePath>
@ -105,13 +106,16 @@
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<LanguageStandard_C>stdc11</LanguageStandard_C>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
</ClCompile>
<Link>
<Profile>true</Profile>
<AdditionalDependencies>libpng16.lib;ZAPDUtils.lib;/WHOLEARCHIVE:ExporterExample.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ZAPDUtils.lib;/WHOLEARCHIVE:ExporterExample.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link>
<PreBuildEvent>
<Command>cd ..
mkdir build\ZAPD
python3 ZAPD/genbuildinfo.py</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
@ -146,6 +150,7 @@ python3 ZAPD/genbuildinfo.py</Command>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\build\ZAPD\BuildInfo.cpp" />
<ClCompile Include="..\lib\libgfxd\gfxd.c" />
<ClCompile Include="..\lib\libgfxd\uc.c" />
<ClCompile Include="..\lib\libgfxd\uc_f3d.c" />
@ -153,19 +158,22 @@ python3 ZAPD/genbuildinfo.py</Command>
<ClCompile Include="..\lib\libgfxd\uc_f3dex.c" />
<ClCompile Include="..\lib\libgfxd\uc_f3dex2.c" />
<ClCompile Include="..\lib\libgfxd\uc_f3dexb.c" />
<ClCompile Include="..\lib\tinyxml2\tinyxml2.cpp" />
<ClCompile Include="Declaration.cpp" />
<ClCompile Include="GameConfig.cpp" />
<ClCompile Include="Globals.cpp" />
<ClCompile Include="ImageBackend.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="OtherStructs\SkinLimbStructs.cpp" />
<ClCompile Include="OutputFormatter.cpp" />
<ClCompile Include="Overlays\ZOverlay.cpp" />
<ClCompile Include="WarningHandler.cpp" />
<ClCompile Include="ZArray.cpp" />
<ClCompile Include="ZBackground.cpp" />
<ClCompile Include="ZCutsceneMM.cpp" />
<ClCompile Include="ZLimb.cpp" />
<ClCompile Include="ZMtx.cpp" />
<ClCompile Include="ZPath.cpp" />
<ClCompile Include="ZPlayerAnimationData.cpp" />
<ClCompile Include="ZRoom\Commands\SetActorCutsceneList.cpp" />
<ClCompile Include="ZRoom\Commands\SetAnimatedMaterialList.cpp" />
<ClCompile Include="ZRoom\Commands\SetCsCamera.cpp" />
@ -213,6 +221,7 @@ python3 ZAPD/genbuildinfo.py</Command>
<ClCompile Include="ZString.cpp" />
<ClCompile Include="ZSymbol.cpp" />
<ClCompile Include="ZTexture.cpp" />
<ClCompile Include="ZTextureAnimation.cpp" />
<ClCompile Include="ZVector.cpp" />
<ClCompile Include="ZVtx.cpp" />
</ItemGroup>
@ -237,10 +246,13 @@ python3 ZAPD/genbuildinfo.py</Command>
<ClInclude Include="..\lib\stb\tinyxml2.h" />
<ClInclude Include="CRC32.h" />
<ClInclude Include="Declaration.h" />
<ClInclude Include="GameConfig.h" />
<ClInclude Include="Globals.h" />
<ClInclude Include="ImageBackend.h" />
<ClInclude Include="OtherStructs\SkinLimbStructs.h" />
<ClInclude Include="OutputFormatter.h" />
<ClInclude Include="Overlays\ZOverlay.h" />
<ClInclude Include="WarningHandler.h" />
<ClInclude Include="ZAnimation.h" />
<ClInclude Include="ZArray.h" />
<ClInclude Include="ZBackground.h" />
@ -253,6 +265,7 @@ python3 ZAPD/genbuildinfo.py</Command>
<ClInclude Include="ZLimb.h" />
<ClInclude Include="ZMtx.h" />
<ClInclude Include="ZPath.h" />
<ClInclude Include="ZPlayerAnimationData.h" />
<ClInclude Include="ZRoom\Commands\SetActorCutsceneList.h" />
<ClInclude Include="ZRoom\Commands\SetAnimatedMaterialList.h" />
<ClInclude Include="ZRoom\Commands\SetCsCamera.h" />
@ -294,6 +307,7 @@ python3 ZAPD/genbuildinfo.py</Command>
<ClInclude Include="ZString.h" />
<ClInclude Include="ZSymbol.h" />
<ClInclude Include="ZTexture.h" />
<ClInclude Include="ZTextureAnimation.h" />
<ClInclude Include="ZVector.h" />
<ClInclude Include="ZVtx.h" />
</ItemGroup>
@ -301,24 +315,29 @@ python3 ZAPD/genbuildinfo.py</Command>
<Text Include="..\SymbolMap_OoTMqDbg.txt">
<DeploymentContent>true</DeploymentContent>
</Text>
<Text Include="any\any\zlib.static.txt" />
<Text Include="NuGet\libpng.static.txt" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\packages\libpng.redist.1.6.28.1\build\native\libpng.redist.targets" Condition="Exists('..\packages\libpng.redist.1.6.28.1\build\native\libpng.redist.targets')" />
<Import Project="..\packages\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\packages\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.targets')" />
<Import Project="..\packages\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.targets" Condition="Exists('..\packages\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" />
<Import Project="..\packages\libpng.1.6.28.1\build\native\libpng.targets" Condition="Exists('..\packages\libpng.1.6.28.1\build\native\libpng.targets')" />
<Import Project="..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.targets" Condition="Exists('..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.targets')" />
<Import Project="..\packages\zlib.static.1.2.5\build\native\zlib.static.targets" Condition="Exists('..\packages\zlib.static.1.2.5\build\native\zlib.static.targets')" />
<Import Project="..\packages\libpng.static.1.6.37\build\native\libpng.static.targets" Condition="Exists('..\packages\libpng.static.1.6.37\build\native\libpng.static.targets')" />
</ImportGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\libpng.redist.1.6.28.1\build\native\libpng.redist.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\libpng.redist.1.6.28.1\build\native\libpng.redist.targets'))" />
<Error Condition="!Exists('..\packages\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v120.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
<Error Condition="!Exists('..\packages\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.1.2.8.8\build\native\zlib.v140.windesktop.msvcstl.dyn.rt-dyn.targets'))" />
<Error Condition="!Exists('..\packages\libpng.1.6.28.1\build\native\libpng.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\libpng.1.6.28.1\build\native\libpng.targets'))" />
<Error Condition="!Exists('..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.props'))" />
<Error Condition="!Exists('..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\YY.NuGet.Import.Helper.1.0.0.4\build\native\YY.NuGet.Import.Helper.targets'))" />
<Error Condition="!Exists('..\packages\zlib.static.1.2.5\build\native\zlib.static.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\zlib.static.1.2.5\build\native\zlib.static.targets'))" />
<Error Condition="!Exists('..\packages\libpng.static.1.6.37\build\native\libpng.static.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\libpng.static.1.6.37\build\native\libpng.static.targets'))" />
</Target>
</Project>

View File

@ -49,6 +49,15 @@
<Filter Include="Header Files\Libraries\libgfxd">
<UniqueIdentifier>{85600275-99fe-491d-8189-bcc3dc1a8903}</UniqueIdentifier>
</Filter>
<Filter Include="any">
<UniqueIdentifier>{ba9990b0-1082-48bb-874c-6108534b5455}</UniqueIdentifier>
</Filter>
<Filter Include="any\any">
<UniqueIdentifier>{ce9d91b0-ba20-4296-bc2d-8630965bb392}</UniqueIdentifier>
</Filter>
<Filter Include="NuGet">
<UniqueIdentifier>{730beb67-6d59-4849-9d9b-702c4a565fc0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp">
@ -135,9 +144,6 @@
<ClCompile Include="ZRoom\Commands\SetCutscenes.cpp">
<Filter>Source Files\Z64\ZRoom\Commands</Filter>
</ClCompile>
<ClCompile Include="..\lib\tinyxml2\tinyxml2.cpp">
<Filter>Source Files\Libraries</Filter>
</ClCompile>
<ClCompile Include="ZAnimation.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
@ -258,6 +264,24 @@
<ClCompile Include="ZString.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
<ClCompile Include="GameConfig.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ZTextureAnimation.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
<ClCompile Include="OtherStructs\SkinLimbStructs.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
<ClCompile Include="..\build\ZAPD\BuildInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ZPlayerAnimationData.cpp">
<Filter>Source Files\Z64</Filter>
</ClCompile>
<ClCompile Include="WarningHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ZRoom\ZRoom.h">
@ -497,11 +521,32 @@
<ClInclude Include="ZString.h">
<Filter>Header Files\Z64</Filter>
</ClInclude>
<ClInclude Include="GameConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ZTextureAnimation.h">
<Filter>Header Files\Z64</Filter>
</ClInclude>
<ClInclude Include="OtherStructs\SkinLimbStructs.h">
<Filter>Header Files\Z64</Filter>
</ClInclude>
<ClInclude Include="ZPlayerAnimationData.h">
<Filter>Header Files\Z64</Filter>
</ClInclude>
<ClInclude Include="WarningHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="..\SymbolMap_OoTMqDbg.txt">
<Filter>Resource Files</Filter>
</Text>
<Text Include="any\any\zlib.static.txt">
<Filter>any\any</Filter>
</Text>
<Text Include="NuGet\libpng.static.txt">
<Filter>NuGet</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />

View File

@ -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);
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "Vec3s.h"

View File

@ -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++)
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"

View File

@ -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()));
}
}
@ -138,6 +133,7 @@ Declaration* ZBackground::DeclareVar(const std::string& prefix,
Declaration* decl = parent->AddDeclarationIncludeArray(rawDataIndex, incStr, GetRawDataSize(),
GetSourceTypeName(), auxName, 0);
decl->arrayItemCntStr = "SCREEN_WIDTH * SCREEN_HEIGHT / 4";
decl->forceArrayCnt = true;
decl->staticConf = staticConf;
return decl;
}

View File

@ -83,11 +83,6 @@ std::string ZBlob::GetBodySourceCode() const
return sourceOutput;
}
std::string ZBlob::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix)
{
return StringHelper::Sprintf("extern u8 %s[];\n", name.c_str());
}
void ZBlob::Save(const fs::path& outFolder)
{
File::WriteAllBytes((outFolder / (name + ".bin")).string(), blobData);

View File

@ -16,7 +16,6 @@ public:
Declaration* DeclareVar(const std::string& prefix, const std::string& bodyStr) override;
std::string GetBodySourceCode() const override;
std::string GetSourceOutputHeader(const std::string& prefix) override;
void Save(const fs::path& outFolder) override;
bool IsExternalResource() const override;

View File

@ -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";

View File

@ -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;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "ZFile.h"

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "ZCutscene.h"

View File

@ -3,6 +3,7 @@
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cinttypes>
#include <cmath>
#include "Globals.h"
@ -11,6 +12,7 @@
#include "Utils/File.h"
#include "Utils/Path.h"
#include "Utils/StringHelper.h"
#include "WarningHandler.h"
#include "gfxd.h"
REGISTER_ZFILENODE(DList, ZDisplayList);
@ -105,7 +107,7 @@ void ZDisplayList::ParseF3DZEX(F3DZEXOpcode opcode, uint64_t data, int32_t i,
switch (opcode)
{
case F3DZEXOpcode::G_NOOP:
sprintf(line, "gsDPNoOpTag(0x%08lX),", data & 0xFFFFFFFF);
sprintf(line, "gsDPNoOpTag(0x%08" PRIX64 "),", data & 0xFFFFFFFF);
break;
case F3DZEXOpcode::G_DL:
Opcode_G_DL(data, prefix, line);
@ -220,7 +222,7 @@ void ZDisplayList::ParseF3DZEX(F3DZEXOpcode opcode, uint64_t data, int32_t i,
break;
case F3DZEXOpcode::G_POPMTX:
{
sprintf(line, "gsSPPopMatrix(%li),", data);
sprintf(line, "gsSPPopMatrix(%" PRIi64 "),", data);
}
break;
case F3DZEXOpcode::G_LOADTLUT:
@ -297,7 +299,7 @@ void ZDisplayList::ParseF3DEX(F3DEXOpcode opcode, uint64_t data, const std::stri
switch (opcode)
{
case F3DEXOpcode::G_NOOP:
sprintf(line, "gsDPNoOpTag(0x%08lX),", data & 0xFFFFFFFF);
sprintf(line, "gsDPNoOpTag(0x%08" PRIX64 "),", data & 0xFFFFFFFF);
break;
case F3DEXOpcode::G_VTX:
Opcode_G_VTX(data, line);
@ -445,11 +447,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);
@ -686,20 +689,20 @@ void ZDisplayList::Opcode_G_DL(uint64_t data, const std::string& prefix, char* l
if (pp != 0)
{
if (!Globals::Instance->HasSegment(segNum))
sprintf(line, "gsSPBranchList(0x%08lX),", data & 0xFFFFFFFF);
sprintf(line, "gsSPBranchList(0x%08" PRIX64 "),", data & 0xFFFFFFFF);
else if (dListDecl != nullptr)
sprintf(line, "gsSPBranchList(%s),", dListDecl->varName.c_str());
else
sprintf(line, "gsSPBranchList(%sDlist0x%06lX),", prefix.c_str(), GETSEGOFFSET(data));
sprintf(line, "gsSPBranchList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), GETSEGOFFSET(data));
}
else
{
if (!Globals::Instance->HasSegment(segNum))
sprintf(line, "gsSPDisplayList(0x%08lX),", data & 0xFFFFFFFF);
sprintf(line, "gsSPDisplayList(0x%08" PRIX64 "),", data & 0xFFFFFFFF);
else if (dListDecl != nullptr)
sprintf(line, "gsSPDisplayList(%s),", dListDecl->varName.c_str());
else
sprintf(line, "gsSPDisplayList(%sDlist0x%06lX),", prefix.c_str(), GETSEGOFFSET(data));
sprintf(line, "gsSPDisplayList(%sDlist0x%06" PRIX64 "),", prefix.c_str(), GETSEGOFFSET(data));
}
// if (segNum == 8 || segNum == 9 || segNum == 10 || segNum == 11 || segNum == 12 || segNum ==
@ -707,9 +710,9 @@ void ZDisplayList::Opcode_G_DL(uint64_t data, const std::string& prefix, char* l
if (!Globals::Instance->HasSegment(segNum))
{
if (pp != 0)
sprintf(line, "gsSPBranchList(0x%08lX),", data & 0xFFFFFFFF);
sprintf(line, "gsSPBranchList(0x%08" PRIX64 "),", data & 0xFFFFFFFF);
else
sprintf(line, "gsSPDisplayList(0x%08lX),", data & 0xFFFFFFFF);
sprintf(line, "gsSPDisplayList(0x%08" PRIX64 "),", data & 0xFFFFFFFF);
}
else
{
@ -941,7 +944,7 @@ void ZDisplayList::Opcode_G_SETTIMG(uint64_t data, const std::string& prefix, ch
sprintf(texStr, "%sTex_%06X", prefix.c_str(), texAddress);
else
{
sprintf(texStr, "0x%08lX", data & 0xFFFFFFFF);
sprintf(texStr, "0x%08" PRIX64, data & 0xFFFFFFFF);
}
sprintf(line, "gsDPSetTextureImage(%s, %s, %i, %s),", fmtTbl[fmt], sizTbl[siz], www + 1,
@ -1522,11 +1525,6 @@ void ZDisplayList::Opcode_G_ENDDL([[maybe_unused]] const std::string& prefix, ch
TextureGenCheck();
}
std::string ZDisplayList::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix)
{
return "";
}
static int32_t GfxdCallback_FormatSingleEntry()
{
ZDisplayList* self = static_cast<ZDisplayList*>(gfxd_udata_get());
@ -1737,7 +1735,7 @@ static int32_t GfxdCallback_Matrix(uint32_t seg)
return 1;
}
std::string ZDisplayList::GetSourceOutputCode(const std::string& prefix)
void ZDisplayList::DeclareReferences(const std::string& prefix)
{
std::string sourceOutput;
@ -1750,7 +1748,7 @@ std::string ZDisplayList::GetSourceOutputCode(const std::string& prefix)
if (vertices.size() > 0)
{
std::vector<std::pair<uint32_t, std::vector<ZVtx>>> verticesSorted(vertices.begin(),
vertices.end());
vertices.end());
for (size_t i = 0; i < verticesSorted.size() - 1; i++)
{
@ -1775,15 +1773,13 @@ 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);
for (auto vtx : item.second)
{
declaration += StringHelper::Sprintf("\t%s,\n", vtx.GetBodySourceCode().c_str());
}
Declaration* decl = parent->AddDeclarationArray(
curAddr, firstVtx.GetDeclarationAlignment(),
@ -1800,7 +1796,7 @@ std::string ZDisplayList::GetSourceOutputCode(const std::string& prefix)
if (vertices.size() > 0)
{
std::vector<std::pair<uint32_t, std::vector<ZVtx>>> verticesSorted(vertices.begin(),
vertices.end());
vertices.end());
for (size_t i = 0; i < verticesSorted.size() - 1; i++)
{
@ -1863,11 +1859,6 @@ std::string ZDisplayList::GetSourceOutputCode(const std::string& prefix)
}
}
}
if (parent != nullptr)
return "";
return sourceOutput;
}
std::string ZDisplayList::ProcessLegacy(const std::string& prefix)
@ -1899,10 +1890,10 @@ std::string ZDisplayList::ProcessLegacy(const std::string& prefix)
}
auto end = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
int64_t diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_DEBUG && diff > 5)
printf("F3DOP: 0x%02X, TIME: %lims\n", opcode, diff);
printf("F3DOP: 0x%02X, TIME: %" PRIi64 "ms\n", opcode, diff);
sourceOutput += line;
@ -1983,7 +1974,7 @@ bool ZDisplayList::TextureGenCheck(int32_t texWidth, int32_t texHeight, uint32_t
}
else
{
// Try to find a non-external file (ie, one we are actually extracting)
// Try to find a non-external file (i.e., one we are actually extracting)
// which has the same segment number we are looking for.
for (auto& otherFile : Globals::Instance->cfg.segmentRefFiles[segmentNumber])
{

View File

@ -363,8 +363,7 @@ public:
size_t GetRawDataSize() const override;
DeclarationAlignment GetDeclarationAlignment() const override;
std::string GetSourceOutputHeader(const std::string& prefix) override;
std::string GetSourceOutputCode(const std::string& prefix) override;
void DeclareReferences(const std::string& prefix) override;
std::string ProcessLegacy(const std::string& prefix);
std::string ProcessGfxDis(const std::string& prefix);

View File

@ -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"
@ -73,19 +74,13 @@ ZFile::ZFile(ZFileMode nMode, tinyxml2::XMLElement* reader, const fs::path& nBas
ZFile::~ZFile()
{
for (ZResource* res : resources)
{
delete res;
}
for (auto d : declarations)
{
delete d.second;
}
for (auto sym : symbolResources)
{
delete sym.second;
}
}
void ZFile::ParseXML(tinyxml2::XMLElement* reader, const std::string& filename)
@ -114,8 +109,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 +126,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 +150,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 +183,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 +216,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)
else
{
fprintf(stderr, "Warning No offset specified for: %s", nameXml);
}
else if (Globals::Instance->errorNoOffset)
{
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 +236,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 +246,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 +281,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, "");
}
}
}
@ -307,7 +307,7 @@ void ZFile::BuildSourceFile()
return;
if (!Directory::Exists(outputPath))
Directory::CreateDirectory(outputPath);
Directory::CreateDirectory(outputPath.string());
GenerateSourceFiles();
}
@ -317,6 +317,11 @@ std::string ZFile::GetName() const
return name;
}
std::string ZFile::GetOutName() const
{
return outName.string();
}
ZFileMode ZFile::GetMode() const
{
return mode;
@ -338,10 +343,10 @@ void ZFile::ExtractResources()
return;
if (!Directory::Exists(outputPath))
Directory::CreateDirectory(outputPath);
Directory::CreateDirectory(outputPath.string());
if (!Directory::Exists(GetSourceOutputFolderPath()))
Directory::CreateDirectory(GetSourceOutputFolderPath());
Directory::CreateDirectory(GetSourceOutputFolderPath().string());
for (size_t i = 0; i < resources.size(); i++)
resources[i]->ParseRawDataLate();
@ -351,8 +356,8 @@ void ZFile::ExtractResources()
if (Globals::Instance->genSourceFile)
GenerateSourceFiles();
MemoryStream* memStream = new MemoryStream();
BinaryWriter writer = BinaryWriter(memStream);
auto memStreamFile = std::shared_ptr<MemoryStream>(new MemoryStream());
BinaryWriter writerFile = BinaryWriter(memStreamFile);
ExporterSet* exporterSet = Globals::Instance->GetExporterSet();
@ -361,6 +366,9 @@ void ZFile::ExtractResources()
for (ZResource* res : resources)
{
auto memStreamRes = std::shared_ptr<MemoryStream>(new MemoryStream());
BinaryWriter writerRes = BinaryWriter(memStreamRes);
if (Globals::Instance->verbosity >= VerbosityLevel::VERBOSITY_INFO)
printf("Saving resource %s\n", res->GetName().c_str());
@ -369,18 +377,24 @@ void ZFile::ExtractResources()
// Check if we have an exporter "registered" for this resource type
ZResourceExporter* exporter = Globals::Instance->GetExporter(res->GetResourceType());
if (exporter != nullptr)
exporter->Save(res, Globals::Instance->outputPath.string(), &writer);
{
//exporter->Save(res, Globals::Instance->outputPath.string(), &writerFile);
exporter->Save(res, Globals::Instance->outputPath.string(), &writerRes);
}
if (exporterSet != nullptr && exporterSet->resSaveFunc != nullptr)
exporterSet->resSaveFunc(res, writerRes);
}
if (memStream->GetLength() > 0)
if (memStreamFile->GetLength() > 0)
{
File::WriteAllBytes(StringHelper::Sprintf("%s%s.bin",
Globals::Instance->outputPath.string().c_str(),
GetName().c_str()),
memStream->ToVector());
memStreamFile->ToVector());
}
writer.Close();
writerFile.Close();
if (exporterSet != nullptr && exporterSet->endFileFunc != nullptr)
exporterSet->endFileFunc(this);
@ -1070,8 +1084,6 @@ std::string ZFile::ProcessDeclarations()
}
}
output += "\n";
return output;
}
@ -1234,11 +1246,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);
}
}
@ -1309,25 +1322,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));
}
}
}

View File

@ -1,6 +1,5 @@
#pragma once
#include <Utils/Directory.h>
#include <string>
#include <vector>
@ -46,6 +45,7 @@ public:
~ZFile();
std::string GetName() const;
std::string GetOutName() const;
ZFileMode GetMode() const;
const fs::path& GetXmlFilePath() const;
const std::vector<uint8_t>& GetRawData() const;

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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;
@ -253,18 +258,21 @@ std::string ZResource::GetDefaultName(const std::string& prefix) const
rawDataIndex);
}
std::string ZResource::GetSourceOutputCode([[maybe_unused]] const std::string& prefix)
void ZResource::GetSourceOutputCode([[maybe_unused]] const std::string& prefix)
{
std::string bodyStr = GetBodySourceCode();
Declaration* decl = parent->GetDeclaration(rawDataIndex);
if (decl == nullptr || decl->isPlaceholder)
decl = DeclareVar(prefix, bodyStr);
else
decl->text = bodyStr;
decl->staticConf = staticConf;
if (bodyStr != "ERROR")
{
Declaration* decl = parent->GetDeclaration(rawDataIndex);
return "";
if (decl == nullptr || decl->isPlaceholder)
decl = DeclareVar(prefix, bodyStr);
else
decl->text = bodyStr;
decl->staticConf = staticConf;
}
}
std::string ZResource::GetSourceOutputHeader([[maybe_unused]] const std::string& prefix)
@ -312,13 +320,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;
}

View File

@ -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
@ -113,7 +112,7 @@ public:
*/
[[nodiscard]] virtual std::string GetDefaultName(const std::string& prefix) const;
virtual std::string GetSourceOutputCode(const std::string& prefix);
virtual void GetSourceOutputCode(const std::string& prefix);
virtual std::string GetSourceOutputHeader(const std::string& prefix);
virtual void CalcHash();
/**

View File

@ -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();
@ -53,11 +54,9 @@ void SetMesh::DeclareReferences(const std::string& prefix)
void GenDListDeclarations(ZRoom* zRoom, ZFile* parent, ZDisplayList* dList)
{
if (dList == nullptr)
{
return;
}
std::string sourceOutput = dList->GetSourceOutputCode(zRoom->GetName());
dList->DeclareReferences(zRoom->GetName());
for (ZDisplayList* otherDList : dList->otherDLists)
GenDListDeclarations(zRoom, parent, otherDList);
@ -143,21 +142,17 @@ std::string PolygonDlist::GetBodySourceCode() const
return bodyStr;
}
std::string PolygonDlist::GetSourceOutputCode(const std::string& prefix)
void PolygonDlist::GetSourceOutputCode(const std::string& prefix)
{
std::string bodyStr = StringHelper::Sprintf("\n\t%s\n", GetBodySourceCode().c_str());
Declaration* decl = parent->GetDeclaration(rawDataIndex);
if (decl == nullptr)
{
DeclareVar(prefix, bodyStr);
}
else
{
decl->text = bodyStr;
}
return "";
if (decl == nullptr)
DeclareVar(prefix, bodyStr);
else
decl->text = bodyStr;
}
std::string PolygonDlist::GetSourceTypeName() const
@ -472,8 +467,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;
}
}
@ -582,9 +577,11 @@ void PolygonType2::DeclareReferences(const std::string& prefix)
polyDListName = StringHelper::Sprintf("%s%s_%06X", prefix.c_str(), polyDlistType.c_str(),
GETSEGOFFSET(start));
parent->AddDeclarationArray(GETSEGOFFSET(start), DeclarationAlignment::Align4,
polyDLists.size() * polyDLists.at(0).GetRawDataSize(),
polyDlistType, polyDListName, polyDLists.size(), declaration);
Declaration* decl = parent->AddDeclarationArray(
GETSEGOFFSET(start), DeclarationAlignment::Align4,
polyDLists.size() * polyDLists.at(0).GetRawDataSize(), polyDlistType, polyDListName,
polyDLists.size(), declaration);
decl->forceArrayCnt = true;
}
parent->AddDeclaration(GETSEGOFFSET(end), DeclarationAlignment::Align4, 4, "s32",

View File

@ -28,7 +28,7 @@ public:
std::string GetBodySourceCode() const override;
std::string GetSourceOutputCode(const std::string& prefix) override;
void GetSourceOutputCode(const std::string& prefix) override;
std::string GetSourceTypeName() const override;
ZResourceType GetResourceType() const override;

View File

@ -115,11 +115,9 @@ std::string RomFile::GetBodySourceCode() const
return declaration;
}
std::string RomFile::GetSourceOutputCode(const std::string& prefix)
void RomFile::GetSourceOutputCode(const std::string& prefix)
{
DeclareVar(prefix, GetBodySourceCode());
return "";
}
std::string RomFile::GetSourceTypeName() const

View File

@ -24,7 +24,7 @@ public:
Declaration* DeclareVar(const std::string& prefix, const std::string& body) override;
std::string GetBodySourceCode() const override;
std::string GetSourceOutputCode(const std::string& prefix) override;
void GetSourceOutputCode(const std::string& prefix) override;
std::string GetSourceTypeName() const override;
virtual ZResourceType GetResourceType() const override;

View File

@ -2,7 +2,9 @@
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cinttypes>
#include <string_view>
#include "Commands/EndMarker.h"
#include "Commands/SetActorCutsceneList.h"
#include "Commands/SetActorList.h"
@ -40,6 +42,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 +126,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, "");
}
}
}
@ -256,9 +261,9 @@ void ZRoom::ParseRawData()
if (Globals::Instance->profile)
{
auto end = std::chrono::steady_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
int64_t diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
if (diff > 50)
printf("OP: %s, TIME: %lims\n", cmd->GetCommandCName().c_str(), diff);
printf("OP: %s, TIME: %" PRIi64 "ms\n", cmd->GetCommandCName().c_str(), diff);
}
cmd->cmdIndex = currentIndex;
@ -392,14 +397,10 @@ size_t ZRoom::GetCommandSizeFromNeighbor(ZRoomCommand* cmd)
return 0;
}
std::string ZRoom::GetSourceOutputCode([[maybe_unused]] const std::string& prefix)
void ZRoom::GetSourceOutputCode([[maybe_unused]] const std::string& prefix)
{
if (hackMode == "syotes_room")
return "";
DeclareVar(prefix, GetBodySourceCode());
return "";
if (hackMode != "syotes_room")
DeclareVar(prefix, GetBodySourceCode());
}
size_t ZRoom::GetRawDataSize() const

View File

@ -34,7 +34,7 @@ public:
Declaration* DeclareVar(const std::string& prefix, const std::string& body) override;
std::string GetBodySourceCode() const override;
std::string GetSourceOutputCode(const std::string& prefix) override;
void GetSourceOutputCode(const std::string& prefix) override;
std::string GetDefaultName(const std::string& prefix) const override;
size_t GetDeclarationSizeFromNeighbor(uint32_t declarationAddress);

View File

@ -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;
}
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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++)
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
#include <string>
#include <vector>
#include "ZResource.h"

View File

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="libpng" version="1.6.28.1" targetFramework="native" />
<package id="libpng.redist" version="1.6.28.1" targetFramework="native" />
<package id="libpng.static" version="1.6.37" targetFramework="native" />
<package id="YY.NuGet.Import.Helper" version="1.0.0.4" targetFramework="native" />
<package id="zlib" version="1.2.8.8" targetFramework="native" />
<package id="zlib.static" version="1.2.5" targetFramework="native" />
<package id="zlib.v120.windesktop.msvcstl.dyn.rt-dyn" version="1.2.8.8" targetFramework="native" />
<package id="zlib.v140.windesktop.msvcstl.dyn.rt-dyn" version="1.2.8.8" targetFramework="native" />
</packages>

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
struct Color3b
{

View File

@ -1,7 +1,7 @@
# Only used for standalone compilation, usually inherits these from the main makefile
CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17
SRC_DIRS := $(shell find -type d -not -path "*build*")
SRC_DIRS := $(shell find . -type d -not -path "*build*")
CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h))

View File

@ -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;

View File

@ -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;

View File

@ -1,7 +1,7 @@
#pragma once
#include <cstdint>
#include <limits>
#include <stdint.h>
#include <vector>
class BitConverter

View File

@ -1,8 +1,8 @@
#pragma once
#include <cstdio>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <string>
#include <vector>
#include "Directory.h"

View File

@ -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)

View File

@ -18,13 +18,13 @@ public:
static std::string GetFileName(const fs::path& input)
{
// https://en.cppreference.com/w/cpp/filesystem/path/filename
return input.filename();
return input.filename().string();
};
static std::string GetFileNameWithoutExtension(const fs::path& input)
{
// https://en.cppreference.com/w/cpp/filesystem/path/stem
return input.stem();
return input.stem().string();
};
static std::string GetFileNameExtension(const std::string& input)

View File

@ -1,7 +1,7 @@
#pragma once
#include <cstdint>
#include <memory>
#include <stdint.h>
enum class SeekOffsetType
{

View File

@ -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:
@ -111,4 +105,10 @@ public:
{
return std::all_of(str.begin(), str.end(), ::isdigit);
}
static bool IEquals(const std::string& a, const std::string& b)
{
return std::equal(a.begin(), a.end(), b.begin(), b.end(),
[](char a, char b) { return tolower(a) == tolower(b); });
}
};

View File

@ -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

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
struct Vec2f
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
struct Vec3f
{

View File

@ -1,6 +1,6 @@
#pragma once
#include <stdint.h>
#include <cstdint>
struct Vec3s
{

View File

@ -43,7 +43,7 @@
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
@ -116,6 +116,8 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard_C>Default</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -155,6 +157,7 @@
<ClInclude Include="Vec3s.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\lib\tinyxml2\tinyxml2.cpp" />
<ClCompile Include="Utils\BinaryReader.cpp" />
<ClCompile Include="Utils\BinaryWriter.cpp" />
<ClCompile Include="Utils\MemoryStream.cpp" />

View File

@ -19,6 +19,9 @@
<Filter Include="Source Files\Utils">
<UniqueIdentifier>{e047919d-7186-49ca-b115-e48fbb5c8743}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Libraries">
<UniqueIdentifier>{3de9dd46-0dfd-4d48-9f20-9f24e5b80fe0}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Utils\BinaryWriter.h">
@ -74,5 +77,8 @@
<ClCompile Include="Utils\BinaryReader.cpp">
<Filter>Source Files\Utils</Filter>
</ClCompile>
<ClCompile Include="..\lib\tinyxml2\tinyxml2.cpp">
<Filter>Source Files\Libraries</Filter>
</ClCompile>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/simonlindholm/asm-differ.git
branch = main
commit = f30d43aceba6291aa3c08b7317b0458b6d734321
parent = e977dfeb374c6de4076ca9a0f44ba5a6a701d849
commit = 70c33cc125666495f84f8c7bee60d3158b4b1164
parent = 62341d8db0c29d1d4f0c360196e428309ac373b6
method = merge
cmdver = 0.4.3

View File

@ -640,6 +640,7 @@ class Text:
class TableMetadata:
headers: Tuple[Text, ...]
current_score: int
max_score: int
previous_score: Optional[int]
@ -832,6 +833,7 @@ class JsonFormatter(Formatter):
for h, name in zip(meta.headers, ("base", "current", "previous"))
}
output["current_score"] = meta.current_score
output["max_score"] = meta.max_score
if meta.previous_score is not None:
output["previous_score"] = meta.previous_score
output_rows: List[Dict[str, Any]] = []
@ -1184,8 +1186,9 @@ def parse_elf_data_references(data: bytes) -> List[Tuple[int, int, str]]:
assert len(symtab_sections) == 1
symtab = sections[symtab_sections[0]]
text_sections = [i for i in range(e_shnum) if sec_names[i] == b".text"]
assert len(text_sections) == 1
text_sections = [i for i in range(e_shnum) if sec_names[i] == b".text" and sections[i].sh_size != 0]
if len(text_sections) != 1:
return []
text_section = text_sections[0]
ret: List[Tuple[int, int, str]] = []
@ -1327,11 +1330,23 @@ def dump_binary(
(objdump_flags + flags2, project.myimg, None),
)
DATA_POOL_PLACEHOLDER = "DATA_POOL_PLACEHOLDER-OFFSET_{}"
DATA_POOL_PLACEHOLDER_PATTERN = re.compile(
r"DATA_POOL_PLACEHOLDER-OFFSET_([a-zA-z0-9]+)"
)
class DifferenceNormalizer:
# Example: "ldr r4, [pc, #56] ; (4c <AddCoins+0x4c>)"
ARM32_LOAD_POOL_PATTERN = r"(ldr\s+r([0-9]|1[0-3]),\s+\[pc,.*;\s*)(\([a-fA-F0-9]+.*\))"
# The base class is a no-op.
class AsmProcessor:
def __init__(self, config: Config) -> None:
self.config = config
def process_reloc(self, row: str, prev: str) -> str:
return prev
def normalize(self, mnemonic: str, row: str) -> str:
"""This should be called exactly once for each line."""
arch = self.config.arch
@ -1342,9 +1357,143 @@ class DifferenceNormalizer:
def _normalize_arch_specific(self, mnemonic: str, row: str) -> str:
return row
def post_process(self, lines: List["Line"]) -> None:
return
class DifferenceNormalizerAArch64(DifferenceNormalizer):
class AsmProcessorMIPS(AsmProcessor):
def process_reloc(self, row: str, prev: str) -> str:
arch = self.config.arch
if "R_MIPS_NONE" in row:
# GNU as emits no-op relocations immediately after real ones when
# assembling with -mabi=64. Return without trying to parse 'imm' as an
# integer.
return prev
before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1]
if imm != "0":
# MIPS uses relocations with addends embedded in the code as immediates.
# If there is an immediate, show it as part of the relocation. Ideally
# we'd show this addend in both %lo/%hi, but annoyingly objdump's output
# doesn't include enough information to pair up %lo's and %hi's...
# TODO: handle unambiguous cases where all addends for a symbol are the
# same, or show "+???".
mnemonic = prev.split()[0]
if (
mnemonic in arch.instructions_with_address_immediates
and not imm.startswith("0x")
):
imm = "0x" + imm
repl += "+" + imm if int(imm, 0) > 0 else imm
if "R_MIPS_LO16" in row:
repl = f"%lo({repl})"
elif "R_MIPS_HI16" in row:
# Ideally we'd pair up R_MIPS_LO16 and R_MIPS_HI16 to generate a
# correct addend for each, but objdump doesn't give us the order of
# the relocations, so we can't find the right LO16. :(
repl = f"%hi({repl})"
elif "R_MIPS_26" in row:
# Function calls
pass
elif "R_MIPS_PC16" in row:
# Branch to glabel. This gives confusing output, but there's not much
# we can do here.
pass
else:
assert False, f"unknown relocation type '{row}' for line '{prev}'"
return before + repl + after
class AsmProcessorPPC(AsmProcessor):
def process_reloc(self, row: str, prev: str) -> str:
arch = self.config.arch
assert any(
r in row for r in ["R_PPC_REL24", "R_PPC_ADDR16", "R_PPC_EMB_SDA21"]
), f"unknown relocation type '{row}' for line '{prev}'"
before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1]
if "R_PPC_REL24" in row:
# function calls
pass
elif "R_PPC_ADDR16_HI" in row:
# absolute hi of addr
repl = f"{repl}@h"
elif "R_PPC_ADDR16_HA" in row:
# adjusted hi of addr
repl = f"{repl}@ha"
elif "R_PPC_ADDR16_LO" in row:
# lo of addr
repl = f"{repl}@l"
elif "R_PPC_ADDR16" in row:
# 16-bit absolute addr
if "+0x7" in repl:
# remove the very large addends as they are an artifact of (label-_SDA(2)_BASE_)
# computations and are unimportant in a diff setting.
if int(repl.split("+")[1], 16) > 0x70000000:
repl = repl.split("+")[0]
elif "R_PPC_EMB_SDA21" in row:
# small data area
pass
return before + repl + after
class AsmProcessorARM32(AsmProcessor):
def process_reloc(self, row: str, prev: str) -> str:
arch = self.config.arch
before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1]
return before + repl + after
def _normalize_arch_specific(self, mnemonic: str, row: str) -> str:
if self.config.ignore_addr_diffs:
row = self._normalize_bl(mnemonic, row)
row = self._normalize_data_pool(row)
return row
def _normalize_bl(self, mnemonic: str, row: str) -> str:
if mnemonic != "bl":
return row
row, _ = split_off_address(row)
return row + "<ignore>"
def _normalize_data_pool(self, row: str) -> str:
pool_match = re.search(ARM32_LOAD_POOL_PATTERN, row)
if pool_match:
offset = pool_match.group(3).split(" ")[0][1:]
repl = DATA_POOL_PLACEHOLDER.format(offset)
return pool_match.group(1) + repl
return row
def post_process(self, lines: List["Line"]) -> None:
lines_by_line_number = {}
for line in lines:
lines_by_line_number[line.line_num] = line
for line in lines:
reloc_match = re.search(
DATA_POOL_PLACEHOLDER_PATTERN, line.normalized_original
)
if reloc_match is None:
continue
# Get value at relocation
reloc = reloc_match.group(0)
line_number = re.search(
DATA_POOL_PLACEHOLDER_PATTERN, reloc).group(1)
line_original = lines_by_line_number[int(line_number, 16)].original
value = line_original.split()[1]
# Replace relocation placeholder with value
replaced = re.sub(
DATA_POOL_PLACEHOLDER_PATTERN,
f"={value} ({line_number})",
line.normalized_original,
)
line.original = replaced
class AsmProcessorAArch64(AsmProcessor):
def __init__(self, config: Config) -> None:
super().__init__(config)
self._adrp_pair_registers: Set[str] = set()
@ -1394,23 +1543,6 @@ class DifferenceNormalizerAArch64(DifferenceNormalizer):
return row
class DifferenceNormalizerARM32(DifferenceNormalizer):
def __init__(self, config: Config) -> None:
super().__init__(config)
def _normalize_arch_specific(self, mnemonic: str, row: str) -> str:
if self.config.ignore_addr_diffs:
row = self._normalize_bl(mnemonic, row)
return row
def _normalize_bl(self, mnemonic: str, row: str) -> str:
if mnemonic != "bl":
return row
row, _ = split_off_address(row)
return row + "<ignore>"
@dataclass
class ArchSettings:
name: str
@ -1420,14 +1552,15 @@ class ArchSettings:
re_sprel: Pattern[str]
re_large_imm: Pattern[str]
re_imm: Pattern[str]
re_reloc: Pattern[str]
branch_instructions: Set[str]
instructions_with_address_immediates: Set[str]
forbidden: Set[str] = field(default_factory=lambda: set(string.ascii_letters + "_"))
arch_flags: List[str] = field(default_factory=list)
branch_likely_instructions: Set[str] = field(default_factory=set)
difference_normalizer: Type[DifferenceNormalizer] = DifferenceNormalizer
proc: Type[AsmProcessor] = AsmProcessor
big_endian: Optional[bool] = True
delay_slot_instructions: Set[str] = field(default_factory=set)
MIPS_BRANCH_LIKELY_INSTRUCTIONS = {
"beql",
@ -1543,10 +1676,13 @@ MIPS_SETTINGS = ArchSettings(
re_sprel=re.compile(r"(?<=,)([0-9]+|0x[0-9a-f]+)\(sp\)"),
re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"),
re_imm=re.compile(r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(sp)|%(lo|hi)\([^)]*\)"),
re_reloc=re.compile(r"R_MIPS_"),
arch_flags=["-m", "mips:4300"],
branch_likely_instructions=MIPS_BRANCH_LIKELY_INSTRUCTIONS,
branch_instructions=MIPS_BRANCH_INSTRUCTIONS,
instructions_with_address_immediates=MIPS_BRANCH_INSTRUCTIONS.union({"jal", "j"}),
delay_slot_instructions=MIPS_BRANCH_INSTRUCTIONS.union({"j", "jal", "jr", "jalr"}),
proc=AsmProcessorMIPS,
)
MIPSEL_SETTINGS = replace(MIPS_SETTINGS, name="mipsel", big_endian=False)
@ -1566,9 +1702,10 @@ ARM32_SETTINGS = ArchSettings(
re_sprel=re.compile(r"sp, #-?(0x[0-9a-fA-F]+|[0-9]+)\b"),
re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"),
re_imm=re.compile(r"(?<!sp, )#-?(0x[0-9a-fA-F]+|[0-9]+)\b"),
re_reloc=re.compile(r"R_ARM_"),
branch_instructions=ARM32_BRANCH_INSTRUCTIONS,
instructions_with_address_immediates=ARM32_BRANCH_INSTRUCTIONS.union({"adr"}),
difference_normalizer=DifferenceNormalizerARM32,
proc=AsmProcessorARM32,
)
AARCH64_SETTINGS = ArchSettings(
@ -1581,9 +1718,10 @@ AARCH64_SETTINGS = ArchSettings(
re_sprel=re.compile(r"sp, #-?(0x[0-9a-fA-F]+|[0-9]+)\b"),
re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"),
re_imm=re.compile(r"(?<!sp, )#-?(0x[0-9a-fA-F]+|[0-9]+)\b"),
re_reloc=re.compile(r"R_AARCH64_"),
branch_instructions=AARCH64_BRANCH_INSTRUCTIONS,
instructions_with_address_immediates=AARCH64_BRANCH_INSTRUCTIONS.union({"bl", "adrp"}),
difference_normalizer=DifferenceNormalizerAArch64,
proc=AsmProcessorAArch64,
)
PPC_SETTINGS = ArchSettings(
@ -1594,8 +1732,10 @@ PPC_SETTINGS = ArchSettings(
re_sprel=re.compile(r"(?<=,)(-?[0-9]+|-?0x[0-9a-f]+)\(r1\)"),
re_large_imm=re.compile(r"-?[1-9][0-9]{2,}|-?0x[0-9a-f]{3,}"),
re_imm=re.compile(r"(\b|-)([0-9]+|0x[0-9a-fA-F]+)\b(?!\(r1)|[^@]*@(ha|h|lo)"),
re_reloc=re.compile(r"R_PPC_"),
branch_instructions=PPC_BRANCH_INSTRUCTIONS,
instructions_with_address_immediates=PPC_BRANCH_INSTRUCTIONS.union({"bl"}),
proc=AsmProcessorPPC,
)
ARCH_SETTINGS = [
@ -1639,84 +1779,6 @@ def parse_relocated_line(line: str) -> Tuple[str, str, str]:
return before, imm, after
def process_mips_reloc(row: str, prev: str, arch: ArchSettings) -> str:
if "R_MIPS_NONE" in row:
# GNU as emits no-op relocations immediately after real ones when
# assembling with -mabi=64. Return without trying to parse 'imm' as an
# integer.
return prev
before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1]
if imm != "0":
# MIPS uses relocations with addends embedded in the code as immediates.
# If there is an immediate, show it as part of the relocation. Ideally
# we'd show this addend in both %lo/%hi, but annoyingly objdump's output
# doesn't include enough information to pair up %lo's and %hi's...
# TODO: handle unambiguous cases where all addends for a symbol are the
# same, or show "+???".
mnemonic = prev.split()[0]
if (
mnemonic in arch.instructions_with_address_immediates
and not imm.startswith("0x")
):
imm = "0x" + imm
repl += "+" + imm if int(imm, 0) > 0 else imm
if "R_MIPS_LO16" in row:
repl = f"%lo({repl})"
elif "R_MIPS_HI16" in row:
# Ideally we'd pair up R_MIPS_LO16 and R_MIPS_HI16 to generate a
# correct addend for each, but objdump doesn't give us the order of
# the relocations, so we can't find the right LO16. :(
repl = f"%hi({repl})"
elif "R_MIPS_26" in row:
# Function calls
pass
elif "R_MIPS_PC16" in row:
# Branch to glabel. This gives confusing output, but there's not much
# we can do here.
pass
else:
assert False, f"unknown relocation type '{row}' for line '{prev}'"
return before + repl + after
def process_ppc_reloc(row: str, prev: str) -> str:
assert any(
r in row for r in ["R_PPC_REL24", "R_PPC_ADDR16", "R_PPC_EMB_SDA21"]
), f"unknown relocation type '{row}' for line '{prev}'"
before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1]
if "R_PPC_REL24" in row:
# function calls
pass
elif "R_PPC_ADDR16_HI" in row:
# absolute hi of addr
repl = f"{repl}@h"
elif "R_PPC_ADDR16_HA" in row:
# adjusted hi of addr
repl = f"{repl}@ha"
elif "R_PPC_ADDR16_LO" in row:
# lo of addr
repl = f"{repl}@l"
elif "R_PPC_ADDR16" in row:
# 16-bit absolute addr
if "+0x7" in repl:
# remove the very large addends as they are an artifact of (label-_SDA(2)_BASE_)
# computations and are unimportant in a diff setting.
if int(repl.split("+")[1], 16) > 0x70000000:
repl = repl.split("+")[0]
elif "R_PPC_EMB_SDA21" in row:
# small data area
pass
return before + repl + after
def process_arm_reloc(row: str, prev: str, arch: ArchSettings) -> str:
before, imm, after = parse_relocated_line(prev)
repl = row.split()[-1]
return before + repl + after
def pad_mnemonic(line: str) -> str:
if "\t" not in line:
return line
@ -1741,7 +1803,7 @@ class Line:
def process(dump: str, config: Config) -> List[Line]:
arch = config.arch
normalizer = arch.difference_normalizer(config)
processor = arch.proc(config)
skip_next = False
source_lines = []
source_filename = None
@ -1783,7 +1845,7 @@ def process(dump: str, config: Config) -> List[Line]:
)
break
if not re.match(r"^ +[0-9a-f]+:\t", row):
if not re.match(r"^\s+[0-9a-f]+:\s+", row):
# This regex is conservative, and assumes the file path does not contain "weird"
# characters like colons, tabs, or angle brackets.
if re.match(
@ -1797,10 +1859,11 @@ def process(dump: str, config: Config) -> List[Line]:
m_comment = re.search(arch.re_comment, row)
comment = m_comment[0] if m_comment else None
row = re.sub(arch.re_comment, "", row)
line_num_str = row.split(":")[0]
row = row.rstrip()
tabs = row.split("\t")
row = "\t".join(tabs[2:])
line_num = eval_line_num(tabs[0].strip())
line_num = eval_line_num(line_num_str.strip())
if line_num in data_refs:
refs = data_refs[line_num]
@ -1835,20 +1898,13 @@ def process(dump: str, config: Config) -> List[Line]:
while i < len(lines):
reloc_row = lines[i]
if "R_AARCH64_" in reloc_row:
# TODO: handle relocation
pass
elif "R_MIPS_" in reloc_row:
original = process_mips_reloc(reloc_row, original, arch)
elif "R_PPC_" in reloc_row:
original = process_ppc_reloc(reloc_row, original)
elif "R_ARM_" in reloc_row:
original = process_arm_reloc(reloc_row, original, arch)
if re.search(arch.re_reloc, reloc_row):
original = processor.process_reloc(reloc_row, original)
else:
break
i += 1
normalized_original = normalizer.normalize(mnemonic, original)
normalized_original = processor.normalize(mnemonic, original)
scorable_line = normalized_original
if not config.score_stack_differences:
@ -1904,6 +1960,7 @@ def process(dump: str, config: Config) -> List[Line]:
elif stop_after_delay_slot:
break
processor.post_process(output)
return output
@ -2123,8 +2180,15 @@ class OutputLine:
class Diff:
lines: List[OutputLine]
score: int
max_score: int
def trim_nops(lines: List[Line], arch: ArchSettings) -> List[Line]:
lines = lines[:]
while lines and lines[-1].mnemonic == "nop" and (len(lines) == 1 or lines[-2].mnemonic not in arch.delay_slot_instructions):
lines.pop()
return lines
def do_diff(lines1: List[Line], lines2: List[Line], config: Config) -> Diff:
if config.show_source:
import cxxfilt
@ -2152,8 +2216,12 @@ def do_diff(lines1: List[Line], lines2: List[Line], config: Config) -> Diff:
btset.add(bt)
sc(str(bt))
lines1 = trim_nops(lines1, arch)
lines2 = trim_nops(lines2, arch)
diffed_lines = diff_lines(lines1, lines2, config.algorithm)
score = score_diff_lines(diffed_lines, config)
max_score = len(lines1) * config.penalty_deletion
line_num_base = -1
line_num_offset = 0
@ -2385,7 +2453,7 @@ def do_diff(lines1: List[Line], lines2: List[Line], config: Config) -> Diff:
)
output = output[config.skip_lines :]
return Diff(lines=output, score=score)
return Diff(lines=output, score=score, max_score=max_score)
def chunk_diff_lines(
@ -2461,6 +2529,7 @@ def align_diffs(
Text(f"{padding}PREVIOUS ({old_diff.score})"),
),
current_score=new_diff.score,
max_score=new_diff.max_score,
previous_score=old_diff.score,
)
old_chunks = chunk_diff_lines(old_diff.lines)
@ -2504,6 +2573,7 @@ def align_diffs(
Text(f"{padding}CURRENT ({new_diff.score})"),
),
current_score=new_diff.score,
max_score=new_diff.max_score,
previous_score=None,
)
diff_lines = [(line, line) for line in new_diff.lines]

View File

@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/z64me/z64compress.git
branch = main
commit = 98ef0ac25f7adb47235c839838e29496d3546917
parent = 69cc19eea8c30e50e280f400e8cf06fe66efca60
commit = ac5b1a0d0b23346362a68a107da3478227f8e703
parent = 33e3aa92181a0543826adc10a5f3304d60b391dd
method = merge
cmdver = 0.4.3

View File

@ -221,7 +221,7 @@ wow_main
}
}
fprintf(printer, "welcome to z64compress 1.0.1 <z64.me>\n");
fprintf(printer, "welcome to z64compress 1.0.2 <z64.me>\n");
if (argc <= 1)
{
@ -356,7 +356,6 @@ wow_main
ARG_ZERO_TEST(Ain , "--in" );
ARG_ZERO_TEST(Aout , "--out" );
ARG_ZERO_TEST(Amb , "--mb" );
ARG_ZERO_TEST(Acodec, "--codec");
#undef ARG_ZERO_TEST

View File

@ -68,7 +68,9 @@ for (dma = rom->dma; (unsigned)(dma - rom->dma) < rom->dma_num; ++dma)
#define PROGRESS_A_B (int)(dma - rom->dma), rom->dma_num
#define ALIGN16(x) (((x) + 0xF) & ~0xF)
#define ALIGN(x, n) (((x) + ((n)-1)) & ~((n)-1))
#define ALIGN16(x) ALIGN(x, 16)
#define ALIGN8MB(x) ALIGN(x, 8 * 0x100000)
/*
*
@ -936,7 +938,7 @@ void rom_compress(struct rom *rom, int mb, int numThreads, bool matching)
cache = rom->cache;
if (compsz > rom->data_sz || mb <= 0)
if (compsz > rom->data_sz || mb < 0)
die("invalid mb argument %d", mb);
/* get encoding functions */
@ -1057,31 +1059,13 @@ void rom_compress(struct rom *rom, int mb, int numThreads, bool matching)
/* sort by original start, ascending */
DMASORT(rom, sortfunc_dma_start_ascend);
if (matching)
{
/* fill the entire (compressed) rom space with 00010203...FF...
in order to match retail rom padding */
unsigned char n = 0; // will intentionally overflow
for (unsigned int j = 0; j < compsz; j++, n++)
{
rom->data[j] = n;
}
}
else
{
/* zero the entire (compressed) rom space */
memset(rom->data, 0, compsz);
}
/* go through dma table, injecting compressed files */
/* determine physical addresses for each segment */
comp_total = 0;
DMA_FOR_EACH
{
unsigned char *dst;
char *fn = dma->compname;
unsigned int sz;
unsigned int sz16;
fprintf(printer, "\r""injecting file %d/%d: ", PROGRESS_A_B);
if (dma->deleted)
continue;
@ -1114,9 +1098,6 @@ void rom_compress(struct rom *rom, int mb, int numThreads, bool matching)
if (sz16 & 15)
sz16 += 16 - (sz16 & 15);
/* put the files in */
dst = rom->data + comp_total;
dma->Pstart = comp_total;
if (dma->compress)
{
@ -1130,26 +1111,66 @@ void rom_compress(struct rom *rom, int mb, int numThreads, bool matching)
dma->Pend = 0;
comp_total += sz16;
if (dma->Pend > compsz)
if (mb != 0 && dma->Pend > compsz)
die("ran out of compressed rom space");
}
/* adaptive final size */
if (mb == 0)
compsz = ALIGN8MB(comp_total);
if (matching)
{
/* fill the entire (compressed) rom space with 00010203...FF...
in order to match retail rom padding */
unsigned char n = 0; /* will intentionally overflow */
for (unsigned int j = 0; j < compsz; j++, n++)
{
rom->data[j] = n;
}
}
else
{
/* zero the entire (compressed) rom space */
memset(rom->data, 0, compsz);
}
/* inject compressed files */
comp_total = 0;
DMA_FOR_EACH
{
unsigned char *dst;
char *fn = dma->compname;
unsigned int sz;
fprintf(printer, "\r""injecting file %d/%d: ", PROGRESS_A_B);
if (dma->deleted)
continue;
dst = rom->data + dma->Pstart;
/* external cached file logic */
if (cache)
{
/* skip entries that don't reference compressed files */
if (!fn)
continue;
/* load file into rom at offset */
dst = file_load_into(cache_codec, fn, &sz, dst);
}
/* otherwise, a simple memcpy */
else
{
memcpy(dst, dma->compbuf, dma->compSz);
if (matching)
{
// since matching rom padding is not zero but file padding is zero,
// fill file padding space with zeros
memset(dst + dma->compSz, 0, ALIGN16(dma->compSz) - dma->compSz);
}
sz = dma->compSz;
}
if (matching)
{
/* since matching rom padding is not zero but file padding is zero,
fill file padding space with zeros */
memset(dst + sz, 0, ALIGN16(sz) - sz);
}
}
fprintf(printer, "\r""injecting file %d/%d: ", dma_num, dma_num);