mirror of
https://github.com/Luca1991/NDSFactory.git
synced 2025-07-09 21:30:12 +02:00
Compare commits
No commits in common. "master" and "v1.1" have entirely different histories.
204
.github/workflows/build.yml
vendored
204
.github/workflows/build.yml
vendored
@ -7,148 +7,124 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-linux:
|
build-linux:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y build-essential libgl1-mesa-dev libglvnd-dev cmake qt6-base-dev
|
sudo apt-get install -y build-essential libgl1-mesa-dev and libglvnd-dev cmake qt6-base-dev
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
make -j4
|
make -j4
|
||||||
|
|
||||||
- name: Archive Artifact
|
- name: Archive Artifact
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
tar -czvf NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz NDSFactory ../README.md ../LICENSE
|
tar -czvf NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz NDSFactory ../README.md ../LICENSE
|
||||||
|
|
||||||
- name: Release on GitHub
|
- name: Release on GitHub
|
||||||
uses: softprops/action-gh-release@v2.0.8
|
uses: softprops/action-gh-release@v2.0.8
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
files: "build/NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz"
|
files: "build/NDSFactory-${{ github.ref_name }}-Linux-x64.tar.gz"
|
||||||
|
|
||||||
build-macos:
|
build-macos:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Install Qt
|
- name: Install Qt
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: "6.7.2"
|
version: '6.5.2'
|
||||||
|
|
||||||
- name: Install CMake
|
- name: Install CMake
|
||||||
uses: lukka/get-cmake@latest
|
uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/x86_64 build/arm64 build/universal
|
mkdir build
|
||||||
|
|
||||||
- name: Configure CMake (x86_64)
|
- name: Configure CMake
|
||||||
working-directory: ${{ github.workspace }}/build/x86_64
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=x86_64 ../..
|
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||||
|
|
||||||
- name: Configure CMake (arm64)
|
- name: Build
|
||||||
working-directory: ${{ github.workspace }}/build/arm64
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 ../..
|
make -j4
|
||||||
|
macdeployqt NDSFactory.app
|
||||||
|
|
||||||
- name: Build (x86_64)
|
- name: Archive Artifact
|
||||||
working-directory: ${{ github.workspace }}/build/x86_64
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
make -j4
|
zip -r NDSFactory-${{ github.ref_name }}-macOS.zip NDSFactory.app ../README.md ../LICENSE
|
||||||
|
|
||||||
- name: Build (arm64)
|
- name: Release on GitHub
|
||||||
working-directory: ${{ github.workspace }}/build/arm64
|
uses: softprops/action-gh-release@v2.0.8
|
||||||
shell: bash
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
run: |
|
with:
|
||||||
make -j4
|
files: "build/NDSFactory-${{ github.ref_name }}-macOS.zip"
|
||||||
|
|
||||||
- name: Create Universal Binary
|
|
||||||
working-directory: ${{ github.workspace }}/build
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cp -R x86_64/NDSFactory.app universal/
|
|
||||||
lipo -create -output universal/NDSFactory.app/Contents/MacOS/NDSFactory x86_64/NDSFactory.app/Contents/MacOS/NDSFactory arm64/NDSFactory.app/Contents/MacOS/NDSFactory
|
|
||||||
|
|
||||||
- name: Deploy Qt Frameworks
|
|
||||||
working-directory: ${{ github.workspace }}/build/universal
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
macdeployqt NDSFactory.app -verbose=1
|
|
||||||
|
|
||||||
- name: Archive Artifact
|
|
||||||
working-directory: ${{ github.workspace }}/build/universal
|
|
||||||
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/universal/NDSFactory-${{ github.ref_name }}-macOS.zip"
|
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4.1.7
|
- uses: actions/checkout@v4.1.7
|
||||||
|
|
||||||
- name: Install Qt
|
- name: Install Qt
|
||||||
uses: jurplel/install-qt-action@v4
|
uses: jurplel/install-qt-action@v4
|
||||||
with:
|
with:
|
||||||
version: "6.7.2"
|
version: '6.5.2'
|
||||||
|
|
||||||
- name: Install CMake
|
- name: Install CMake
|
||||||
uses: lukka/get-cmake@latest
|
uses: lukka/get-cmake@latest
|
||||||
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
run: |
|
run: |
|
||||||
cmake ..
|
cmake ..
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
run: |
|
run: |
|
||||||
cmake --build . -j4 --config Release
|
cmake --build . -j4 --config Release
|
||||||
mkdir .\Release\prod
|
mkdir .\Release\prod
|
||||||
move .\Release\NDSFactory.exe .\Release\prod
|
move .\Release\NDSFactory.exe .\Release\prod
|
||||||
windeployqt .\Release\prod\NDSFactory.exe
|
windeployqt .\Release\prod\NDSFactory.exe
|
||||||
|
|
||||||
- name: Archive Artifact
|
- name: Archive Artifact
|
||||||
working-directory: ${{github.workspace}}/build/Release
|
working-directory: ${{github.workspace}}/build/Release
|
||||||
run: |
|
run: |
|
||||||
xcopy ..\..\README.md .\prod
|
xcopy ..\..\README.md .\prod
|
||||||
xcopy ..\..\LICENSE .\prod
|
xcopy ..\..\LICENSE .\prod
|
||||||
powershell "Compress-Archive -Path .\prod\* -DestinationPath .\NDSFactory-${{ github.ref_name }}-Windows-x64.zip"
|
powershell "Compress-Archive -Path .\prod\* -DestinationPath .\NDSFactory-${{ github.ref_name }}-Windows-x64.zip"
|
||||||
|
|
||||||
- name: Release on GitHub
|
- name: Release on GitHub
|
||||||
uses: softprops/action-gh-release@v2.0.8
|
uses: softprops/action-gh-release@v2.0.8
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
files: "build/Release/NDSFactory-${{ github.ref_name }}-Windows-x64.zip"
|
files: "build/Release/NDSFactory-${{ github.ref_name }}-Windows-x64.zip"
|
@ -40,9 +40,6 @@ file(GLOB_RECURSE TABS_SOURCES ui/tabs/*.cpp)
|
|||||||
file(GLOB_RECURSE MODELS_HEADERS ui/models/*.h)
|
file(GLOB_RECURSE MODELS_HEADERS ui/models/*.h)
|
||||||
file(GLOB_RECURSE MODELS_SOURCES ui/models/*.cpp)
|
file(GLOB_RECURSE MODELS_SOURCES ui/models/*.cpp)
|
||||||
|
|
||||||
## Utils
|
|
||||||
file(GLOB_RECURSE UTILS_HEADERS ui/utils/*.h)
|
|
||||||
|
|
||||||
## NDSFactory
|
## NDSFactory
|
||||||
file(GLOB_RECURSE NDSFACTORY_SOURCES ndsfactory/*.cpp)
|
file(GLOB_RECURSE NDSFACTORY_SOURCES ndsfactory/*.cpp)
|
||||||
file(GLOB_RECURSE NDSFACTORY_HEADERS ndsfactory/*.h)
|
file(GLOB_RECURSE NDSFACTORY_HEADERS ndsfactory/*.h)
|
||||||
@ -62,7 +59,6 @@ SET(HEADERS
|
|||||||
${TABS_HEADERS}
|
${TABS_HEADERS}
|
||||||
${MODELS_HEADERS}
|
${MODELS_HEADERS}
|
||||||
${DIALOGS_HEADERS}
|
${DIALOGS_HEADERS}
|
||||||
${UTILS_HEADERS}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(FORMS
|
set(FORMS
|
||||||
@ -84,7 +80,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set C++ standard for the target
|
# Set C++ standard for the target
|
||||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
|
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_14)
|
||||||
|
|
||||||
# Enable Qt's automatic features for the target
|
# Enable Qt's automatic features for the target
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
|
35
README.md
35
README.md
@ -10,6 +10,8 @@ If you find this software useful, please consider supporting it:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
**!!!ROMS WITH OVERLAY ARE CURRENTLY NOT SUPPORTED!!!**
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
NDSFactory helps you easily unpack and repack Nintendo DS ROMs, but **some technical knowledge is required.**
|
NDSFactory helps you easily unpack and repack Nintendo DS ROMs, but **some technical knowledge is required.**
|
||||||
@ -17,13 +19,11 @@ NDSFactory helps you easily unpack and repack Nintendo DS ROMs, but **some techn
|
|||||||
A typical NDS ROM consists of the following sections:
|
A typical NDS ROM consists of the following sections:
|
||||||
* Header
|
* Header
|
||||||
* ARM9 Binary
|
* ARM9 Binary
|
||||||
* ARM9 Overlay (Optional)
|
|
||||||
* ARM9 Overlay Files (Optional)
|
|
||||||
* ARM7 Binary
|
* ARM7 Binary
|
||||||
* ARM7 Overlay (Optional)
|
|
||||||
* ARM7 Overlay Files (Optional)
|
|
||||||
* FNT (Filename Table)
|
* FNT (Filename Table)
|
||||||
* FAT (File Allocation Table)
|
* FAT (File Allocation Table)
|
||||||
|
* ARM9/ARM7 Overlay (Optional)
|
||||||
|
* ARM9/ARM7 Overlay Files (Optional)
|
||||||
* 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.)
|
||||||
|
|
||||||
@ -34,33 +34,22 @@ This tool is particularly useful for modding games or writing trainers.
|
|||||||
# How to use
|
# How to use
|
||||||
|
|
||||||
## Unpacker Tab
|
## Unpacker Tab
|
||||||
In the Unpacker Tab, you can load your Nintendo DS software (.nds) and extract the ROM sections. 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 or if you want to extract its contents.
|
In the Unpacker Tab, you can load your Nintendo DS software (.nds) and extract the ROM sections, including individual FAT files. Take note of the original address of the FAT files, as you will need this value if you alter the addresses and sizes of the sections.
|
||||||
|
|
||||||
**You can then do what you want with these sections (inject code, apply patches etc.)**
|
**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 recreate a .nds file using your edited sections.
|
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).
|
||||||
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).
|
|
||||||
|
|
||||||
WARNING: if the ROM contains ARM9/ARM7 overlays and your sections are larger than the original, you must manually update the overlay offsets in the ovr and fat binaries (using an hex editor).
|
|
||||||
|
|
||||||
## Fat Tools Tab
|
## Fat Tools Tab
|
||||||
In this tab, you can:
|
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.
|
||||||
* extract the FAT files from fat_data.bin.
|
|
||||||
* rebuild the FAT files into a new fat.bin and fat_data.bin.
|
|
||||||
If the ROM contains ARM9/ARM7 overlays you must provide the original fat.bin to extract the overlay offsets.
|
|
||||||
|
|
||||||
WARNING: DO NOT MODIFY FAT FILES NAMES OR EXTENSIONS, OR YOU WILL NEED A NEW fnt.bin.
|
# Known Limitations/Possible Future Features/Bugs
|
||||||
* 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.
|
|
||||||
|
|
||||||
# Credits
|
* Add support for ROMs with overlays.
|
||||||
|
* Add support to rebuild a new fat_data.bin and fat.bin from a set of files inside a directory.
|
||||||
|
|
||||||
If you find a bug, feel free to open an issue or submit a pull request :)
|
If you find a bug, feel free to open an issue or submit a pull request :)
|
||||||
|
|
||||||
Special thanks to [Antonio Barba](https://github.com/antoniobarba) & [Davide Trogu](https://github.com/Dax89)
|
### Developed with ❤ by Luca D'Amico
|
||||||
|
### Special thanks to Antonio Barba & Davide Trogu
|
||||||
Developed with ❤ by Luca D'Amico
|
|
||||||
|
18
main.cpp
18
main.cpp
@ -1,23 +1,13 @@
|
|||||||
#include "ui/mainwindow.h"
|
#include "ui/mainwindow.h"
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include "ui/utils/theme.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
QApplication::setStyle(QStyleFactory::create("Fusion"));
|
||||||
QApplication app(argc, argv);
|
QApplication a(argc, argv);
|
||||||
app.setApplicationName("NDSFactory");
|
MainWindow w;
|
||||||
app.setOrganizationName("NDSFactory");
|
w.show();
|
||||||
|
|
||||||
QString theme = getCurrentTheme();
|
return a.exec();
|
||||||
if(theme == "dark")
|
|
||||||
setDarkTheme(app);
|
|
||||||
else if(theme == "light")
|
|
||||||
setLightTheme(app);
|
|
||||||
|
|
||||||
MainWindow mainWindow;
|
|
||||||
mainWindow.show();
|
|
||||||
|
|
||||||
return app.exec();
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef CRCTABLE_H
|
||||||
|
#define CRCTABLE_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@ -38,3 +39,5 @@ static const uint16_t lCRCTable[] =
|
|||||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // CRCTABLE_H
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef FATSTRUCT_H
|
||||||
|
#define FATSTRUCT_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@ -7,7 +8,4 @@ struct FatRange {
|
|||||||
uint32_t endAddr;
|
uint32_t endAddr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FatFileID {
|
#endif // FATSTRUCT_H
|
||||||
uint16_t id;
|
|
||||||
std::string path;
|
|
||||||
};
|
|
||||||
|
@ -2,114 +2,105 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <filesystem>
|
|
||||||
#include <format>
|
|
||||||
#include "ndsfactory.h"
|
#include "ndsfactory.h"
|
||||||
#include "fatstruct.h"
|
#include "fatstruct.h"
|
||||||
#include "crctable.h"
|
#include "crctable.h"
|
||||||
|
|
||||||
|
|
||||||
// Byte offsets for interpreting memory
|
NDSFactory::NDSFactory()
|
||||||
#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
|
|
||||||
|
|
||||||
|
bool NDSFactory::loadRomHeader(const std::string& romPath, std::vector<char>& romHeader)
|
||||||
NFResult NDSFactory::loadRomHeader(const std::string& romPath, std::vector<char>& romHeader)
|
|
||||||
{
|
{
|
||||||
std::streampos headerSize = sizeof(NDSHeader);
|
std::streampos headerSize = sizeof(NDSHeader);
|
||||||
std::ifstream romFile (romPath, std::ios::binary);
|
std::ifstream romFile (romPath, std::ios::in|std::ios::binary|std::ios::ate);
|
||||||
if (!romFile.is_open())
|
if (romFile.is_open())
|
||||||
return NFResult({ false, "Error opening file: " + romPath });
|
{
|
||||||
|
romHeader.resize(static_cast<unsigned long>(headerSize));
|
||||||
|
|
||||||
romHeader.resize(static_cast<unsigned long>(headerSize));
|
romFile.seekg (0, std::ios::beg);
|
||||||
romFile.read (romHeader.data(), headerSize);
|
romFile.read (romHeader.data(), headerSize);
|
||||||
romFile.close();
|
romFile.close();
|
||||||
return NFResult({ true, "" });
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult NDSFactory::dumpDataFromFile(const std::string& romPath, const std::string& savePath, uint32_t startAddr, uint32_t size)
|
bool NDSFactory::dumpDataFromFile(const std::string& romPath, const std::string& savePath, uint32_t startAddr, uint32_t size)
|
||||||
{
|
{
|
||||||
std::ifstream romFile (romPath, std::ios::binary);
|
std::ifstream romFile (romPath, std::ios::in|std::ios::binary|std::ios::ate);
|
||||||
std::ofstream savedFile (savePath, std::ios::binary);
|
std::ofstream savedFile (savePath, std::ios::out|std::ios::binary|std::ios::ate);
|
||||||
if (!romFile.is_open()) return NFResult({ false, "Error opening file: " + romPath });
|
if (romFile.is_open() && savedFile.is_open())
|
||||||
if (!savedFile.is_open()) return NFResult({ false, "Error creating file: " + savePath });
|
{
|
||||||
|
std::vector<char> dumpBuffer(size);
|
||||||
|
romFile.seekg (startAddr, std::ios::beg);
|
||||||
|
romFile.read (dumpBuffer.data(), size);
|
||||||
|
romFile.close();
|
||||||
|
|
||||||
std::vector<char> dumpBuffer(size);
|
savedFile.write(dumpBuffer.data(), size);
|
||||||
romFile.seekg (startAddr, std::ios::beg);
|
savedFile.close();
|
||||||
romFile.read (dumpBuffer.data(), size);
|
return true;
|
||||||
romFile.close();
|
}
|
||||||
|
return false;
|
||||||
savedFile.write(dumpBuffer.data(), size);
|
|
||||||
savedFile.close();
|
|
||||||
return NFResult({ true, "" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NDSFactory::logToFile(const std::string& logPath, const std::string& log)
|
|
||||||
{
|
|
||||||
std::ofstream savedFile(logPath, std::ios::out | std::ios::binary | std::ios::app);
|
|
||||||
if (!savedFile.is_open()) return false;
|
|
||||||
|
|
||||||
savedFile.write(log.c_str(), log.size());
|
bool NDSFactory::readBytesFromFile(std::vector<char>& byteBuffer, const std::string& romPath, uint32_t startAddr, uint32_t size)
|
||||||
savedFile.close();
|
{
|
||||||
|
std::ifstream romFile (romPath, std::ios::in|std::ios::binary|std::ios::ate);
|
||||||
|
if (romFile.is_open())
|
||||||
|
{
|
||||||
|
romFile.seekg (startAddr, std::ios::beg);
|
||||||
|
romFile.read (byteBuffer.data(), size);
|
||||||
|
romFile.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NDSFactory::writeSectionToFile(const std::string& sectionPath, const std::string& savePath, uint32_t startAddr, uint32_t size)
|
||||||
|
{
|
||||||
|
std::ifstream sectionFile (sectionPath, std::ios::in|std::ios::binary|std::ios::ate);
|
||||||
|
std::ofstream savedFile (savePath, std::ios::out|std::ios::binary|std::ios::app);
|
||||||
|
if (sectionFile.is_open() && savedFile.is_open())
|
||||||
|
{
|
||||||
|
std::vector<char> dumpBuffer(size);
|
||||||
|
sectionFile.seekg (0, std::ios::beg);
|
||||||
|
sectionFile.read (dumpBuffer.data(), size);
|
||||||
|
sectionFile.close();
|
||||||
|
|
||||||
|
savedFile.seekp(startAddr, std::ios::beg);
|
||||||
|
savedFile.write(dumpBuffer.data(), size);
|
||||||
|
savedFile.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NDSFactory::writeBytesToFile(std::vector<char>& byteBuffer, const std::string& savePath, uint32_t startAddr, uint32_t size)
|
||||||
NFResult NDSFactory::readBytesFromFile(std::vector<char>& byteBuffer, const std::string& romPath, uint32_t startAddr, uint32_t size)
|
|
||||||
{
|
{
|
||||||
std::ifstream romFile (romPath, std::ios::binary);
|
std::ofstream savedFile (savePath, std::ios::out|std::ios::binary|std::ios::app);
|
||||||
if (!romFile.is_open())
|
if (savedFile.is_open())
|
||||||
return NFResult({ false, "Error opening file: " + romPath });
|
|
||||||
|
|
||||||
romFile.seekg (startAddr, std::ios::beg);
|
|
||||||
romFile.read (byteBuffer.data(), size);
|
|
||||||
romFile.close();
|
|
||||||
return NFResult({ true, "" });
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult NDSFactory::writeSectionToFile(const std::string& sectionPath, const std::string& savePath, uint32_t startAddr, uint32_t size)
|
|
||||||
{
|
|
||||||
std::ifstream sectionFile (sectionPath, std::ios::binary);
|
|
||||||
if (!sectionFile.is_open())
|
|
||||||
return NFResult({ false, "Error opening file: " + sectionPath });
|
|
||||||
|
|
||||||
std::vector<char> dumpBuffer(size);
|
|
||||||
sectionFile.read (dumpBuffer.data(), size);
|
|
||||||
sectionFile.close();
|
|
||||||
return writeBytesToFile(dumpBuffer, savePath, startAddr, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult NDSFactory::writeBytesToFile(std::vector<char>& byteBuffer, const std::string& savePath, uint32_t startAddr, uint32_t size)
|
|
||||||
{
|
|
||||||
std::ofstream savedFile (savePath, std::ios::in | std::ios::out | std::ios::binary);
|
|
||||||
if (!savedFile.is_open())
|
|
||||||
{
|
{
|
||||||
savedFile.open(savePath, std::ios::out | std::ios::binary);
|
savedFile.seekp(startAddr, std::ios::beg);
|
||||||
if (!savedFile.is_open()) {
|
savedFile.write(byteBuffer.data(), size);
|
||||||
return NFResult({ false, "Error creating file: " + savePath });
|
|
||||||
}
|
|
||||||
savedFile.close();
|
savedFile.close();
|
||||||
savedFile.open(savePath, std::ios::in | std::ios::out | std::ios::binary);
|
return true;
|
||||||
if (!savedFile.is_open())
|
|
||||||
return NFResult({ false, "Error opening file: " + savePath });
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
savedFile.seekp(startAddr);
|
|
||||||
savedFile.write(byteBuffer.data(), size);
|
|
||||||
savedFile.close();
|
|
||||||
return NFResult({ true, "" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NFResult NDSFactory::writePaddingToFile(char paddingChar, const std::string& filePath, uint32_t startAddr, const uint32_t size)
|
bool NDSFactory::writePaddingToFile(char paddingChar, const std::string& filePath, uint32_t startAddr, const uint32_t size)
|
||||||
{
|
{
|
||||||
std::vector<char> paddingBytes(size, paddingChar);
|
std::vector<char> paddingBytes(size, paddingChar);
|
||||||
return writeBytesToFile(paddingBytes, filePath, startAddr, size);
|
return writeBytesToFile(paddingBytes, filePath, startAddr, size);
|
||||||
@ -122,7 +113,7 @@ int NDSFactory::getCardSizeInBytes(int cardType)
|
|||||||
|
|
||||||
bool NDSFactory::checkArm9FooterPresence(const std::string& sectionPath, uint32_t size)
|
bool NDSFactory::checkArm9FooterPresence(const std::string& sectionPath, uint32_t size)
|
||||||
{
|
{
|
||||||
std::ifstream sectionFile (sectionPath, 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())
|
||||||
{
|
{
|
||||||
std::streamoff sectionRealSize = sectionFile.tellg();
|
std::streamoff sectionRealSize = sectionFile.tellg();
|
||||||
@ -135,150 +126,13 @@ bool NDSFactory::checkArm9FooterPresence(const std::string& sectionPath, uint32_
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult NDSFactory::extractFatData(const std::string& fatDataSectionPath, const std::string& fatSectionPath,
|
bool NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftSize, const std::string& savePath)
|
||||||
const std::string& fntSectionPath, uint32_t originalFatDataAddr, const std::string& savePath, bool logFileIDs)
|
|
||||||
{
|
|
||||||
std::vector<char> fatDataBytes;
|
|
||||||
std::vector<char> fatBytes;
|
|
||||||
std::vector<char> fntBytes;
|
|
||||||
|
|
||||||
std::ifstream fatDataSectionFile(fatDataSectionPath, std::ios::in | std::ios::binary | std::ios::ate);
|
|
||||||
if (!fatDataSectionFile.is_open()) return NFResult({ false, "Error opening file: " + fatDataSectionPath });
|
|
||||||
std::streamoff fatDataSectionSize = fatDataSectionFile.tellg();
|
|
||||||
fatDataBytes.resize(fatDataSectionSize);
|
|
||||||
fatDataSectionFile.seekg(0, std::ios::beg);
|
|
||||||
fatDataSectionFile.read(fatDataBytes.data(), fatDataSectionSize);
|
|
||||||
fatDataSectionFile.close();
|
|
||||||
|
|
||||||
std::ifstream fatSectionFile(fatSectionPath, std::ios::in | std::ios::binary | std::ios::ate);
|
|
||||||
if (!fatSectionFile.is_open()) return NFResult({ false, "Error opening file: " + fatSectionPath });
|
|
||||||
std::streamoff fatSectionSize = fatSectionFile.tellg();
|
|
||||||
fatBytes.resize(fatSectionSize);
|
|
||||||
fatSectionFile.seekg(0, std::ios::beg);
|
|
||||||
fatSectionFile.read(fatBytes.data(), fatSectionSize);
|
|
||||||
fatSectionFile.close();
|
|
||||||
|
|
||||||
std::ifstream fntSectionFile(fntSectionPath, std::ios::in | std::ios::binary | std::ios::ate);
|
|
||||||
if (!fntSectionFile.is_open()) return NFResult({ false, "Error opening file: " + fntSectionPath });
|
|
||||||
std::streamoff fntSectionSize = fntSectionFile.tellg();
|
|
||||||
fntBytes.resize(fntSectionSize);
|
|
||||||
fntSectionFile.seekg(0, std::ios::beg);
|
|
||||||
fntSectionFile.read(fntBytes.data(), fntSectionSize);
|
|
||||||
fntSectionFile.close();
|
|
||||||
|
|
||||||
FatRange* pfatrange = reinterpret_cast<FatRange*>(fatBytes.data());
|
|
||||||
|
|
||||||
// This lambda function was written by NyuBlara, all credits to him.
|
|
||||||
// I edited it a bit to make it work with the rest of the updated code.
|
|
||||||
auto parseFolder = [this, fntBytes, pfatrange, fatDataSectionPath, originalFatDataAddr, savePath, logFileIDs](uint32_t folderId, std::string curPath, auto& parseFolder) {
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
std::string newPath = 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;
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(newPath))
|
|
||||||
if (!std::filesystem::create_directory(newPath)) return NFResult({ false, "Error creating directory: " + newPath });
|
|
||||||
|
|
||||||
if (logFileIDs)
|
|
||||||
{
|
|
||||||
std::string log = std::format("{:x}",subFolderId) + ":::" + newPath.substr(savePath.size()+1) + '\n';
|
|
||||||
if (!logToFile(savePath + "/_file_IDs.txt", log)) return NFResult({ false, "Error writing to file: " + savePath + "/_file_IDs.txt" });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Jump back to the FNT header and repeat the process for subdirectory !
|
|
||||||
if (!parseFolder(subFolderId, newPath, parseFolder).result) return NFResult({ false, "Error parsing folder: " + newPath });
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
|
|
||||||
uint32_t fileStartAddr = (pfatrange + fatOffset)->startAddr - originalFatDataAddr;
|
|
||||||
uint32_t fileSize = (pfatrange + fatOffset)->endAddr - (pfatrange + fatOffset)->startAddr;
|
|
||||||
if (!dumpDataFromFile(fatDataSectionPath, newPath, fileStartAddr, fileSize).result) return NFResult({ false, "Error dumping file: " + newPath });
|
|
||||||
|
|
||||||
if (logFileIDs)
|
|
||||||
{
|
|
||||||
std::string log = std::format("{:x}", fatOffset) + ":::" + newPath.substr(savePath.size()+1) + '\n';
|
|
||||||
if (!logToFile(savePath + "/_file_IDs.txt", log)) return NFResult({ false, "Error writing to file: " + savePath + "/_file_IDs.txt" });
|
|
||||||
}
|
|
||||||
|
|
||||||
fatOffset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NFResult({ true, "" });
|
|
||||||
};
|
|
||||||
|
|
||||||
return parseFolder(ROOT_DIRECTORY_ADDRESS, savePath, parseFolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftSize, const std::string& savePath)
|
|
||||||
{
|
{
|
||||||
std::vector<char> fatBytes;
|
std::vector<char> fatBytes;
|
||||||
|
|
||||||
std::ifstream sectionFile (fatSectionPath, std::ios::in|std::ios::binary|std::ios::ate);
|
std::ifstream sectionFile (fatSectionPath, std::ios::in|std::ios::binary|std::ios::ate);
|
||||||
if (!sectionFile.is_open())
|
if (!sectionFile.is_open())
|
||||||
return { false, "Error opening file: " + fatSectionPath };
|
return false;
|
||||||
|
|
||||||
std::streamoff sectionSize = sectionFile.tellg();
|
std::streamoff sectionSize = sectionFile.tellg();
|
||||||
fatBytes.resize(sectionSize);
|
fatBytes.resize(sectionSize);
|
||||||
@ -288,6 +142,7 @@ NFResult NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftS
|
|||||||
sectionFile.read (fatBytes.data(), sectionSize);
|
sectionFile.read (fatBytes.data(), sectionSize);
|
||||||
sectionFile.close();
|
sectionFile.close();
|
||||||
|
|
||||||
|
|
||||||
FatRange* pfatrange = reinterpret_cast<FatRange*>(fatBytes.data());
|
FatRange* pfatrange = reinterpret_cast<FatRange*>(fatBytes.data());
|
||||||
|
|
||||||
for(size_t i = 0; i < fatBytes.size(); i += sizeof(FatRange), pfatrange++) {
|
for(size_t i = 0; i < fatBytes.size(); i += sizeof(FatRange), pfatrange++) {
|
||||||
@ -295,97 +150,9 @@ NFResult NDSFactory::patchFat(const std::string& fatSectionPath, uint32_t shiftS
|
|||||||
pfatrange->endAddr += shiftSize;
|
pfatrange->endAddr += shiftSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::remove(savePath.c_str());
|
|
||||||
|
|
||||||
return writeBytesToFile(fatBytes, savePath, 0, static_cast<uint32_t>(sectionSize));
|
return writeBytesToFile(fatBytes, savePath, 0, static_cast<uint32_t>(sectionSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult NDSFactory::buildFatData(const std::string& fatDataDirPath, const std::string& originalFatPath, uint32_t fatDataAddr, const std::string& savePath)
|
|
||||||
{
|
|
||||||
std::vector<char> fatDataBytes;
|
|
||||||
std::vector<FatRange> fat;
|
|
||||||
std::vector<char> fntBytes;
|
|
||||||
|
|
||||||
std::vector<FatFileID> fileIDs;
|
|
||||||
std::ifstream fileIDsFile(fatDataDirPath + "/_file_IDs.txt", std::ios::in);
|
|
||||||
if (!fileIDsFile.is_open()) return { false, "Error opening file: " + fatDataDirPath + "/_file_IDs.txt" };
|
|
||||||
std::string fileIDsLine;
|
|
||||||
while (std::getline(fileIDsFile, fileIDsLine))
|
|
||||||
{
|
|
||||||
FatFileID fatFileID;
|
|
||||||
fatFileID.id = static_cast<uint16_t>(std::stoi(fileIDsLine.substr(0, fileIDsLine.find(":::")), nullptr, 16));
|
|
||||||
fatFileID.path = fileIDsLine.substr(fileIDsLine.find(":::") + 3);
|
|
||||||
fileIDs.push_back(fatFileID);
|
|
||||||
}
|
|
||||||
fileIDsFile.close();
|
|
||||||
|
|
||||||
// This loop is needed to detect if roms has overlay files
|
|
||||||
// and if so, we need to extract their addresses from the original fat.bin
|
|
||||||
// it is a hacky but it works
|
|
||||||
for (FatFileID fatFileID : fileIDs)
|
|
||||||
{
|
|
||||||
std::string currentFile = fatDataDirPath + "/" + fatFileID.path;
|
|
||||||
if (std::filesystem::is_directory(std::filesystem::path(currentFile))) continue;
|
|
||||||
|
|
||||||
int firstFileId = fatFileID.id;
|
|
||||||
if (firstFileId > 0)
|
|
||||||
{
|
|
||||||
std::ifstream originalFatFile(originalFatPath, std::ios::in | std::ios::binary);
|
|
||||||
if (!originalFatFile.is_open()) return { false, "Error opening file: " + originalFatPath };
|
|
||||||
std::vector<char> ovrBytes;
|
|
||||||
uint32_t requiredBytes = firstFileId * sizeof(FatRange);
|
|
||||||
ovrBytes.resize(requiredBytes);
|
|
||||||
originalFatFile.read(ovrBytes.data(), requiredBytes);
|
|
||||||
originalFatFile.close();
|
|
||||||
|
|
||||||
FatRange* pfatrange = reinterpret_cast<FatRange*>(ovrBytes.data());
|
|
||||||
for (size_t i = 0; i < ovrBytes.size(); i += sizeof(FatRange), pfatrange++)
|
|
||||||
fat.push_back({ pfatrange->startAddr, pfatrange->endAddr });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (FatFileID fatFileID : fileIDs)
|
|
||||||
{
|
|
||||||
std::string currentFile = fatDataDirPath + "/" + fatFileID.path;
|
|
||||||
|
|
||||||
if (std::filesystem::is_directory(std::filesystem::path(currentFile))) continue;
|
|
||||||
|
|
||||||
FatRange fatRange;
|
|
||||||
fatRange.startAddr = fatDataAddr + static_cast<uint32_t>(fatDataBytes.size());
|
|
||||||
|
|
||||||
std::ifstream currentFatDataFile(currentFile, std::ios::in | std::ios::binary | std::ios::ate);
|
|
||||||
if (!currentFatDataFile.is_open()) return NFResult({ false, "Error opening file: " + currentFile });
|
|
||||||
std::streamsize size = currentFatDataFile.tellg();
|
|
||||||
currentFatDataFile.seekg(0, std::ios::beg);
|
|
||||||
|
|
||||||
std::vector<char> buffer(size);
|
|
||||||
if (currentFatDataFile.read(buffer.data(), size))
|
|
||||||
fatDataBytes.insert(fatDataBytes.end(), buffer.begin(), buffer.end());
|
|
||||||
else
|
|
||||||
{
|
|
||||||
currentFatDataFile.close();
|
|
||||||
return NFResult({ false, "Error reading file: " + currentFile });
|
|
||||||
}
|
|
||||||
currentFatDataFile.close();
|
|
||||||
|
|
||||||
fatRange.endAddr = fatDataAddr + static_cast<uint32_t>(fatDataBytes.size());
|
|
||||||
fat.push_back(fatRange);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char* fat_ptr = reinterpret_cast<const char*>(fat.data());
|
|
||||||
std::vector<char> fatBytes(fat_ptr, fat_ptr + fat.size() * sizeof(FatRange));
|
|
||||||
std::remove((savePath + "/fat_data.bin").c_str());
|
|
||||||
std::remove((savePath + "/fat.bin").c_str());
|
|
||||||
if (!writeBytesToFile(fatDataBytes, savePath + "/fat_data.bin", 0, static_cast<uint32_t>(fatDataBytes.size())).result)
|
|
||||||
return NFResult({ false, "Error writing to file: " + savePath + "/fat_data.bin" });
|
|
||||||
if (!writeBytesToFile(fatBytes, savePath + "/fat.bin", 0, static_cast<uint32_t>(fatBytes.size())).result)
|
|
||||||
return NFResult({ false, "Error writing to file: " + savePath + "/fat.bin" });
|
|
||||||
|
|
||||||
return NFResult({ true, "" });
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t NDSFactory::calcHeaderCrc16(const std::vector<char>& romHeader)
|
uint16_t NDSFactory::calcHeaderCrc16(const std::vector<char>& romHeader)
|
||||||
{
|
{
|
||||||
uint8_t loc;
|
uint8_t loc;
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
#pragma once
|
#ifndef NDSFACTORY_H
|
||||||
|
#define NDSFACTORY_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "ndsheader.h"
|
#include "ndsheader.h"
|
||||||
#include "fatstruct.h"
|
#include "fatstruct.h"
|
||||||
#include "nfresult.h"
|
|
||||||
|
|
||||||
|
|
||||||
class NDSFactory
|
class NDSFactory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NFResult loadRomHeader(const std::string& romPath, std::vector<char>& header);
|
NDSFactory();
|
||||||
NFResult dumpDataFromFile(const std::string& romPath, const std::string& savePath, uint32_t startAddr, uint32_t size);
|
bool loadRomHeader(const std::string& romPath, std::vector<char>& header);
|
||||||
NFResult readBytesFromFile(std::vector<char>& byteBuffer, const std::string& romPath, uint32_t startAddr, uint32_t size);
|
bool dumpDataFromFile(const std::string& romPath, const std::string& savePath, uint32_t startAddr, uint32_t size);
|
||||||
NFResult writeSectionToFile(const std::string& sectionPath, 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);
|
||||||
NFResult writeBytesToFile(std::vector<char>& byteBuffer, 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);
|
||||||
NFResult writePaddingToFile(char paddingChar, 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 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);
|
||||||
NFResult extractFatData(const std::string& fatDataSectionPath, const std::string& fatSectionPath,
|
bool patchFat(const std::string& sectionPath, uint32_t shiftSize, const std::string& savePath);
|
||||||
const std::string& fntSectionPath, uint32_t originalFatDataAddr, const std::string& savePath, bool logFileIDs);
|
|
||||||
NFResult patchFat(const std::string& sectionPath, uint32_t shiftSize, const std::string& savePath);
|
|
||||||
NFResult buildFatData(const std::string& fatDataDirPath, const std::string& originalFatPath, uint32_t fatDataAddr, const std::string& savePath);
|
|
||||||
uint16_t calcHeaderCrc16(const std::vector<char>& romHeader);
|
uint16_t calcHeaderCrc16(const std::vector<char>& romHeader);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool logToFile(const std::string& logPath, const std::string& log);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // NDSFACTORY_H
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef NDSHEADER_H
|
||||||
|
#define NDSHEADER_H
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
@ -68,3 +69,5 @@ struct NDSHeader
|
|||||||
unsigned char Reserved4[0x90];
|
unsigned char Reserved4[0x90];
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#endif // NDSHEADER_H
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
struct NFResult
|
|
||||||
{
|
|
||||||
bool result;
|
|
||||||
std::string message;
|
|
||||||
};
|
|
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 62 KiB |
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef ABOUTDIALOG_H
|
||||||
|
#define ABOUTDIALOG_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
@ -17,3 +18,5 @@ class AboutDialog : public QDialog
|
|||||||
Ui::AboutDialog *ui;
|
Ui::AboutDialog *ui;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // ABOUTDIALOG_H
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>NDSFactory V1.3.2</string>
|
<string>NDS Factory V1.1</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
@ -58,7 +58,7 @@
|
|||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>(C) 2019-2025 - Luca D'Amico</string>
|
<string>(C) 2019-2024 - Luca D'Amico</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#ifndef REVISION_H
|
#ifndef REVISION_H
|
||||||
#define REVISION_H
|
#define REVISION_H
|
||||||
|
|
||||||
#define GIT_COMMIT_HASH "c916f47"
|
#define GIT_COMMIT_HASH "c7eaa8e"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
#include "dialogs/about/aboutdialog.h"
|
#include "dialogs/about/aboutdialog.h"
|
||||||
#include "utils/theme.h"
|
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
@ -27,18 +26,3 @@ void MainWindow::on_actionAbout_triggered()
|
|||||||
AboutDialog aboutDialog;
|
AboutDialog aboutDialog;
|
||||||
aboutDialog.exec();
|
aboutDialog.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionDark_triggered()
|
|
||||||
{
|
|
||||||
setTheme("dark");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionLight_triggered()
|
|
||||||
{
|
|
||||||
setTheme("light");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionDefault_triggered()
|
|
||||||
{
|
|
||||||
setTheme("default");
|
|
||||||
}
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -31,10 +32,9 @@ private slots:
|
|||||||
void on_unpackerDumpArm9OverlayFilesBtn_clicked();
|
void on_unpackerDumpArm9OverlayFilesBtn_clicked();
|
||||||
void on_unpackerDumpArm7OverlayFilesBtn_clicked();
|
void on_unpackerDumpArm7OverlayFilesBtn_clicked();
|
||||||
void on_unpackerDumpEverythingBtn_clicked();
|
void on_unpackerDumpEverythingBtn_clicked();
|
||||||
|
void on_unpackerDecodeFatFilesBtn_clicked();
|
||||||
|
void notifyExtractionResult(bool result);
|
||||||
|
|
||||||
void on_actionDark_triggered();
|
|
||||||
void on_actionLight_triggered();
|
|
||||||
void on_actionDefault_triggered();
|
|
||||||
void on_actionExit_triggered();
|
void on_actionExit_triggered();
|
||||||
void on_actionAbout_triggered();
|
void on_actionAbout_triggered();
|
||||||
|
|
||||||
@ -49,18 +49,13 @@ private slots:
|
|||||||
void on_packerLoadArm7OverlayFilesBtn_clicked();
|
void on_packerLoadArm7OverlayFilesBtn_clicked();
|
||||||
void on_packerLoadIconTitleBtn_clicked();
|
void on_packerLoadIconTitleBtn_clicked();
|
||||||
void on_packerLoadFatFilesBtn_clicked();
|
void on_packerLoadFatFilesBtn_clicked();
|
||||||
void on_packerCalcHeaderCrcBtn_clicked();
|
|
||||||
void on_packerBuildNDSRomBtn_clicked();
|
void on_packerBuildNDSRomBtn_clicked();
|
||||||
|
|
||||||
void on_fatPatcherLoadFatBtn_clicked();
|
void on_fatPatcherLoadFatBtn_clicked();
|
||||||
|
|
||||||
void on_fatPatcherPatchFatBtn_clicked();
|
void on_fatPatcherPatchFatBtn_clicked();
|
||||||
void on_fatExtractorLoadFatDataBtn_clicked();
|
|
||||||
void on_fatExtractorLoadFatBtn_clicked();
|
void on_packerCalcHeaderCrcBtn_clicked();
|
||||||
void on_fatExtractorLoadFntBtn_clicked();
|
|
||||||
void on_fatExtractorExtractBtn_clicked();
|
|
||||||
void on_fatBuilderOpenFatDataDirBtn_clicked();
|
|
||||||
void on_fatBuilderLoadOriginalFatBtn_clicked();
|
|
||||||
void on_fatBuilderBuildBtn_clicked();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
@ -69,48 +64,54 @@ private:
|
|||||||
void populateHeader(NDSHeader* ndsHeader);
|
void populateHeader(NDSHeader* ndsHeader);
|
||||||
void enableExtractionButtons();
|
void enableExtractionButtons();
|
||||||
void disableExtractionButtons();
|
void disableExtractionButtons();
|
||||||
NFResult dumpHeader(const std::string& dirPath);
|
bool dumpHeader(const std::string& dirPath);
|
||||||
NFResult dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes);
|
bool dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes);
|
||||||
NFResult dumpArm7Bin(const std::string& dirPath);
|
bool dumpArm7Bin(const std::string& dirPath);
|
||||||
NFResult dumpFnt(const std::string& dirPath);
|
bool dumpFnt(const std::string& dirPath);
|
||||||
NFResult dumpFat(const std::string& dirPath);
|
bool dumpFat(const std::string& dirPath);
|
||||||
NFResult dumpArm9Overlay(const std::string& dirPath);
|
bool dumpArm9Overlay(const std::string& dirPath);
|
||||||
NFResult dumpArm9OverlayFiles(const std::string& dirPath);
|
bool dumpArm9OverlayFiles(const std::string& dirPath);
|
||||||
NFResult dumpArm7Overlay(const std::string& dirPath);
|
bool dumpArm7Overlay(const std::string& dirPath);
|
||||||
NFResult dumpArm7OverlayFiles(const std::string& dirPath);
|
bool dumpArm7OverlayFiles(const std::string& dirPath);
|
||||||
NFResult dumpIconTitle(const std::string& dirPath);
|
bool dumpIconTitle(const std::string& dirPath);
|
||||||
NFResult dumpFatFiles(const std::string& dirPath);
|
bool dumpFatFiles(const std::string& dirPath);
|
||||||
NFResult dumpEverything(QString dirPath);
|
bool dumpEverything(QString dirPath);
|
||||||
|
|
||||||
void populatePackerSectionHeader(NDSHeader *ndsHeader);
|
void populatePackerSectionHeader(NDSHeader *ndsHeader);
|
||||||
void enableCalcCrcButton();
|
void enableCalcCrcButton();
|
||||||
void enableBuildRomButton();
|
void enableBuildRomButton();
|
||||||
void generateHeader(NDSHeader* pRomHeader);
|
void generateHeader(NDSHeader* pRomHeader);
|
||||||
NFResult writeHeader(const std::string& savePath);
|
bool writeHeader(const std::string& savePath);
|
||||||
void calcHeaderCrc16();
|
void calcHeaderCrc16();
|
||||||
NFResult writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent);
|
bool writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent);
|
||||||
NFResult writeArm7Bin(const std::string& savePath);
|
bool writeArm7Bin(const std::string& savePath);
|
||||||
NFResult writeFnt(const std::string& savePath);
|
bool writeFnt(const std::string& savePath);
|
||||||
NFResult writeFat(const std::string& savePath);
|
bool writeFat(const std::string& savePath);
|
||||||
NFResult writeArm9Overlay(const std::string& savePath);
|
bool writeArm9Overlay(const std::string& savePath);
|
||||||
NFResult writeArm9OverlayFiles(const std::string& savePath);
|
bool writeArm9OverlayFiles(const std::string& savePath);
|
||||||
NFResult writeArm7Overlay(const std::string& savePath);
|
bool writeArm7Overlay(const std::string& savePath);
|
||||||
NFResult writeArm7OverlayFiles(const std::string& savePath);
|
bool writeArm7OverlayFiles(const std::string& savePath);
|
||||||
NFResult writeIconTitle(const std::string& savePath);
|
bool writeIconTitle(const std::string& savePath);
|
||||||
NFResult writeFatFiles(const std::string& savePath);
|
bool writeFatFiles(const std::string& savePath);
|
||||||
NFResult writeEverything(const std::string& savePath);
|
bool writeEverything(const std::string& savePath);
|
||||||
|
|
||||||
NFResult writeHeaderPadding(char paddingByte, const std::string& savePath);
|
bool writeHeaderPadding(char paddingByte, const std::string& savePath);
|
||||||
NFResult writeArm9BinPadding(char paddingByte, const std::string& savePath, bool isArm9FooterPresent);
|
bool writeArm9BinPadding(char paddingByte, const std::string& savePath, bool isArm9FooterPresent);
|
||||||
NFResult writeArm7BinPadding(char paddingByte, const std::string& savePath);
|
bool writeArm7BinPadding(char paddingByte, const std::string& savePath);
|
||||||
NFResult writeFntPadding(char paddingByte, const std::string& savePath);
|
bool writeFntPadding(char paddingByte, const std::string& savePath);
|
||||||
NFResult writeFatPadding(char paddingByte, const std::string& savePath);
|
bool writeFatPadding(char paddingByte, const std::string& savePath);
|
||||||
NFResult writeRomPadding(const std::string& savePath);
|
bool writeArm9OverlayPadding(char paddingByte, const std::string& savePath);
|
||||||
|
bool writeArm9OverlayFilesPadding(char paddingByte, const std::string& savePath);
|
||||||
|
bool writeArm7OverlayPadding(char paddingByte, const std::string& savePath);
|
||||||
|
bool writeArm7OverlayFilesPadding(char paddingByte, const std::string& savePath);
|
||||||
|
bool writeRomPadding(const std::string& savePath);
|
||||||
|
|
||||||
|
//QString extractUnpackerHeaderTableData(int index);
|
||||||
QString extractPackerHeaderTableData(int index);
|
QString extractPackerHeaderTableData(int index);
|
||||||
|
|
||||||
NFResult extractFatData(const std::string& fatDataSectionPath, const std::string& fatSectionPath,
|
bool decodeFatFiles(QString dirPath);
|
||||||
const std::string& fntSectionPath, uint32_t originalFatDataAddr, const std::string& savePath, bool logFileIDs);
|
|
||||||
NFResult 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);
|
||||||
NFResult buildFatData(const std::string& fatDataDirPath, const std::string& originalFatPath, uint32_t fatDataAddr, const std::string& savePath);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
|
286
ui/mainwindow.ui
286
ui/mainwindow.ui
@ -274,6 +274,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="unpackerDecodeFatFilesBtn">
|
||||||
|
<property name="text">
|
||||||
|
<string>Decode FAT Contents</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -594,223 +601,11 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||||
<property name="spacing">
|
<property name="spacing">
|
||||||
<number>6</number>
|
<number>4</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeConstraint">
|
<property name="sizeConstraint">
|
||||||
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_7">
|
|
||||||
<property name="title">
|
|
||||||
<string>FAT Data Extractor</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_38">
|
|
||||||
<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="fatExtractorFatDataPathEdt"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="fatExtractorLoadFatDataBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Load FAT Data(fat_data.bin)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_40">
|
|
||||||
<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="fatExtractorFntPathEdt"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="fatExtractorLoadFntBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Load FNT(fnt.bin)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_39" stretch="0,0">
|
|
||||||
<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="fatExtractorFatPathEdt"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="fatExtractorLoadFatBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Load FAT(fat.bin)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>Original Fat Files (fat_data.bin) Addr:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="fatExtractorOriginalFatFilesAddrEdt"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="fatExtractorSaveFileIDsCbx">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save file IDs to _file_IDs.txt (required for rebuilding FAT)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_41">
|
|
||||||
<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="fatExtractorExtractBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Extract FAT Data!</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_8">
|
|
||||||
<property name="title">
|
|
||||||
<string>FAT Builder</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Original fat.bin is required ONLY if the ROM has an overlay...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="fatBuilderFatDirPathEdt"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="fatBuilderOpenFatDataDirBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open FAT Data Directory</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="fatBuilderOriginalFatPathEdt"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="fatBuilderLoadOriginalFatBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Load Original fat.bin</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Fat Files (fat_data.bin) Addr:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="fatBuilderFatAddrEdt"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="fatBuilderBuildBtn">
|
|
||||||
<property name="text">
|
|
||||||
<string>Build!</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -822,27 +617,23 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
<widget class="QLabel" name="label_83">
|
||||||
<item>
|
<property name="sizePolicy">
|
||||||
<widget class="QLabel" name="label_83">
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
<property name="sizePolicy">
|
<horstretch>0</horstretch>
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
<verstretch>0</verstretch>
|
||||||
<horstretch>0</horstretch>
|
</sizepolicy>
|
||||||
<verstretch>0</verstretch>
|
</property>
|
||||||
</sizepolicy>
|
<property name="text">
|
||||||
</property>
|
<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 name="text">
|
</property>
|
||||||
<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 name="scaledContents">
|
||||||
</property>
|
<bool>false</bool>
|
||||||
<property name="scaledContents">
|
</property>
|
||||||
<bool>false</bool>
|
<property name="alignment">
|
||||||
</property>
|
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||||
<property name="alignment">
|
</property>
|
||||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
</widget>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_35">
|
<layout class="QHBoxLayout" name="horizontalLayout_35">
|
||||||
@ -939,9 +730,6 @@
|
|||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Orientation::Vertical</enum>
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeType">
|
|
||||||
<enum>QSizePolicy::Policy::Expanding</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" stdset="0">
|
||||||
<size>
|
<size>
|
||||||
<width>20</width>
|
<width>20</width>
|
||||||
@ -972,15 +760,6 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>File</string>
|
<string>File</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuTheme">
|
|
||||||
<property name="title">
|
|
||||||
<string>Theme</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="actionDark"/>
|
|
||||||
<addaction name="actionLight"/>
|
|
||||||
<addaction name="actionDefault"/>
|
|
||||||
</widget>
|
|
||||||
<addaction name="menuTheme"/>
|
|
||||||
<addaction name="actionExit"/>
|
<addaction name="actionExit"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuHelp">
|
<widget class="QMenu" name="menuHelp">
|
||||||
@ -1007,21 +786,6 @@
|
|||||||
<string>Exit</string>
|
<string>Exit</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDark">
|
|
||||||
<property name="text">
|
|
||||||
<string>Dark</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionLight">
|
|
||||||
<property name="text">
|
|
||||||
<string>Light</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionDefault">
|
|
||||||
<property name="text">
|
|
||||||
<string>Default</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -151,7 +151,7 @@ bool NDSHeaderModel::setData(const QModelIndex &index, const QVariant &value, in
|
|||||||
case 37: ndsHeader->DebugRomAddr = static_cast<uint32_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 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 39: ndsHeader->DebugRamAddr = static_cast<uint32_t>(value.toString().toUInt(nullptr, 16)); break;
|
||||||
case 40: QMessageBox::information(nullptr, tr("NDSFactory"), tr("FAT files address is automatically calculated based on Icon/Title address!")); 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;
|
default: return false;
|
||||||
}
|
}
|
||||||
Q_EMIT this->dataChanged(index, index);
|
Q_EMIT this->dataChanged(index, index);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef NDSHEADERMODEL_H
|
||||||
|
#define NDSHEADERMODEL_H
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
@ -20,3 +21,5 @@ private:
|
|||||||
NDSHeader *ndsHeader;
|
NDSHeader *ndsHeader;
|
||||||
bool isValueRowEditable = false;
|
bool isValueRowEditable = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // NDSHEADERMODEL_H
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef HEADERNAMES_H
|
||||||
|
#define HEADERNAMES_H
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -51,3 +52,5 @@ namespace NDSHeaderNames {
|
|||||||
FATFilesAddress
|
FATFilesAddress
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // HEADERNAMES_H
|
||||||
|
@ -1,19 +1,7 @@
|
|||||||
#include <filesystem>
|
|
||||||
#include "./../../mainwindow.h"
|
#include "./../../mainwindow.h"
|
||||||
|
|
||||||
|
|
||||||
NFResult MainWindow::extractFatData(const std::string& fatDataSectionPath, const std::string& fatSectionPath,
|
bool MainWindow::patchFat(const std::string& loadPath, uint32_t shiftSize, const std::string& savePath)
|
||||||
const std::string& fntSectionPath, uint32_t originalFatDataAddr, const std::string& savePath, bool logFileIDs)
|
|
||||||
{
|
|
||||||
return ndsFactory.extractFatData(fatDataSectionPath, fatSectionPath, fntSectionPath, originalFatDataAddr, savePath, logFileIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::patchFat(const std::string& loadPath, uint32_t shiftSize, const std::string& savePath)
|
|
||||||
{
|
{
|
||||||
return ndsFactory.patchFat(loadPath, shiftSize, savePath);
|
return ndsFactory.patchFat(loadPath, shiftSize, savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::buildFatData(const std::string& fatDataDirPath, const std::string& originalFatPath, uint32_t fatDataAddr, const std::string& savePath)
|
|
||||||
{
|
|
||||||
return ndsFactory.buildFatData(fatDataDirPath, originalFatPath, fatDataAddr, savePath);
|
|
||||||
}
|
|
||||||
|
@ -2,154 +2,48 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include "./../../mainwindow.h"
|
#include "./../../mainwindow.h"
|
||||||
#include "./../../ui_mainwindow.h"
|
#include "./../../ui_mainwindow.h"
|
||||||
#include "./../../utils/filepicker.h"
|
|
||||||
|
|
||||||
void MainWindow::on_fatExtractorLoadFatDataBtn_clicked()
|
|
||||||
{
|
|
||||||
QString FatDataPath = QFileDialog::getOpenFileName(
|
|
||||||
Q_NULLPTR,
|
|
||||||
"NDS Fat Data",
|
|
||||||
"",
|
|
||||||
"NDS FAT_DATA (*.bin)");
|
|
||||||
|
|
||||||
if (!FatDataPath.isNull())
|
|
||||||
{
|
|
||||||
ui->fatExtractorFatDataPathEdt->setText(FatDataPath.toUtf8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatExtractorLoadFatBtn_clicked()
|
|
||||||
{
|
|
||||||
QString FatPath = QFileDialog::getOpenFileName(
|
|
||||||
Q_NULLPTR,
|
|
||||||
"NDS Fat",
|
|
||||||
"",
|
|
||||||
"NDS FAT (*.bin)");
|
|
||||||
|
|
||||||
if (!FatPath.isNull())
|
|
||||||
{
|
|
||||||
ui->fatExtractorFatPathEdt->setText(FatPath.toUtf8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatExtractorLoadFntBtn_clicked()
|
|
||||||
{
|
|
||||||
QString FntPath = QFileDialog::getOpenFileName(
|
|
||||||
Q_NULLPTR,
|
|
||||||
"NDS Fnt",
|
|
||||||
"",
|
|
||||||
"NDS FNT (*.bin)");
|
|
||||||
|
|
||||||
if (!FntPath.isNull())
|
|
||||||
{
|
|
||||||
ui->fatExtractorFntPathEdt->setText(FntPath.toUtf8());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatExtractorExtractBtn_clicked()
|
|
||||||
{
|
|
||||||
ui->fatExtractorExtractBtn->setEnabled(false);
|
|
||||||
|
|
||||||
QString dirPath = QFileDialog::getExistingDirectory(
|
|
||||||
this, tr("Select Directory"),
|
|
||||||
"",
|
|
||||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
||||||
|
|
||||||
if (!dirPath.isNull()) {
|
|
||||||
NFResult nfResult = extractFatData(ui->fatExtractorFatDataPathEdt->text().toStdString(),
|
|
||||||
ui->fatExtractorFatPathEdt->text().toStdString(),
|
|
||||||
ui->fatExtractorFntPathEdt->text().toStdString(),
|
|
||||||
ui->fatExtractorOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16),
|
|
||||||
dirPath.toStdString(),
|
|
||||||
ui->fatExtractorSaveFileIDsCbx->isChecked());
|
|
||||||
nfResult.result? QMessageBox::information(this, tr("NDSFactory"), tr("FAT files extraction completed!"))
|
|
||||||
: QMessageBox::critical(this, tr("NDSFactory"), nfResult.message.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->fatExtractorExtractBtn->setEnabled(true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatPatcherLoadFatBtn_clicked()
|
void MainWindow::on_fatPatcherLoadFatBtn_clicked()
|
||||||
{
|
{
|
||||||
QString fatPath = QFileDialog::getOpenFileName(
|
QString fatPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Fat",
|
"NDS Fat",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS Fat (*.bin)");
|
"NDS Fat (*.bin)");
|
||||||
|
|
||||||
if(!fatPath.isNull())
|
if( !fatPath.isNull() )
|
||||||
ui->fatPatcherFatPathEdt->setText(fatPath.toUtf8());
|
{
|
||||||
|
ui->fatPatcherFatPathEdt->setText(fatPath.toUtf8());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_fatPatcherPatchFatBtn_clicked()
|
void MainWindow::on_fatPatcherPatchFatBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->fatPatcherPatchFatBtn->setEnabled(false);
|
|
||||||
|
|
||||||
uint32_t positionDiff = 0;
|
uint32_t positionDiff = 0;
|
||||||
uint32_t originalPos = ui->fatPatcherOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16);
|
uint32_t originalPos = ui->fatPatcherOriginalFatFilesAddrEdt->text().toUInt(nullptr, 16);
|
||||||
uint32_t newPos = ui->fatPatcherNewFatFilesAddrEdt->text().toUInt(nullptr, 16);
|
uint32_t newPos = ui->fatPatcherNewFatFilesAddrEdt->text().toUInt(nullptr, 16);
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS FAT",
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
"fat.bin",
|
Q_NULLPTR,
|
||||||
"Binary (*.bin)");
|
"NDS FAT",
|
||||||
|
"fat.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
if (!dirPath.isNull())
|
if(dirPath.isNull())
|
||||||
{
|
{
|
||||||
if(originalPos < newPos)
|
return;
|
||||||
positionDiff = newPos - originalPos;
|
|
||||||
else
|
|
||||||
positionDiff = originalPos - newPos;
|
|
||||||
|
|
||||||
NFResult nfResult = patchFat(ui->fatPatcherFatPathEdt->text().toStdString(), positionDiff, dirPath.toStdString());
|
|
||||||
nfResult.result ? QMessageBox::information(this, tr("NDSFactory"), tr("FAT patching completed!"))
|
|
||||||
: QMessageBox::critical(this, tr("NDSFactory"), nfResult.message.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->fatPatcherPatchFatBtn->setEnabled(true);
|
if (originalPos < newPos)
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatBuilderOpenFatDataDirBtn_clicked()
|
|
||||||
{
|
|
||||||
QString fatDirPat = QFileDialog::getExistingDirectory(
|
|
||||||
this, tr("Select Directory"),
|
|
||||||
"",
|
|
||||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
||||||
|
|
||||||
if (!fatDirPat.isNull())
|
|
||||||
ui->fatBuilderFatDirPathEdt->setText(fatDirPat.toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatBuilderLoadOriginalFatBtn_clicked()
|
|
||||||
{
|
|
||||||
QString fatPath = QFileDialog::getOpenFileName(
|
|
||||||
Q_NULLPTR,
|
|
||||||
"NDS Fat",
|
|
||||||
"",
|
|
||||||
"NDS Fat (*.bin)");
|
|
||||||
|
|
||||||
if (!fatPath.isNull())
|
|
||||||
ui->fatBuilderOriginalFatPathEdt->setText(fatPath.toUtf8());
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_fatBuilderBuildBtn_clicked()
|
|
||||||
{
|
|
||||||
ui->fatBuilderOpenFatDataDirBtn->setEnabled(false);
|
|
||||||
|
|
||||||
QString dirPath = QFileDialog::getExistingDirectory(
|
|
||||||
this, tr("Select Directory"),
|
|
||||||
"",
|
|
||||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
|
||||||
|
|
||||||
if (!dirPath.isNull())
|
|
||||||
{
|
{
|
||||||
NFResult nfResult = buildFatData(ui->fatBuilderFatDirPathEdt->text().toStdString(),
|
positionDiff = newPos-originalPos;
|
||||||
ui->fatBuilderOriginalFatPathEdt->text().toStdString(),
|
} else {
|
||||||
ui->fatBuilderFatAddrEdt->text().toUInt(nullptr, 16),
|
positionDiff = originalPos-newPos;
|
||||||
dirPath.toStdString());
|
|
||||||
nfResult.result? QMessageBox::information(this, tr("NDSFactory"), tr("fat_data.bin and fat.bin correctly built!"))
|
|
||||||
: QMessageBox::critical(this, tr("NDSFactory"), nfResult.message.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->fatBuilderOpenFatDataDirBtn->setEnabled(true);
|
patchFat(ui->fatPatcherFatPathEdt->text().toStdString(), positionDiff, dirPath.toStdString())
|
||||||
|
? QMessageBox::information(this, tr("NDS Factory"), tr("FAT patching completed!"))
|
||||||
|
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error patching FAT!"));
|
||||||
|
|
||||||
}
|
}
|
@ -91,6 +91,17 @@ void MainWindow::generateHeader(NDSHeader* pRomHeader)
|
|||||||
std::fill(std::begin(pRomHeader->Reserved4), std::end(pRomHeader->Reserved4), 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()
|
void MainWindow::calcHeaderCrc16()
|
||||||
{
|
{
|
||||||
std::vector<char> romHeaderBuffer(sizeof(NDSHeader));
|
std::vector<char> romHeaderBuffer(sizeof(NDSHeader));
|
||||||
@ -102,29 +113,7 @@ void MainWindow::calcHeaderCrc16()
|
|||||||
ui->packerHeaderDataTable->model()->setData(headerCrcIndex, QString::number(ndsFactory.calcHeaderCrc16(romHeaderBuffer), 16), Qt::EditRole);
|
ui->packerHeaderDataTable->model()->setData(headerCrcIndex, QString::number(ndsFactory.calcHeaderCrc16(romHeaderBuffer), 16), Qt::EditRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeHeader(const std::string& savePath)
|
bool MainWindow::writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent)
|
||||||
{
|
|
||||||
std::vector<char> romHeaderBuffer(sizeof(NDSHeader));
|
|
||||||
NDSHeader* pRomHeader = reinterpret_cast<NDSHeader*>(romHeaderBuffer.data());
|
|
||||||
|
|
||||||
generateHeader(pRomHeader);
|
|
||||||
|
|
||||||
return ndsFactory.writeBytesToFile(romHeaderBuffer, savePath, 0, sizeof(NDSHeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeArm9Bin(const std::string& savePath, bool isArm9FooterPresent)
|
|
||||||
{
|
{
|
||||||
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16);
|
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16);
|
||||||
if (isArm9FooterPresent)
|
if (isArm9FooterPresent)
|
||||||
@ -136,52 +125,7 @@ NFResult MainWindow::writeArm9Bin(const std::string& savePath, bool isArm9Footer
|
|||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::writeArm7Bin(const std::string& savePath)
|
||||||
NFResult MainWindow::writeArm9BinPadding(char paddingType, const std::string& savePath, bool isFooterPresent)
|
|
||||||
{
|
|
||||||
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9RomAddress).toUInt(nullptr, 16) +
|
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16);
|
|
||||||
uint32_t size;
|
|
||||||
if (extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) != 0)
|
|
||||||
size = extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) - startAddr;
|
|
||||||
else
|
|
||||||
size = extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16) - startAddr;
|
|
||||||
|
|
||||||
if (isFooterPresent)
|
|
||||||
{
|
|
||||||
startAddr += Arm9FooterSize;
|
|
||||||
size -= Arm9FooterSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ndsFactory.writePaddingToFile(
|
|
||||||
paddingType,
|
|
||||||
savePath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeArm9OverlayFiles(const std::string& savePath)
|
|
||||||
{
|
|
||||||
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) +
|
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16);
|
|
||||||
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16) - startAddr;
|
|
||||||
return ndsFactory.writeSectionToFile(
|
|
||||||
ui->loadedArm9OverlayFilesPathEdt->text().toStdString(),
|
|
||||||
savePath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeArm7Bin(const std::string& savePath)
|
|
||||||
{
|
{
|
||||||
return ndsFactory.writeSectionToFile(
|
return ndsFactory.writeSectionToFile(
|
||||||
ui->loadedArm7BinPathEdt->text().toStdString(),
|
ui->loadedArm7BinPathEdt->text().toStdString(),
|
||||||
@ -190,45 +134,7 @@ NFResult MainWindow::writeArm7Bin(const std::string& savePath)
|
|||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM7Size).toUInt(nullptr, 16));
|
extractPackerHeaderTableData(NDSHeaderNames::ARM7Size).toUInt(nullptr, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeArm7BinPadding(char paddingType, const std::string& savePath)
|
bool MainWindow::writeFnt(const std::string& savePath)
|
||||||
{
|
|
||||||
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7RomAddress).toUInt(nullptr, 16) +
|
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM7Size).toUInt(nullptr, 16);
|
|
||||||
uint32_t size;
|
|
||||||
if (extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlayAddress).toUInt(nullptr, 16) != 0)
|
|
||||||
size = extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlayAddress).toUInt(nullptr, 16) - startAddr;
|
|
||||||
else
|
|
||||||
size = extractPackerHeaderTableData(NDSHeaderNames::FilenameTableAddress).toUInt(nullptr, 16) - startAddr;
|
|
||||||
|
|
||||||
return ndsFactory.writePaddingToFile(
|
|
||||||
paddingType,
|
|
||||||
savePath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeArm7Overlay(const std::string& savePath)
|
|
||||||
{
|
|
||||||
return ndsFactory.writeSectionToFile(
|
|
||||||
ui->loadedArm7OverlayPathEdt->text().toStdString(),
|
|
||||||
savePath,
|
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlayAddress).toUInt(nullptr, 16),
|
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlaySize).toUInt(nullptr, 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeArm7OverlayFiles(const std::string& savePath)
|
|
||||||
{
|
|
||||||
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlayAddress).toUInt(nullptr, 16) +
|
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlaySize).toUInt(nullptr, 16);
|
|
||||||
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::FilenameTableAddress).toUInt(nullptr, 16) - startAddr;
|
|
||||||
return ndsFactory.writeSectionToFile(
|
|
||||||
ui->loadedArm7OverlayFilesPathEdt->text().toStdString(),
|
|
||||||
savePath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeFnt(const std::string& savePath)
|
|
||||||
{
|
{
|
||||||
return ndsFactory.writeSectionToFile(
|
return ndsFactory.writeSectionToFile(
|
||||||
ui->loadedFntPathEdt->text().toStdString(),
|
ui->loadedFntPathEdt->text().toStdString(),
|
||||||
@ -237,20 +143,7 @@ NFResult MainWindow::writeFnt(const std::string& savePath)
|
|||||||
extractPackerHeaderTableData(NDSHeaderNames::FilenameTableSize).toUInt(nullptr, 16));
|
extractPackerHeaderTableData(NDSHeaderNames::FilenameTableSize).toUInt(nullptr, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeFntPadding(char paddingType, const std::string& savePath)
|
bool MainWindow::writeFat(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
NFResult MainWindow::writeFat(const std::string& savePath)
|
|
||||||
{
|
{
|
||||||
return ndsFactory.writeSectionToFile(
|
return ndsFactory.writeSectionToFile(
|
||||||
ui->loadedFatPathEdt->text().toStdString(),
|
ui->loadedFatPathEdt->text().toStdString(),
|
||||||
@ -259,20 +152,35 @@ NFResult MainWindow::writeFat(const std::string& savePath)
|
|||||||
extractPackerHeaderTableData(NDSHeaderNames::FATSize).toUInt(nullptr, 16));
|
extractPackerHeaderTableData(NDSHeaderNames::FATSize).toUInt(nullptr, 16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeFatPadding(char paddingType, const std::string& savePath)
|
bool MainWindow::writeArm9Overlay(const std::string& savePath)
|
||||||
{
|
{
|
||||||
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::FATAddress).toUInt(nullptr, 16) +
|
return ndsFactory.writeSectionToFile(
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::FATSize).toUInt(nullptr, 16);
|
ui->loadedArm9OverlayPathEdt->text().toStdString(),
|
||||||
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16) - startAddr;
|
savePath,
|
||||||
|
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16),
|
||||||
return ndsFactory.writePaddingToFile(
|
extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlaySize).toUInt(nullptr, 16));
|
||||||
paddingType,
|
|
||||||
savePath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeIconTitle(const std::string& savePath)
|
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(
|
return ndsFactory.writeSectionToFile(
|
||||||
ui->loadedIconTitlePathEdt->text().toStdString(),
|
ui->loadedIconTitlePathEdt->text().toStdString(),
|
||||||
@ -281,7 +189,7 @@ NFResult MainWindow::writeIconTitle(const std::string& savePath)
|
|||||||
IconTitleSize);
|
IconTitleSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeFatFiles(const std::string& savePath)
|
bool MainWindow::writeFatFiles(const std::string& savePath)
|
||||||
{
|
{
|
||||||
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16) + IconTitleSize;
|
uint32_t startAddr = extractPackerHeaderTableData(NDSHeaderNames::IconTitleAddress).toUInt(nullptr, 16) + IconTitleSize;
|
||||||
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::UsedRomSize).toUInt(nullptr, 16) - startAddr;
|
uint32_t size = extractPackerHeaderTableData(NDSHeaderNames::UsedRomSize).toUInt(nullptr, 16) - startAddr;
|
||||||
@ -293,7 +201,95 @@ NFResult MainWindow::writeFatFiles(const std::string& savePath)
|
|||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeRomPadding(const std::string& savePath)
|
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 startAddr = extractPackerHeaderTableData(NDSHeaderNames::UsedRomSize).toUInt(nullptr, 16);
|
||||||
uint32_t size = static_cast<uint32_t>(ndsFactory.getCardSizeInBytes(extractPackerHeaderTableData(NDSHeaderNames::CardSize).toInt())) - startAddr;
|
uint32_t size = static_cast<uint32_t>(ndsFactory.getCardSizeInBytes(extractPackerHeaderTableData(NDSHeaderNames::CardSize).toInt())) - startAddr;
|
||||||
@ -305,12 +301,12 @@ NFResult MainWindow::writeRomPadding(const std::string& savePath)
|
|||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::writeEverything(const std::string& savePath)
|
bool MainWindow::writeEverything(const std::string& savePath)
|
||||||
{
|
{
|
||||||
NFResult nfResult;
|
bool res = true;
|
||||||
char paddingType;
|
char paddingType;
|
||||||
bool isArm9FooterPresent = ndsFactory.checkArm9FooterPresence(ui->loadedArm9BinPathEdt->text().toStdString(),
|
bool isArm9FooterPresent = ndsFactory.checkArm9FooterPresence(ui->loadedArm9BinPathEdt->text().toStdString(),
|
||||||
extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16));
|
extractPackerHeaderTableData(NDSHeaderNames::ARM9Size).toUInt(nullptr, 16));
|
||||||
if (ui->packerPadType00RdBtn->isChecked())
|
if (ui->packerPadType00RdBtn->isChecked())
|
||||||
paddingType = static_cast<char>('\x00');
|
paddingType = static_cast<char>('\x00');
|
||||||
else
|
else
|
||||||
@ -318,49 +314,35 @@ NFResult MainWindow::writeEverything(const std::string& savePath)
|
|||||||
|
|
||||||
std::remove(savePath.c_str());
|
std::remove(savePath.c_str());
|
||||||
|
|
||||||
nfResult = writeHeader(savePath);
|
res &= writeHeader(savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeHeaderPadding(paddingType, savePath);
|
||||||
nfResult = writeHeaderPadding(paddingType, savePath);
|
res &= writeArm9Bin(savePath, isArm9FooterPresent);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeArm9BinPadding(paddingType, savePath, isArm9FooterPresent);
|
||||||
nfResult = writeArm9Bin(savePath, isArm9FooterPresent);
|
res &= writeArm7Bin(savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeArm7BinPadding(paddingType, savePath);
|
||||||
nfResult = writeArm9BinPadding(paddingType, savePath, isArm9FooterPresent);
|
res &= writeFnt(savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeFntPadding(paddingType, savePath);
|
||||||
if (extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) != 0)
|
res &= writeFat(savePath);
|
||||||
{
|
res &= writeFatPadding(paddingType, savePath);
|
||||||
nfResult = writeArm9Overlay(savePath);
|
if(extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) != 0) {
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeArm9Overlay(savePath);
|
||||||
nfResult = writeArm9OverlayFiles(savePath);
|
res &= writeArm9OverlayPadding(paddingType, savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeArm9OverlayFiles(savePath);
|
||||||
|
res &= writeArm9OverlayFilesPadding(paddingType, savePath);
|
||||||
}
|
}
|
||||||
nfResult = writeArm7Bin(savePath);
|
if(extractPackerHeaderTableData(NDSHeaderNames::ARM9OverlayAddress).toUInt(nullptr, 16) != 0) {
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeArm7Overlay(savePath);
|
||||||
nfResult = writeArm7BinPadding(paddingType, savePath);
|
res &= writeArm7OverlayPadding(paddingType, savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeArm7OverlayFiles(savePath);
|
||||||
if (extractPackerHeaderTableData(NDSHeaderNames::ARM7OverlayAddress).toUInt(nullptr, 16) != 0) {
|
res &= writeArm7OverlayFilesPadding(paddingType, savePath);
|
||||||
nfResult = writeArm7Overlay(savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = writeArm7OverlayFiles(savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
}
|
}
|
||||||
nfResult = writeFnt(savePath);
|
res &= writeIconTitle(savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
res &= writeFatFiles(savePath);
|
||||||
nfResult = writeFntPadding(paddingType, savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = writeFat(savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = writeFatPadding(paddingType, savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = writeIconTitle(savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = writeFatFiles(savePath);
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
if(!ui->packerTrimRomsCbx->isChecked())
|
if(!ui->packerTrimRomsCbx->isChecked())
|
||||||
{
|
{
|
||||||
nfResult = writeRomPadding(savePath);
|
res &= writeRomPadding(savePath);
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
}
|
}
|
||||||
return { true, "" };
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MainWindow::extractPackerHeaderTableData(int index)
|
QString MainWindow::extractPackerHeaderTableData(int index)
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include "./../../mainwindow.h"
|
#include "./../../mainwindow.h"
|
||||||
#include "./../../ui_mainwindow.h"
|
#include "./../../ui_mainwindow.h"
|
||||||
#include "./../../utils/filepicker.h"
|
|
||||||
#include "../commons/headernames.h"
|
#include "../commons/headernames.h"
|
||||||
|
|
||||||
|
|
||||||
@ -16,9 +15,13 @@ void MainWindow::on_packerLoadHeaderBtn_clicked()
|
|||||||
QDir::currentPath(),
|
QDir::currentPath(),
|
||||||
"NDS Header (*.bin)");
|
"NDS Header (*.bin)");
|
||||||
|
|
||||||
if (headerPath.isNull()) return;
|
if(headerPath.isNull())
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, tr("NDS Factory"), tr("Unable to open file!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ndsFactory.loadRomHeader(headerPath.toStdString(), romHeader).result)
|
if (ndsFactory.loadRomHeader(headerPath.toStdString(), romHeader))
|
||||||
{
|
{
|
||||||
pNDSHeader = reinterpret_cast<NDSHeader*>(romHeader.data());
|
pNDSHeader = reinterpret_cast<NDSHeader*>(romHeader.data());
|
||||||
populatePackerSectionHeader(pNDSHeader);
|
populatePackerSectionHeader(pNDSHeader);
|
||||||
@ -32,7 +35,7 @@ void MainWindow::on_packerLoadArm9BinBtn_clicked()
|
|||||||
QString arm9BinPath = QFileDialog::getOpenFileName(
|
QString arm9BinPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Arm9Bin",
|
"NDS Arm9Bin",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS Arm9Bin (*.bin)");
|
"NDS Arm9Bin (*.bin)");
|
||||||
|
|
||||||
if(!arm9BinPath.isNull())
|
if(!arm9BinPath.isNull())
|
||||||
@ -46,7 +49,7 @@ void MainWindow::on_packerLoadArm7BinBtn_clicked()
|
|||||||
QString arm7BinPath = QFileDialog::getOpenFileName(
|
QString arm7BinPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Arm7Bin",
|
"NDS Arm7Bin",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS Arm7Bin (*.bin)");
|
"NDS Arm7Bin (*.bin)");
|
||||||
|
|
||||||
if(!arm7BinPath.isNull())
|
if(!arm7BinPath.isNull())
|
||||||
@ -60,7 +63,7 @@ void MainWindow::on_packerLoadFntBtn_clicked()
|
|||||||
QString fntPath = QFileDialog::getOpenFileName(
|
QString fntPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Fnt",
|
"NDS Fnt",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS Fnt (*.bin)");
|
"NDS Fnt (*.bin)");
|
||||||
|
|
||||||
if(!fntPath.isNull())
|
if(!fntPath.isNull())
|
||||||
@ -74,7 +77,7 @@ void MainWindow::on_packerLoadFatBtn_clicked()
|
|||||||
QString fatPath = QFileDialog::getOpenFileName(
|
QString fatPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Fat",
|
"NDS Fat",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS Fat (*.bin)");
|
"NDS Fat (*.bin)");
|
||||||
|
|
||||||
if(!fatPath.isNull())
|
if(!fatPath.isNull())
|
||||||
@ -88,7 +91,7 @@ void MainWindow::on_packerLoadArm9OverlayBtn_clicked()
|
|||||||
QString arm9OverlayPath = QFileDialog::getOpenFileName(
|
QString arm9OverlayPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Arm9Overlay",
|
"NDS Arm9Overlay",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS A9OVR (*.bin)");
|
"NDS A9OVR (*.bin)");
|
||||||
|
|
||||||
if( !arm9OverlayPath.isNull() )
|
if( !arm9OverlayPath.isNull() )
|
||||||
@ -102,7 +105,7 @@ void MainWindow::on_packerLoadArm9OverlayFilesBtn_clicked()
|
|||||||
QString arm9OverlayFilesPath = QFileDialog::getOpenFileName(
|
QString arm9OverlayFilesPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Arm9Overlay Data",
|
"NDS Arm9Overlay Data",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS A9OVR_DATA (*.bin)");
|
"NDS A9OVR_DATA (*.bin)");
|
||||||
|
|
||||||
if(!arm9OverlayFilesPath.isNull())
|
if(!arm9OverlayFilesPath.isNull())
|
||||||
@ -116,7 +119,7 @@ void MainWindow::on_packerLoadArm7OverlayBtn_clicked()
|
|||||||
QString arm7OverlayPath = QFileDialog::getOpenFileName(
|
QString arm7OverlayPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Arm7Overlay",
|
"NDS Arm7Overlay",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS A7OVR (*.bin)");
|
"NDS A7OVR (*.bin)");
|
||||||
|
|
||||||
if(!arm7OverlayPath.isNull())
|
if(!arm7OverlayPath.isNull())
|
||||||
@ -130,7 +133,7 @@ void MainWindow::on_packerLoadArm7OverlayFilesBtn_clicked()
|
|||||||
QString arm7OverlayFilesPath = QFileDialog::getOpenFileName(
|
QString arm7OverlayFilesPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Arm7Overlay Data",
|
"NDS Arm7Overlay Data",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS A7OVR_DATA (*.bin)");
|
"NDS A7OVR_DATA (*.bin)");
|
||||||
|
|
||||||
if(!arm7OverlayFilesPath.isNull())
|
if(!arm7OverlayFilesPath.isNull())
|
||||||
@ -144,7 +147,7 @@ void MainWindow::on_packerLoadIconTitleBtn_clicked()
|
|||||||
QString iconTitlePath = QFileDialog::getOpenFileName(
|
QString iconTitlePath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS IconTitleLogo",
|
"NDS IconTitleLogo",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS ITL (*.bin)");
|
"NDS ITL (*.bin)");
|
||||||
|
|
||||||
if(!iconTitlePath.isNull())
|
if(!iconTitlePath.isNull())
|
||||||
@ -158,7 +161,7 @@ void MainWindow::on_packerLoadFatFilesBtn_clicked()
|
|||||||
QString fatFilesPath = QFileDialog::getOpenFileName(
|
QString fatFilesPath = QFileDialog::getOpenFileName(
|
||||||
Q_NULLPTR,
|
Q_NULLPTR,
|
||||||
"NDS Fat Data",
|
"NDS Fat Data",
|
||||||
"",
|
QDir::currentPath(),
|
||||||
"NDS FAT_DATA (*.bin)");
|
"NDS FAT_DATA (*.bin)");
|
||||||
|
|
||||||
if(!fatFilesPath.isNull())
|
if(!fatFilesPath.isNull())
|
||||||
@ -169,19 +172,17 @@ void MainWindow::on_packerLoadFatFilesBtn_clicked()
|
|||||||
|
|
||||||
void MainWindow::on_packerBuildNDSRomBtn_clicked()
|
void MainWindow::on_packerBuildNDSRomBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->packerBuildNDSRomBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
QString dirPath = customSaveFileDialog("NDS Rom",
|
"NDS Rom",
|
||||||
"rom.nds",
|
"rom.nds",
|
||||||
"NDS ROM (*.nds)");
|
"NDS ROM (*.nds)");
|
||||||
|
|
||||||
if (!dirPath.isNull())
|
if (!dirPath.isNull())
|
||||||
{
|
{
|
||||||
NFResult nfResult = writeEverything(dirPath.toStdString());
|
writeEverything(dirPath.toStdString()) ? QMessageBox::information(this, tr("NDS Factory"), tr("Creation completed!"))
|
||||||
nfResult.result? QMessageBox::information(this, tr("NDSFactory"), tr("Creation completed!"))
|
: QMessageBox::critical(this, tr("NDS Factory"), tr("Error during the creation!"));
|
||||||
: QMessageBox::critical(this, tr("NDSFactory"), nfResult.message.c_str());
|
|
||||||
}
|
}
|
||||||
ui->packerBuildNDSRomBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_packerCalcHeaderCrcBtn_clicked()
|
void MainWindow::on_packerCalcHeaderCrcBtn_clicked()
|
||||||
|
@ -8,6 +8,18 @@
|
|||||||
#include "../../models/ndsheadermodel.h"
|
#include "../../models/ndsheadermodel.h"
|
||||||
#include "../../../ndsfactory/fatstruct.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
|
// Size constants
|
||||||
#define ICON_TITLE_SIZE 0xA00
|
#define ICON_TITLE_SIZE 0xA00
|
||||||
|
|
||||||
@ -23,26 +35,14 @@ void MainWindow::enableExtractionButtons()
|
|||||||
{
|
{
|
||||||
ui->unpackerExtractorGbx->setEnabled(true);
|
ui->unpackerExtractorGbx->setEnabled(true);
|
||||||
ui->unpackerExtraGbx->setEnabled(true);
|
ui->unpackerExtraGbx->setEnabled(true);
|
||||||
if (ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16) == 0)
|
if (ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16) == 0){
|
||||||
{
|
|
||||||
ui->unpackerDumpArm9OverlayBtn->setEnabled(false);
|
ui->unpackerDumpArm9OverlayBtn->setEnabled(false);
|
||||||
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(false);
|
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(false);
|
||||||
}
|
}
|
||||||
else
|
if (ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16) == 0){
|
||||||
{
|
|
||||||
ui->unpackerDumpArm9OverlayBtn->setEnabled(true);
|
|
||||||
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(true);
|
|
||||||
}
|
|
||||||
if (ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16) == 0)
|
|
||||||
{
|
|
||||||
ui->unpackerDumpArm7OverlayBtn->setEnabled(false);
|
ui->unpackerDumpArm7OverlayBtn->setEnabled(false);
|
||||||
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(false);
|
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(false);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ui->unpackerDumpArm7OverlayBtn->setEnabled(true);
|
|
||||||
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::disableExtractionButtons()
|
void MainWindow::disableExtractionButtons()
|
||||||
@ -51,7 +51,7 @@ void MainWindow::disableExtractionButtons()
|
|||||||
ui->unpackerExtraGbx->setEnabled(false);
|
ui->unpackerExtraGbx->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpHeader(const std::string& dirPath)
|
bool MainWindow::dumpHeader(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -60,7 +60,7 @@ NFResult MainWindow::dumpHeader(const std::string& dirPath)
|
|||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::HeaderSize, 1).data().toString().toUInt(nullptr,16));
|
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::HeaderSize, 1).data().toString().toUInt(nullptr,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes)
|
bool MainWindow::dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes)
|
||||||
{
|
{
|
||||||
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9Size, 1).data().toString().toUInt(nullptr,16);
|
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9Size, 1).data().toString().toUInt(nullptr,16);
|
||||||
if (dumpExtraBytes)
|
if (dumpExtraBytes)
|
||||||
@ -72,7 +72,7 @@ NFResult MainWindow::dumpArm9Bin(const std::string& dirPath, bool dumpExtraBytes
|
|||||||
size);
|
size);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpArm7Bin(const std::string& dirPath)
|
bool MainWindow::dumpArm7Bin(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -81,7 +81,7 @@ NFResult MainWindow::dumpArm7Bin(const std::string& dirPath)
|
|||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7Size, 1).data().toString().toUInt(nullptr,16));
|
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7Size, 1).data().toString().toUInt(nullptr,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpFnt(const std::string& dirPath)
|
bool MainWindow::dumpFnt(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -90,7 +90,7 @@ NFResult MainWindow::dumpFnt(const std::string& dirPath)
|
|||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableSize, 1).data().toString().toUInt(nullptr,16));
|
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableSize, 1).data().toString().toUInt(nullptr,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpFat(const std::string& dirPath)
|
bool MainWindow::dumpFat(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -99,7 +99,7 @@ NFResult MainWindow::dumpFat(const std::string& dirPath)
|
|||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FATSize, 1).data().toString().toUInt(nullptr,16));
|
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FATSize, 1).data().toString().toUInt(nullptr,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpArm9Overlay(const std::string& dirPath)
|
bool MainWindow::dumpArm9Overlay(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -108,20 +108,12 @@ NFResult MainWindow::dumpArm9Overlay(const std::string& dirPath)
|
|||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlaySize, 1).data().toString().toUInt(nullptr,16));
|
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlaySize, 1).data().toString().toUInt(nullptr,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpArm9OverlayFiles(const std::string& dirPath)
|
bool MainWindow::dumpArm9OverlayFiles([[maybe_unused]] const std::string& dirPath)
|
||||||
{
|
{
|
||||||
uint32_t startAddr = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr, 16) +
|
return false; // TODO: implement me!
|
||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlaySize, 1).data().toString().toUInt(nullptr, 16);
|
|
||||||
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7RomAddress, 1).data().toString().toUInt(nullptr, 16) - startAddr;
|
|
||||||
|
|
||||||
return ndsFactory.dumpDataFromFile(
|
|
||||||
ui->loadedRomPath->text().toStdString(),
|
|
||||||
dirPath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpArm7Overlay(const std::string& dirPath)
|
bool MainWindow::dumpArm7Overlay(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -130,20 +122,12 @@ NFResult MainWindow::dumpArm7Overlay(const std::string& dirPath)
|
|||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlaySize, 1).data().toString().toUInt(nullptr,16));
|
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlaySize, 1).data().toString().toUInt(nullptr,16));
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpArm7OverlayFiles(const std::string& dirPath)
|
bool MainWindow::dumpArm7OverlayFiles([[maybe_unused]] const std::string& dirPath)
|
||||||
{
|
{
|
||||||
uint32_t startAddr = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr, 16) +
|
return false; // TODO: implement me!
|
||||||
ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlaySize, 1).data().toString().toUInt(nullptr, 16);
|
|
||||||
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::FilenameTableAddress, 1).data().toString().toUInt(nullptr, 16) - startAddr;
|
|
||||||
|
|
||||||
return ndsFactory.dumpDataFromFile(
|
|
||||||
ui->loadedRomPath->text().toStdString(),
|
|
||||||
dirPath,
|
|
||||||
startAddr,
|
|
||||||
size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpIconTitle(const std::string& dirPath)
|
bool MainWindow::dumpIconTitle(const std::string& dirPath)
|
||||||
{
|
{
|
||||||
return ndsFactory.dumpDataFromFile(
|
return ndsFactory.dumpDataFromFile(
|
||||||
ui->loadedRomPath->text().toStdString(),
|
ui->loadedRomPath->text().toStdString(),
|
||||||
@ -152,7 +136,7 @@ NFResult MainWindow::dumpIconTitle(const std::string& dirPath)
|
|||||||
ICON_TITLE_SIZE);
|
ICON_TITLE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
NFResult MainWindow::dumpFatFiles(const std::string& dirPath)
|
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 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;
|
uint32_t size = ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::UsedRomSize, 1).data().toString().toUInt(nullptr,16) - startAddr;
|
||||||
@ -165,34 +149,170 @@ NFResult MainWindow::dumpFatFiles(const std::string& dirPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NFResult MainWindow::dumpEverything(QString dirPath)
|
bool MainWindow::dumpEverything(QString dirPath)
|
||||||
{
|
{
|
||||||
NFResult nfResult;
|
bool result = true;
|
||||||
nfResult = dumpHeader(QDir::toNativeSeparators(dirPath + "/header.bin").toStdString());
|
result &= dumpHeader(QDir::toNativeSeparators(dirPath+"/header.bin").toStdString());
|
||||||
if (!nfResult.result) return nfResult;
|
result &= dumpArm9Bin(QDir::toNativeSeparators(dirPath+"/arm9.bin").toStdString(), true);
|
||||||
nfResult = dumpArm9Bin(QDir::toNativeSeparators(dirPath+"/arm9.bin").toStdString(), true);
|
result &= dumpArm7Bin(QDir::toNativeSeparators(dirPath+"/arm7.bin").toStdString());
|
||||||
if (!nfResult.result) return nfResult;
|
result &= dumpFnt(QDir::toNativeSeparators(dirPath+"/fnt.bin").toStdString());
|
||||||
nfResult = dumpArm7Bin(QDir::toNativeSeparators(dirPath+"/arm7.bin").toStdString());
|
result &= dumpFat(QDir::toNativeSeparators(dirPath+"/fat.bin").toStdString());
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = dumpFnt(QDir::toNativeSeparators(dirPath+"/fnt.bin").toStdString());
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
nfResult = dumpFat(QDir::toNativeSeparators(dirPath+"/fat.bin").toStdString());
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
if(ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16) != 0) {
|
if(ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM9OverlayAddress, 1).data().toString().toUInt(nullptr,16) != 0) {
|
||||||
nfResult = dumpArm9Overlay(QDir::toNativeSeparators(dirPath+"/a9ovr.bin").toStdString());
|
result &= dumpArm9Overlay(QDir::toNativeSeparators(dirPath+"/a9ovr.bin").toStdString());
|
||||||
if (!nfResult.result) return nfResult;
|
result &= dumpArm9OverlayFiles(QDir::toNativeSeparators(dirPath+"/a9ovr_data.bin").toStdString());
|
||||||
nfResult = dumpArm9OverlayFiles(QDir::toNativeSeparators(dirPath+"/a9ovr_data.bin").toStdString());
|
|
||||||
if (!nfResult.result) return nfResult;
|
|
||||||
}
|
}
|
||||||
if(ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16) != 0) {
|
if(ui->unpackerHeaderDataTable->model()->index(NDSHeaderNames::ARM7OverlayAddress, 1).data().toString().toUInt(nullptr,16) != 0) {
|
||||||
nfResult = dumpArm7Overlay(QDir::toNativeSeparators(dirPath+"/a7ovr.bin").toStdString());
|
result &= dumpArm7Overlay(QDir::toNativeSeparators(dirPath+"/a7ovr.bin").toStdString());
|
||||||
if (!nfResult.result) return nfResult;
|
result &= dumpArm7OverlayFiles(QDir::toNativeSeparators(dirPath+"/a7ovr_data.bin").toStdString());
|
||||||
nfResult = dumpArm7OverlayFiles(QDir::toNativeSeparators(dirPath+"/a7ovr_data.bin").toStdString());
|
}
|
||||||
if (!nfResult.result) return nfResult;
|
result &= dumpIconTitle(QDir::toNativeSeparators(dirPath+"/itl.bin").toStdString());
|
||||||
}
|
result &= dumpFatFiles(QDir::toNativeSeparators(dirPath+"/fat_data.bin").toStdString());
|
||||||
nfResult = dumpIconTitle(QDir::toNativeSeparators(dirPath+"/itl.bin").toStdString());
|
return result;
|
||||||
if (!nfResult.result) return nfResult;
|
}
|
||||||
nfResult = dumpFatFiles(QDir::toNativeSeparators(dirPath+"/fat_data.bin").toStdString());
|
|
||||||
if (!nfResult.result) return nfResult;
|
bool MainWindow::decodeFatFiles(QString dirPath)
|
||||||
return { true, "" };
|
{
|
||||||
|
// 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);
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include "./../../mainwindow.h"
|
#include "./../../mainwindow.h"
|
||||||
#include "./../../ui_mainwindow.h"
|
#include "./../../ui_mainwindow.h"
|
||||||
#include "./../../utils/filepicker.h"
|
|
||||||
#include "./../../utils/ui.h"
|
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::on_loadRomBtn_clicked()
|
void MainWindow::on_loadRomBtn_clicked()
|
||||||
@ -17,11 +15,12 @@ void MainWindow::on_loadRomBtn_clicked()
|
|||||||
QDir::currentPath(),
|
QDir::currentPath(),
|
||||||
"NDS Rom (*.nds)");
|
"NDS Rom (*.nds)");
|
||||||
|
|
||||||
if (romPath.isNull()) return;
|
if( !romPath.isNull() )
|
||||||
|
{
|
||||||
|
ui->loadedRomPath->setText(romPath.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
ui->loadedRomPath->setText(romPath.toUtf8());
|
if (ndsFactory.loadRomHeader(ui->loadedRomPath->text().toStdString(), romHeader))
|
||||||
|
|
||||||
if (ndsFactory.loadRomHeader(ui->loadedRomPath->text().toStdString(), romHeader).result)
|
|
||||||
{
|
{
|
||||||
pNDSHeader = reinterpret_cast<NDSHeader*>(romHeader.data());
|
pNDSHeader = reinterpret_cast<NDSHeader*>(romHeader.data());
|
||||||
populateHeader(pNDSHeader);
|
populateHeader(pNDSHeader);
|
||||||
@ -35,135 +34,132 @@ void MainWindow::on_loadRomBtn_clicked()
|
|||||||
|
|
||||||
void MainWindow::on_unpackerDumpHeaderBtn_clicked()
|
void MainWindow::on_unpackerDumpHeaderBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpHeaderBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS Header",
|
||||||
|
"header.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS Header", "header.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpHeader(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpHeader(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpHeaderBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpArm9Btn_clicked()
|
void MainWindow::on_unpackerDumpArm9Btn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpArm9Btn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
QString dirPath = customSaveFileDialog("NDS ARM9", "arm9.bin", "Binary (*.bin)");
|
"NDS ARM9",
|
||||||
|
"arm9.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QMessageBox::StandardButton dumpExtraBytes = QMessageBox::question(
|
QMessageBox::StandardButton dumpExtraBytes = QMessageBox::question(
|
||||||
this,
|
this,
|
||||||
"NDSFactory",
|
"NDS Factory",
|
||||||
"Do you want to dump the extra 12 bytes? (click yes if you want a 1:1 arm9 dump)",
|
"Do you want to dump the extra 12 bytes? (click yes if you want a 1:1 arm9 dump)",
|
||||||
QMessageBox::Yes|QMessageBox::No);
|
QMessageBox::Yes|QMessageBox::No);
|
||||||
|
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpArm9Bin(dirPath.toStdString(), dumpExtraBytes == QMessageBox::Yes ? true : false));
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpArm9Bin(dirPath.toStdString(), dumpExtraBytes == QMessageBox::Yes ? true : false));
|
||||||
ui->unpackerDumpArm9Btn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpArm7Btn_clicked()
|
void MainWindow::on_unpackerDumpArm7Btn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpArm7Btn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS ARM7",
|
||||||
|
"arm7.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS ARM7", "arm7.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpArm7Bin(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpArm7Bin(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpArm7Btn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpFntBtn_clicked()
|
void MainWindow::on_unpackerDumpFntBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpFntBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS FNT",
|
||||||
|
"fnt.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS FNT", "fnt.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpFnt(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpFnt(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpFntBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpFatBtn_clicked()
|
void MainWindow::on_unpackerDumpFatBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpFatBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS FAT",
|
||||||
|
"fat.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS FAT", "fat.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpFat(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpFat(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpFatBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked()
|
void MainWindow::on_unpackerDumpArm9OverlayBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpArm9OverlayBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS ARM9 Overlay",
|
||||||
|
"a9ovr.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS ARM9 Overlay", "a9ovr.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpArm9Overlay(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpArm9Overlay(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpArm9OverlayBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked()
|
void MainWindow::on_unpackerDumpArm7OverlayBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpArm7OverlayBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS ARM7 Overlay",
|
||||||
|
"a7ovr.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS ARM7 Overlay", "a7ovr.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpArm7Overlay(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpArm7Overlay(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpArm7OverlayBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked()
|
void MainWindow::on_unpackerDumpIconTitleLogoBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpIconTitleLogoBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS IconTitleLogo",
|
||||||
|
"itl.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS IconTitleLogo", "itl.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpIconTitle(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpIconTitle(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpIconTitleLogoBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpFatFilesBtn_clicked()
|
void MainWindow::on_unpackerDumpFatFilesBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpFatFilesBtn->setEnabled(false);
|
QString dirPath = QFileDialog::getSaveFileName(
|
||||||
|
Q_NULLPTR,
|
||||||
|
"NDS FAT Files",
|
||||||
|
"fat_data.bin",
|
||||||
|
"Binary (*.bin)");
|
||||||
|
|
||||||
QString dirPath = customSaveFileDialog("NDS FAT Files", "fat_data.bin", "Binary (*.bin)");
|
if (!dirPath.isNull())
|
||||||
|
notifyExtractionResult(dumpFatFiles(dirPath.toStdString()));
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpFatFiles(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpFatFilesBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpArm9OverlayFilesBtn_clicked()
|
void MainWindow::on_unpackerDumpArm9OverlayFilesBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(false);
|
QMessageBox::warning(this, tr("NDS Factory"), tr("This function is currently not implemented!"));
|
||||||
|
//dumpArm9OverlayFiles()
|
||||||
QString dirPath = customSaveFileDialog("NDS ARM9 Overlay Data", "a9ovr_data.bin", "Binary (*.bin)");
|
|
||||||
|
|
||||||
if (!dirPath.isNull()) notifyExtractionResult(dumpArm9OverlayFiles(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpArm9OverlayFilesBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpArm7OverlayFilesBtn_clicked()
|
void MainWindow::on_unpackerDumpArm7OverlayFilesBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(false);
|
QMessageBox::warning(this, tr("NDS Factory"), tr("This function is currently not implemented!"));
|
||||||
|
//dumpArm7OverlayFiles()
|
||||||
QString dirPath = customSaveFileDialog("NDS ARM7 Overlay Data", "a7ovr_data.bin", "Binary (*.bin)");
|
|
||||||
|
|
||||||
if (!dirPath.isNull())
|
|
||||||
notifyExtractionResult(dumpArm7OverlayFiles(dirPath.toStdString()));
|
|
||||||
|
|
||||||
ui->unpackerDumpArm7OverlayFilesBtn->setEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_unpackerDumpEverythingBtn_clicked()
|
void MainWindow::on_unpackerDumpEverythingBtn_clicked()
|
||||||
{
|
{
|
||||||
ui->unpackerDumpEverythingBtn->setEnabled(false);
|
|
||||||
QString dirPath = QFileDialog::getExistingDirectory(
|
QString dirPath = QFileDialog::getExistingDirectory(
|
||||||
this, tr("Select Directory"),
|
this, tr("Select Directory"),
|
||||||
"",
|
"",
|
||||||
@ -171,5 +167,27 @@ void MainWindow::on_unpackerDumpEverythingBtn_clicked()
|
|||||||
|
|
||||||
if (!dirPath.isNull())
|
if (!dirPath.isNull())
|
||||||
notifyExtractionResult(dumpEverything(dirPath));
|
notifyExtractionResult(dumpEverything(dirPath));
|
||||||
ui->unpackerDumpEverythingBtn->setEnabled(true);
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_unpackerDecodeFatFilesBtn_clicked()
|
||||||
|
{
|
||||||
|
QString dirPath = QFileDialog::getExistingDirectory(
|
||||||
|
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!"));
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,20 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QFileDialog>
|
|
||||||
|
|
||||||
inline QString customSaveFileDialog(const QString& title, const QString& defaultName, const QString& filter)
|
|
||||||
{
|
|
||||||
|
|
||||||
static QString lastUsedPath;
|
|
||||||
|
|
||||||
QString selectedPath = QFileDialog::getSaveFileName(
|
|
||||||
Q_NULLPTR,
|
|
||||||
title,
|
|
||||||
lastUsedPath + defaultName,
|
|
||||||
filter);
|
|
||||||
|
|
||||||
if (!selectedPath.isNull())
|
|
||||||
lastUsedPath = selectedPath.mid(0, selectedPath.lastIndexOf('/', Qt::CaseInsensitive)+1);
|
|
||||||
|
|
||||||
return selectedPath;
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QPalette>
|
|
||||||
#include <QSettings>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
inline void setDarkTheme(QApplication& app)
|
|
||||||
{
|
|
||||||
QPalette darkPalette;
|
|
||||||
darkPalette.setColor(QPalette::Window, QColor(53, 53, 53));
|
|
||||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
|
||||||
darkPalette.setColor(QPalette::Base, QColor(35, 35, 35));
|
|
||||||
darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
|
|
||||||
darkPalette.setColor(QPalette::ToolTipBase, Qt::white);
|
|
||||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
|
||||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
|
||||||
darkPalette.setColor(QPalette::Button, QColor(53, 53, 53));
|
|
||||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
|
||||||
darkPalette.setColor(QPalette::BrightText, Qt::red);
|
|
||||||
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
|
|
||||||
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
|
|
||||||
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
|
|
||||||
|
|
||||||
app.setPalette(darkPalette);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setLightTheme(QApplication& app)
|
|
||||||
{
|
|
||||||
QPalette lightPalette;
|
|
||||||
lightPalette.setColor(QPalette::Window, QColor(240, 240, 240));
|
|
||||||
lightPalette.setColor(QPalette::WindowText, Qt::black);
|
|
||||||
lightPalette.setColor(QPalette::Base, QColor(255, 255, 255));
|
|
||||||
lightPalette.setColor(QPalette::AlternateBase, QColor(233, 233, 233));
|
|
||||||
lightPalette.setColor(QPalette::ToolTipBase, Qt::black);
|
|
||||||
lightPalette.setColor(QPalette::ToolTipText, Qt::white);
|
|
||||||
lightPalette.setColor(QPalette::Text, Qt::black);
|
|
||||||
lightPalette.setColor(QPalette::Button, QColor(240, 240, 240));
|
|
||||||
lightPalette.setColor(QPalette::ButtonText, Qt::black);
|
|
||||||
lightPalette.setColor(QPalette::BrightText, Qt::red);
|
|
||||||
lightPalette.setColor(QPalette::Link, QColor(42, 130, 218));
|
|
||||||
lightPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
|
|
||||||
lightPalette.setColor(QPalette::HighlightedText, Qt::white);
|
|
||||||
|
|
||||||
app.setPalette(lightPalette);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setTheme(QString themeValue)
|
|
||||||
{
|
|
||||||
QSettings settings;
|
|
||||||
settings.setValue("theme", themeValue);
|
|
||||||
QMessageBox::information(nullptr, "NDSFactory", "Restart NDSFactory to change theme!");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QString getCurrentTheme()
|
|
||||||
{
|
|
||||||
QSettings settings;
|
|
||||||
return settings.value("theme", "default").toString();
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include "../../ndsfactory/nfresult.h"
|
|
||||||
|
|
||||||
void notifyExtractionResult(NFResult nfResult)
|
|
||||||
{
|
|
||||||
if (nfResult.result)
|
|
||||||
{
|
|
||||||
QMessageBox::information(Q_NULLPTR, "NDSFactory", "Extraction completed!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QMessageBox::critical(Q_NULLPTR, "NDSFactory", nfResult.message.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user