21 Commits

Author SHA1 Message Date
Luca D'Amico
aa2ed50ade v1.1 (#16) 2024-08-04 20:09:19 +02:00
NyuBlara
ec81e2bfbe Feat/fat decoding (#14)
* First step in implementing FAT file decoding : brute-force extraction without FNT lookup.

The FAT alone contains enough information to extract every file in a
folder chosen by the user. However, reference to the file name table
(FNT) is needed to restore the files' names and the directory structure
(and avoid dumping useless data that may be left over in the data
section).

This commit only implements the dumping of all data by incrementing
through the FAT and writing every section marked by a FAT range into a
separate file, giving them incremental names.

The next commit will use the FNT to name them properly.

* Proper FAT decoding : FNT lookup and directory structure

Code comments explain the algorithm (which was understood thanks to the 
wonderfully simple "FNT-Tool" script at : 
https://github.com/RoadrunnerWMC/FNT-Tool) ; the implementation is more 
or less a C++ port of the Python code.

Everything may still be a little dirty, but it works !

* Updated README!

* Updated README!

* MINOR compliance modifications 

- Removed extra entry in .gitignore
- Removed superfluous debug inclusions 
- Replaced magic values by preprocessor macros

Co-authored-by: rblard <rblard@enseirb-matmeca.fr>
2022-11-16 18:46:13 +01:00
Luca D'Amico
30425b6bb8 Bugfix: check if file exists before overwrite 2021-04-12 00:34:58 +02:00
Luca D'Amico
319d0e232e UI redesign: now use QTableView (#12)
* Switched to QTableView in Unpacker Tab

* Switched to QTableView in Packer Tab
2021-04-07 22:44:07 +02:00
Luca D'Amico
f64b0702a4 Force Fusion theme - fixes macOS UI bug 2021-03-09 22:23:55 +01:00
Luca D'Amico
31148e2337 Update .gitignore 2021-03-09 22:03:51 +01:00
Luca D'Amico
7f81130d90 Removed build directory (leftover) 2021-03-02 18:24:22 +01:00
Luca D'Amico
93a037e6c1 Display revision and build informations in about dialog 2021-03-02 18:20:48 +01:00
Luca D'Amico
658ca1b74c Better project organization 2021-03-01 18:56:19 +01:00
Luca D'Amico
c8fc9006f2 Add Windows CI (via GitHub Actions) (#11)
* Create GUI executable if building on Windows
* Enable Windows CI (via GitHub Actions)
2021-03-01 16:50:12 +01:00
Luca D'Amico
b334ff78ff GitHub Actions - Use commit hash as release version 2021-02-25 19:57:41 +01:00
Luca D'Amico
3c7bae69f8 Remove old autobuild releases 2021-02-25 19:33:33 +01:00
Luca D'Amico
bf8224eeb0 Add autorelease (via GitHub Actions) (#8)
* Add autorelease action
2021-02-25 19:12:30 +01:00
Luca D'Amico
439fe70f31 Add macOS CI (via GitHub Actions) (#6)
* Updated build.yml (macOS CI)
2021-02-25 13:05:30 +01:00
Luca D'Amico
573fc3b3cd Create app bundle if building on macOS 2021-02-25 12:50:10 +01:00
Luca D'Amico
1b7e29a7b0 fixed typos in README 2021-02-24 23:43:26 +01:00
Luca D'Amico
a4c6b5f66e Add Linux CI (via GitHub Actions) (#4)
* Created build.yml (Linux CI)
2021-02-24 23:05:06 +01:00
Luca D'Amico
a3e006fa2f Switched to CMake 2020-12-07 14:14:34 +01:00
Luca
d0d4138d3f Merge remote-tracking branch 'origin/master' 2019-09-15 20:47:16 +02:00
Luca
aaa60c9bb0 Implemented header crc16 calculation 2019-09-15 20:47:02 +02:00
Luca D'Amico
33d797ca21 Update README.md 2019-09-13 14:48:01 +02:00
40 changed files with 2790 additions and 2824 deletions

130
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,130 @@
name: Build and Release on Tag
on:
push:
tags:
- v*
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.1.7
- name: Create Build Environment
run: |
sudo apt-get update
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=Release ..
- name: Build
working-directory: ${{github.workspace}}/build
shell: bash
run: |
make -j4
- name: Archive Artifact
working-directory: ${{github.workspace}}/build
shell: bash
run: |
tar -czvf NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz NDSFactory ../README.md ../LICENSE
- name: Release on GitHub
uses: softprops/action-gh-release@v2.0.8
if: startsWith(github.ref, 'refs/tags/')
with:
files: "build/NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz"
build-macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4.1.7
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: '6.5.2'
- name: Install CMake
uses: lukka/get-cmake@latest
- name: Create Build Environment
run: |
mkdir build
- name: Configure CMake
working-directory: ${{github.workspace}}/build
shell: bash
run: |
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}}/build
shell: bash
run: |
zip -r NDSFactory-${{ github.ref_name }}-macOS.zip NDSFactory.app ../README.md ../LICENSE
- name: Release on GitHub
uses: softprops/action-gh-release@v2.0.8
if: startsWith(github.ref, 'refs/tags/')
with:
files: "build/NDSFactory-${{ github.ref_name }}-macOS.zip"
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4.1.7
- name: Install Qt
uses: jurplel/install-qt-action@v4
with:
version: '6.5.2'
- name: Install CMake
uses: lukka/get-cmake@latest
- name: Create Build Environment
run: |
mkdir build
- name: Configure CMake
working-directory: ${{github.workspace}}/build
run: |
cmake ..
- name: Build
working-directory: ${{github.workspace}}/build
run: |
cmake --build . -j4 --config Release
mkdir .\Release\prod
move .\Release\NDSFactory.exe .\Release\prod
windeployqt .\Release\prod\NDSFactory.exe
- name: Archive Artifact
working-directory: ${{github.workspace}}/build/Release
run: |
xcopy ..\..\README.md .\prod
xcopy ..\..\LICENSE .\prod
powershell "Compress-Archive -Path .\prod\* -DestinationPath .\NDSFactory-${{ github.ref_name }}-Windows-x64.zip"
- name: Release on GitHub
uses: softprops/action-gh-release@v2.0.8
if: startsWith(github.ref, 'refs/tags/')
with:
files: "build/Release/NDSFactory-${{ github.ref_name }}-Windows-x64.zip"

398
.gitignore vendored
View File

@@ -41,3 +41,401 @@ target_wrapper.*
# QtCreator CMake # QtCreator CMake
CMakeLists.txt.user* 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

101
CMakeLists.txt Normal file
View File

@@ -0,0 +1,101 @@
cmake_minimum_required(VERSION 3.25)
project(NDSFactory)
# Require Qt6 components
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
# 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
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
else()
set(GIT_COMMIT_HASH "")
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
)
# 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
file(GLOB_RECURSE TABS_HEADERS ui/tabs/*.h)
file(GLOB_RECURSE TABS_SOURCES ui/tabs/*.cpp)
## Models
file(GLOB_RECURSE MODELS_HEADERS ui/models/*.h)
file(GLOB_RECURSE MODELS_SOURCES ui/models/*.cpp)
## NDSFactory
file(GLOB_RECURSE NDSFACTORY_SOURCES ndsfactory/*.cpp)
file(GLOB_RECURSE NDSFACTORY_HEADERS ndsfactory/*.h)
set(SOURCES
main.cpp
ui/mainwindow.cpp
${NDSFACTORY_SOURCES}
${DIALOGS_SOURCES}
${MODELS_SOURCES}
${TABS_SOURCES}
)
SET(HEADERS
ui/mainwindow.h
${NDSFACTORY_HEADERS}
${TABS_HEADERS}
${MODELS_HEADERS}
${DIALOGS_HEADERS}
)
set(FORMS
ui/mainwindow.ui
${DIALOGS_UIS}
)
# 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()
# 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)

22
CMakePresets.json Normal file
View File

@@ -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="
}
}
}

76
CMakeUserPresets.json Normal file
View File

@@ -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="
}
}
}

View File

@@ -1,53 +0,0 @@
#-------------------------------------------------
#
# Project created by QtCreator 2019-08-29T12:15:45
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = NDSFactory
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
CONFIG += c++11
SOURCES += \
main.cpp \
mainwindow.cpp \
ndsfactory.cpp \
aboutdialog.cpp \
unpackertabfunctions.cpp \
unpackertabsignals.cpp \
packertabsignals.cpp \
packertabfunctions.cpp \
fatpatchingtabsignals.cpp \
fatpatchingtabfunctions.cpp
HEADERS += \
mainwindow.h \
ndsheader.h \
ndsfactory.h \
aboutdialog.h \
fatstruct.h
FORMS += \
mainwindow.ui \
aboutdialog.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

View File

@@ -3,20 +3,20 @@
[![GPL Licence](https://badges.frapsoft.com/os/gpl/gpl.png?v=103)](https://opensource.org/licenses/GPL-3.0/) [![GPL Licence](https://badges.frapsoft.com/os/gpl/gpl.png?v=103)](https://opensource.org/licenses/GPL-3.0/)
A tool to unpack &amp; repack Nintendo DS roms (.nds) A tool to unpack &amp; repack Nintendo DS ROMs (.nds)
If you find this software useful, please consider supporting it:
If you find this software useful, please [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Z8Z511SOI) [![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) ![screenshot](https://raw.githubusercontent.com/Luca1991/NDSFactory/master/screenshot.png)
**!!!ROM WITH OVERLAY ARE CURRENTLY NOT SUPPORTED!!!** **!!!ROMS WITH OVERLAY ARE CURRENTLY NOT SUPPORTED!!!**
# Description # 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 * Header
* ARM9 Binary * ARM9 Binary
* ARM7 Binary * ARM7 Binary
@@ -27,38 +27,29 @@ Basically an NDS software is composed of the following sections:
* Icon/Title Logo * Icon/Title Logo
* FAT Files (The actual files used by the software, like Graphics, Music etc.) * FAT Files (The actual files used by the software, like Graphics, Music etc.)
With NDSFactory you can extract these sections, modify them using your prefered way and the rebuild the rom with your edited sections. 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.**
If the modified sections are bigger than the original ones, you can specify their new physical adddress 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).
**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 ## Unpacker Tab
In the upacker tab you can load your Nintendo DS software (.nds) and then you can extract the rom 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.
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.
**You can then do what you want with these sections (inject code, apply patches etc.)** **You can then do what you want with these sections (inject code, apply patches etc.)**
## Packer Tab ## 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 adddress and end andress), 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 ## Fat Tools 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. 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.
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.
# Known Limitations/Possible Future Features/Bugs
# Know Limitations/Possible Future Featurs/Bugs * 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.
* Add support for roms with OVERLAY If you find a bug, feel free to open an issue or submit a pull request :)
* Add support to decode FAT Files (extract single files one by one)
* 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
If you found a bug, feel free to open an issue or send a PR :)
### Developed with ❤ by Luca D'Amico ### Developed with ❤ by Luca D'Amico
### Special thanks to Antonio Barba & Davide Trogu ### Special thanks to Antonio Barba & Davide Trogu

View File

@@ -1,15 +0,0 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
}
AboutDialog::~AboutDialog()
{
delete ui;
}

55
cmake/sanitizers.cmake Normal file
View File

@@ -0,0 +1,55 @@
# Build Types
set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel tsan asan lsan msan ubsan"
FORCE)
# ThreadSanitizer
set(CMAKE_C_FLAGS_TSAN
"-fsanitize=thread -g -O1"
CACHE STRING "Flags used by the C compiler during ThreadSanitizer builds."
FORCE)
set(CMAKE_CXX_FLAGS_TSAN
"-fsanitize=thread -g -O1"
CACHE STRING "Flags used by the C++ compiler during ThreadSanitizer builds."
FORCE)
# AddressSanitize
set(CMAKE_C_FLAGS_ASAN
"-fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1"
CACHE STRING "Flags used by the C compiler during AddressSanitizer builds."
FORCE)
set(CMAKE_CXX_FLAGS_ASAN
"-fsanitize=address -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1"
CACHE STRING "Flags used by the C++ compiler during AddressSanitizer builds."
FORCE)
# LeakSanitizer
set(CMAKE_C_FLAGS_LSAN
"-fsanitize=leak -fno-omit-frame-pointer -g -O1"
CACHE STRING "Flags used by the C compiler during LeakSanitizer builds."
FORCE)
set(CMAKE_CXX_FLAGS_LSAN
"-fsanitize=leak -fno-omit-frame-pointer -g -O1"
CACHE STRING "Flags used by the C++ compiler during LeakSanitizer builds."
FORCE)
# MemorySanitizer
set(CMAKE_C_FLAGS_MSAN
"-fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O2"
CACHE STRING "Flags used by the C compiler during MemorySanitizer builds."
FORCE)
set(CMAKE_CXX_FLAGS_MSAN
"-fsanitize=memory -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -g -O2"
CACHE STRING "Flags used by the C++ compiler during MemorySanitizer builds."
FORCE)
# UndefinedBehaviour
set(CMAKE_C_FLAGS_UBSAN
"-fsanitize=undefined"
CACHE STRING "Flags used by the C compiler during UndefinedBehaviourSanitizer builds."
FORCE)
set(CMAKE_CXX_FLAGS_UBSAN
"-fsanitize=undefined"
CACHE STRING "Flags used by the C++ compiler during UndefinedBehaviourSanitizer builds."
FORCE)

View File

@@ -1,8 +1,10 @@
#include "mainwindow.h" #include "ui/mainwindow.h"
#include <QApplication> #include <QApplication>
#include <QStyleFactory>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication::setStyle(QStyleFactory::create("Fusion"));
QApplication a(argc, argv); QApplication a(argc, argv);
MainWindow w; MainWindow w;
w.show(); w.show();

File diff suppressed because it is too large Load Diff

43
ndsfactory/crctable.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef CRCTABLE_H
#define CRCTABLE_H
#include <cstdint>
static const uint16_t lCRCTable[] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
#endif // CRCTABLE_H

View File

@@ -4,6 +4,7 @@
#include <cmath> #include <cmath>
#include "ndsfactory.h" #include "ndsfactory.h"
#include "fatstruct.h" #include "fatstruct.h"
#include "crctable.h"
NDSFactory::NDSFactory() NDSFactory::NDSFactory()
@@ -79,6 +80,12 @@ bool NDSFactory::writeSectionToFile(const std::string& sectionPath, const std::s
return false; return false;
} }
bool NDSFactory::writeFatSectionToFile(const std::string& romPath, FatRange* pfatrange, const std::string& savePath){
uint32_t size=pfatrange->endAddr-pfatrange->startAddr;
if(!dumpDataFromFile(romPath, savePath, pfatrange->startAddr, size)) return false;
return true;
}
bool NDSFactory::writeBytesToFile(std::vector<char>& byteBuffer, const std::string& savePath, uint32_t startAddr, uint32_t size) bool NDSFactory::writeBytesToFile(std::vector<char>& byteBuffer, const std::string& savePath, uint32_t startAddr, uint32_t size)
{ {
std::ofstream savedFile (savePath, std::ios::out|std::ios::binary|std::ios::app); std::ofstream savedFile (savePath, std::ios::out|std::ios::binary|std::ios::app);
@@ -109,7 +116,7 @@ bool NDSFactory::checkArm9FooterPresence(const std::string& sectionPath, uint32_
std::ifstream sectionFile (sectionPath, std::ios::in|std::ios::binary|std::ios::ate); std::ifstream sectionFile (sectionPath, std::ios::in|std::ios::binary|std::ios::ate);
if (sectionFile.is_open()) if (sectionFile.is_open())
{ {
long sectionRealSize = sectionFile.tellg(); std::streamoff sectionRealSize = sectionFile.tellg();
sectionFile.close(); sectionFile.close();
if (sectionRealSize >= size + Arm9FooterSize) if (sectionRealSize >= size + Arm9FooterSize)
{ {
@@ -127,8 +134,8 @@ bool NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftSize,
if (!sectionFile.is_open()) if (!sectionFile.is_open())
return false; return false;
long sectionSize = sectionFile.tellg(); std::streamoff sectionSize = sectionFile.tellg();
fatBytes.resize(static_cast<unsigned long>(sectionSize)); fatBytes.resize(sectionSize);
sectionFile.seekg (0, std::ios::beg); sectionFile.seekg (0, std::ios::beg);
@@ -145,3 +152,21 @@ bool NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftSize,
return writeBytesToFile(fatBytes, savePath, 0, static_cast<uint32_t>(sectionSize)); return writeBytesToFile(fatBytes, savePath, 0, static_cast<uint32_t>(sectionSize));
} }
uint16_t NDSFactory::calcHeaderCrc16(const std::vector<char>& romHeader)
{
uint8_t loc;
uint16_t crc = 0xFFFF;
size_t size = 0x15E;
size_t index = 0;
while (size--)
{
loc = static_cast<unsigned char>(romHeader[index] ^ crc);
index++;
crc >>= 8;
crc ^= lCRCTable[loc];
}
return crc;
}

View File

@@ -5,6 +5,7 @@
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include "ndsheader.h" #include "ndsheader.h"
#include "fatstruct.h"
@@ -16,11 +17,13 @@ public:
bool dumpDataFromFile(const std::string& romPath, const std::string& savePath, uint32_t startAddr, uint32_t size); bool dumpDataFromFile(const std::string& romPath, const std::string& savePath, uint32_t startAddr, uint32_t size);
bool readBytesFromFile(std::vector<char>& byteBuffer, const std::string& romPath, uint32_t startAddr, uint32_t size); bool readBytesFromFile(std::vector<char>& byteBuffer, const std::string& romPath, uint32_t startAddr, uint32_t size);
bool writeSectionToFile(const std::string& sectionPath, const std::string& savePath, uint32_t startAddr, uint32_t size); bool writeSectionToFile(const std::string& sectionPath, const std::string& savePath, uint32_t startAddr, uint32_t size);
bool writeFatSectionToFile(const std::string& romPath, FatRange* pfatrange, const std::string& savePath);
bool writeBytesToFile(std::vector<char>& byteBuffer, const std::string& savePath, uint32_t startAddr, uint32_t size); bool writeBytesToFile(std::vector<char>& byteBuffer, const std::string& savePath, uint32_t startAddr, uint32_t size);
bool writePaddingToFile(char paddingChar, const std::string& savePath, uint32_t startAddr, uint32_t size); bool writePaddingToFile(char paddingChar, const std::string& savePath, uint32_t startAddr, uint32_t size);
int getCardSizeInBytes(int cardType); int getCardSizeInBytes(int cardType);
bool checkArm9FooterPresence(const std::string& sectionPath, uint32_t size); bool checkArm9FooterPresence(const std::string& sectionPath, uint32_t size);
bool patchFat(const std::string& sectionPath, uint32_t shiftSize, const std::string& savePath); bool patchFat(const std::string& sectionPath, uint32_t shiftSize, const std::string& savePath);
uint16_t calcHeaderCrc16(const std::vector<char>& romHeader);
private: private:

View File

@@ -70,5 +70,4 @@ struct NDSHeader
}; };
#pragma pack(pop) #pragma pack(pop)
#endif // NDSHEADER_H #endif // NDSHEADER_H

View File

@@ -1,353 +0,0 @@
#include <QDir>
#include <cstring>
#include <algorithm>
#include "mainwindow.h"
#include "ui_mainwindow.h"
void MainWindow::populatePackerSectionHeader(NDSHeader *ndsHeader)
{
ui->packerGameTitleEdt->setText(QString::fromUtf8(ndsHeader->GameTitle, 0xC));
ui->packerGameCodeEdt->setText(QString::fromUtf8(ndsHeader->GameCode, 0x4));
ui->packerMakerCodeEdt->setText(QString::fromUtf8(reinterpret_cast<char*>(ndsHeader->MakerCode), 0x2));
ui->packerUnitCodeEdt->setText(QString::number(ndsHeader->UnitCode, 16));
ui->packerDeviceCodeEdt->setText(QString::number(ndsHeader->DeviceType, 16));
ui->packerCardSizeEdt->setText(QString::number(ndsHeader->DeviceSize, 16));
ui->packerCardInfoEdt->setText(QString::number(ndsHeader->RomVersion, 16));
ui->packerFlagsEdt->setText(QString::number(ndsHeader->Flags, 16));
ui->packerARM9RomAddrEdt->setText(QString::number(ndsHeader->Arm9RomAddr, 16));
ui->packerARM9EntryAddrEdt->setText(QString::number(ndsHeader->Arm9EntryAddr, 16));
ui->packerARM9RamAddrEdt->setText(QString::number(ndsHeader->Arm9RamAddr, 16));
ui->packerARM9SizeEdt->setText(QString::number(ndsHeader->Arm9Size, 16));
ui->packerARM7RomAddrEdt->setText(QString::number(ndsHeader->Arm7RomAddr, 16));
ui->packerARM7EntryAddrEdt->setText(QString::number(ndsHeader->Arm7EntryAddr, 16));
ui->packerARM7RamAddrEdt->setText(QString::number(ndsHeader->Arm7RamAddr, 16));
ui->packerARM7SizeEdt->setText(QString::number(ndsHeader->Arm7Size, 16));
ui->packerFilenameTableAddrEdt->setText(QString::number(ndsHeader->FilenameTableAddr, 16));
ui->packerFilenameTableSizeEdt->setText(QString::number(ndsHeader->FilenameSize, 16));
ui->packerFATAddrEdt->setText(QString::number(ndsHeader->FATAddr, 16));
ui->packerFATSizeEdt->setText(QString::number(ndsHeader->FATSize, 16));
ui->packerARM9OverlayAddrEdt->setText(QString::number(ndsHeader->Arm9OverlayAddr, 16));
ui->packerARM9OverlaySizeEdt->setText(QString::number(ndsHeader->Arm9OverlaySize, 16));
ui->packerARM7OverlayAddrEdt->setText(QString::number(ndsHeader->Arm7OverlayAddr, 16));
ui->packerARM7OverlaySizeEdt->setText(QString::number(ndsHeader->Arm7OverlaySize, 16));
ui->packerPortNCEdt->setText(QString::number(ndsHeader->NormalCommandsSettings, 16));
ui->packerPortKCEdt->setText(QString::number(ndsHeader->Key1CommandsSettings, 16));
ui->packerIconTitleEdt->setText(QString::number(ndsHeader->IconTitleAddr, 16));
ui->packerSecureAreaCRC16Edt->setText(QString::number(ndsHeader->SecureAreaCRC16, 16));
ui->packerSecureAreaTimeoutEdt->setText(QString::number(ndsHeader->SecureAreaLoadingTimeout, 16));
ui->packerARM9AURamAddrEdt->setText(QString::number(ndsHeader->ARM9AutoLoadListRamAddr, 16));
ui->packerARM7AURamAddrEdt->setText(QString::number(ndsHeader->ARM7AutoLoadListRamAddr, 16));
ui->packerSecureAreaDisableEdt->setText(QString::number(ndsHeader->SecureAreaDisable, 16));
ui->packerUsedRomSizeEdt->setText(QString::number(ndsHeader->RomSize, 16));
ui->packerHeaderSizeEdt->setText(QString::number(ndsHeader->HeaderSize, 16));
ui->packerNintendoLogoEdt->setText(QByteArray::fromRawData(reinterpret_cast<char*>(ndsHeader->NintendoLogo), 0x9C).toHex());
ui->packerNintendoLogoCRCEdt->setText(QString::number(ndsHeader->NintendoLogoCRC, 16));
ui->packerHeaderCRCEdt->setText(QString::number(ndsHeader->HeaderCRC16, 16));
ui->packerDebugRomAddrEdt->setText(QString::number(ndsHeader->DebugRomAddr, 16));
ui->packerDebugSizeEdt->setText(QString::number(ndsHeader->DebugSize, 16));
ui->packerDebugRamAddrEdt->setText(QString::number(ndsHeader->DebugRamAddr, 16));
}
bool MainWindow::writeHeader(const std::string& savePath)
{
std::vector<char> romHeader(sizeof(NDSHeader));
NDSHeader* pRomHeader = reinterpret_cast<NDSHeader*>(romHeader.data());
std::copy_n(ui->packerGameTitleEdt->text().toLatin1().data(), 0xc, std::begin(pRomHeader->GameTitle));
std::copy_n(ui->packerGameCodeEdt->text().toStdString().data(), 0x4, std::begin(pRomHeader->GameCode));
std::copy_n(ui->packerMakerCodeEdt->text().toStdString().data(), 0x2, std::begin(pRomHeader->MakerCode));
pRomHeader->UnitCode = static_cast<unsigned char>(ui->packerUnitCodeEdt->text().toUInt(nullptr, 16));
pRomHeader->DeviceType = static_cast<unsigned char>(ui->packerDeviceCodeEdt->text().toUInt(nullptr, 16));
pRomHeader->DeviceSize = static_cast<unsigned char>(ui->packerCardSizeEdt->text().toUInt(nullptr, 16));
std::fill(std::begin(pRomHeader->Reserved1), std::end(pRomHeader->Reserved1), 0);
pRomHeader->RomVersion = static_cast<unsigned char>(ui->packerCardInfoEdt->text().toUInt(nullptr, 16));
pRomHeader->Flags = static_cast<unsigned char>(ui->packerFlagsEdt->text().toUInt(nullptr, 16));
pRomHeader->Arm9RomAddr = ui->packerARM9RomAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm9EntryAddr = ui->packerARM9EntryAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm9RamAddr = ui->packerARM9RamAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm9Size = ui->packerARM9SizeEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm7RomAddr = ui->packerARM7RomAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm7EntryAddr = ui->packerARM7EntryAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm7RamAddr = ui->packerARM7RamAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm7Size = ui->packerARM7SizeEdt->text().toUInt(nullptr, 16);
pRomHeader->FilenameTableAddr = ui->packerFilenameTableAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->FilenameSize = ui->packerFilenameTableSizeEdt->text().toUInt(nullptr, 16);
pRomHeader->FATAddr = ui->packerFATAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->FATSize = ui->packerFATSizeEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm9OverlayAddr = ui->packerARM9OverlayAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm9OverlaySize = ui->packerARM9OverlaySizeEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm7OverlayAddr = ui->packerARM7OverlayAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->Arm7OverlaySize = ui->packerARM7OverlaySizeEdt->text().toUInt(nullptr, 16);
pRomHeader->NormalCommandsSettings = ui->packerPortNCEdt->text().toUInt(nullptr, 16);
pRomHeader->Key1CommandsSettings = ui->packerPortKCEdt->text().toUInt(nullptr, 16);
pRomHeader->IconTitleAddr = ui->packerIconTitleEdt->text().toUInt(nullptr, 16);
pRomHeader->SecureAreaCRC16 = ui->packerSecureAreaCRC16Edt->text().toUShort(nullptr, 16);
pRomHeader->SecureAreaLoadingTimeout = ui->packerSecureAreaTimeoutEdt->text().toUShort(nullptr, 16);
pRomHeader->ARM9AutoLoadListRamAddr = ui->packerARM9AURamAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->ARM7AutoLoadListRamAddr = ui->packerARM7AURamAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->SecureAreaDisable = ui->packerSecureAreaDisableEdt->text().toULong(nullptr, 16);
pRomHeader->RomSize = ui->packerUsedRomSizeEdt->text().toUInt(nullptr, 16);
pRomHeader->HeaderSize = ui->packerHeaderSizeEdt->text().toUInt(nullptr, 16);
std::fill(std::begin(pRomHeader->Reserved2), std::end(pRomHeader->Reserved2), 0);
std::copy_n(std::begin(QByteArray::fromHex(ui->packerNintendoLogoEdt->text().toUtf8())), 0x9C, std::begin(pRomHeader->NintendoLogo));
pRomHeader->NintendoLogoCRC = ui->packerNintendoLogoCRCEdt->text().toUShort(nullptr, 16);
pRomHeader->HeaderCRC16 = ui->packerHeaderCRCEdt->text().toUShort(nullptr, 16);
pRomHeader->DebugRomAddr = ui->packerDebugRomAddrEdt->text().toUInt(nullptr, 16);
pRomHeader->DebugSize = ui->packerDebugSizeEdt->text().toUInt(nullptr, 16);
pRomHeader->DebugRamAddr = ui->packerDebugRamAddrEdt->text().toUInt(nullptr, 16);
std::fill(std::begin(pRomHeader->Reserved3), std::end(pRomHeader->Reserved3), 0);
std::fill(std::begin(pRomHeader->Reserved4), std::end(pRomHeader->Reserved4), 0);
return ndsFactory.writeBytesToFile(romHeader, savePath, 0, sizeof(NDSHeader));;
}
bool MainWindow::writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent)
{
uint32_t size = ui->packerARM9SizeEdt->text().toUInt(nullptr, 16);
if (isArm9FooterPresent)
size += Arm9FooterSize;
return ndsFactory.writeSectionToFile(
ui->loadedArm9BinPathEdt->text().toStdString(),
savePath,
ui->packerARM9RomAddrEdt->text().toUInt(nullptr, 16),
size);
}
bool MainWindow::writeArm7Bin(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedArm7BinPathEdt->text().toStdString(),
savePath,
ui->packerARM7RomAddrEdt->text().toUInt(nullptr, 16),
ui->packerARM7SizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::writeFnt(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedFntPathEdt->text().toStdString(),
savePath,
ui->packerFilenameTableAddrEdt->text().toUInt(nullptr, 16),
ui->packerFilenameTableSizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::writeFat(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedFatPathEdt->text().toStdString(),
savePath,
ui->packerFATAddrEdt->text().toUInt(nullptr, 16),
ui->packerFATSizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::writeArm9Overlay(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedArm9OverlayPathEdt->text().toStdString(),
savePath,
ui->packerARM9OverlayAddrEdt->text().toUInt(nullptr, 16),
ui->packerARM9OverlaySizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::writeArm9OverlayFiles(const std::string& savePath)
{
return false; // TODO: implement me!
}
bool MainWindow::writeArm7Overlay(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedArm7OverlayPathEdt->text().toStdString(),
savePath,
ui->packerARM7OverlayAddrEdt->text().toUInt(nullptr, 16),
ui->packerARM7OverlaySizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::writeArm7OverlayFiles(const std::string& savePath)
{
return false; // TODO: implement me!
}
bool MainWindow::writeIconTitle(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedIconTitlePathEdt->text().toStdString(),
savePath,
ui->packerIconTitleEdt->text().toUInt(nullptr, 16),
IconTitleSize);
}
bool MainWindow::writeFatFiles(const std::string& savePath)
{
uint32_t startAddr = ui->packerIconTitleEdt->text().toUInt(nullptr, 16) + IconTitleSize;
uint32_t size = ui->packerUsedRomSizeEdt->text().toUInt(nullptr, 16) - startAddr;
return ndsFactory.writeSectionToFile(
ui->loadedFatFilesPathEdt->text().toStdString(),
savePath,
startAddr,
size);
}
bool MainWindow::writeHeaderPadding(char paddingType, const std::string& savePath)
{
uint32_t startAddr = sizeof(NDSHeader);
uint32_t size = ui->packerARM9RomAddrEdt->text().toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeArm9BinPadding(char paddingType, const std::string& savePath, bool isFooterPresent)
{ // FIXME check ARM9 Overlay
uint32_t startAddr = ui->packerARM9RomAddrEdt->text().toUInt(nullptr, 16) + ui->packerARM9SizeEdt->text().toUInt(nullptr, 16);
uint32_t size = ui->packerARM7RomAddrEdt->text().toUInt(nullptr, 16) - startAddr;
if (isFooterPresent)
size -= Arm9FooterSize;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeArm7BinPadding(char paddingType, const std::string& savePath)
{ // FIXME check ARM7 Overlay
uint32_t startAddr = ui->packerARM7RomAddrEdt->text().toUInt(nullptr, 16) + ui->packerARM7SizeEdt->text().toUInt(nullptr, 16);
uint32_t size = ui->packerFilenameTableAddrEdt->text().toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeFntPadding(char paddingType, const std::string& savePath)
{
uint32_t startAddr = ui->packerFilenameTableAddrEdt->text().toUInt(nullptr, 16) + ui->packerFilenameTableSizeEdt->text().toUInt(nullptr, 16);
uint32_t size = ui->packerFATAddrEdt->text().toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeFatPadding(char paddingType, const std::string& savePath)
{
uint32_t startAddr = ui->packerFATAddrEdt->text().toUInt(nullptr, 16) + ui->packerFATSizeEdt->text().toUInt(nullptr, 16);
uint32_t size = ui->packerIconTitleEdt->text().toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeArm9OverlayPadding(char paddingType, const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeArm9OverlayFilesPadding(char paddingType, const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeArm7OverlayPadding(char paddingType, const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeArm7OverlayFilesPadding(char paddingType, const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeRomPadding(const std::string& savePath)
{
uint32_t startAddr = ui->packerUsedRomSizeEdt->text().toUInt(nullptr, 16);
uint32_t size = static_cast<uint32_t>(ndsFactory.getCardSizeInBytes(ui->packerCardSizeEdt->text().toInt())) - startAddr;
return ndsFactory.writePaddingToFile(
static_cast<char>('\xff'),
savePath,
startAddr,
size);
}
bool MainWindow::writeEverything(const std::string& savePath)
{
bool res = true;
char paddingType;
bool isArm9FooterPresent = ndsFactory.checkArm9FooterPresence(ui->loadedArm9BinPathEdt->text().toStdString(),
ui->packerARM9SizeEdt->text().toUInt(nullptr, 16));
if (ui->packerPadType00RdBtn->isChecked())
paddingType = static_cast<char>('\x00');
else
paddingType = static_cast<char>('\xff');
res &= writeHeader(savePath);
res &= writeHeaderPadding(paddingType, savePath);
res &= writeArm9Bin(savePath, isArm9FooterPresent);
res &= writeArm9BinPadding(paddingType, savePath, isArm9FooterPresent);
res &= writeArm7Bin(savePath);
res &= writeArm7BinPadding(paddingType, savePath);
res &= writeFnt(savePath);
res &= writeFntPadding(paddingType, savePath);
res &= writeFat(savePath);
res &= writeFatPadding(paddingType, savePath);
if(ui->packerARM9OverlayAddrEdt->text().toUInt(nullptr, 16) != 0) {
res &= writeArm9Overlay(savePath);
res &= writeArm9OverlayPadding(paddingType, savePath);
res &= writeArm9OverlayFiles(savePath);
res &= writeArm9OverlayFilesPadding(paddingType, savePath);
}
if(ui->packerARM7OverlayAddrEdt->text().toUInt(nullptr, 16) != 0) {
res &= writeArm7Overlay(savePath);
res &= writeArm7OverlayPadding(paddingType, savePath);
res &= writeArm7OverlayFiles(savePath);
res &= writeArm7OverlayFilesPadding(paddingType, savePath);
}
res &= writeIconTitle(savePath);
res &= writeFatFiles(savePath);
if(!ui->packerTrimRomsCbx->isChecked())
{
res &= writeRomPadding(savePath);
}
return res;
}

BIN
res/ndsfactory.icns Normal file

Binary file not shown.

BIN
res/ndsfactory.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

1
res/resources.rc Normal file
View File

@@ -0,0 +1 @@
IDI_ICON1 ICON "ndsfactory.ico"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -0,0 +1,21 @@
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include "revision.h"
AboutDialog::AboutDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
QString currentVersion = ui->aboutSoftwareNameLbl->text();
QString currentRevision = QString("Rev: %1").arg(GIT_COMMIT_HASH);
ui->aboutSoftwareNameLbl->setText(currentVersion + " " + currentRevision);
QString buildInfo = QString("Build Date: %1 Time: %2").arg(__DATE__, __TIME__);
ui->aboutSoftwareBuildLbl->setText(buildInfo);
}
AboutDialog::~AboutDialog()
{
delete ui;
}

View File

@@ -10,12 +10,12 @@ class AboutDialog;
class AboutDialog : public QDialog class AboutDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
public: public:
AboutDialog(QWidget *parent = nullptr); AboutDialog(QWidget *parent = nullptr);
~AboutDialog(); ~AboutDialog();
private: private:
Ui::AboutDialog *ui; Ui::AboutDialog *ui;
}; };

View File

@@ -7,33 +7,33 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>400</width>
<height>300</height> <height>179</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>About</string>
</property> </property>
<widget class="QDialogButtonBox" name="aboutCloseBtnBx"> <widget class="QDialogButtonBox" name="aboutCloseBtnBx">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>300</x> <x>300</x>
<y>260</y> <y>140</y>
<width>81</width> <width>81</width>
<height>32</height> <height>32</height>
</rect> </rect>
</property> </property>
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Orientation::Horizontal</enum>
</property> </property>
<property name="standardButtons"> <property name="standardButtons">
<set>QDialogButtonBox::Ok</set> <set>QDialogButtonBox::StandardButton::Ok</set>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="aboutSoftwareNameLbl"> <widget class="QLabel" name="aboutSoftwareNameLbl">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
<y>150</y> <y>20</y>
<width>381</width> <width>381</width>
<height>31</height> <height>31</height>
</rect> </rect>
@@ -42,33 +42,33 @@
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="text"> <property name="text">
<string>NDS Factory V1.0</string> <string>NDS Factory V1.1</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignmentFlag::AlignCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="aboutSoftwareAuthorLbl"> <widget class="QLabel" name="aboutSoftwareAuthorLbl">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
<y>180</y> <y>70</y>
<width>381</width> <width>381</width>
<height>20</height> <height>20</height>
</rect> </rect>
</property> </property>
<property name="text"> <property name="text">
<string>(C) 2019 - Luca D'Amico</string> <string>(C) 2019-2024 - Luca D'Amico</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignmentFlag::AlignCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="aboutSpecialThanks"> <widget class="QLabel" name="aboutSpecialThanks">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
<y>200</y> <y>90</y>
<width>381</width> <width>381</width>
<height>20</height> <height>20</height>
</rect> </rect>
@@ -77,14 +77,14 @@
<string>Special Thanks To:</string> <string>Special Thanks To:</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignmentFlag::AlignCenter</set>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="aboutSpecialThanks2ndLine"> <widget class="QLabel" name="aboutSpecialThanks2ndLine">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>10</x>
<y>220</y> <y>110</y>
<width>381</width> <width>381</width>
<height>20</height> <height>20</height>
</rect> </rect>
@@ -93,7 +93,23 @@
<string>Dax89 (Davide Trogu) &amp; Kaneb (Antonio Barba)</string> <string>Dax89 (Davide Trogu) &amp; Kaneb (Antonio Barba)</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="aboutSoftwareBuildLbl">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>381</width>
<height>20</height>
</rect>
</property>
<property name="text">
<string>Build Info</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property> </property>
</widget> </widget>
</widget> </widget>

View File

@@ -0,0 +1,6 @@
#ifndef REVISION_H
#define REVISION_H
#define GIT_COMMIT_HASH "c7eaa8e"
#endif

View File

@@ -0,0 +1,6 @@
#ifndef REVISION_H
#define REVISION_H
#define GIT_COMMIT_HASH "@GIT_COMMIT_HASH@"
#endif

View File

@@ -1,6 +1,7 @@
#include <QApplication>
#include "mainwindow.h" #include "mainwindow.h"
#include "aboutdialog.h"
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include "dialogs/about/aboutdialog.h"
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent), QMainWindow(parent),

View File

@@ -3,7 +3,7 @@
#include <QMainWindow> #include <QMainWindow>
#include <cstdint> #include <cstdint>
#include "ndsfactory.h" #include "../ndsfactory/ndsfactory.h"
namespace Ui { namespace Ui {
@@ -33,6 +33,7 @@ private slots:
void on_unpackerDumpArm7OverlayFilesBtn_clicked(); void on_unpackerDumpArm7OverlayFilesBtn_clicked();
void on_unpackerDumpEverythingBtn_clicked(); void on_unpackerDumpEverythingBtn_clicked();
void on_unpackerDecodeFatFilesBtn_clicked(); void on_unpackerDecodeFatFilesBtn_clicked();
void notifyExtractionResult(bool result);
void on_actionExit_triggered(); void on_actionExit_triggered();
void on_actionAbout_triggered(); void on_actionAbout_triggered();
@@ -50,13 +51,16 @@ private slots:
void on_packerLoadFatFilesBtn_clicked(); void on_packerLoadFatFilesBtn_clicked();
void on_packerBuildNDSRomBtn_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();
private: private:
Ui::MainWindow *ui; Ui::MainWindow *ui;
NDSFactory ndsFactory; NDSFactory ndsFactory;
std::vector<char> romHeader;
void populateHeader(NDSHeader* ndsHeader); void populateHeader(NDSHeader* ndsHeader);
void enableExtractionButtons(); void enableExtractionButtons();
void disableExtractionButtons(); void disableExtractionButtons();
@@ -74,7 +78,11 @@ private:
bool dumpEverything(QString dirPath); bool dumpEverything(QString dirPath);
void populatePackerSectionHeader(NDSHeader *ndsHeader); void populatePackerSectionHeader(NDSHeader *ndsHeader);
void enableCalcCrcButton();
void enableBuildRomButton();
void generateHeader(NDSHeader* pRomHeader);
bool writeHeader(const std::string& savePath); bool writeHeader(const std::string& savePath);
void calcHeaderCrc16();
bool writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent); bool writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent);
bool writeArm7Bin(const std::string& savePath); bool writeArm7Bin(const std::string& savePath);
bool writeFnt(const std::string& savePath); bool writeFnt(const std::string& savePath);
@@ -98,7 +106,10 @@ private:
bool writeArm7OverlayFilesPadding(char paddingByte, const std::string& savePath); bool writeArm7OverlayFilesPadding(char paddingByte, const std::string& savePath);
bool writeRomPadding(const std::string& savePath); bool writeRomPadding(const std::string& savePath);
bool decodeFatFiles(); //QString extractUnpackerHeaderTableData(int index);
QString extractPackerHeaderTableData(int index);
bool decodeFatFiles(QString dirPath);
bool patchFat(const std::string& loadPath, uint32_t shiftSize, const std::string& savePath); bool patchFat(const std::string& loadPath, uint32_t shiftSize, const std::string& savePath);
}; };

793
ui/mainwindow.ui Normal file
View File

@@ -0,0 +1,793 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>770</width>
<height>844</height>
</rect>
</property>
<property name="windowTitle">
<string>NDSFactory</string>
</property>
<widget class="QWidget" name="centralWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>756</width>
<height>800</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetMinAndMaxSize</enum>
</property>
<item>
<widget class="QTabWidget" name="mainTab">
<property name="locale">
<locale language="English" country="UnitedStates"/>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="unpackerTab">
<attribute name="title">
<string>Unpacker</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Rom</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>4</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QLineEdit" name="loadedRomPath">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loadRomBtn">
<property name="text">
<string>Load Rom</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Header</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QTableView" name="unpackerHeaderDataTable">
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Tools</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="unpackerExtractorGbx">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>Single Binary Extractor</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QPushButton" name="unpackerDumpHeaderBtn">
<property name="text">
<string>Header</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpArm9Btn">
<property name="text">
<string>ARM9 Bin</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpArm7Btn">
<property name="text">
<string>ARM7 Bin</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpFntBtn">
<property name="text">
<string>Filename Table</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QPushButton" name="unpackerDumpFatBtn">
<property name="text">
<string>FAT</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpFatFilesBtn">
<property name="text">
<string>FAT Files</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpArm9OverlayBtn">
<property name="text">
<string>ARM9 Overlay</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpArm9OverlayFilesBtn">
<property name="text">
<string>ARM9 Overlay Files</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QPushButton" name="unpackerDumpArm7OverlayBtn">
<property name="text">
<string>ARM7 Overlay</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpArm7OverlayFilesBtn">
<property name="text">
<string>ARM7 Overlay Files</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDumpIconTitleLogoBtn">
<property name="text">
<string>Icon/Title Logo</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="unpackerExtraGbx">
<property name="enabled">
<bool>false</bool>
</property>
<property name="title">
<string>AIO</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="unpackerDumpEverythingBtn">
<property name="text">
<string>Extract Everything</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="unpackerDecodeFatFilesBtn">
<property name="text">
<string>Decode FAT Contents</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="packerTab">
<attribute name="title">
<string>Packer</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Header</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QTableView" name="packerHeaderDataTable">
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_33">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="packerCalcHeaderCrcBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Calc Header CRC</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="packerLoadHeaderBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Import Header From File</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="unpackerInjectorGbx">
<property name="title">
<string>Injector</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_26">
<item>
<widget class="QLineEdit" name="loadedArm9BinPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadArm9BinBtn">
<property name="text">
<string>Load Arm9 Bin</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="loadedArm7BinPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadArm7BinBtn">
<property name="text">
<string>Load Arm7 Bin</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_28">
<item>
<widget class="QLineEdit" name="loadedFntPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadFntBtn">
<property name="text">
<string>Load FNT</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="loadedFatPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadFatBtn">
<property name="text">
<string>Load FAT</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_29">
<item>
<widget class="QLineEdit" name="loadedArm9OverlayPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadArm9OverlayBtn">
<property name="text">
<string>Load ARM9 Overlay</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="loadedArm9OverlayFilesPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadArm9OverlayFilesBtn">
<property name="text">
<string>Load ARM9 Overlay Files</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_30">
<item>
<widget class="QLineEdit" name="loadedArm7OverlayPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadArm7OverlayBtn">
<property name="text">
<string>Load ARM7 Overlay</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="loadedArm7OverlayFilesPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadArm7OverlayFilesBtn">
<property name="text">
<string>Load ARM7 Overlay Files</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_31">
<item>
<widget class="QLineEdit" name="loadedIconTitlePathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadIconTitleBtn">
<property name="text">
<string>Load Icon/Title</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="loadedFatFilesPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="packerLoadFatFilesBtn">
<property name="text">
<string>Load FAT Files</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="title">
<string>Builder</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignVCenter</set>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_32">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
<item>
<widget class="QRadioButton" name="packerPadType00RdBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PAD Sections With 00s</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="packerPadTypeFFRdBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PAD Sections With FFs</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QCheckBox" name="packerTrimRomsCbx">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Generate Trimmed Rom</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QPushButton" name="packerBuildNDSRomBtn">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Build NDS Rom</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="fatToolsTab">
<attribute name="title">
<string>Fat Tools</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<layout class="QVBoxLayout" name="verticalLayout_14">
<property name="spacing">
<number>4</number>
</property>
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>FAT Patcher</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<widget class="QLabel" name="label_83">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>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...</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_35">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="fatPatcherFatPathEdt"/>
</item>
<item>
<widget class="QPushButton" name="fatPatcherLoadFatBtn">
<property name="text">
<string>Load FAT (fat.bin)</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_36">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_84">
<property name="text">
<string>Original Fat Files (fat_data.bin) Addr:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fatPatcherOriginalFatFilesAddrEdt"/>
</item>
<item>
<widget class="QLabel" name="label_85">
<property name="text">
<string>New Fat Files Addr:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="fatPatcherNewFatFilesAddrEdt"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_37">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="fatPatcherPatchFatBtn">
<property name="text">
<string>Apply Patch!</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>770</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="actionAbout"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusBar">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
<action name="actionAbout">
<property name="text">
<string>About</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,190 @@
#include <QMessageBox>
#include "ndsheadermodel.h"
#include "../../ndsfactory/ndsheader.h"
#include "../tabs/commons/headernames.h"
NDSHeaderModel::NDSHeaderModel(NDSHeader *ndsHeader, QObject *parent) : QAbstractTableModel(parent)
{
this->ndsHeader = ndsHeader;
}
int NDSHeaderModel::rowCount([[maybe_unused]] const QModelIndex &parent) const
{
return static_cast<int>(ndsHeaderNamesArr.size());
}
int NDSHeaderModel::columnCount([[maybe_unused]] const QModelIndex &parent) const
{
return 2;
}
QVariant NDSHeaderModel::data(const QModelIndex &index, int role) const
{
if(role == Qt::DisplayRole || role == Qt::EditRole)
{
if(index.column() == 0)
return QString::fromStdString(ndsHeaderNamesArr.at(static_cast<size_t>(index.row())));
else if(index.column() == 1) {
switch (index.row())
{
case 0: return QString::fromUtf8(ndsHeader->GameTitle, 0xC);
case 1: return QString::fromUtf8(ndsHeader->GameCode, 0x4);
case 2: return QString::fromUtf8(reinterpret_cast<char*>(ndsHeader->MakerCode), 0x2);
case 3: return QString::number(ndsHeader->UnitCode, 16);
case 4: return QString::number(ndsHeader->DeviceType, 16);
case 5: return QString::number(ndsHeader->DeviceSize, 16);
case 6: return QString::number(ndsHeader->RomVersion, 16);
case 7: return QString::number(ndsHeader->Flags, 16);
case 8: return QString::number(ndsHeader->Arm9RomAddr,16);
case 9: return QString::number(ndsHeader->Arm9EntryAddr,16);
case 10: return QString::number(ndsHeader->Arm9RamAddr,16);
case 11: return QString::number(ndsHeader->Arm9Size,16);
case 12: return QString::number(ndsHeader->Arm7RomAddr,16);
case 13: return QString::number(ndsHeader->Arm7EntryAddr,16);
case 14: return QString::number(ndsHeader->Arm7RamAddr,16);
case 15: return QString::number(ndsHeader->Arm7Size,16);
case 16: return QString::number(ndsHeader->FilenameTableAddr,16);
case 17: return QString::number(ndsHeader->FilenameSize,16);
case 18: return QString::number(ndsHeader->FATAddr,16);
case 19: return QString::number(ndsHeader->FATSize,16);
case 20: return QString::number(ndsHeader->Arm9OverlayAddr,16);
case 21: return QString::number(ndsHeader->Arm9OverlaySize,16);
case 22: return QString::number(ndsHeader->Arm7OverlayAddr,16);
case 23: return QString::number(ndsHeader->Arm7OverlaySize,16);
case 24: return QString::number(ndsHeader->NormalCommandsSettings,16);
case 25: return QString::number(ndsHeader->Key1CommandsSettings,16);
case 26: return QString::number(ndsHeader->IconTitleAddr,16);
case 27: return QString::number(ndsHeader->SecureAreaCRC16,16);
case 28: return QString::number(ndsHeader->SecureAreaLoadingTimeout,16);
case 29: return QString::number(ndsHeader->ARM9AutoLoadListRamAddr,16);
case 30: return QString::number(ndsHeader->ARM7AutoLoadListRamAddr,16);
case 31: return QString::number(ndsHeader->SecureAreaDisable,16);
case 32: return QString::number(ndsHeader->RomSize,16);
case 33: return QString::number(ndsHeader->HeaderSize,16);
case 34: return QByteArray::fromRawData(reinterpret_cast<char*>(ndsHeader->NintendoLogo), 0x9C).toHex();
case 35: return QString::number(ndsHeader->NintendoLogoCRC,16);
case 36: return QString::number(ndsHeader->HeaderCRC16,16);
case 37: return QString::number(ndsHeader->DebugRomAddr,16);
case 38: return QString::number(ndsHeader->DebugSize,16);
case 39: return QString::number(ndsHeader->DebugRamAddr,16);
case 40: return QString::number((ndsHeader->IconTitleAddr+IconTitleSize),16);
default: return QString("");
}
}
}
return QVariant();
}
bool NDSHeaderModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if(role != Qt::EditRole)
return QAbstractTableModel::setData(index, value, role);
switch (index.row())
{
case 0:
{
std::fill_n(ndsHeader->GameTitle, 0xC, 0x0);
QString gameTitleStr = value.toString().toUpper();
size_t size = std::min<size_t>(gameTitleStr.size(), 0xC);
std::copy_n(qUtf8Printable(gameTitleStr), size, ndsHeader->GameTitle);
break;
}
case 1:
{
std::fill_n(ndsHeader->GameCode, 0x4, 0x0);
QString gameCodeStr = value.toString().toUpper();
size_t size = std::min<size_t>(gameCodeStr.size(), 0x4);
std::copy_n(qUtf8Printable(gameCodeStr), size, ndsHeader->GameCode);
break;
}
case 2:
{
std::fill_n(ndsHeader->MakerCode, 0x2, 0x0);
QString makerCodeStr = value.toString().toUpper();
size_t size = std::min<size_t>(makerCodeStr.size(), 0x2);
std::copy_n(qUtf8Printable(makerCodeStr), size, ndsHeader->MakerCode);
break;
}
case 3: ndsHeader->UnitCode = static_cast<unsigned char>(value.toString().toUInt(nullptr, 16)); break;
case 4: ndsHeader->DeviceType = static_cast<unsigned char>(value.toString().toUInt(nullptr, 16)); break;
case 5: ndsHeader->DeviceSize = static_cast<unsigned char>(value.toString().toUInt(nullptr, 16)); break;
case 6: ndsHeader->RomVersion = static_cast<unsigned char>(value.toString().toUInt(nullptr, 16)); break;
case 7: ndsHeader->Flags = static_cast<unsigned char>(value.toString().toUInt(nullptr, 16)); break;
case 8: ndsHeader->Arm9RomAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 9: ndsHeader->Arm9EntryAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 10: ndsHeader->Arm9RamAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 11: ndsHeader->Arm9Size = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 12: ndsHeader->Arm7RomAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 13: ndsHeader->Arm7EntryAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 14: ndsHeader->Arm7RamAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 15: ndsHeader->Arm7Size = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 16: ndsHeader->FilenameTableAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 17: ndsHeader->FilenameSize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 18: ndsHeader->FATAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 19: ndsHeader->FATSize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 20: ndsHeader->Arm9OverlayAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 21: ndsHeader->Arm9OverlaySize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 22: ndsHeader->Arm7OverlayAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 23: ndsHeader->Arm7OverlaySize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 24: ndsHeader->NormalCommandsSettings = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 25: ndsHeader->Key1CommandsSettings = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 26: ndsHeader->IconTitleAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 27: ndsHeader->SecureAreaCRC16 = static_cast<uint16_t>(value.toString().toUInt(nullptr, 16)); break;
case 28: ndsHeader->SecureAreaLoadingTimeout = static_cast<uint16_t>(value.toString().toUInt(nullptr, 16)); break;
case 29: ndsHeader->ARM9AutoLoadListRamAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 30: ndsHeader->ARM7AutoLoadListRamAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 31: ndsHeader->SecureAreaDisable = static_cast<uint64_t>(value.toString().toUInt(nullptr, 16)); break;
case 32: ndsHeader->RomSize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 33: ndsHeader->HeaderSize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 34:
{
std::fill_n(ndsHeader->NintendoLogo, 0x9C, 0x0);
QByteArray nintendoLogoBytes = QByteArray::fromHex(qUtf8Printable(value.toString()));
size_t size = std::min<size_t>(nintendoLogoBytes.size(), 0x9C);
std::copy_n(std::begin(nintendoLogoBytes), size, ndsHeader->NintendoLogo);
break;
}
case 35: ndsHeader->NintendoLogoCRC = static_cast<uint16_t>(value.toString().toUInt(nullptr, 16)); break;
case 36: ndsHeader->HeaderCRC16 = static_cast<uint16_t>(value.toString().toUInt(nullptr, 16)); break;
case 37: ndsHeader->DebugRomAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 38: ndsHeader->DebugSize = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 39: ndsHeader->DebugRamAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
case 40: QMessageBox::information(nullptr, tr("NDS Factory"), tr("FAT files address is automatically calculated based on Icon/Title address!")); break;
default: return false;
}
Q_EMIT this->dataChanged(index, index);
return true;
}
QVariant NDSHeaderModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Horizontal)
{
if(role == Qt::DisplayRole)
{
switch(section)
{
case 0:
return "Name";
case 1:
return "Value";
}
}
}
return QVariant();
}
Qt::ItemFlags NDSHeaderModel::flags(const QModelIndex &index) const
{
if (index.isValid() && index.column() == 1 && isValueRowEditable)
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
return QAbstractItemModel::flags(index);
}
void NDSHeaderModel::setValueRowEditable(bool isEditable)
{
isValueRowEditable = isEditable;
}

View File

@@ -0,0 +1,25 @@
#ifndef NDSHEADERMODEL_H
#define NDSHEADERMODEL_H
#include <QAbstractTableModel>
struct NDSHeader;
class NDSHeaderModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit NDSHeaderModel(NDSHeader *ndsHeader, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
void setValueRowEditable(bool isEditable);
private:
NDSHeader *ndsHeader;
bool isValueRowEditable = false;
};
#endif // NDSHEADERMODEL_H

View File

@@ -0,0 +1,45 @@
#include "headernames.h"
std::vector<std::string> ndsHeaderNamesArr = {
"Game Title",
"Game Code",
"Maker Code",
"Unit Code",
"Device Code",
"Card Size",
"Card Info",
"Flags",
"ARM9 Rom Address",
"ARM9 Entry Address",
"ARM9 Ram Address",
"ARM9 Size",
"ARM7 Rom Address",
"ARM7 Entry Address",
"ARM7 Ram Address",
"ARM7 Size",
"Filename Table Address",
"Filename Table Size",
"FAT Address",
"FAT Size",
"ARM9 Overlay Address",
"ARM9 Overlay Size",
"ARM7 Overlay Address",
"ARM7 Overlay Size",
"Port 40001A4h NC",
"Port 40001a4h KC",
"Icon/Title Address",
"Secure Area CRC16",
"Secure Area Timeout",
"ARM9 AL Ram Address",
"ARM7 AL Ram Address",
"Secure Area Disable",
"Used Rom Size",
"Header Size",
"Nintendo Logo",
"Nintendo Logo CRC",
"Header CRC",
"Debug Rom Address",
"Debug Size",
"Debug Ram Address",
"FAT Files Address"
};

View File

@@ -0,0 +1,56 @@
#ifndef HEADERNAMES_H
#define HEADERNAMES_H
#include <array>
#include <string>
#include <vector>
extern std::vector<std::string> ndsHeaderNamesArr;
namespace NDSHeaderNames {
enum {
GameTitle,
GameCode,
MakerCode,
UnitCode,
DeviceCode,
CardSize,
CardInfo,
Flags,
ARM9RomAddress,
ARM9EntryAddress,
ARM9RamAddress,
ARM9Size,
ARM7RomAddress,
ARM7EntryAddress,
ARM7RamAddress,
ARM7Size,
FilenameTableAddress,
FilenameTableSize,
FATAddress,
FATSize,
ARM9OverlayAddress,
ARM9OverlaySize,
ARM7OverlayAddress,
ARM7OverlaySize,
Port40001A4hNC,
Port40001a4hKC,
IconTitleAddress,
SecureAreaCRC16,
SecureAreaTimeout,
ARM9ALRamAddress,
ARM7ALRamAddress,
SecureAreaDisable,
UsedRomSize,
HeaderSize,
NintendoLogo,
NintendoLogoCRC,
HeaderCRC,
DebugRomAddress,
DebugSize,
DebugRamAddress,
FATFilesAddress
};
}
#endif // HEADERNAMES_H

View File

@@ -1,4 +1,4 @@
#include "mainwindow.h" #include "./../../mainwindow.h"
bool MainWindow::patchFat(const std::string& loadPath, uint32_t shiftSize, const std::string& savePath) bool MainWindow::patchFat(const std::string& loadPath, uint32_t shiftSize, const std::string& savePath)

View File

@@ -1,10 +1,10 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include "mainwindow.h" #include "./../../mainwindow.h"
#include "ui_mainwindow.h" #include "./../../ui_mainwindow.h"
void MainWindow::on_fatPatchingLoadFatBtn_clicked() void MainWindow::on_fatPatcherLoadFatBtn_clicked()
{ {
QString fatPath = QFileDialog::getOpenFileName( QString fatPath = QFileDialog::getOpenFileName(
Q_NULLPTR, Q_NULLPTR,
@@ -14,15 +14,15 @@ void MainWindow::on_fatPatchingLoadFatBtn_clicked()
if( !fatPath.isNull() ) 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 positionDiff = 0;
uint32_t originalPos = ui->fatPatchingOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16); uint32_t originalPos = ui->fatPatcherOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16);
uint32_t newPos = ui->fatPatchingNewFatFilesAddrEdt->text().toUInt(nullptr, 16); uint32_t newPos = ui->fatPatcherNewFatFilesAddrEdt->text().toUInt(nullptr, 16);
QString dirPath = QFileDialog::getSaveFileName( QString dirPath = QFileDialog::getSaveFileName(
Q_NULLPTR, Q_NULLPTR,
@@ -42,7 +42,7 @@ void MainWindow::on_fatPatchingPatchFatBtn_clicked()
positionDiff = originalPos-newPos; 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::information(this, tr("NDS Factory"), tr("FAT patching completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error patching FAT!")); : QMessageBox::critical(this, tr("NDS Factory"), tr("Error patching FAT!"));

View File

@@ -0,0 +1,351 @@
#include <QDir>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include "./../../mainwindow.h"
#include "./../../ui_mainwindow.h"
#include "../commons/headernames.h"
#include "../../models/ndsheadermodel.h"
void MainWindow::populatePackerSectionHeader(NDSHeader *ndsHeader)
{
auto* headerDataModel = new NDSHeaderModel(ndsHeader);
headerDataModel->setValueRowEditable(true);
ui->packerHeaderDataTable->setModel(headerDataModel);
ui->packerHeaderDataTable->setEditTriggers(QAbstractItemView::AllEditTriggers);
ui->packerHeaderDataTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeMode::ResizeToContents);
ui->packerHeaderDataTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
}
void MainWindow::enableCalcCrcButton()
{
ui->packerCalcHeaderCrcBtn->setEnabled(true);
}
void MainWindow::enableBuildRomButton()
{
ui->packerBuildNDSRomBtn->setEnabled(true);
}
void MainWindow::generateHeader(NDSHeader* pRomHeader)
{
std::copy_n(extractPackerHeaderTableData(NDSHeaderNames::GameTitle).toLatin1().data(), 0xc, std::begin(pRomHeader->GameTitle));
std::copy_n(extractPackerHeaderTableData(NDSHeaderNames::GameCode).toLatin1().data(), 0x4, std::begin(pRomHeader->GameCode));
std::copy_n(extractPackerHeaderTableData(NDSHeaderNames::MakerCode).toLatin1().data(), 0x2, std::begin(pRomHeader->MakerCode));
pRomHeader->UnitCode = static_cast<unsigned char>(extractPackerHeaderTableData(NDSHeaderNames::UnitCode).toUInt(nullptr, 16));
pRomHeader->DeviceType = static_cast<unsigned char>(extractPackerHeaderTableData(NDSHeaderNames::DeviceCode).toUInt(nullptr, 16));
pRomHeader->DeviceSize = static_cast<unsigned char>(extractPackerHeaderTableData(NDSHeaderNames::CardSize).toUInt(nullptr, 16));
std::fill(std::begin(pRomHeader->Reserved1), std::end(pRomHeader->Reserved1), 0);
pRomHeader->RomVersion = static_cast<unsigned char>(extractPackerHeaderTableData(NDSHeaderNames::CardInfo).toUInt(nullptr, 16));
pRomHeader->Flags = static_cast<unsigned char>(extractPackerHeaderTableData(NDSHeaderNames::Flags).toUInt(nullptr, 16));
pRomHeader->Arm9RomAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9RomAddress).toUInt(nullptr, 16);
pRomHeader->Arm9EntryAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9EntryAddress).toUInt(nullptr, 16);
pRomHeader->Arm9RamAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9RamAddress).toUInt(nullptr, 16);
pRomHeader->Arm9Size = extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16);
pRomHeader->Arm7RomAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16);
pRomHeader->Arm7EntryAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7EntryAddress).toUInt(nullptr, 16);
pRomHeader->Arm7RamAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7RamAddress).toUInt(nullptr, 16);
pRomHeader->Arm7Size = extractPackerHeaderTableData(NDSHeaderNames::ARM7Size).toUInt(nullptr, 16);
pRomHeader->FilenameTableAddr = extractPackerHeaderTableData(NDSHeaderNames::FilenameTableAddress).toUInt(nullptr, 16);
pRomHeader->FilenameSize = extractPackerHeaderTableData(NDSHeaderNames::FilenameTableSize).toUInt(nullptr, 16);
pRomHeader->FATAddr = extractPackerHeaderTableData(NDSHeaderNames::FATAddress).toUInt(nullptr, 16);
pRomHeader->FATSize = extractPackerHeaderTableData(NDSHeaderNames::FATSize).toUInt(nullptr, 16);
pRomHeader->Arm9OverlayAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16);
pRomHeader->Arm9OverlaySize = extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16);
pRomHeader->Arm7OverlayAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlayAddress).toUInt(nullptr, 16);
pRomHeader->Arm7OverlaySize = extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlaySize).toUInt(nullptr, 16);
pRomHeader->NormalCommandsSettings = extractPackerHeaderTableData(NDSHeaderNames::Port40001A4hNC).toUInt(nullptr, 16);
pRomHeader->Key1CommandsSettings = extractPackerHeaderTableData(NDSHeaderNames::Port40001a4hKC).toUInt(nullptr, 16);
pRomHeader->IconTitleAddr = extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16);
pRomHeader->SecureAreaCRC16 = extractPackerHeaderTableData(NDSHeaderNames::SecureAreaCRC16).toUShort(nullptr, 16);
pRomHeader->SecureAreaLoadingTimeout = extractPackerHeaderTableData(NDSHeaderNames::SecureAreaTimeout).toUShort(nullptr, 16);
pRomHeader->ARM9AutoLoadListRamAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9ALRamAddress).toUInt(nullptr, 16);
pRomHeader->ARM7AutoLoadListRamAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7ALRamAddress).toUInt(nullptr, 16);
pRomHeader->SecureAreaDisable = extractPackerHeaderTableData(NDSHeaderNames::SecureAreaDisable).toULong(nullptr, 16);
pRomHeader->RomSize = extractPackerHeaderTableData(NDSHeaderNames::UsedRomSize).toUInt(nullptr, 16);
pRomHeader->HeaderSize = extractPackerHeaderTableData(NDSHeaderNames::HeaderSize).toUInt(nullptr, 16);
std::fill(std::begin(pRomHeader->Reserved2), std::end(pRomHeader->Reserved2), 0);
std::copy_n(std::begin(QByteArray::fromHex(extractPackerHeaderTableData(NDSHeaderNames::NintendoLogo).toUtf8())), 0x9C, std::begin(pRomHeader->NintendoLogo));
pRomHeader->NintendoLogoCRC = extractPackerHeaderTableData(NDSHeaderNames::NintendoLogoCRC).toUShort(nullptr, 16);
pRomHeader->HeaderCRC16 = extractPackerHeaderTableData(NDSHeaderNames::HeaderCRC).toUShort(nullptr, 16);
pRomHeader->DebugRomAddr = extractPackerHeaderTableData(NDSHeaderNames::DebugRomAddress).toUInt(nullptr, 16);
pRomHeader->DebugSize = extractPackerHeaderTableData(NDSHeaderNames::DebugSize).toUInt(nullptr, 16);
pRomHeader->DebugRamAddr = extractPackerHeaderTableData(NDSHeaderNames::DebugRamAddress).toUInt(nullptr, 16);
std::fill(std::begin(pRomHeader->Reserved3), std::end(pRomHeader->Reserved3), 0);
std::fill(std::begin(pRomHeader->Reserved4), std::end(pRomHeader->Reserved4), 0);
}
bool MainWindow::writeHeader(const std::string& savePath)
{
std::vector<char> romHeaderBuffer(sizeof(NDSHeader));
NDSHeader* pRomHeader = reinterpret_cast<NDSHeader*>(romHeaderBuffer.data());
generateHeader(pRomHeader);
return ndsFactory.writeBytesToFile(romHeaderBuffer, savePath, 0, sizeof(NDSHeader));;
}
void MainWindow::calcHeaderCrc16()
{
std::vector<char> romHeaderBuffer(sizeof(NDSHeader));
NDSHeader* pRomHeader = reinterpret_cast<NDSHeader*>(romHeaderBuffer.data());
generateHeader(pRomHeader);
QModelIndex headerCrcIndex = ui->packerHeaderDataTable->model()->index(NDSHeaderNames::HeaderCRC, 1);
ui->packerHeaderDataTable->model()->setData(headerCrcIndex, QString::number(ndsFactory.calcHeaderCrc16(romHeaderBuffer), 16), Qt::EditRole);
}
bool MainWindow::writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent)
{
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16);
if (isArm9FooterPresent)
size += Arm9FooterSize;
return ndsFactory.writeSectionToFile(
ui->loadedArm9BinPathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::ARM9RomAddress).toUInt(nullptr, 16),
size);
}
bool MainWindow::writeArm7Bin(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedArm7BinPathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16),
extractPackerHeaderTableData(NDSHeaderNames::ARM7Size).toUInt(nullptr, 16));
}
bool MainWindow::writeFnt(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedFntPathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::FilenameTableAddress).toUInt(nullptr, 16),
extractPackerHeaderTableData(NDSHeaderNames::FilenameTableSize).toUInt(nullptr, 16));
}
bool MainWindow::writeFat(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedFatPathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::FATAddress).toUInt(nullptr, 16),
extractPackerHeaderTableData(NDSHeaderNames::FATSize).toUInt(nullptr, 16));
}
bool MainWindow::writeArm9Overlay(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedArm9OverlayPathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16),
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16));
}
bool MainWindow::writeArm9OverlayFiles([[maybe_unused]] const std::string& savePath)
{
return false; // TODO: implement me!
}
bool MainWindow::writeArm7Overlay(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedArm7OverlayPathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16),
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16));
}
bool MainWindow::writeArm7OverlayFiles([[maybe_unused]] const std::string& savePath)
{
return false; // TODO: implement me!
}
bool MainWindow::writeIconTitle(const std::string& savePath)
{
return ndsFactory.writeSectionToFile(
ui->loadedIconTitlePathEdt->text().toStdString(),
savePath,
extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16),
IconTitleSize);
}
bool MainWindow::writeFatFiles(const std::string& savePath)
{
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16) + IconTitleSize;
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::UsedRomSize).toUInt(nullptr, 16) - startAddr;
return ndsFactory.writeSectionToFile(
ui->loadedFatFilesPathEdt->text().toStdString(),
savePath,
startAddr,
size);
}
bool MainWindow::writeHeaderPadding(char paddingType, const std::string& savePath)
{
uint32_t startAddr = sizeof(NDSHeader);
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::ARM9RomAddress).toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeArm9BinPadding(char paddingType, const std::string& savePath, bool isFooterPresent)
{ // FIXME check ARM9 Overlay
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9RomAddress).toUInt(nullptr, 16) +
extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16);
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16) - startAddr;
if (isFooterPresent)
size -= Arm9FooterSize;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeArm7BinPadding(char paddingType, const std::string& savePath)
{ // FIXME check ARM7 Overlay
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16) +
extractPackerHeaderTableData(NDSHeaderNames::ARM7Size).toUInt(nullptr, 16);
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::FilenameTableAddress).toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeFntPadding(char paddingType, const std::string& savePath)
{
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::FilenameTableAddress).toUInt(nullptr, 16) +
extractPackerHeaderTableData(NDSHeaderNames::FilenameTableSize).toUInt(nullptr, 16);
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::FATAddress).toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeFatPadding(char paddingType, const std::string& savePath)
{
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::FATAddress).toUInt(nullptr, 16) +
extractPackerHeaderTableData(NDSHeaderNames::FATSize).toUInt(nullptr, 16);
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16) - startAddr;
return ndsFactory.writePaddingToFile(
paddingType,
savePath,
startAddr,
size);
}
bool MainWindow::writeArm9OverlayPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeArm9OverlayFilesPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeArm7OverlayPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeArm7OverlayFilesPadding([[maybe_unused]] char paddingType, [[maybe_unused]] const std::string& savePath)
{ // FIXME TODO
return true;
}
bool MainWindow::writeRomPadding(const std::string& savePath)
{
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::UsedRomSize).toUInt(nullptr, 16);
uint32_t size = static_cast<uint32_t>(ndsFactory.getCardSizeInBytes(extractPackerHeaderTableData(NDSHeaderNames::CardSize).toInt())) - startAddr;
return ndsFactory.writePaddingToFile(
static_cast<char>('\xff'),
savePath,
startAddr,
size);
}
bool MainWindow::writeEverything(const std::string& savePath)
{
bool res = true;
char paddingType;
bool isArm9FooterPresent = ndsFactory.checkArm9FooterPresence(ui->loadedArm9BinPathEdt->text().toStdString(),
extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16));
if (ui->packerPadType00RdBtn->isChecked())
paddingType = static_cast<char>('\x00');
else
paddingType = static_cast<char>('\xff');
std::remove(savePath.c_str());
res &= writeHeader(savePath);
res &= writeHeaderPadding(paddingType, savePath);
res &= writeArm9Bin(savePath, isArm9FooterPresent);
res &= writeArm9BinPadding(paddingType, savePath, isArm9FooterPresent);
res &= writeArm7Bin(savePath);
res &= writeArm7BinPadding(paddingType, savePath);
res &= writeFnt(savePath);
res &= writeFntPadding(paddingType, savePath);
res &= writeFat(savePath);
res &= writeFatPadding(paddingType, savePath);
if(extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) != 0) {
res &= writeArm9Overlay(savePath);
res &= writeArm9OverlayPadding(paddingType, savePath);
res &= writeArm9OverlayFiles(savePath);
res &= writeArm9OverlayFilesPadding(paddingType, savePath);
}
if(extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) != 0) {
res &= writeArm7Overlay(savePath);
res &= writeArm7OverlayPadding(paddingType, savePath);
res &= writeArm7OverlayFiles(savePath);
res &= writeArm7OverlayFilesPadding(paddingType, savePath);
}
res &= writeIconTitle(savePath);
res &= writeFatFiles(savePath);
if(!ui->packerTrimRomsCbx->isChecked())
{
res &= writeRomPadding(savePath);
}
return res;
}
QString MainWindow::extractPackerHeaderTableData(int index)
{
return ui->packerHeaderDataTable->model()->index(index, 1).data().toString();
}

View File

@@ -1,11 +1,12 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include "mainwindow.h" #include "./../../mainwindow.h"
#include "ui_mainwindow.h" #include "./../../ui_mainwindow.h"
#include "../commons/headernames.h"
void MainWindow::on_packerLoadHeaderBtn_clicked() void MainWindow::on_packerLoadHeaderBtn_clicked()
{ {
std::vector<char> romHeader;
NDSHeader *pNDSHeader; NDSHeader *pNDSHeader;
QString headerPath = QFileDialog::getOpenFileName( QString headerPath = QFileDialog::getOpenFileName(
@@ -24,6 +25,8 @@ void MainWindow::on_packerLoadHeaderBtn_clicked()
{ {
pNDSHeader = reinterpret_cast<NDSHeader*>(romHeader.data()); pNDSHeader = reinterpret_cast<NDSHeader*>(romHeader.data());
populatePackerSectionHeader(pNDSHeader); populatePackerSectionHeader(pNDSHeader);
enableCalcCrcButton();
enableBuildRomButton();
} }
} }
@@ -164,7 +167,6 @@ void MainWindow::on_packerLoadFatFilesBtn_clicked()
if(!fatFilesPath.isNull()) if(!fatFilesPath.isNull())
{ {
ui->loadedFatFilesPathEdt->setText(fatFilesPath.toUtf8()); ui->loadedFatFilesPathEdt->setText(fatFilesPath.toUtf8());
ui->packerFatFilesAddrEdt->setText(QString::number((ui->packerIconTitleEdt->text().toUInt(nullptr, 16) + IconTitleSize), 16));
} }
} }
@@ -183,3 +185,7 @@ void MainWindow::on_packerBuildNDSRomBtn_clicked()
} }
} }
void MainWindow::on_packerCalcHeaderCrcBtn_clicked()
{
calcHeaderCrc16();
}

View File

@@ -0,0 +1,318 @@
#include <QDir>
#include <stdlib.h>
#include <sstream>
#include <iomanip>
#include "../../mainwindow.h"
#include "../../ui_mainwindow.h"
#include "../commons/headernames.h"
#include "../../models/ndsheadermodel.h"
#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);
ui->unpackerHeaderDataTable->setModel(headerDataModel);
ui->unpackerHeaderDataTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeMode::ResizeToContents);
ui->unpackerHeaderDataTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeMode::Stretch);
}
void MainWindow::enableExtractionButtons()
{
ui->unpackerExtractorGbx->setEnabled(true);
ui->unpackerExtraGbx->setEnabled(true);
if (ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16) == 0){
ui->unpackerDumpArm9OverlayBtn->setEnabled(false);
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(false);
}
if (ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16) == 0){
ui->unpackerDumpArm7OverlayBtn->setEnabled(false);
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(false);
}
}
void MainWindow::disableExtractionButtons()
{
ui->unpackerExtractorGbx->setEnabled(false);
ui->unpackerExtraGbx->setEnabled(false);
}
bool MainWindow::dumpHeader(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
0,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::HeaderSize, 1).data().toString().toUInt(nullptr,16));
}
bool MainWindow::dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes)
{
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9Size, 1).data().toString().toUInt(nullptr,16);
if (dumpExtraBytes)
size += 12;
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9RomAddress, 1).data().toString().toUInt(nullptr,16),
size);
}
bool MainWindow::dumpArm7Bin(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7RomAddress, 1).data().toString().toUInt(nullptr,16),
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7Size, 1).data().toString().toUInt(nullptr,16));
}
bool MainWindow::dumpFnt(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableAddress, 1).data().toString().toUInt(nullptr,16),
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableSize, 1).data().toString().toUInt(nullptr,16));
}
bool MainWindow::dumpFat(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FATAddress, 1).data().toString().toUInt(nullptr,16),
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FATSize, 1).data().toString().toUInt(nullptr,16));
}
bool MainWindow::dumpArm9Overlay(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16),
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlaySize, 1).data().toString().toUInt(nullptr,16));
}
bool MainWindow::dumpArm9OverlayFiles([[maybe_unused]] const std::string& dirPath)
{
return false; // TODO: implement me!
}
bool MainWindow::dumpArm7Overlay(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16),
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlaySize, 1).data().toString().toUInt(nullptr,16));
}
bool MainWindow::dumpArm7OverlayFiles([[maybe_unused]] const std::string& dirPath)
{
return false; // TODO: implement me!
}
bool MainWindow::dumpIconTitle(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::IconTitleAddress, 1).data().toString().toUInt(nullptr,16),
ICON_TITLE_SIZE);
}
bool MainWindow::dumpFatFiles(const std::string& dirPath)
{
uint32_t startAddr = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::IconTitleAddress, 1).data().toString().toUInt(nullptr,16) + IconTitleSize ;
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::UsedRomSize, 1).data().toString().toUInt(nullptr,16) - startAddr;
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
startAddr,
size);
}
bool MainWindow::dumpEverything(QString dirPath)
{
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) {
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) {
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)
{
// Prepare necessary info from ROM
std::string romPath = ui->loadedRomPath->text().toStdString(); // ROM itself
// Addresses of the file allocation table and file name table
uint32_t fatAddr = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FATAddress, 1).data().toString().toUInt(nullptr,16);
uint32_t fatSize = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FATSize, 1).data().toString().toUInt(nullptr,16);
// Sizes of these tables
uint32_t fntAddr = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableAddress, 1).data().toString().toUInt(nullptr,16);
uint32_t fntSize = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableSize, 1).data().toString().toUInt(nullptr,16);
// Buffers to receive the contents of the FAT and FNT
std::vector<char> fatBytes(static_cast<unsigned long>(fatSize));
std::vector<char> fntBytes(static_cast<unsigned long>(fntSize));
// Fill them
if(!ndsFactory.readBytesFromFile(fatBytes, romPath, fatAddr, fatSize)) return false;
if(!ndsFactory.readBytesFromFile(fntBytes, romPath, fntAddr, fntSize)) return false;
// Use the available FAT range struct and read the FAT bytes as such
FatRange* pfatrange = reinterpret_cast<FatRange*>(fatBytes.data());
// Recursive function that looks up FNT info to find file names and directory structures,
// And writes the ROM data in the ranges indicated by the FAT simultaneously.
auto parseFolder = [this, fntBytes, pfatrange, romPath](uint32_t folderId, std::string curPath, auto& parseFolder){
if(false) return false; // this is stupid, but it's C++
// If we take it out, the compiler will complain because it doesn't known the return type of the lambda
// But we can't make the lambda bool either...so this is the best option...
QDir curDir(QString::fromStdString(curPath)); // useful a bit later
uint32_t currentOffset = 8 * (folderId & FNT_HEADER_OFFSET_MASK); // offset for the current directory's info in the FNT header
// Only the lower 12 bit of the given offset are relevant
// ---------------------------------------------------------------------
// About how the FAT and FNT work :
// The FNT has two sections :
// a "header" where every entry contains :
// - a 4-byte address where the corresponding directory's data starts in the body
// - a 2-byte offset that is the index of the first file of the directory in the FAT
// (e.g. : if the offset is 42, the first file in the directory is situated at the ROM addresses stored in the 42nd FAT entry)
// (and its second will be 43, etc.)
// a "body" where every entry contains :
// - a length+status/control byte : lower 7 bits (control byte & 0x7F) are a length, highest bit (control byte & 0x80) is set if entry is a directory, and not set if it's a file
// - a name which length is the length portion of the previous control byte (e.g. : if the control byte was 0x83, the name is three bytes long)
// - if the entry is a directory, a 2-byte address (where only the lower 12 bit are relevant for some reason) at which this directory's info is located in the FNT header
// Thus, the FNT reading operation will consist in bouncing back and forth between body and header every time we must process a subdirectory
// Thank Heavens for random-access containers !
// ---------------------------------------------------------------------
// Get the 4-byte address for the folder data
uint32_t fntBodyOffset =
(uint32_t)((unsigned char) fntBytes[currentOffset+3] << (uint32_t) FOURTH_BYTE_SHIFT |
(unsigned char) fntBytes[currentOffset+2] << (uint32_t) THIRD_BYTE_SHIFT |
(unsigned char) fntBytes[currentOffset + 1] << (uint32_t) SECOND_BYTE_SHIFT |
(unsigned char) fntBytes[currentOffset]);
currentOffset+=4;
// Get the 2-byte offset for the folder's first file in the FAT
uint16_t fatOffset =
(uint16_t)((unsigned char) fntBytes[currentOffset+1] << SECOND_BYTE_SHIFT |
(unsigned char) fntBytes[currentOffset]);
// Jump to FNT body a specified address
currentOffset = fntBodyOffset;
uint8_t controlByte = DUMMY_CONTROL_VALUE;
while(true){
controlByte = fntBytes[currentOffset]; // Entry's control byte
if(controlByte==0) break; // A control byte of 0 terminates the directory's contents
currentOffset++;
uint8_t nameLength = controlByte & CONTROL_BYTE_LENGTH_MASK; // length of entry name
bool isDir = controlByte & CONTROL_BYTE_DIR_MASK; // set if entry is a directory
// Reconstitute name from bytes
// Btw I wish I could use the actual byte type but I have to comply with the software's choice of using char
std::vector<char> nameString;
for(size_t i = 0 ; i<nameLength ; i++) nameString.push_back(fntBytes[currentOffset++]);
std::string name(&nameString[0], (size_t)nameLength);
// We'll need this either way
QString newPath(QDir::toNativeSeparators(QString::fromStdString(curPath+"/"+name)));
if(isDir){
// Get the 2-byte address for this folder's info in the FNT header
uint16_t subFolderId = ((unsigned char) fntBytes[currentOffset+1] << SECOND_BYTE_SHIFT |
(unsigned char) fntBytes[currentOffset]);
currentOffset+=2;
// Now the QDir we created earlier comes into play :
// C++ doesn't automatically create directories (!!!) so we have to rely on QT to do that manually.
// Otherwise, the ofstream will not open,
// And even if we force it open, it will just write into nothingness !!!
if(!curDir.exists(newPath)) curDir.mkdir(newPath); // I don't think the check is even necessary, actually
// Jump back to the FNT header and repeat the process for subdirectory !
if(!parseFolder(subFolderId,newPath.toStdString(),parseFolder)) return false;
}
else{
// Remember we have the offset for the directory's first file in the FAT.
// From then, every file is just the next entry.
// So we just have to use that offset and increment it every time.
if(!ndsFactory.writeFatSectionToFile(
romPath,
pfatrange+fatOffset,
newPath.toStdString()))
return false;
fatOffset++;
}
}
return true;
};
// The root folder's ID is, obviously, 0 (only the lower 12-bit count!)
return parseFolder(ROOT_DIRECTORY_ADDRESS,dirPath.toStdString(),parseFolder);
}

View File

@@ -1,13 +1,12 @@
#include <QFileDialog> #include <QFileDialog>
#include <vector> #include <vector>
#include <QMessageBox> #include <QMessageBox>
#include "mainwindow.h" #include "./../../mainwindow.h"
#include "ui_mainwindow.h" #include "./../../ui_mainwindow.h"
void MainWindow::on_loadRomBtn_clicked() void MainWindow::on_loadRomBtn_clicked()
{ {
std::vector<char> romHeader;
NDSHeader *pNDSHeader; NDSHeader *pNDSHeader;
QString romPath = QFileDialog::getOpenFileName( QString romPath = QFileDialog::getOpenFileName(
@@ -42,10 +41,7 @@ void MainWindow::on_unpackerDumpHeaderBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpHeader(dirPath.toStdString()));
dumpHeader(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpArm9Btn_clicked() void MainWindow::on_unpackerDumpArm9Btn_clicked()
@@ -63,11 +59,7 @@ void MainWindow::on_unpackerDumpArm9Btn_clicked()
QMessageBox::Yes|QMessageBox::No); QMessageBox::Yes|QMessageBox::No);
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpArm9Bin(dirPath.toStdString(), dumpExtraBytes == QMessageBox::Yes ? true : false));
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!"));
}
} }
void MainWindow::on_unpackerDumpArm7Btn_clicked() void MainWindow::on_unpackerDumpArm7Btn_clicked()
@@ -79,10 +71,7 @@ void MainWindow::on_unpackerDumpArm7Btn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpArm7Bin(dirPath.toStdString()));
dumpArm7Bin(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpFntBtn_clicked() void MainWindow::on_unpackerDumpFntBtn_clicked()
@@ -94,10 +83,7 @@ void MainWindow::on_unpackerDumpFntBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpFnt(dirPath.toStdString()));
dumpFnt(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpFatBtn_clicked() void MainWindow::on_unpackerDumpFatBtn_clicked()
@@ -109,10 +95,7 @@ void MainWindow::on_unpackerDumpFatBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpFat(dirPath.toStdString()));
dumpFat(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked() void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked()
@@ -124,10 +107,7 @@ void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpArm9Overlay(dirPath.toStdString()));
dumpArm9Overlay(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked() void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked()
@@ -139,10 +119,7 @@ void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpArm7Overlay(dirPath.toStdString()));
dumpArm7Overlay(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked() void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked()
@@ -154,10 +131,7 @@ void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpIconTitle(dirPath.toStdString()));
dumpIconTitle(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpFatFilesBtn_clicked() void MainWindow::on_unpackerDumpFatFilesBtn_clicked()
@@ -169,10 +143,7 @@ void MainWindow::on_unpackerDumpFatFilesBtn_clicked()
"Binary (*.bin)"); "Binary (*.bin)");
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpFatFiles(dirPath.toStdString()));
dumpFatFiles(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDumpArm9OverlayFilesBtn_clicked() void MainWindow::on_unpackerDumpArm9OverlayFilesBtn_clicked()
@@ -195,15 +166,28 @@ void MainWindow::on_unpackerDumpEverythingBtn_clicked()
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if (!dirPath.isNull()) if (!dirPath.isNull())
{ notifyExtractionResult(dumpEverything(dirPath));
dumpEverything(dirPath) ? QMessageBox::information(this, tr("NDS Factory"), tr("Extraction completed!"))
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the extraction!"));
}
} }
void MainWindow::on_unpackerDecodeFatFilesBtn_clicked() void MainWindow::on_unpackerDecodeFatFilesBtn_clicked()
{ {
QMessageBox::warning(this, tr("NDS Factory"), tr("This function is currently not implemented!")); QString dirPath = QFileDialog::getExistingDirectory(
decodeFatFiles(); this, tr("Select Directory"),
"",
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if (!dirPath.isNull())
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!"));
}
}

View File

@@ -1,222 +0,0 @@
#include <QDir>
#include <stdlib.h>
#include <cstring>
#include <sstream>
#include <iomanip>
#include "mainwindow.h"
#include "ui_mainwindow.h"
void MainWindow::populateHeader(NDSHeader* ndsHeader)
{
ui->unpackerGameTitleEdt->setText(QString::fromUtf8(ndsHeader->GameTitle, 0xC));
ui->unpackerGameCodeEdt->setText(QString::fromUtf8(ndsHeader->GameCode, 0x4));
ui->unpackerMakerCodeEdt->setText(QString::fromUtf8(reinterpret_cast<char*>(ndsHeader->MakerCode), 0x2));
ui->unpackerUnitCodeEdt->setText(QString::number(ndsHeader->UnitCode, 16));
ui->unpackerDeviceCodeEdt->setText(QString::number(ndsHeader->DeviceType, 16));
ui->unpackerCardSizeEdt->setText(QString::number(ndsHeader->DeviceSize, 16));
ui->unpackerCardInfoEdt->setText(QString::number(ndsHeader->RomVersion, 16));
ui->unpackerFlagsEdt->setText(QString::number(ndsHeader->Flags, 16));
ui->unpackerARM9RomAddrEdt->setText(QString::number(ndsHeader->Arm9RomAddr,16));
ui->unpackerARM9EntryAddrEdt->setText(QString::number(ndsHeader->Arm9EntryAddr,16));
ui->unpackerARM9RamAddrEdt->setText(QString::number(ndsHeader->Arm9RamAddr,16));
ui->unpackerARM9SizeEdt->setText(QString::number(ndsHeader->Arm9Size,16));
ui->unpackerARM7RomAddrEdt->setText(QString::number(ndsHeader->Arm7RomAddr,16));
ui->unpackerARM7EntryAddrEdt->setText(QString::number(ndsHeader->Arm7EntryAddr,16));
ui->unpackerARM7RamAddrEdt->setText(QString::number(ndsHeader->Arm7RamAddr,16));
ui->unpackerARM7SizeEdt->setText(QString::number(ndsHeader->Arm7Size,16));
ui->unpackerFilenameTableAddrEdt->setText(QString::number(ndsHeader->FilenameTableAddr,16));
ui->unpackerFilenameTableSizeEdt->setText(QString::number(ndsHeader->FilenameSize,16));
ui->unpackerFATAddrEdt->setText(QString::number(ndsHeader->FATAddr,16));
ui->unpackerFATSizeEdt->setText(QString::number(ndsHeader->FATSize,16));
ui->unpackerARM9OverlayAddrEdt->setText(QString::number(ndsHeader->Arm9OverlayAddr,16));
ui->unpackerARM9OverlaySizeEdt->setText(QString::number(ndsHeader->Arm9OverlaySize,16));
ui->unpackerARM7OverlayAddrEdt->setText(QString::number(ndsHeader->Arm7OverlayAddr,16));
ui->unpackerARM7OverlaySizeEdt->setText(QString::number(ndsHeader->Arm7OverlaySize,16));
ui->unpackerPortNCEdt->setText(QString::number(ndsHeader->NormalCommandsSettings,16));
ui->unpackerPortKCEdt->setText(QString::number(ndsHeader->Key1CommandsSettings,16));
ui->unpackerIconTitleEdt->setText(QString::number(ndsHeader->IconTitleAddr,16));
ui->unpackerSecureAreaCRC16Edt->setText(QString::number(ndsHeader->SecureAreaCRC16,16));
ui->unpackerSecureAreaTimeoutEdt->setText(QString::number(ndsHeader->SecureAreaLoadingTimeout,16));
ui->unpackerARM9AURamAddrEdt->setText(QString::number(ndsHeader->ARM9AutoLoadListRamAddr,16));
ui->unpackerARM7AURamAddrEdt->setText(QString::number(ndsHeader->ARM7AutoLoadListRamAddr,16));
ui->unpackerSecureAreaDisableEdt->setText(QString::number(ndsHeader->SecureAreaDisable,16));
ui->unpackerUsedRomSizeEdt->setText(QString::number(ndsHeader->RomSize,16));
ui->unpackerHeaderSizeEdt->setText(QString::number(ndsHeader->HeaderSize,16));
ui->unpackerNintendoLogoEdt->setText(QByteArray::fromRawData(reinterpret_cast<char*>(ndsHeader->NintendoLogo), 0x9C).toHex());
ui->unpackerNintendoLogoCRCEdt->setText(QString::number(ndsHeader->NintendoLogoCRC,16));
ui->unpackerHeaderCRCEdt->setText(QString::number(ndsHeader->HeaderCRC16,16));
ui->unpackerDebugRomAddrEdt->setText(QString::number(ndsHeader->DebugRomAddr,16));
ui->unpackerDebugSizeEdt->setText(QString::number(ndsHeader->DebugSize,16));
ui->unpackerDebugRamAddrEdt->setText(QString::number(ndsHeader->DebugRamAddr,16));
ui->unpackerFatFilesOriginalAddrEdt->setText(QString::number((ndsHeader->IconTitleAddr+IconTitleSize),16));
}
void MainWindow::enableExtractionButtons()
{
ui->unpackerExtractorGbx->setEnabled(true);
ui->unpackerExtraGbx->setEnabled(true);
if (ui->unpackerARM9OverlayAddrEdt->text().toUInt(nullptr, 16) == 0){
ui->unpackerDumpArm9OverlayBtn->setEnabled(false);
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(false);
}
if (ui->unpackerARM7OverlayAddrEdt->text().toUInt(nullptr, 16) == 0){
ui->unpackerDumpArm7OverlayBtn->setEnabled(false);
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(false);
}
}
void MainWindow::disableExtractionButtons()
{
ui->unpackerExtractorGbx->setEnabled(false);
ui->unpackerExtraGbx->setEnabled(false);
}
bool MainWindow::dumpHeader(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
0,
ui->unpackerHeaderSizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes)
{
uint32_t size = ui->unpackerARM9SizeEdt->text().toUInt(nullptr, 16);
if (dumpExtraBytes)
size += 12;
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerARM9RomAddrEdt->text().toUInt(nullptr, 16),
size);
}
bool MainWindow::dumpArm7Bin(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerARM7RomAddrEdt->text().toUInt(nullptr, 16),
ui->unpackerARM7SizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::dumpFnt(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerFilenameTableAddrEdt->text().toUInt(nullptr, 16),
ui->unpackerFilenameTableSizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::dumpFat(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerFATAddrEdt->text().toUInt(nullptr, 16),
ui->unpackerFATSizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::dumpArm9Overlay(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerARM9OverlayAddrEdt->text().toUInt(nullptr, 16),
ui->unpackerARM9OverlaySizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::dumpArm9OverlayFiles(const std::string& dirPath)
{
return false; // TODO: implement me!
}
bool MainWindow::dumpArm7Overlay(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerARM7OverlayAddrEdt->text().toUInt(nullptr, 16),
ui->unpackerARM7OverlaySizeEdt->text().toUInt(nullptr, 16));
}
bool MainWindow::dumpArm7OverlayFiles(const std::string& dirPath)
{
return false; // TODO: implement me!
}
bool MainWindow::dumpIconTitle(const std::string& dirPath)
{
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
ui->unpackerIconTitleEdt->text().toUInt(nullptr, 16),
0xA00);
}
bool MainWindow::dumpFatFiles(const std::string& dirPath)
{
uint32_t startAddr = ui->unpackerIconTitleEdt->text().toUInt(nullptr, 16) + IconTitleSize;
uint32_t size = ui->unpackerUsedRomSizeEdt->text().toUInt(nullptr, 16) - startAddr;
return ndsFactory.dumpDataFromFile(
ui->loadedRomPath->text().toStdString(),
dirPath,
startAddr,
size);
}
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;
if(ui->unpackerARM9OverlayAddrEdt->text().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;
}
if(ui->unpackerARM7OverlayAddrEdt->text().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;
}
bool MainWindow::decodeFatFiles()
{
// TODO: implement me!
}