diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2fc8d2e..2f8ea12 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,40 +1,29 @@ -name: NDSFactory-Builds +name: Build and Release on Tag on: push: - branches: master - -env: - BUILD_TYPE: Release + tags: + - v* jobs: - clean-old-autorelease: - runs-on: ubuntu-latest - - steps: - - uses: dev-drprasad/delete-tag-and-release@v0.1.3 - with: - delete_release: true - tag_name: autobuild - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - build-linux: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4.1.7 - name: Create Build Environment run: | sudo apt-get update - sudo apt-get install -y build-essential qt5-default cmake + sudo apt-get install -y build-essential libgl1-mesa-dev and libglvnd-dev cmake qt6-base-dev mkdir build + - name: Configure CMake working-directory: ${{github.workspace}}/build shell: bash run: | - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. + cmake -DCMAKE_BUILD_TYPE=Release .. + - name: Build working-directory: ${{github.workspace}}/build shell: bash @@ -42,28 +31,27 @@ jobs: make -j4 - name: Archive Artifact - working-directory: ${{github.workspace}} + working-directory: ${{github.workspace}}/build shell: bash run: | - git_hash=$(git rev-parse --short "$GITHUB_SHA") - cd build - tar -czvf NDSFactory_${git_hash}__Linux_x86_64.tar.gz NDSFactory ../README.md ../LICENSE + tar -czvf NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz NDSFactory ../README.md ../LICENSE + - name: Release on GitHub - uses: ncipollo/release-action@v1 + uses: softprops/action-gh-release@v2.0.8 + if: startsWith(github.ref, 'refs/tags/') with: - artifacts: "build/NDSFactory_*__Linux_x86_64.tar.gz" - allowUpdates: true - tag: "autobuild" - token: ${{ secrets.GITHUB_TOKEN }} + files: "build/NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz" build-macos: runs-on: macos-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4.1.7 - name: Install Qt - uses: jurplel/install-qt-action@v2 + uses: jurplel/install-qt-action@v4 + with: + version: '6.5.2' - name: Install CMake uses: lukka/get-cmake@latest @@ -76,37 +64,37 @@ jobs: working-directory: ${{github.workspace}}/build shell: bash run: | - cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. + cmake -DCMAKE_BUILD_TYPE=Release .. + - name: Build working-directory: ${{github.workspace}}/build shell: bash run: | make -j4 macdeployqt NDSFactory.app - + - name: Archive Artifact - working-directory: ${{github.workspace}} + working-directory: ${{github.workspace}}/build shell: bash run: | - git_hash=$(git rev-parse --short "$GITHUB_SHA") - cd build - zip -r NDSFactory_${git_hash}__macOS_x86_64.zip NDSFactory.app ../README.md ../LICENSE + zip -r NDSFactory-${{ github.ref_name }}-macOS.zip NDSFactory.app ../README.md ../LICENSE + - name: Release on GitHub - uses: ncipollo/release-action@v1 + uses: softprops/action-gh-release@v2.0.8 + if: startsWith(github.ref, 'refs/tags/') with: - artifacts: "build/NDSFactory_*__macOS_x86_64.zip" - allowUpdates: true - tag: "autobuild" - token: ${{ secrets.GITHUB_TOKEN }} + files: "build/NDSFactory-${{ github.ref_name }}-macOS.zip" build-windows: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4.1.7 - name: Install Qt - uses: jurplel/install-qt-action@v2 + uses: jurplel/install-qt-action@v4 + with: + version: '6.5.2' - name: Install CMake uses: lukka/get-cmake@latest @@ -133,12 +121,10 @@ jobs: run: | xcopy ..\..\README.md .\prod xcopy ..\..\LICENSE .\prod - powershell "Compress-Archive -Path .\prod\* -DestinationPath .\NDSFactory_AUTOBUILD__Windows_x86_64.zip" + powershell "Compress-Archive -Path .\prod\* -DestinationPath .\NDSFactory-${{ github.ref_name }}-Windows-x64.zip" - name: Release on GitHub - uses: ncipollo/release-action@v1 + uses: softprops/action-gh-release@v2.0.8 + if: startsWith(github.ref, 'refs/tags/') with: - artifacts: "build/Release/NDSFactory_*__Windows_x86_64.zip" - allowUpdates: true - tag: "autobuild" - token: ${{ secrets.GITHUB_TOKEN }} + files: "build/Release/NDSFactory-${{ github.ref_name }}-Windows-x64.zip" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 807c0c4..dac1701 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,397 @@ CMakeLists.txt.user* # OS specific .DS_Store +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ +out/ build/ +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/CMakeLists.txt b/CMakeLists.txt index f96faf6..7ec6ba6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,14 @@ -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.25) project(NDSFactory) -find_package(Qt5Core REQUIRED) -find_package(Qt5Gui REQUIRED) -find_package(Qt5Widgets REQUIRED) +# Require Qt6 components +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) -set(CMAKE_CXX_STANDARD 14) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTOUIC ON) - -include(${CMAKE_SOURCE_DIR}/sanitizers.cmake) +# Include sanitizers +include(${CMAKE_SOURCE_DIR}/cmake/sanitizers.cmake) +# Determine the Git commit hash if in a git repository if(EXISTS "${CMAKE_SOURCE_DIR}/.git") execute_process( COMMAND git log -1 --format=%h @@ -19,29 +16,31 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/.git") OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) -else(EXISTS "${CMAKE_SOURCE_DIR}/.git") +else() set(GIT_COMMIT_HASH "") -endif(EXISTS "${CMAKE_SOURCE_DIR}/.git") +endif() +# Configure the revision header file configure_file( ${CMAKE_SOURCE_DIR}/ui/dialogs/about/revision.h.in ${CMAKE_SOURCE_DIR}/ui/dialogs/about/revision.h ) -# Dialogs +# Collect source and header files +## Dialogs file(GLOB_RECURSE DIALOGS_HEADERS ui/dialogs/*.h) file(GLOB_RECURSE DIALOGS_SOURCES ui/dialogs/*.cpp) file(GLOB_RECURSE DIALOGS_UIS ui/dialogs/*.ui) -# Tabs +## Tabs file(GLOB_RECURSE TABS_HEADERS ui/tabs/*.h) file(GLOB_RECURSE TABS_SOURCES ui/tabs/*.cpp) -# Models +## Models file(GLOB_RECURSE MODELS_HEADERS ui/models/*.h) file(GLOB_RECURSE MODELS_SOURCES ui/models/*.cpp) -# NDSFactory +## NDSFactory file(GLOB_RECURSE NDSFACTORY_SOURCES ndsfactory/*.cpp) file(GLOB_RECURSE NDSFACTORY_HEADERS ndsfactory/*.h) @@ -67,12 +66,36 @@ set(FORMS ${DIALOGS_UIS} ) -if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SOURCES} ${HEADERS} ${FORMS}) -elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") - add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${FORMS}) +# Platform-specific executable creation +if(APPLE) + set(MACOSX_BUNDLE_ICON_FILE ndsfactory.icns) + set(MACOS_ICNS "res/ndsfactory.icns") + set_source_files_properties(${MACOS_ICNS} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${SOURCES} ${HEADERS} ${FORMS} ${MACOS_ICNS}) +elseif(WIN32) + set(WIN32_RESOURCES "res/resources.rc") + add_executable(${PROJECT_NAME} WIN32 ${SOURCES} ${HEADERS} ${FORMS} ${WIN32_RESOURCES}) else() add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS} ${FORMS}) endif() -target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Gui Qt5::Widgets) +# Set C++ standard for the target +target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14) + +# Enable Qt's automatic features for the target +set_target_properties(${PROJECT_NAME} PROPERTIES + AUTOMOC ON + AUTOUIC ON +) + +# Add compile options for different compilers +if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE /WX /W4 /EHsc) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror) +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Werror) +endif() + +# Link the necessary Qt6 libraries +target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..56c4ce3 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,22 @@ +{ + "version": 3, + "configurePresets": [ + { + "hidden": true, + "name": "Qt", + "cacheVariables": { + "CMAKE_PREFIX_PATH": "$env{QTDIR}" + }, + "vendor": { + "qt-project.org/Qt": { + "checksum": "wVa86FgEkvdCTVp1/nxvrkaemJc=" + } + } + } + ], + "vendor": { + "qt-project.org/Presets": { + "checksum": "67SmY24ZeVbebyKD0fGfIzb/bGI=" + } + } +} \ No newline at end of file diff --git a/CMakeUserPresets.json b/CMakeUserPresets.json new file mode 100644 index 0000000..f67172b --- /dev/null +++ b/CMakeUserPresets.json @@ -0,0 +1,76 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "Qt-Debug", + "inherits": "Qt-Default", + "binaryDir": "${sourceDir}/out/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_FLAGS": "-DQT_QML_DEBUG" + }, + "environment": { + "QML_DEBUG_ARGS": "-qmljsdebugger=file:{f93ee848-589e-4ca8-9f00-8ec9e59822e9},block" + } + }, + { + "name": "Qt-Release", + "inherits": "Qt-Default", + "binaryDir": "${sourceDir}/out/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "hidden": true, + "name": "Qt-Default", + "inherits": "6.7.2_msvc2019_64", + "vendor": { + "qt-project.org/Default": { + "checksum": "gw/ERk1cQwC3YNpVspzQ2Sww4Qk=" + } + } + }, + { + "hidden": true, + "name": "6.7.2_msvc2019_64", + "inherits": "Qt", + "environment": { + "QTDIR": "C:/Qt/6.7.2/msvc2019_64" + }, + "architecture": { + "strategy": "external", + "value": "x64" + }, + "generator": "Ninja", + "vendor": { + "qt-project.org/Version": { + "checksum": "Bix3VTiu0VJT9MULsciS2xuiRSY=" + } + } + }, + { + "hidden": true, + "name": "QtDesignStudio_qt6_design_studio_reduced_version", + "inherits": "Qt", + "environment": { + "QTDIR": "C:/Qt/Tools/QtDesignStudio/qt6_design_studio_reduced_version" + }, + "architecture": { + "strategy": "external", + "value": "x64" + }, + "generator": "Ninja", + "vendor": { + "qt-project.org/Version": { + "checksum": "ygR+cS5HulD9XNDRlzjWPEl2jZo=" + } + } + } + ], + "vendor": { + "qt-project.org/Presets": { + "checksum": "Uup2yLzTIsD1yvrCY3TjhVEtXMo=" + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 78a96ea..464c632 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ A tool to unpack & repack Nintendo DS ROMs (.nds) -If you find this software useful, please [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Z8Z511SOI) +If you find this software useful, please consider supporting it: +[![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Z8Z511SOI) ![screenshot](https://raw.githubusercontent.com/Luca1991/NDSFactory/master/screenshot.png) @@ -13,9 +14,9 @@ If you find this software useful, please [![ko-fi](https://www.ko-fi.com/img/git # Description -This software will help you to easily unpack and repack Nintendo DS roms, but **IT REQUIRES SOME KNOWLEDGE!** +NDSFactory helps you easily unpack and repack Nintendo DS ROMs, but **some technical knowledge is required.** -Basically an NDS software is composed of the following sections: +A typical NDS ROM consists of the following sections: * Header * ARM9 Binary * ARM7 Binary @@ -26,35 +27,29 @@ Basically an NDS software is composed of the following sections: * Icon/Title Logo * FAT Files (The actual files used by the software, like Graphics, Music etc.) -With NDSFactory you can extract these sections, modify them using your preferred way and the rebuild the rom with your edited sections. -If the modified sections are bigger than the original ones, you can specify their new physical address and size in the header: if so, **make -sure that they DON'T OVERLAP, and remember to PATCH THE FAT.BIN** (more on this later). +NDSFactory allows you to extract these sections, modify them as needed, and rebuild the ROM with your edited sections. If modified sections are larger than the original, you must specify their new physical address and size in the header. **Ensure that sections do not overlap and remember to patch the FAT.BIN if necessary.** -**This software will be particularly useful if you want to mod your games or write a trainer for them.** +This tool is particularly useful for modding games or writing trainers. -# How to use it +# How to use ## Unpacker Tab -In the unpacker tab you can load your Nintendo DS software (.nds) and then you can extract the ROM sections, including the individual FAT files. -Please note the Original Address of the FAT Files, you will need this value later if you are going to alter the addresses and size of the sections. +In the Unpacker Tab, you can load your Nintendo DS software (.nds) and extract the ROM sections, including individual FAT files. Take note of the original address of the FAT files, as you will need this value if you alter the addresses and sizes of the sections. **You can then do what you want with these sections (inject code, apply patches etc.)** ## Packer Tab -In the packer tab you can re-create an .nds file using your edited sections. If your sections are bigger than the originals, you have to edit their addresses and size (in the header). **Make sure that the addresses don't overlap, or the final rom will be broken**. If you are repacking edited sections, and the FAT Files Address is different than the original one, **make sure to patch the FAT (fat.bin)**: the FAT is a list of absolute addresses (representing each file start address and end address), so you need to update them (you can easily do this using the FAT Patching Tab). +In the Packer Tab, you can recreate a .nds file using your edited sections. If your sections are larger than the originals, you must update their addresses and sizes in the header. Ensure that the addresses do not overlap, or the final ROM will be broken. If you repack edited sections and the FAT files' address is different from the original, you must patch the FAT (fat.bin). The FAT contains absolute addresses representing each file's start and end addresses, so you need to update them accordingly (use the FAT Patching Tab for this). -## Fat Patching Tab -In this tab you can easily patch the FAT section (fat.bin). You have to do this only if the FAT Files (fat_data.bin) final address is different than the original one. -Patching the FAT is easy, all you have to do is load your fat.bin, and fill the original address and the new address of fat_data.bin. This will produce a patched fat.bin that -you can use in the packing process. +## Fat Tools Tab +In this tab, you can patch the FAT section (fat.bin). This is only necessary if the FAT files' final address (fat_data.bin) differs from the original. Patching the FAT is straightforward: load your fat.bin, and fill in the original and new addresses of fat_data.bin. This will produce a patched fat.bin for use in the packing process. # Known Limitations/Possible Future Features/Bugs -* Add support for roms with OVERLAY -* Add support to rebuild a new fat_data.bin and fat.bin from a set of files inside a directory -* Design a nice logo/icon +* Add support for ROMs with overlays. +* Add support to rebuild a new fat_data.bin and fat.bin from a set of files inside a directory. -If you found a bug, feel free to open an issue or send a PR :) +If you find a bug, feel free to open an issue or submit a pull request :) ### Developed with ❤ by Luca D'Amico ### Special thanks to Antonio Barba & Davide Trogu diff --git a/sanitizers.cmake b/cmake/sanitizers.cmake similarity index 100% rename from sanitizers.cmake rename to cmake/sanitizers.cmake diff --git a/ndsfactory/ndsfactory.cpp b/ndsfactory/ndsfactory.cpp index 0c9476a..4ed9c86 100644 --- a/ndsfactory/ndsfactory.cpp +++ b/ndsfactory/ndsfactory.cpp @@ -116,7 +116,7 @@ bool NDSFactory::checkArm9FooterPresence(const std::string& sectionPath, uint32_ std::ifstream sectionFile (sectionPath, std::ios::in|std::ios::binary|std::ios::ate); if (sectionFile.is_open()) { - long sectionRealSize = sectionFile.tellg(); + std::streamoff sectionRealSize = sectionFile.tellg(); sectionFile.close(); if (sectionRealSize >= size + Arm9FooterSize) { @@ -134,8 +134,8 @@ bool NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftSize, if (!sectionFile.is_open()) return false; - long sectionSize = sectionFile.tellg(); - fatBytes.resize(static_cast(sectionSize)); + std::streamoff sectionSize = sectionFile.tellg(); + fatBytes.resize(sectionSize); sectionFile.seekg (0, std::ios::beg); diff --git a/res/ndsfactory.icns b/res/ndsfactory.icns new file mode 100644 index 0000000..9e0ddc1 Binary files /dev/null and b/res/ndsfactory.icns differ diff --git a/res/ndsfactory.ico b/res/ndsfactory.ico new file mode 100644 index 0000000..64f1482 Binary files /dev/null and b/res/ndsfactory.ico differ diff --git a/res/resources.rc b/res/resources.rc new file mode 100644 index 0000000..c4a2638 --- /dev/null +++ b/res/resources.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON "ndsfactory.ico" \ No newline at end of file diff --git a/ui/dialogs/about/aboutdialog.ui b/ui/dialogs/about/aboutdialog.ui index edafc4b..919a559 100644 --- a/ui/dialogs/about/aboutdialog.ui +++ b/ui/dialogs/about/aboutdialog.ui @@ -7,33 +7,33 @@ 0 0 400 - 300 + 179 - Dialog + About 300 - 260 + 140 81 32 - Qt::Horizontal + Qt::Orientation::Horizontal - QDialogButtonBox::Ok + QDialogButtonBox::StandardButton::Ok 10 - 140 + 20 381 31 @@ -42,33 +42,33 @@ false - NDS Factory V1.0 + NDS Factory V1.1 - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter 10 - 190 + 70 381 20 - (C) 2019-2021 - Luca D'Amico + (C) 2019-2024 - Luca D'Amico - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter 10 - 210 + 90 381 20 @@ -77,14 +77,14 @@ Special Thanks To: - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter 10 - 230 + 110 381 20 @@ -93,14 +93,14 @@ Dax89 (Davide Trogu) & Kaneb (Antonio Barba) - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter 10 - 170 + 50 381 20 @@ -109,7 +109,7 @@ Build Info - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter diff --git a/ui/dialogs/about/revision.h b/ui/dialogs/about/revision.h index e91ab8c..128590b 100644 --- a/ui/dialogs/about/revision.h +++ b/ui/dialogs/about/revision.h @@ -1,6 +1,6 @@ #ifndef REVISION_H #define REVISION_H -#define GIT_COMMIT_HASH "30425b6" +#define GIT_COMMIT_HASH "c7eaa8e" #endif diff --git a/ui/mainwindow.h b/ui/mainwindow.h index b86a2c0..f1f16d5 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -33,6 +33,7 @@ private slots: void on_unpackerDumpArm7OverlayFilesBtn_clicked(); void on_unpackerDumpEverythingBtn_clicked(); void on_unpackerDecodeFatFilesBtn_clicked(); + void notifyExtractionResult(bool result); void on_actionExit_triggered(); void on_actionAbout_triggered(); @@ -50,9 +51,9 @@ private slots: void on_packerLoadFatFilesBtn_clicked(); void on_packerBuildNDSRomBtn_clicked(); - void on_fatPatchingLoadFatBtn_clicked(); + void on_fatPatcherLoadFatBtn_clicked(); - void on_fatPatchingPatchFatBtn_clicked(); + void on_fatPatcherPatchFatBtn_clicked(); void on_packerCalcHeaderCrcBtn_clicked(); diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 5e89ee4..42272cf 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -11,7 +11,7 @@ - NDS Factory + NDSFactory @@ -28,10 +28,13 @@ - QLayout::SetMinAndMaxSize + QLayout::SizeConstraint::SetMinAndMaxSize + + + 0 @@ -50,7 +53,7 @@ 4 - QLayout::SetMinimumSize + QLayout::SizeConstraint::SetMinimumSize 1 @@ -93,10 +96,10 @@ - QAbstractScrollArea::AdjustToContents + QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers false @@ -124,7 +127,7 @@ false - Extractor + Single Binary Extractor @@ -261,7 +264,7 @@ false - Extra + AIO @@ -300,17 +303,17 @@ - QAbstractScrollArea::AdjustToContents + QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QLayout::SetMinimumSize + QLayout::SizeConstraint::SetMinimumSize 0 @@ -327,7 +330,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -356,7 +359,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Import Header From File @@ -500,7 +503,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight false @@ -509,13 +512,13 @@ Builder - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint @@ -559,7 +562,7 @@ - Qt::LeftToRight + Qt::LayoutDirection::LeftToRight Generate Trimmed Rom @@ -590,9 +593,9 @@ - + - Fat Patching + Fat Tools @@ -601,27 +604,8 @@ 4 - QLayout::SetDefaultConstraint + QLayout::SizeConstraint::SetDefaultConstraint - - - - - 0 - 0 - - - - If you FAT Files Address (fat_data.bin) is different from the original ROM position, you have to patch the FAT (fat.bin)... - - - false - - - Qt::AlignCenter - - - @@ -632,6 +616,25 @@ FAT Patcher + + + + + 0 + 0 + + + + If the address of the fat_data.bin file is different from the original location in ROM, you need to patch the fat.bin file... + + + false + + + Qt::AlignmentFlag::AlignCenter + + + @@ -647,10 +650,10 @@ 0 - + - + Load FAT (fat.bin) @@ -680,7 +683,7 @@ - + @@ -690,7 +693,7 @@ - + @@ -709,7 +712,7 @@ 0 - + Apply Patch! @@ -725,7 +728,7 @@ - Qt::Vertical + Qt::Orientation::Vertical @@ -750,7 +753,7 @@ 0 0 770 - 22 + 21 diff --git a/ui/models/ndsheadermodel.cpp b/ui/models/ndsheadermodel.cpp index 2c0ed9c..9c0d770 100644 --- a/ui/models/ndsheadermodel.cpp +++ b/ui/models/ndsheadermodel.cpp @@ -9,12 +9,12 @@ NDSHeaderModel::NDSHeaderModel(NDSHeader *ndsHeader, QObject *parent) : QAbstrac this->ndsHeader = ndsHeader; } -int NDSHeaderModel::rowCount(const QModelIndex &parent) const +int NDSHeaderModel::rowCount([[maybe_unused]] const QModelIndex &parent) const { return static_cast(ndsHeaderNamesArr.size()); } -int NDSHeaderModel::columnCount(const QModelIndex &parent) const +int NDSHeaderModel::columnCount([[maybe_unused]] const QModelIndex &parent) const { return 2; } diff --git a/ui/tabs/fatpatching/fatpatchingtabfunctions.cpp b/ui/tabs/fattools/fattoolstabfunctions.cpp similarity index 100% rename from ui/tabs/fatpatching/fatpatchingtabfunctions.cpp rename to ui/tabs/fattools/fattoolstabfunctions.cpp diff --git a/ui/tabs/fatpatching/fatpatchingtabsignals.cpp b/ui/tabs/fattools/fattoolstabsignals.cpp similarity index 66% rename from ui/tabs/fatpatching/fatpatchingtabsignals.cpp rename to ui/tabs/fattools/fattoolstabsignals.cpp index e4b2467..9fd706d 100644 --- a/ui/tabs/fatpatching/fatpatchingtabsignals.cpp +++ b/ui/tabs/fattools/fattoolstabsignals.cpp @@ -4,7 +4,7 @@ #include "./../../ui_mainwindow.h" -void MainWindow::on_fatPatchingLoadFatBtn_clicked() +void MainWindow::on_fatPatcherLoadFatBtn_clicked() { QString fatPath = QFileDialog::getOpenFileName( Q_NULLPTR, @@ -14,15 +14,15 @@ void MainWindow::on_fatPatchingLoadFatBtn_clicked() if( !fatPath.isNull() ) { - ui->fatPatchingFatPathEdt->setText(fatPath.toUtf8()); + ui->fatPatcherFatPathEdt->setText(fatPath.toUtf8()); } } -void MainWindow::on_fatPatchingPatchFatBtn_clicked() +void MainWindow::on_fatPatcherPatchFatBtn_clicked() { uint32_t positionDiff = 0; - uint32_t originalPos = ui->fatPatchingOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16); - uint32_t newPos = ui->fatPatchingNewFatFilesAddrEdt->text().toUInt(nullptr, 16); + uint32_t originalPos = ui->fatPatcherOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16); + uint32_t newPos = ui->fatPatcherNewFatFilesAddrEdt->text().toUInt(nullptr, 16); QString dirPath = QFileDialog::getSaveFileName( Q_NULLPTR, @@ -42,7 +42,7 @@ void MainWindow::on_fatPatchingPatchFatBtn_clicked() positionDiff = originalPos-newPos; } - patchFat(ui->fatPatchingFatPathEdt->text().toStdString(), positionDiff, dirPath.toStdString()) + patchFat(ui->fatPatcherFatPathEdt->text().toStdString(), positionDiff, dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("FAT patching completed!")) : QMessageBox::critical(this, tr("NDS Factory"), tr("Error patching FAT!")); diff --git a/ui/tabs/packer/packertabfunctions.cpp b/ui/tabs/packer/packertabfunctions.cpp index 89c2c1f..2099d68 100644 --- a/ui/tabs/packer/packertabfunctions.cpp +++ b/ui/tabs/packer/packertabfunctions.cpp @@ -94,23 +94,23 @@ void MainWindow::generateHeader(NDSHeader* pRomHeader) bool MainWindow::writeHeader(const std::string& savePath) { - std::vector romHeader(sizeof(NDSHeader)); - NDSHeader* pRomHeader = reinterpret_cast(romHeader.data()); + std::vector romHeaderBuffer(sizeof(NDSHeader)); + NDSHeader* pRomHeader = reinterpret_cast(romHeaderBuffer.data()); generateHeader(pRomHeader); - return ndsFactory.writeBytesToFile(romHeader, savePath, 0, sizeof(NDSHeader));; + return ndsFactory.writeBytesToFile(romHeaderBuffer, savePath, 0, sizeof(NDSHeader));; } void MainWindow::calcHeaderCrc16() { - std::vector romHeader(sizeof(NDSHeader)); - NDSHeader* pRomHeader = reinterpret_cast(romHeader.data()); + std::vector romHeaderBuffer(sizeof(NDSHeader)); + NDSHeader* pRomHeader = reinterpret_cast(romHeaderBuffer.data()); generateHeader(pRomHeader); QModelIndex headerCrcIndex = ui->packerHeaderDataTable->model()->index(NDSHeaderNames::HeaderCRC, 1); - ui->packerHeaderDataTable->model()->setData(headerCrcIndex, QString::number(ndsFactory.calcHeaderCrc16(romHeader), 16), Qt::EditRole); + ui->packerHeaderDataTable->model()->setData(headerCrcIndex, QString::number(ndsFactory.calcHeaderCrc16(romHeaderBuffer), 16), Qt::EditRole); } bool MainWindow::writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent) @@ -161,7 +161,7 @@ bool MainWindow::writeArm9Overlay(const std::string& savePath) extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16)); } -bool MainWindow::writeArm9OverlayFiles(const std::string& savePath) +bool MainWindow::writeArm9OverlayFiles([[maybe_unused]] const std::string& savePath) { return false; // TODO: implement me! } @@ -175,7 +175,7 @@ bool MainWindow::writeArm7Overlay(const std::string& savePath) extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16)); } -bool MainWindow::writeArm7OverlayFiles(const std::string& savePath) +bool MainWindow::writeArm7OverlayFiles([[maybe_unused]] const std::string& savePath) { return false; // TODO: implement me! } @@ -268,23 +268,23 @@ bool MainWindow::writeFatPadding(char paddingType, const std::string& savePath) size); } -bool MainWindow::writeArm9OverlayPadding(char paddingType, const std::string& savePath) +bool MainWindow::writeArm9OverlayPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath) { // FIXME TODO return true; } -bool MainWindow::writeArm9OverlayFilesPadding(char paddingType, const std::string& savePath) +bool MainWindow::writeArm9OverlayFilesPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath) { // FIXME TODO return true; } -bool MainWindow::writeArm7OverlayPadding(char paddingType, const std::string& savePath) +bool MainWindow::writeArm7OverlayPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath) { // FIXME TODO return true; } -bool MainWindow::writeArm7OverlayFilesPadding(char paddingType, const std::string& savePath) +bool MainWindow::writeArm7OverlayFilesPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath) { // FIXME TODO return true; } diff --git a/ui/tabs/unpacker/unpackertabfunctions.cpp b/ui/tabs/unpacker/unpackertabfunctions.cpp index 3d55dee..cacef12 100644 --- a/ui/tabs/unpacker/unpackertabfunctions.cpp +++ b/ui/tabs/unpacker/unpackertabfunctions.cpp @@ -9,19 +9,20 @@ #include "../../../ndsfactory/fatstruct.h" // Byte offsets for interpreting memory - #define SECOND_BYTE_SHIFT 8 #define THIRD_BYTE_SHIFT 16 #define FOURTH_BYTE_SHIFT 24 // Magic values for FAT extraction - #define CONTROL_BYTE_LENGTH_MASK 0x7F #define CONTROL_BYTE_DIR_MASK 0x80 #define DUMMY_CONTROL_VALUE 0xFF #define FNT_HEADER_OFFSET_MASK 0XFFF #define ROOT_DIRECTORY_ADDRESS 0xF000 +// Size constants +#define ICON_TITLE_SIZE 0xA00 + void MainWindow::populateHeader(NDSHeader* ndsHeader) { auto* headerDataModel = new NDSHeaderModel(ndsHeader); @@ -107,7 +108,7 @@ bool MainWindow::dumpArm9Overlay(const std::string& dirPath) ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlaySize, 1).data().toString().toUInt(nullptr,16)); } -bool MainWindow::dumpArm9OverlayFiles(const std::string& dirPath) +bool MainWindow::dumpArm9OverlayFiles([[maybe_unused]] const std::string& dirPath) { return false; // TODO: implement me! } @@ -121,7 +122,7 @@ bool MainWindow::dumpArm7Overlay(const std::string& dirPath) ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlaySize, 1).data().toString().toUInt(nullptr,16)); } -bool MainWindow::dumpArm7OverlayFiles(const std::string& dirPath) +bool MainWindow::dumpArm7OverlayFiles([[maybe_unused]] const std::string& dirPath) { return false; // TODO: implement me! } @@ -132,7 +133,7 @@ bool MainWindow::dumpIconTitle(const std::string& dirPath) ui->loadedRomPath->text().toStdString(), dirPath, ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::IconTitleAddress, 1).data().toString().toUInt(nullptr,16), - 0xA00); + ICON_TITLE_SIZE); } bool MainWindow::dumpFatFiles(const std::string& dirPath) @@ -150,34 +151,23 @@ bool MainWindow::dumpFatFiles(const std::string& dirPath) bool MainWindow::dumpEverything(QString dirPath) { - if(!dumpHeader(QDir::toNativeSeparators(dirPath+"/header.bin").toStdString())) - return false; - if(!dumpArm9Bin(QDir::toNativeSeparators(dirPath+"/arm9.bin").toStdString(), true)) - return false; - if(!dumpArm7Bin(QDir::toNativeSeparators(dirPath+"/arm7.bin").toStdString())) - return false; - if(!dumpFnt(QDir::toNativeSeparators(dirPath+"/fnt.bin").toStdString())) - return false; - if(!dumpFat(QDir::toNativeSeparators(dirPath+"/fat.bin").toStdString())) - return false; + bool result = true; + result &= dumpHeader(QDir::toNativeSeparators(dirPath+"/header.bin").toStdString()); + result &= dumpArm9Bin(QDir::toNativeSeparators(dirPath+"/arm9.bin").toStdString(), true); + result &= dumpArm7Bin(QDir::toNativeSeparators(dirPath+"/arm7.bin").toStdString()); + result &= dumpFnt(QDir::toNativeSeparators(dirPath+"/fnt.bin").toStdString()); + result &= dumpFat(QDir::toNativeSeparators(dirPath+"/fat.bin").toStdString()); if(ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16) != 0) { - if(!dumpArm9Overlay(QDir::toNativeSeparators(dirPath+"/a9ovr.bin").toStdString())) - return false; - if(!dumpArm9OverlayFiles(QDir::toNativeSeparators(dirPath+"/a9ovr_data.bin").toStdString())) - return false; - } + result &= dumpArm9Overlay(QDir::toNativeSeparators(dirPath+"/a9ovr.bin").toStdString()); + result &= dumpArm9OverlayFiles(QDir::toNativeSeparators(dirPath+"/a9ovr_data.bin").toStdString()); + } if(ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16) != 0) { - if(!dumpArm7Overlay(QDir::toNativeSeparators(dirPath+"/a7ovr.bin").toStdString())) - return false; - if(!dumpArm7OverlayFiles(QDir::toNativeSeparators(dirPath+"/a7ovr_data.bin").toStdString())) - return false; - } - if(!dumpIconTitle(QDir::toNativeSeparators(dirPath+"/itl.bin").toStdString())) - return false; - if(!dumpFatFiles(QDir::toNativeSeparators(dirPath+"/fat_data.bin").toStdString())) - return false; - - return true; + result &= dumpArm7Overlay(QDir::toNativeSeparators(dirPath+"/a7ovr.bin").toStdString()); + result &= dumpArm7OverlayFiles(QDir::toNativeSeparators(dirPath+"/a7ovr_data.bin").toStdString()); + } + result &= dumpIconTitle(QDir::toNativeSeparators(dirPath+"/itl.bin").toStdString()); + result &= dumpFatFiles(QDir::toNativeSeparators(dirPath+"/fat_data.bin").toStdString()); + return result; } bool MainWindow::decodeFatFiles(QString dirPath) diff --git a/ui/tabs/unpacker/unpackertabsignals.cpp b/ui/tabs/unpacker/unpackertabsignals.cpp index d02607a..403b192 100644 --- a/ui/tabs/unpacker/unpackertabsignals.cpp +++ b/ui/tabs/unpacker/unpackertabsignals.cpp @@ -41,10 +41,7 @@ void MainWindow::on_unpackerDumpHeaderBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpHeader(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpHeader(dirPath.toStdString())); } void MainWindow::on_unpackerDumpArm9Btn_clicked() @@ -62,11 +59,7 @@ void MainWindow::on_unpackerDumpArm9Btn_clicked() QMessageBox::Yes|QMessageBox::No); if (!dirPath.isNull()) - { - dumpArm9Bin(dirPath.toStdString(), dumpExtraBytes == QMessageBox::Yes ? true : false) - ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpArm9Bin(dirPath.toStdString(), dumpExtraBytes == QMessageBox::Yes ? true : false)); } void MainWindow::on_unpackerDumpArm7Btn_clicked() @@ -78,10 +71,7 @@ void MainWindow::on_unpackerDumpArm7Btn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpArm7Bin(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpArm7Bin(dirPath.toStdString())); } void MainWindow::on_unpackerDumpFntBtn_clicked() @@ -93,10 +83,7 @@ void MainWindow::on_unpackerDumpFntBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpFnt(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpFnt(dirPath.toStdString())); } void MainWindow::on_unpackerDumpFatBtn_clicked() @@ -108,10 +95,7 @@ void MainWindow::on_unpackerDumpFatBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpFat(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpFat(dirPath.toStdString())); } void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked() @@ -123,10 +107,7 @@ void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpArm9Overlay(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpArm9Overlay(dirPath.toStdString())); } void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked() @@ -138,10 +119,7 @@ void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpArm7Overlay(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpArm7Overlay(dirPath.toStdString())); } void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked() @@ -153,10 +131,7 @@ void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpIconTitle(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpIconTitle(dirPath.toStdString())); } void MainWindow::on_unpackerDumpFatFilesBtn_clicked() @@ -168,10 +143,7 @@ void MainWindow::on_unpackerDumpFatFilesBtn_clicked() "Binary (*.bin)"); if (!dirPath.isNull()) - { - dumpFatFiles(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpFatFiles(dirPath.toStdString())); } void MainWindow::on_unpackerDumpArm9OverlayFilesBtn_clicked() @@ -194,10 +166,7 @@ void MainWindow::on_unpackerDumpEverythingBtn_clicked() QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (!dirPath.isNull()) - { - dumpEverything(dirPath) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); - } + notifyExtractionResult(dumpEverything(dirPath)); } void MainWindow::on_unpackerDecodeFatFilesBtn_clicked() @@ -208,8 +177,17 @@ void MainWindow::on_unpackerDecodeFatFilesBtn_clicked() QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (!dirPath.isNull()) - { - decodeFatFiles(dirPath) ? QMessageBox::information(this, tr("NDS Factory"), tr("FAT files successfully decoded!")) - : QMessageBox::critical(this, tr("NDS Factory"), tr("Error during FAT file decoding!")); - } + notifyExtractionResult(decodeFatFiles(dirPath)); } + +void MainWindow::notifyExtractionResult(bool result) +{ + if(result) + { + QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!")); + } + else + { + QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!")); + } +} \ No newline at end of file