Correct readme, update few icons, add freedesktop entry and svg icon. Could be useful for packagers.
continuous-integration/drone/push Build is failing Details

master
Dmitry Isaenko 2022-12-23 07:08:22 +03:00
parent 8b23b8967b
commit 55df39923f
32 changed files with 2433 additions and 205 deletions

View File

@ -17,6 +17,7 @@ steps:
commands:
- mkdir -p /builds/ns-usbloader
- cp target/ns-usbloader-*jar /builds/ns-usbloader/
- cp target/ns-usbloader-*exe /builds/ns-usbloader/
volumes:
- name: builds
path: /builds
@ -27,6 +28,7 @@ steps:
- . ./.make_legacy
- mvn -B -DskipTests clean package
- cp target/ns-usbloader-*jar /builds/ns-usbloader/
- cp target/ns-usbloader-*exe /builds/ns-usbloader/
volumes:
- name: m2
path: /root/.m2

View File

@ -1,2 +1,3 @@
sed -z -i -e 's/<groupId>org.usb4java<\/groupId>\n\s*<artifactId>usb4java<\/artifactId>\s*<version>1.3.0<\/version>/<groupId>org.usb4java<\/groupId>\n<artifactId>usb4java<\/artifactId>\n<version>1.2.0<\/version>/g' pom.xml
sed -z -i -e 's/<finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}<\/finalName>/<finalName>${project.artifactId}-${project.version}-legacy-${maven.build.timestamp}<\/finalName>/g' pom.xml
sed -z -i -e 's/<outfile>target\/NS-USBloader-${project.version}-${maven.build.timestamp}.exe<\/outfile>/<outfile>target\/NS-USBloader-${project.version}-legacy-${maven.build.timestamp}.exe<\/outfile>/g' pom.xml

View File

@ -1,9 +1,9 @@
# NS-USBloader
<h1 align="center"><img src="screenshots/ApplicationLogo.svg" alt="NS-USBloader" width="450px"/></h1>
![License](https://img.shields.io/badge/License-GPLv3-blue.svg) ![Releases](https://img.shields.io/github/downloads/developersu/ns-usbloader/total.svg) ![LatestVer](https://img.shields.io/github/release/developersu/ns-usbloader.svg) [![Build Status](https://ci.redrise.ru/api/badges/desu/ns-usbloader/status.svg)](https://ci.redrise.ru/desu/ns-usbloader)
NS-USBloader is:
* A PC-side installer for **[Huntereb/Awoo-Installer](https://github.com/Huntereb/Awoo-Installer)** / other compatible installers (USB and Network supported) and **[XorTroll/GoldLeaf](https://github.com/XorTroll/Goldleaf)** (USB) NSP installer.
* A PC-side installer for **[Huntereb/Awoo-Installer](https://github.com/Huntereb/Awoo-Installer)** / other compatible installers (USB and Network supported) and **[XorTroll/Goldleaf](https://github.com/XorTroll/Goldleaf)** (USB) NSP installer.
Alternative to default **usb_install_pc.py**, **remote_install_pc.py**, **GoldTree**/**Quark**.
* RCM payload tool that works on Windows, macOS (Intel and Apple Silicon) and Linux (x86, amd64 and Raspberry Pi ARM).
* It's a tool for creating split files!
@ -59,14 +59,16 @@ Sometimes I add new posts about this project [on my blog page](https://developer
* Japanese by [kuragehime](https://github.com/kuragehimekurara1)
* Ryukyuan languages by [kuragehime](https://github.com/kuragehimekurara1)
* angelodalzotto makes packages in AUR
### System requirements
JRE/JDK 8u60 or higher for Windows
JDK 11 for MacOS and Linux
### Supported GoldLeaf versions
| GoldLeaf version | NS-USBloader version |
### Supported Goldleaf versions
| Goldleaf version | NS-USBloader version |
|------------------|----------------------|
| v0.5 | v0.4 - v0.5.2, v0.8+ |
| v0.6 | none |
@ -136,7 +138,7 @@ Set 'Security & Privacy' settings if needed.
#### And how to use it?
The first thing you should do it install Awoo ([Huntereb](https://github.com/Huntereb/Awoo-Installer)) or GoldLeaf ([XorTroll](https://github.com/XorTroll/Goldleaf)) on your NS.
The first thing you should do it install Awoo ([Huntereb](https://github.com/Huntereb/Awoo-Installer)) or Goldleaf ([XorTroll](https://github.com/XorTroll/Goldleaf)) on your NS.
Take a look on app, find where is the option to install from USB and/or Network. Maybe (very old) [this article (about TinFoil)](https://developersu.blogspot.com/2019/02/ns-usbloader-en.html) will be helpful.
@ -146,19 +148,19 @@ There are three tabs. First one is main.
##### 'Gamepad' tab.
At the top of you selecting from drop-down application and protocol that you're going to use. For GoldLeaf only USB is available. Lamp icon stands for switching themes (light or dark).
At the top of you selecting from drop-down application and protocol that you're going to use. For Goldleaf only USB is available. Lamp icon stands for switching themes (light or dark).
Then you may drag-n-drop files (split-files aka folders) to application or use 'Select NSP files' button. Multiple selection for files available. Click it again and select files from another folder it you want, it will be added into the table.
Table.
There you can select checkbox for files that will be sent to application (AW/GL). ~~Since GoldLeaf v0.5 allow you only one file transmission per time, only one file is available for selection.~~
There you can select checkbox for files that will be sent to application (AW/GL). ~~Since Goldleaf v0.5 allow you only one file transmission per time, only one file is available for selection.~~
Also you can use space to select/un-select files and 'delete' button for deleting. By right-mouse-click you can see context menu where you can delete one OR all items from the table.
For GoldLeaf v0.6.1 and NS-USBloader v0.6 (and higher) you will have to use 'Explore content' -> 'Remote PC (via USB)' You will see two drives HOME:/ and VIRT:/. First drive is pointing to your home directory. Second one is reflection of what you've added to table (first application tab). Also VIRT:/ drive have limited functionality in comparison to HOME:/. E.g. you can't write files to this drive since it's not a drive. But don't worry, it won't make any impact on GoldLeaf or your NS if you try.
For Goldleaf v0.6.1 and NS-USBloader v0.6 (and higher) you will have to use 'Explore content' -> 'Remote PC (via USB)' You will see two drives HOME:/ and VIRT:/. First drive is pointing to your home directory. Second one is reflection of what you've added to table (first application tab). Also VIRT:/ drive have limited functionality in comparison to HOME:/. E.g. you can't write files to this drive since it's not a drive. But don't worry, it won't make any impact on Goldleaf or your NS if you try.
Also, for GoldLeaf write files (from NS to PC): You have to 'Stop execution' properly before accessing files transferred from GL. Usually you have to wait 5sec or less. It will guarantee that your files properly written to PC.
Also, for Goldleaf write files (from NS to PC): You have to 'Stop execution' properly before accessing files transferred from GL. Usually you have to wait 5sec or less. It will guarantee that your files properly written to PC.
##### 'RCM' tab
@ -174,7 +176,7 @@ Here you can configure settings for network file transmission. Usually you shoul
Also here you can:
* Set 'Auto-check for updates' for checking for updates when application starts, or click button to verify if new version released immediately.
* Set 'Show only *.nsp in GoldLeaf' to filter all files displayed at HOME:/ drive. So only NSP files will appear.
* Set 'Show only *.nsp in Goldleaf' to filter all files displayed at HOME:/ drive. So only NSP files will appear.
##### 'Dialog with three dots' tab.
@ -187,7 +189,7 @@ To get help run ``$ java -jar ns-usbloader-4.0.jar --help``
```
-c,--clean Remove/reset settings and exit
-g,--goldleaf <...> Install via GoldLeaf mode. Check '-g help' for information.
-g,--Goldleaf <...> Install via Goldleaf mode. Check '-g help' for information.
-h,--help Show this help
-m,--merge <...> Merge files. Check '-m help' for information.
-n,--tfn <...> Install via Awoo Network mode. Check '-n help' for information.
@ -218,7 +220,7 @@ Send RCM payload:
$ java -jar ns-usbloader-4.0.jar -r C:\Users\Superhero\hekate.bin
Send files to Awoo Installer via Net-install:
$ java -jar ns-usbloader-4.0.jar -n nsip=192.168.0.1 ./file.nsz ./file.nsp ~/*.xci
Send files to GoldLeaf v0.8:
Send files to Goldleaf v0.8:
$ java -jar ns-usbloader-4.0.jar -g ver=v0.8 ./*
Split files:
$ java -jar ns-usbloader-4.0.jar -s /tmp/ ~/*.nsp
@ -229,7 +231,7 @@ $ java -jar ns-usbloader-4.0.jar -m /tmp/ ~/*.nsp
### Other notes
'Status' = 'Uploaded' that appears in the table does not mean that file has been installed. It means that it has been sent to NS without any issues! That's what this app about.
Handling successful/failed installation is a purpose of the other side application: Awoo/Awoo-like or GoldLeaf. And they don't provide any feedback interfaces so I can't detect success/failure.
Handling successful/failed installation is a purpose of the other side application: Awoo/Awoo-like or Goldleaf. And they don't provide any feedback interfaces so I can't detect success/failure.
#### What is this '-legacy' jar?!

View File

@ -0,0 +1,9 @@
#!/usr/bin/env xdg-open
[Desktop Entry]
Type=Application
Name=NS-USBloader
Exec=ns-usbloader
Comment=NS multi tool
Terminal=false
Icon=ns-usbloader.svg
Categories=Game;

View File

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="45mm"
height="45mm"
viewBox="0 0 45.000001 45"
version="1.1"
id="svg8"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
sodipodi:docname="ns-usbloader.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="5.6568543"
inkscape:cx="206.82873"
inkscape:cy="90.421279"
inkscape:document-units="mm"
inkscape:current-layer="svg8"
showgrid="false"
units="mm"
inkscape:window-width="3754"
inkscape:window-height="2127"
inkscape:window-x="1166"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:document-rotation="0"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid829"
originx="-40.993993"
originy="-37.999754" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="g851"
inkscape:label="mainGRP"
transform="translate(-40.993968,-26.999903)">
<path
id="path847"
transform="scale(0.26458333)"
d="m 188.97656,102.04688 c -18.97637,0 -34.01562,18.70089 -34.01562,30.23632 -0.0219,42.2441 -0.0386,69.16374 0,109.60742 0,11.85827 15.03925,30.23633 34.01562,30.23633 h 48.94141 V 102.04688 Z"
style="fill:#00c8fc;fill-opacity:1;stroke-width:1"
inkscape:connector-curvature="0"
inkscape:label="con" />
<path
id="rect823"
d="m 64.973294,26.999903 v 45 h 21.02 v -45 z"
style="fill:#ec0000;fill-opacity:1;stroke-width:0.116442"
inkscape:connector-curvature="0"
inkscape:label="big" />
</g>
<path
id="path862"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.392613"
d="m 11.547015,28.4105 a 2.1593723,2.1593723 0 0 0 -2.2000565,2.117691 2.1593723,2.1593723 0 0 0 2.1176905,2.200059 2.1593723,2.1593723 0 0 0 2.200555,-2.1167 2.1593723,2.1593723 0 0 0 -2.1167,-2.20105 l -0.04267,2.158874 z m 3.840427,-3.937182 a 2.1593723,2.1593723 0 0 0 -2.199561,2.117693 2.1593723,2.1593723 0 0 0 2.117195,2.200057 2.1593723,2.1593723 0 0 0 2.200555,-2.117195 2.1593723,2.1593723 0 0 0 -2.1167,-2.200555 l -0.04217,2.158876 z m -7.6809635,0 a 2.1593722,2.1593722 0 0 0 -2.200057,2.117693 2.1593722,2.1593722 0 0 0 2.117691,2.200057 2.1593722,2.1593722 0 0 0 2.200554,-2.117195 2.1593722,2.1593722 0 0 0 -2.117195,-2.200555 l -0.04218,2.158876 z m 3.8405365,-3.938173 a 2.1593723,2.1593723 0 0 0 -2.2000565,2.117691 2.1593723,2.1593723 0 0 0 2.1176905,2.200059 2.1593723,2.1593723 0 0 0 2.200555,-2.1167 2.1593723,2.1593723 0 0 0 -2.1167,-2.20105 l -0.04267,2.158874 z"
inkscape:label="small_c"
inkscape:connector-curvature="0" />
<g
inkscape:label="slogan"
id="layer1"
transform="translate(-40.993968,-213.9999)"
inkscape:groupmode="layer">
<g
aria-label="everywhere"
transform="matrix(0.26458333,0,0,0.26458333,-24.077084,181.70833)"
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:35.0667px;line-height:1.25;font-family:Raleway;-inkscape-font-specification:'Raleway, Light';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
id="flowRoot1022"
inkscape:label="flowRoot1022"
inkscape:groupmode="layer" />
</g>
<path
id="path853"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.272727"
d="m 11.506852,6.300096 a 4.5000001,4.5000001 0 0 1 4.49918,4.500616 4.5000001,4.5000001 0 0 1 -4.500411,4.499384 4.5000001,4.5000001 0 0 1 -4.4995895,-4.500205 4.5000001,4.5000001 0 0 1 4.5000005,-4.499795"
inkscape:label="big_c"
inkscape:connector-curvature="0" />
<path
id="path1334"
d="m 35.091899,7.050931 -1.966235,3.404775 h 1.402615 v 17.402765 l -3.579993,-3.388515 c -0.231149,-0.288377 -0.393301,-0.665687 -0.402284,-1.053816 0,-1.570143 -3.97e-4,-2.502567 -9.76e-4,-2.845788 0.662828,-0.232646 1.141253,-0.857572 1.141253,-1.600489 0,-0.939842 -0.76265,-1.702559 -1.702831,-1.702559 -0.940589,0 -1.702967,0.76265 -1.702967,1.702559 0,0.742917 0.478154,1.367843 1.140438,1.600489 l -4.76e-4,2.812447 c 0,0.762241 0.418205,1.560957 0.90847,2.069322 -0.01456,-0.01388 -0.03007,-0.02831 2.83e-4,8.15e-4 0.01211,0.01075 3.797875,3.595101 3.797875,3.595101 0.230809,0.287762 0.39194,0.664868 0.401196,1.052727 v 1.968677 c -1.30057,0.260954 -2.28042,1.409421 -2.28042,2.787065 0,1.570687 1.273194,2.843881 2.843405,2.843881 1.570686,0 2.843946,-1.273194 2.843946,-2.843881 0,-1.377917 -0.980663,-2.526381 -2.282303,-2.787335 v -1.934186 c 0,-0.005 2.59e-4,-0.0099 0,-0.01498 v -4.278078 c 0.0098,-0.38711 0.171203,-0.763741 0.402285,-1.051231 0,0 3.785488,-3.583532 3.797733,-3.594625 0.03043,-0.02872 0.01454,-0.01444 2.59e-4,-2.58e-4 0.490197,-0.508364 0.908134,-1.307418 0.908134,-2.069798 l -3.97e-4,-2.710376 h 1.141588 v -3.405646 h -3.405338 v 3.405663 h 1.140097 c 0,0 -0.0012,0.713861 -0.0012,2.743583 -0.0089,0.388196 -0.170862,0.765917 -0.402012,1.054155 l -3.580815,3.389238 V 10.455706 h 1.404858 z"
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke-width:0.0680452"
inkscape:label="usb_logo" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.264583"
d="m 21.967046,0 c -0.0065,-1.9994448e-6 -0.01188,0.0054 -0.01188,0.01188 v 44.976581 c 0,0.0065 0.0054,0.01188 0.01188,0.01188 h 2.000395 c 0.0065,0 0.01188,-0.0054 0.01188,-0.01188 V 0.011885 c 0,-0.0065 -0.0054,-0.011879999445 -0.01188,-0.011879999445 z"
id="rect1136"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssssssc" />
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

78
pom.xml
View File

@ -12,7 +12,7 @@
<url>https://redrise.ru</url>
<description>
NS multi-tool
NS multi tool
</description>
<inceptionYear>2019</inceptionYear>
<organization>
@ -61,28 +61,28 @@
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
@ -90,28 +90,28 @@
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
@ -119,31 +119,60 @@
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>18.0.1</version>
<version>19</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19</version>
<classifier>mac-aarch64</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>19</version>
<classifier>mac-aarch64</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>19</version>
<classifier>mac-aarch64</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>19</version>
<classifier>mac-aarch64</classifier>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.usb4java/usb4java -->
<dependency>
<groupId>org.usb4java</groupId>
@ -170,6 +199,13 @@
<version>5.9.0</version>
<scope>test</scope>
</dependency>
<!-- picked from local repo -->
<dependency>
<groupId>ru.redrise</groupId>
<artifactId>libKonogonka</artifactId>
<version>0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}-${project.version}-${maven.build.timestamp}</finalName>
@ -243,10 +279,10 @@
</execution>
</executions>
</plugin>
<!-- Launch4j
<plugin>
<!-- https://mvnrepository.com/artifact/com.akathist.maven.plugins.launch4j/launch4j-maven-plugin -->
<groupId>com.akathist.maven.plugins.launch4j</groupId>
<version>1.7.25</version>
<version>2.2.0</version>
<artifactId>launch4j-maven-plugin</artifactId>
<executions>
<execution>
@ -258,8 +294,8 @@
<configuration>
<headerType>gui</headerType>
<icon>appicon.ico</icon>
<outfile>target/NS-USBloader-${project.version}.exe</outfile>
<jar>target/ns-usbloader-${project.version}-jar-with-dependencies.jar</jar>
<outfile>target/NS-USBloader-${project.version}-${maven.build.timestamp}.exe</outfile>
<jar>target/${project.artifactId}-${project.version}-${maven.build.timestamp}.jar</jar>
<errTitle>NS-USBloader</errTitle>
<classPath>
<mainClass>nsusbloader.Main</mainClass>
@ -267,13 +303,14 @@
<preCp>anything</preCp>
</classPath>
<jre>
<minVersion>1.8</minVersion>
<minVersion>1.8.0</minVersion>
<path>%JAVA_HOME%;%PATH%</path>
</jre>
<versionInfo>
<fileVersion>1.0.0.0</fileVersion>
<txtFileVersion>${project.version}</txtFileVersion>
<fileDescription>Awoo and GoldLeaf installer for your NS</fileDescription>
<copyright>GNU General Public License v3, 2019 ${project.organization.name}. Russia/LPR.</copyright>
<fileDescription>NS multi tool</fileDescription>
<copyright>GNU General Public License v3, 2019 ${project.organization.name}, Russia.</copyright>
<productVersion>1.0.0.0</productVersion>
<txtProductVersion>${project.version}</txtProductVersion>
<companyName>${project.organization.name}</companyName>
@ -285,7 +322,6 @@
</execution>
</executions>
</plugin>
-->
</plugins>
</build>
</project>

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="132.50603mm"
height="58.000351mm"
viewBox="0 0 132.50603 58.000351"
height="45.000351mm"
viewBox="0 0 132.50603 45.000351"
version="1.1"
id="svg8"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="Application Logo.svg">
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
sodipodi:docname="Application Logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<sodipodi:namedview
@ -23,28 +23,31 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="383.67648"
inkscape:cy="100.29922"
inkscape:zoom="4.0000001"
inkscape:cx="233.49999"
inkscape:cy="127.875"
inkscape:document-units="mm"
inkscape:current-layer="svg8"
inkscape:current-layer="flowRoot1022"
showgrid="false"
units="mm"
inkscape:window-width="1860"
inkscape:window-height="1058"
inkscape:window-x="1980"
inkscape:window-width="3754"
inkscape:window-height="2127"
inkscape:window-x="1166"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:document-rotation="0">
inkscape:document-rotation="0"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid829"
originx="-40.993969"
originy="-37.999746" />
originx="-40.99399"
originy="-37.999752" />
</sodipodi:namedview>
<metadata
id="metadata5">
@ -54,7 +57,6 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
@ -114,145 +116,65 @@
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke-width:0.0680452"
inkscape:label="usb_logo" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.43163px;line-height:1.25;font-family:Play;-inkscape-font-specification:'Play, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.357908"
x="47.959785"
y="17.188828"
id="text982"
<g
aria-label="NS-USBloader"
transform="scale(0.97866107,1.0218042)"
inkscape:label="ns-usbloader"><tspan
sodipodi:role="line"
id="tspan980"
x="47.959785"
y="17.188828"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3619px;font-family:Play;-inkscape-font-specification:'Play, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;stroke-width:0.357908">NS-USBloader</tspan></text>
id="text982"
style="font-size:1.43163px;line-height:1.25;font-family:Play;-inkscape-font-specification:'Play, Normal';letter-spacing:0px;word-spacing:0px;fill:#ffffff;stroke-width:0.357908"
inkscape:label="ns-usbloader">
<path
d="M 56.49804,17.188828 H 54.934697 L 50.217947,9.9065918 V 17.188828 H 49.082185 V 8.5169542 h 1.563342 l 4.716751,7.1619788 V 8.5169542 h 1.135762 z"
style="font-size:13.3619px"
id="path880" />
<path
d="m 64.488451,14.249209 v 0.62801 q 0,1.389637 -0.788353,1.924113 -0.788352,0.521115 -2.458589,0.521115 -1.068952,0 -2.645656,-0.213791 v -1.082314 q 1.576704,0.334048 2.725827,0.334048 0.921971,0 1.403,-0.200429 0.49439,-0.21379 0.49439,-0.8418 v -1.122399 q 0,-0.547838 -0.320686,-0.77499 -0.307323,-0.240515 -1.122399,-0.240515 H 60.76048 q -1.309466,0 -1.83058,-0.521114 -0.507752,-0.534476 -0.507752,-1.563342 v -0.694819 q 0,-1.0288662 0.721542,-1.5232565 0.734905,-0.4943903 2.685742,-0.4943903 0.935333,0 2.231438,0.1469809 v 0.9754187 q -1.483171,-0.2271523 -2.324971,-0.2271523 -1.242657,0 -1.656876,0.2538761 -0.400857,0.2405142 -0.400857,0.8284374 v 0.988781 q 0,0.454305 0.320686,0.668095 0.320686,0.200429 1.135762,0.200429 h 1.042228 q 1.349552,0 1.83058,0.49439 0.481029,0.481028 0.481029,1.536618 z"
style="font-size:13.3619px"
id="path882" />
<path
d="m 69.472442,13.848352 h -3.714608 v -0.962056 h 3.714608 z"
style="font-size:13.3619px"
id="path884" />
<path
d="m 77.903799,8.5169542 v 6.4537978 q 0,2.351695 -3.393923,2.351695 -0.681456,0 -1.215932,-0.09353 -0.534476,-0.08017 -1.055591,-0.307323 -0.521114,-0.240515 -0.815076,-0.734905 -0.293961,-0.49439 -0.293961,-1.215933 V 8.5169542 h 1.242656 V 14.95739 q 0,0.855162 0.574562,1.175847 0.574562,0.320686 1.590066,0.320686 1.015505,0 1.563343,-0.320686 0.561199,-0.320685 0.561199,-1.175847 V 8.5169542 Z"
style="font-size:13.3619px"
id="path886" />
<path
d="m 85.907587,14.249209 v 0.62801 q 0,1.389637 -0.788352,1.924113 -0.788353,0.521115 -2.45859,0.521115 -1.068952,0 -2.645656,-0.213791 v -1.082314 q 1.576704,0.334048 2.725827,0.334048 0.921971,0 1.403,-0.200429 0.49439,-0.21379 0.49439,-0.8418 v -1.122399 q 0,-0.547838 -0.320686,-0.77499 -0.307323,-0.240515 -1.122399,-0.240515 h -1.015505 q -1.309466,0 -1.83058,-0.521114 -0.507752,-0.534476 -0.507752,-1.563342 v -0.694819 q 0,-1.0288662 0.721542,-1.5232565 0.734905,-0.4943903 2.685742,-0.4943903 0.935333,0 2.231438,0.1469809 v 0.9754187 q -1.483171,-0.2271523 -2.324971,-0.2271523 -1.242657,0 -1.656875,0.2538761 -0.400857,0.2405142 -0.400857,0.8284374 v 0.988781 q 0,0.454305 0.320685,0.668095 0.320686,0.200429 1.135762,0.200429 h 1.042228 q 1.349552,0 1.83058,0.49439 0.481029,0.481028 0.481029,1.536618 z"
style="font-size:13.3619px"
id="path888" />
<path
d="m 94.031625,14.008695 v 1.456447 q 0,0.948695 -0.721543,1.33619 -0.721542,0.387496 -2.351694,0.387496 H 87.764894 V 8.5169542 h 3.099961 q 1.122399,0 1.750409,0.2271523 0.641371,0.2271523 0.828437,0.5611998 0.200429,0.3340475 0.200429,0.8551617 v 1.162485 q 0,0.534476 -0.307324,0.815076 -0.293962,0.2806 -0.881885,0.414219 v 0.05345 q 0.694819,0.120257 1.135761,0.481028 0.440943,0.360771 0.440943,0.921971 z m -1.603428,-2.725827 v -1.015505 q 0,-0.4943902 -0.360771,-0.6948187 -0.360772,-0.2004285 -1.202571,-0.2004285 h -1.803857 v 2.9396182 h 1.843942 q 0.828438,0 1.175848,-0.240514 0.347409,-0.253876 0.347409,-0.788352 z m 0.307324,4.128827 v -1.309466 q 0,-0.34741 -0.146981,-0.547838 -0.133619,-0.213791 -0.440943,-0.293962 -0.293962,-0.09353 -0.534476,-0.106895 -0.227152,-0.02672 -0.654733,-0.02672 h -1.89739 v 3.16677 h 1.89739 q 0.975419,0 1.376276,-0.200428 0.400857,-0.200429 0.400857,-0.681457 z"
style="font-size:13.3619px"
id="path890" />
<path
d="M 97.07815,17.188828 H 95.875579 V 7.8354973 h 1.202571 z"
style="font-size:13.3619px"
id="path892" />
<path
d="m 104.8815,12.899658 v 2.244799 q 0,0.601285 -0.14698,1.015504 -0.14698,0.414219 -0.37413,0.641371 -0.22715,0.227153 -0.65474,0.34741 -0.41421,0.120257 -0.80171,0.146981 -0.37413,0.02672 -1.00214,0.02672 -0.80172,0 -1.25602,-0.05345 -0.44094,-0.05345 -0.895248,-0.253876 -0.440942,-0.213791 -0.641371,-0.668095 -0.187067,-0.454305 -0.187067,-1.202571 v -2.244799 q 0,-0.641372 0.146981,-1.082314 0.160343,-0.440943 0.374134,-0.681457 0.227152,-0.240515 0.654731,-0.360772 0.42758,-0.133619 0.78835,-0.160342 0.37414,-0.02672 1.01551,-0.02672 0.64137,0 1.00214,0.02672 0.37413,0.02672 0.80171,0.160342 0.42759,0.120257 0.64138,0.360772 0.22715,0.240514 0.37413,0.681457 0.16034,0.440942 0.16034,1.082314 z m -1.22929,2.418503 v -2.618932 q 0,-0.895247 -0.36077,-1.109038 -0.36078,-0.21379 -1.38964,-0.21379 -1.02887,0 -1.38964,0.21379 -0.36077,0.213791 -0.36077,1.109038 v 2.618932 q 0,0.427581 0.0935,0.681457 0.0935,0.253876 0.34741,0.374134 0.25388,0.106895 0.52112,0.133619 0.26723,0.02672 0.78835,0.02672 0.52111,0 0.78835,-0.02672 0.26724,-0.02672 0.52111,-0.133619 0.25388,-0.120258 0.34741,-0.374134 0.0935,-0.253876 0.0935,-0.681457 z"
style="font-size:13.3619px"
id="path894" />
<path
d="m 111.85643,17.188828 h -1.16249 V 16.57418 q -0.14698,0.748267 -1.95084,0.748267 -1.33619,0 -1.8573,-0.400857 -0.50775,-0.414219 -0.50775,-1.656876 0,-1.082314 0.48103,-1.483171 0.48103,-0.414219 1.8573,-0.414219 h 1.93748 v -1.028866 q 0,-0.534476 -0.33405,-0.721543 -0.32069,-0.187067 -1.2293,-0.187067 -0.98878,0 -2.21807,0.160343 v -0.881885 q 1.32283,-0.120257 2.39178,-0.120257 1.63015,0 2.11118,0.400857 0.48103,0.387495 0.48103,1.630152 z m -1.20257,-1.309467 V 14.11559 h -1.85731 q -0.82844,0 -1.04223,0.213791 -0.20042,0.21379 -0.20042,0.975419 0,0.681456 0.21379,0.962056 0.22715,0.267238 0.93533,0.267238 h 0.24051 q 0.34741,0 0.57456,-0.01336 0.24052,-0.01336 0.53448,-0.06681 0.29396,-0.06681 0.44094,-0.200429 0.16035,-0.14698 0.16035,-0.374134 z"
style="font-size:13.3619px"
id="path896" />
<path
d="m 119.59297,17.188828 h -1.17585 v -0.761629 q 0,0.34741 -0.58792,0.62801 -0.57456,0.267238 -1.5767,0.267238 -1.403,0 -1.97757,-0.440943 -0.57456,-0.440943 -0.57456,-1.61679 v -2.846085 q 0,-0.975419 0.60129,-1.402999 0.60128,-0.427581 2.01765,-0.427581 0.76162,0 1.40299,0.200428 0.65474,0.200429 0.6681,0.62801 h 0.0267 q -0.0267,-1.095676 -0.0267,-1.6435142 V 7.8354973 h 1.20257 z m -1.20257,-1.696962 v -3.193494 q 0,-0.868524 -1.77713,-0.868524 -1.06895,0 -1.403,0.160343 -0.32069,0.160343 -0.32069,0.708181 v 3.193494 q 0,0.547838 0.36077,0.77499 0.37414,0.227153 1.25602,0.227153 0.98878,0 1.42973,-0.227153 0.4543,-0.227152 0.4543,-0.77499 z"
style="font-size:13.3619px"
id="path898" />
<path
d="m 126.88855,14.222486 h -4.34261 v 0.975418 q 0,0.681457 0.48103,0.975419 0.48102,0.2806 1.42972,0.2806 0.92197,0 2.17799,-0.320686 v 0.921972 q -1.20257,0.267238 -2.33833,0.267238 -2.96635,0 -2.96635,-1.977562 v -2.552123 q 0,-1.189209 0.68146,-1.696961 0.68146,-0.507752 2.17799,-0.507752 1.403,0 2.04437,0.49439 0.65473,0.481028 0.65473,1.710323 z m -1.20257,-0.788352 v -1.015505 q 0,-0.587924 -0.36077,-0.801714 -0.36077,-0.227152 -1.20257,-0.227152 -0.80171,0 -1.18921,0.21379 -0.38749,0.213791 -0.38749,0.815076 v 1.015505 z"
style="font-size:13.3619px"
id="path900" />
<path
d="m 132.20659,11.616915 h -0.6681 q -0.82844,0 -1.22929,0.21379 -0.3875,0.213791 -0.3875,0.801715 v 4.556408 h -1.20257 v -6.46716 h 1.13576 v 1.05559 q 0,-0.467667 0.57456,-0.828438 0.58793,-0.360771 1.18921,-0.360771 h 0.58793 z"
style="font-size:13.3619px"
id="path902" />
</g>
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.264583"
d="m 21.967046,0 c -0.0065,-1.9994448e-6 -0.01188,0.0054 -0.01188,0.01188 v 44.976581 c 0,0.0065 0.0054,0.01188 0.01188,0.01188 h 2.000395 c 0.0065,0 0.01188,-0.0054 0.01188,-0.01188 V 0.011885 c 0,-0.0065 -0.0054,-0.011879999445 -0.01188,-0.011879999445 z"
id="rect1136"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csssssssc" />
<g
inkscape:label="CREATIVE_COMMONS_SHIELD"
transform="matrix(0.1713381,0,0,0.17131892,77.526533,36.479842)"
id="g287"
inkscape:export-filename="/mnt/hgfs/Bov/Documents/Work/2007/cc/identity/srr buttons/big/by-sa.png"
inkscape:export-xdpi="300.23013"
inkscape:export-ydpi="300.23013">
<path
id="path3817_2_"
nodetypes="ccccccc"
d="m 182.23532,75.39014 114.06396,0.20312 c 1.59375,0 3.01758,-0.23682 3.01758,3.18018 l -0.13965,37.56689 H 179.3569 V 78.63379 c 0,-1.68457 0.16309,-3.24365 2.87842,-3.24365 z"
style="fill:#aab2ab" />
<g
id="g5908_2_"
transform="matrix(0.872921,0,0,0.872921,50.12536,143.2144)">
<path
id="path5906_2_"
cx="296.35416"
ry="22.939548"
cy="264.3577"
type="arc"
rx="22.939548"
d="m 187.20944,-55.6792 c 0.006,8.68024 -7.02786,15.72095 -15.7081,15.72708 -8.68021,0.005 -15.72205,-7.02786 -15.72708,-15.70804 0,-0.0067 0,-0.01233 0,-0.01904 -0.005,-8.68134 7.02783,-15.72205 15.70807,-15.72711 8.68134,-0.0056 15.72208,7.02789 15.72711,15.70807 0,0.0056 0,0.01233 0,0.01904 z"
style="fill:#ffffff" />
<g
id="g5706_2_"
transform="translate(-289.6157,99.0653)">
<path
id="path5708_2_"
d="m 473.88455,-167.54724 c 3.48541,3.48596 5.22839,7.75391 5.22839,12.80273 0,5.04938 -1.7128,9.27148 -5.13834,12.66736 -3.63531,3.5766 -7.93179,5.36432 -12.88947,5.36432 -4.89777,0 -9.11987,-1.77261 -12.6651,-5.31955 -3.54584,-3.54581 -5.31845,-7.78299 -5.31845,-12.71213 0,-4.92859 1.77261,-9.19598 5.31845,-12.80273 3.4552,-3.48651 7.67725,-5.22894 12.6651,-5.22894 5.04829,0 9.31401,1.74243 12.79942,5.22894 z m -23.11798,2.34485 c -2.94675,2.97638 -4.41956,6.46289 -4.41956,10.46234 0,3.99835 1.45828,7.4552 4.37424,10.37067 2.91653,2.9165 6.38849,4.37476 10.41705,4.37476 4.02853,0 7.53018,-1.47281 10.50656,-4.41901 2.8259,-2.73584 4.23941,-6.17706 4.23941,-10.32642 0,-4.11804 -1.43646,-7.61292 -4.30768,-10.48474 -2.87064,-2.87067 -6.34988,-4.30652 -10.43829,-4.30652 -4.08837,0 -7.54638,1.44318 -10.37173,4.32892 z m 7.75449,8.70312 c -0.45032,-0.98163 -1.12433,-1.47223 -2.02325,-1.47223 -1.58914,0 -2.38342,1.06952 -2.38342,3.2085 0,2.13959 0.79428,3.20911 2.38342,3.20911 1.04938,0 1.79895,-0.5213 2.24866,-1.56512 l 2.20276,1.17303 c -1.04993,1.86548 -2.62506,2.79901 -4.72549,2.79901 -1.6199,0 -2.91763,-0.4967 -3.89206,-1.48956 -0.97607,-0.99341 -1.46274,-2.36273 -1.46274,-4.10797 0,-1.71558 0.50229,-3.07709 1.50748,-4.08563 1.00519,-1.00793 2.25705,-1.51251 3.75781,-1.51251 2.22012,0 3.80984,0.87488 4.77081,2.62286 z m 10.36334,0 c -0.45087,-0.98163 -1.11148,-1.47223 -1.98239,-1.47223 -1.62106,0 -2.43213,1.06952 -2.43213,3.2085 0,2.13959 0.81107,3.20911 2.43213,3.20911 1.05103,0 1.78717,-0.5213 2.20724,-1.56512 l 2.25201,1.17303 c -1.04825,1.86548 -2.62119,2.79901 -4.71768,2.79901 -1.61771,0 -2.91263,-0.4967 -3.88647,-1.48956 -0.97217,-0.99341 -1.45938,-2.36273 -1.45938,-4.10797 0,-1.71558 0.49448,-3.07709 1.48288,-4.08563 0.98782,-1.00793 2.24527,-1.51251 3.77347,-1.51251 2.21619,0 3.80368,0.87488 4.76132,2.62286 z" />
</g>
</g>
<path
d="M 297.29639,74.91064 H 181.06688 c -1.24658,0 -2.26074,1.01465 -2.26074,2.26123 v 39.49561 c 0,0.28174 0.22852,0.51074 0.51025,0.51074 h 119.73 c 0.28174,0 0.51074,-0.229 0.51074,-0.51074 v -39.4956 c 0,-1.24659 -1.01416,-2.26124 -2.26074,-2.26124 z m -116.22951,1.02149 h 116.22951 c 0.68359,0 1.23926,0.55615 1.23926,1.23975 0,0 0,15.91943 0,27.41846 H 215.4619 c -3.04492,5.50537 -8.91113,9.24365 -15.64355,9.24365 -6.73535,0 -12.6001,-3.73486 -15.64355,-9.24365 h -4.34814 c 0,-11.49902 0,-27.41846 0,-27.41846 -2e-5,-0.6836 0.55663,-1.23975 1.24022,-1.23975 z"
id="path294" />
<g
enable-background="new "
id="g296">
<path
d="m 265.60986,112.8833 c 0.0801,0.15576 0.1875,0.28174 0.32129,0.37842 0.13379,0.0962 0.29004,0.16797 0.46973,0.21436 0.18066,0.0469 0.36719,0.0703 0.55957,0.0703 0.12988,0 0.26953,-0.0107 0.41895,-0.0327 0.14844,-0.0215 0.28809,-0.064 0.41895,-0.12598 0.12988,-0.062 0.23926,-0.14795 0.3252,-0.25684 0.0879,-0.10889 0.13086,-0.24707 0.13086,-0.41553 0,-0.18018 -0.0576,-0.32617 -0.17285,-0.43848 -0.11426,-0.1123 -0.26562,-0.20508 -0.45215,-0.28027 -0.18555,-0.0742 -0.39746,-0.13965 -0.63281,-0.1958 -0.23633,-0.0562 -0.47559,-0.11816 -0.71777,-0.18701 -0.24902,-0.062 -0.49121,-0.13818 -0.72754,-0.22852 -0.23535,-0.0898 -0.44727,-0.20703 -0.63379,-0.3501 -0.18652,-0.14307 -0.33691,-0.32178 -0.45215,-0.53662 -0.11426,-0.21484 -0.17188,-0.47461 -0.17188,-0.7793 0,-0.34277 0.0732,-0.63965 0.21875,-0.8916 0.14648,-0.25195 0.33789,-0.46191 0.57422,-0.63037 0.23535,-0.16797 0.50293,-0.29248 0.80176,-0.37354 0.29785,-0.0806 0.59668,-0.12109 0.89453,-0.12109 0.34863,0 0.68262,0.0391 1.00293,0.11719 0.31934,0.0776 0.60449,0.2041 0.85254,0.37842 0.24902,0.17432 0.44629,0.39697 0.59277,0.66797 0.14551,0.271 0.21875,0.59961 0.21875,0.98535 h -1.42188 c -0.0127,-0.19922 -0.0547,-0.36426 -0.125,-0.49463 -0.0713,-0.13086 -0.16602,-0.2334 -0.2832,-0.30859 -0.11816,-0.0742 -0.25293,-0.12744 -0.4043,-0.1582 -0.15234,-0.0312 -0.31738,-0.0469 -0.49707,-0.0469 -0.11719,0 -0.23535,0.0127 -0.35254,0.0371 -0.11816,0.0254 -0.22461,0.0688 -0.32031,0.13086 -0.0967,0.0625 -0.17578,0.14014 -0.2373,0.2334 -0.0615,0.0937 -0.0928,0.21191 -0.0928,0.35498 0,0.13086 0.0244,0.23682 0.0742,0.31738 0.0498,0.0811 0.14844,0.15576 0.29395,0.22412 0.14551,0.0684 0.34766,0.13721 0.60547,0.20557 0.25781,0.0684 0.59473,0.15576 1.01172,0.26123 0.12402,0.0249 0.2959,0.0703 0.5166,0.13574 0.2207,0.0654 0.43945,0.16943 0.65723,0.3125 0.21777,0.14355 0.40527,0.33496 0.56445,0.57422 0.1582,0.23975 0.2373,0.54639 0.2373,0.91992 0,0.30518 -0.0596,0.58838 -0.17773,0.84961 -0.11816,0.26172 -0.29395,0.4873 -0.52734,0.67676 -0.2334,0.19043 -0.52246,0.33789 -0.86719,0.44385 -0.3457,0.10596 -0.74609,0.15869 -1.19922,0.15869 -0.36719,0 -0.72363,-0.0454 -1.06934,-0.13574 -0.34473,-0.0903 -0.65039,-0.23242 -0.91504,-0.42578 -0.26367,-0.19336 -0.47363,-0.43994 -0.62988,-0.73877 -0.15527,-0.29932 -0.22949,-0.65381 -0.22363,-1.06494 h 1.42188 c -3e-5,0.22412 0.04,0.41406 0.12106,0.56933 z"
id="path298"
style="fill:#ffffff" />
<path
d="m 273.8667,107.8667 2.49316,6.66406 h -1.52246 l -0.50391,-1.48438 h -2.49316 l -0.52246,1.48438 h -1.47461 l 2.52051,-6.66406 z m 0.084,4.08594 -0.83984,-2.44336 h -0.0186 l -0.86914,2.44336 z"
id="path300"
style="fill:#ffffff" />
</g>
<g
enable-background="new "
id="g302">
<path
d="m 239.17821,107.8667 c 0.31738,0 0.60742,0.0283 0.86914,0.084 0.26172,0.0561 0.48633,0.14795 0.67383,0.27539 0.18652,0.12744 0.33203,0.29688 0.43457,0.5083 0.10254,0.21142 0.1543,0.47266 0.1543,0.78369 0,0.33594 -0.0762,0.61523 -0.22949,0.83936 -0.15234,0.22412 -0.37891,0.40723 -0.67773,0.55029 0.41211,0.11816 0.71973,0.3252 0.92285,0.62109 0.20312,0.29589 0.30469,0.65234 0.30469,1.06934 0,0.33594 -0.0654,0.62695 -0.19629,0.87305 -0.13086,0.24561 -0.30762,0.44629 -0.52832,0.60205 -0.22168,0.15576 -0.47461,0.271 -0.75781,0.34521 -0.28418,0.0752 -0.5752,0.1123 -0.875,0.1123 h -3.23633 v -6.66406 h 3.14159 z m -0.1875,2.69531 c 0.26172,0 0.47656,-0.062 0.64551,-0.18604 0.16797,-0.12451 0.25195,-0.32568 0.25195,-0.60498 0,-0.15527 -0.0283,-0.28271 -0.084,-0.38184 -0.0566,-0.0996 -0.13086,-0.17676 -0.22461,-0.23291 -0.0937,-0.0557 -0.20117,-0.0947 -0.32227,-0.11621 -0.12207,-0.022 -0.24805,-0.0327 -0.37891,-0.0327 h -1.37305 v 1.55469 z m 0.0859,2.82813 c 0.14355,0 0.28027,-0.0137 0.41113,-0.042 0.13086,-0.0278 0.24707,-0.0747 0.34668,-0.13965 0.0996,-0.0654 0.17871,-0.1543 0.23828,-0.26611 0.0596,-0.11181 0.0889,-0.25488 0.0889,-0.4292 0,-0.3418 -0.0967,-0.58594 -0.29004,-0.73193 -0.19336,-0.14599 -0.44922,-0.21924 -0.7666,-0.21924 h -1.59961 v 1.82812 z"
id="path304"
style="fill:#ffffff" />
<path
d="m 241.88914,107.8667 h 1.64355 l 1.56055,2.63184 1.55078,-2.63184 h 1.63379 l -2.47363,4.10645 v 2.55762 h -1.46875 v -2.59473 z"
id="path306"
style="fill:#ffffff" />
</g>
<g
id="g6316_1_"
transform="matrix(0.624995,0,0,0.624995,391.2294,176.9332)">
<path
id="path6318_1_"
cx="475.97119"
ry="29.209877"
cy="252.08646"
type="arc"
rx="29.209877"
d="m -175.0083,-139.1153 c 0.006,9.4118 -7.61725,17.04779 -17.02982,17.05481 -9.41101,0.007 -17.047,-7.61725 -17.05481,-17.02979 0,-0.008 0,-0.0172 0,-0.025 -0.006,-9.41254 7.6188,-17.047 17.02982,-17.05481 9.41257,-0.007 17.04855,7.61804 17.05481,17.02985 0,0.009 0,0.0164 0,0.025 z"
style="fill:#ffffff" />
<g
id="g6320_1_"
transform="translate(-23.9521,-89.72962)">
<path
id="path6322_1_"
d="m -168.2204,-68.05536 c -5.17194,0 -9.54852,1.80469 -13.13135,5.41333 -3.67661,3.73444 -5.51413,8.1532 -5.51413,13.25635 0,5.10315 1.83752,9.49152 5.51413,13.1626 3.67502,3.67194 8.05316,5.50787 13.13135,5.50787 5.14066,0 9.59537,-1.85156 13.36728,-5.55475 3.55005,-3.51562 5.3266,-7.88831 5.3266,-13.11572 0,-5.22662 -1.8078,-9.64697 -5.42191,-13.25635 -3.61407,-3.60864 -8.03756,-5.41333 -13.27197,-5.41333 z m 0.0469,3.36017 c 4.23752,0 7.836,1.49298 10.79697,4.48053 2.98907,2.9563 4.48441,6.56567 4.48441,10.82898 0,4.29382 -1.46252,7.85712 -4.39224,10.68915 -3.08438,3.04926 -6.71411,4.57349 -10.88913,4.57349 -4.17505,0 -7.7735,-1.5094 -10.79541,-4.52661 -3.02188,-3.01953 -4.53284,-6.59692 -4.53284,-10.73602 0,-4.13831 1.52658,-7.74847 4.57971,-10.82898 2.92815,-2.98756 6.51098,-4.48054 10.74853,-4.48054 z" />
<path
id="path6324_1_"
d="m -176.49548,-52.02087 c 0.74377,-4.69769 4.05161,-7.20862 8.1954,-7.20862 5.96097,0 9.59225,4.32501 9.59225,10.09229 0,5.62738 -3.86411,9.99927 -9.686,9.99927 -4.00473,0 -7.58914,-2.46484 -8.24228,-7.30084 h 4.70319 c 0.14062,2.51099 1.77032,3.39459 4.09845,3.39459 2.65317,0 4.37817,-2.4649 4.37817,-6.23291 0,-3.95233 -1.49063,-6.04535 -4.28598,-6.04535 -2.04846,0 -3.8172,0.74457 -4.19064,3.30157 l 1.36874,-0.007 -3.70316,3.7016 -3.7016,-3.7016 z" />
</g>
</g>
<g
id="g313">
<circle
cx="242.56226"
cy="90.224609"
r="10.8064"
id="circle315"
style="fill:#ffffff" />
<g
id="g317">
<path
d="m 245.68994,87.09766 c 0,-0.4165 -0.33789,-0.75342 -0.75391,-0.75342 h -4.77246 c -0.41602,0 -0.75391,0.33691 -0.75391,0.75342 v 4.77295 h 1.33105 v 5.65234 h 3.61719 v -5.65234 h 1.33203 v -4.77295 z"
id="path319" />
<circle
cx="242.5498"
cy="84.083008"
r="1.63232"
id="circle321" />
</g>
<path
clip-rule="evenodd"
d="m 242.53467,78.31836 c -3.23145,0 -5.96826,1.12744 -8.20752,3.38379 -2.29785,2.33301 -3.44629,5.09521 -3.44629,8.28418 0,3.18897 1.14844,5.93213 3.44629,8.22705 2.29785,2.29443 5.03418,3.44189 8.20752,3.44189 3.21289,0 5.99805,-1.15674 8.35352,-3.47168 2.2207,-2.19678 3.33008,-4.92969 3.33008,-8.19727 0,-3.26758 -1.12891,-6.02881 -3.3877,-8.28418 -2.25879,-2.25634 -5.02442,-3.38378 -8.2959,-3.38378 z m 0.0293,2.09961 c 2.64844,0 4.89746,0.93359 6.74707,2.80078 1.87012,1.84717 2.80469,4.10352 2.80469,6.76758 0,2.68359 -0.91504,4.91113 -2.74609,6.68066 -1.92773,1.90576 -4.19629,2.8584 -6.80566,2.8584 -2.60937,0 -4.8584,-0.94287 -6.74658,-2.82959 -1.88965,-1.88623 -2.8335,-4.12256 -2.8335,-6.70947 0,-2.58643 0.9541,-4.84229 2.8623,-6.76758 1.83057,-1.86719 4.07031,-2.80078 6.71777,-2.80078 z"
id="path323"
style="fill-rule:evenodd" />
</g>
</g>
<text
inkscape:label="HeyMomLookAtMe"
inkscape:transform-center-y="-0.1984375"
inkscape:transform-center-x="-0.33072917"
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:2.82222px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="108.57767"
y="48.318489"
id="text921"><tspan
sodipodi:role="line"
x="108.57767"
y="48.318489"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.82222px;font-family:'Nunito Sans';-inkscape-font-specification:'Nunito Sans Bold';stroke-width:0.264583"
id="tspan923">Dmitry Isaenko</tspan></text>
</svg>

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -88,6 +88,8 @@ public class AppPreferences {
public String getHostIp(){ return preferences.get("HOSTIP", "0.0.0.0").replaceAll("(\\s)|(\t)", "");} // who the hell said 'paranoid'?
public void setHostIp(String ip){preferences.put("HOSTIP", ip);}
public void give(){preferences.putBoolean("man", true);}
public boolean take(){return preferences.getBoolean("man", false);}
public String getHostPort(){
String value = preferences.get("HOSTPORT", "6042");
if (!value.matches("^[0-9]{1,5}$"))
@ -138,4 +140,10 @@ public class AppPreferences {
public String getLastOpenedTab(){ return preferences.get("recent_tab", ""); }
public void setLastOpenedTab(String tabId){ preferences.put("recent_tab", tabId); }
// Patches
public String getKeysLocation(){ return preferences.get("keys", ""); }
public void setKeysLocation(String path){ preferences.put("keys", path); }
public String getPatchesSaveToLocation(){ return FilesHelper.getRealFolder(preferences.get("patches_saveto", System.getProperty("user.home"))); }
public void setPatchesSaveToLocation(String value){ preferences.put("patches_saveto", value); }
}

View File

@ -43,7 +43,7 @@ public class NSLMainController implements Initializable {
@FXML
private TabPane mainTabPane;
@FXML
private Tab GamesTabHolder, RCMTabHolder, SMTabHolder;
private Tab GamesTabHolder, RCMTabHolder, SMTabHolder, PatchesTabHolder;
@FXML
private GamesController GamesTabController;
@ -55,6 +55,8 @@ public class NSLMainController implements Initializable {
private RcmController RcmTabController;
@FXML
private NxdtController NXDTabController;
@FXML
private PatchesController PatchesTabController;
@Override
public void initialize(URL url, ResourceBundle rb) {
@ -71,7 +73,7 @@ public class NSLMainController implements Initializable {
if (AppPreferences.getInstance().getAutoCheckUpdates()){
checkForUpdates();
}
if (! AppPreferences.getInstance().take()) mainTabPane.getTabs().remove(3);
openLastOpenedTab();
}
private void checkForUpdates(){
@ -127,6 +129,8 @@ public class NSLMainController implements Initializable {
public RcmController getRcmCtrlr(){ return RcmTabController; }
public NxdtController getNXDTabController(){ return NXDTabController; }
public PatchesController getPatchesTabController(){ return PatchesTabController; }
/**
* Save preferences before exit
* */
@ -136,7 +140,7 @@ public class NSLMainController implements Initializable {
SplitMergeTabController.updatePreferencesOnExit(); // NOTE: This shit above should be re-written to similar pattern
RcmTabController.updatePreferencesOnExit();
NXDTabController.updatePreferencesOnExit();
PatchesTabController.updatePreferencesOnExit();
saveLastOpenedTab();
}
@ -152,6 +156,9 @@ public class NSLMainController implements Initializable {
case "SMTabHolder":
mainTabPane.getSelectionModel().select(SMTabHolder);
break;
case "PatchesTabHolder":
mainTabPane.getSelectionModel().select(PatchesTabHolder);
break;
}
}
private void saveLastOpenedTab(){

View File

@ -0,0 +1,225 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Controllers;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.input.DragEvent;
import javafx.scene.input.TransferMode;
import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import nsusbloader.AppPreferences;
import nsusbloader.FilesHelper;
import nsusbloader.MediatorControl;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.ServiceWindow;
import nsusbloader.Utilities.patches.es.EsPatchMaker;
// TODO: CLI SUPPORT
public class PatchesController implements Initializable {
@FXML
private VBox patchesToolPane;
@FXML
private Button selFwFolderBtn, selProdKeysBtn, makeEsBtn;
@FXML
private Label shortNameFirmwareLbl, locationFirmwareLbl, saveToLbl, shortNameKeysLbl, locationKeysLbl, statusLbl;
private Thread workThread;
private String previouslyOpenedPath;
private ResourceBundle resourceBundle;
private Region convertRegion;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
this.previouslyOpenedPath = System.getProperty("user.home");
String myRegexp;
if (File.separator.equals("/"))
myRegexp = "^.+/";
else
myRegexp = "^.+\\\\";
locationFirmwareLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
shortNameFirmwareLbl.setText(updatedText.replaceAll(myRegexp, "")));
locationKeysLbl.textProperty().addListener((observableValue, currentText, updatedText) ->
shortNameKeysLbl.setText(updatedText.replaceAll(myRegexp, "")));
convertRegion = new Region();
convertRegion.getStyleClass().add("regionCake");
makeEsBtn.setGraphic(convertRegion);
AppPreferences preferences = AppPreferences.getInstance();
String keysLocation = preferences.getKeysLocation();
File keysFile = new File(keysLocation);
if (keysFile.exists() && keysFile.isFile()) {
locationKeysLbl.setText(keysLocation);
}
saveToLbl.setText(preferences.getPatchesSaveToLocation());
//makeEsBtn.disableProperty().bind(Bindings.isEmpty(locationFirmwareLbl.textProperty()));
makeEsBtn.setOnAction(actionEvent -> makeEs());
}
/**
* Drag-n-drop support (dragOver consumer)
* */
@FXML
private void handleDragOver(DragEvent event){
if (event.getDragboard().hasFiles())
event.acceptTransferModes(TransferMode.ANY);
event.consume();
}
/**
* Drag-n-drop support (drop consumer)
* */
@FXML
private void handleDrop(DragEvent event){
List<File> filesDropped = event.getDragboard().getFiles();
for (File file : filesDropped){
if (file.isDirectory()) {
locationFirmwareLbl.setText(file.getAbsolutePath());
continue;
}
String fileName = file.getName().toLowerCase();
if ((fileName.endsWith(".dat")) ||
(fileName.endsWith(".keys") &&
! fileName.equals("dev.keys") &&
! fileName.equals("title.keys")))
locationKeysLbl.setText(file.getAbsolutePath());
}
event.setDropCompleted(true);
event.consume();
}
@FXML
private void selectFirmware(){
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setTitle(resourceBundle.getString("tabPatches_Lbl_Firmware"));
directoryChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
File firmware = directoryChooser.showDialog(patchesToolPane.getScene().getWindow());
if (firmware == null)
return;
locationFirmwareLbl.setText(firmware.getAbsolutePath());
}
@FXML
private void selectSaveTo(){
DirectoryChooser directoryChooser = new DirectoryChooser();
directoryChooser.setTitle(resourceBundle.getString("tabSplMrg_Btn_SelectFolder"));
directoryChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
File saveToDir = directoryChooser.showDialog(patchesToolPane.getScene().getWindow());
if (saveToDir == null)
return;
saveToLbl.setText(saveToDir.getAbsolutePath());
}
@FXML
private void selectProdKeys(){
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle(resourceBundle.getString("tabPatches_Lbl_Keys"));
fileChooser.setInitialDirectory(new File(FilesHelper.getRealFolder(previouslyOpenedPath)));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("keys", "*.dat", "*.keys"));
File keys = fileChooser.showOpenDialog(patchesToolPane.getScene().getWindow());
if (keys != null && keys.exists()) {
locationKeysLbl.setText(keys.getAbsolutePath());
}
}
private void makeEs(){
if (locationFirmwareLbl.getText().isEmpty() || locationKeysLbl.getText().isEmpty()){
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
resourceBundle.getString("tabPatches_ServiceWindowMessage"));
return;
}
if (workThread != null && workThread.isAlive())
return;
statusLbl.setText("");
if (MediatorControl.getInstance().getTransferActive()) {
ServiceWindow.getErrorNotification(resourceBundle.getString("windowTitleError"),
resourceBundle.getString("windowBodyPleaseStopOtherProcessFirst"));
return;
}
EsPatchMaker esPatchMaker = new EsPatchMaker(locationFirmwareLbl.getText(), locationKeysLbl.getText(),
saveToLbl.getText());
workThread = new Thread(esPatchMaker);
workThread.setDaemon(true);
workThread.start();
}
private void interruptProcessOfPatchMaking(){
if (workThread == null || ! workThread.isAlive())
return;
workThread.interrupt();
}
public void notifyThreadStarted(boolean isActive, EModule type) {
if (! type.equals(EModule.PATCHES)) {
patchesToolPane.setDisable(isActive);
return;
}
convertRegion.getStyleClass().clear();
if (isActive) {
MediatorControl.getInstance().getContoller().logArea.clear();
convertRegion.getStyleClass().add("regionStop");
makeEsBtn.setOnAction(e-> interruptProcessOfPatchMaking());
makeEsBtn.setText(resourceBundle.getString("btn_Stop"));
makeEsBtn.getStyleClass().remove("buttonUp");
makeEsBtn.getStyleClass().add("buttonStop");
}
else {
convertRegion.getStyleClass().add("regionCake");
makeEsBtn.setOnAction(actionEvent -> makeEs());
makeEsBtn.setText(resourceBundle.getString("tabPatches_Btn_MakeEs"));
makeEsBtn.getStyleClass().remove("buttonStop");
makeEsBtn.getStyleClass().add("buttonUp");
}
}
public void setOneLineStatus(boolean statusSuccess){
if (statusSuccess)
statusLbl.setText(resourceBundle.getString("done_txt"));
else
statusLbl.setText(resourceBundle.getString("failure_txt"));
}
void updatePreferencesOnExit(){
AppPreferences.getInstance().setPatchesSaveToLocation(saveToLbl.getText());
if (locationKeysLbl.getText().isEmpty())
return;
AppPreferences.getInstance().setKeysLocation(locationKeysLbl.getText());
}
}

View File

@ -40,11 +40,12 @@ public class MediatorControl {
}
public NSLMainController getContoller(){ return mainController; }
public GamesController getGamesController(){ return mainController.getGamesCtrlr(); };
public SettingsController getSettingsController(){ return mainController.getSettingsCtrlr(); };
public SplitMergeController getSplitMergeController(){ return mainController.getSmCtrlr(); };
public RcmController getRcmController(){ return mainController.getRcmCtrlr(); };
public NxdtController getNxdtController(){ return mainController.getNXDTabController(); };
public GamesController getGamesController(){ return mainController.getGamesCtrlr(); }
public SettingsController getSettingsController(){ return mainController.getSettingsCtrlr(); }
public SplitMergeController getSplitMergeController(){ return mainController.getSmCtrlr(); }
public RcmController getRcmController(){ return mainController.getRcmCtrlr(); }
public NxdtController getNxdtController(){ return mainController.getNXDTabController(); }
public PatchesController getPatchesController(){ return mainController.getPatchesTabController(); }
public ResourceBundle getResourceBundle(){
return mainController.getResourceBundle();
@ -56,6 +57,7 @@ public class MediatorControl {
getSplitMergeController().notifyThreadStarted(isActive, appModuleType);
getRcmController().notifyThreadStarted(isActive, appModuleType);
getNxdtController().notifyThreadStarted(isActive, appModuleType);
getPatchesController().notifyThreadStarted(isActive, appModuleType);
}
public synchronized boolean getTransferActive() { return this.isTransferActive.get(); }
}

View File

@ -112,6 +112,8 @@ public class MessagesConsumer extends AnimationTimer {
case SPLIT_MERGE_TOOL:
MediatorControl.getInstance().getSplitMergeController().setOneLineStatus(oneLinerStatus.get());
break;
case PATCHES:
MediatorControl.getInstance().getPatchesController().setOneLineStatus(oneLinerStatus.get());
}
this.stop();
}

View File

@ -22,5 +22,6 @@ public enum EModule {
USB_NET_TRANSFERS,
SPLIT_MERGE_TOOL,
RCM,
NXDT
NXDT,
PATCHES
}

View File

@ -28,6 +28,7 @@ import nsusbloader.Controllers.NSLMainController;
import nsusbloader.cli.CommandLineInterface;
import java.util.Locale;
import java.util.Objects;
import java.util.ResourceBundle;
public class NSLMain extends Application {
@ -47,10 +48,10 @@ public class NSLMain extends Application {
Parent root = loader.load();
primaryStage.getIcons().addAll(
new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")),
new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")),
new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")),
new Image(getClass().getResourceAsStream("/res/app_icon128x128.png"))
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon32x32.png"))),
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon48x48.png"))),
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon64x64.png"))),
new Image(Objects.requireNonNull(getClass().getResourceAsStream("/res/app_icon128x128.png")))
);
primaryStage.setTitle("NS-USBloader "+appVersion);

View File

@ -0,0 +1,526 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es;
import libKonogonka.Converter;
import nsusbloader.Main;
import nsusbloader.NSLMain;
public class BinToAsmPrinter {
static {
boolean notWindows = ! System.getProperty("os.name").toLowerCase().contains("windows");
if(notWindows && NSLMain.isCli){
ANSI_RESET = "\u001B[0m";
ANSI_GREEN = "\u001B[32m";
ANSI_BLUE = "\u001B[34m";
ANSI_YELLOW = "\u001B[33m";
ANSI_PURPLE = "\u001B[35m";
ANSI_CYAN = "\u001B[36m";
ANSI_RED = "\u001B[31m";
}
else {
ANSI_RESET = ANSI_RED = ANSI_GREEN = ANSI_BLUE = ANSI_YELLOW = ANSI_PURPLE = ANSI_CYAN = "";
}
}
private static final String ANSI_RESET;
private static final String ANSI_RED;
private static final String ANSI_GREEN;
private static final String ANSI_BLUE;
private static final String ANSI_YELLOW;
private static final String ANSI_PURPLE;
private static final String ANSI_CYAN;
public static String print(int instructionExpression, int offset){
if (instructionExpression == 0xd503201f)
return printNOP(instructionExpression);
if ((instructionExpression & 0x7FE0FFE0) == 0x2A0003E0) {
return printMOVRegister(instructionExpression);
}
switch ((instructionExpression >> 23 & 0b011111111)){
case 0xA5:
return printMOV(instructionExpression);
case 0x62:
if (((instructionExpression & 0x1f) == 0x1f)){
return printCMN(instructionExpression, offset);
}
}
switch (instructionExpression >> 24 & 0xff) {
case 0x34:
case 0xb4:
return printCBZ(instructionExpression, offset);
case 0xb5:
case 0x35:
return printCBNZ(instructionExpression, offset);
case 0x36:
case 0xb6:
return printTBZ(instructionExpression, offset);
case 0x54:
return printBConditional(instructionExpression, offset);
}
switch ((instructionExpression >> 26 & 0b111111)) {
case 0x5:
return printB(instructionExpression, offset);
case 0x25:
return printBL(instructionExpression, offset);
}
return printUnknown(instructionExpression);
}
public static String printSimplified(int instructionExpression, int offset){
if (instructionExpression == 0xd503201f)
return printNOPSimplified(instructionExpression, offset);
if ((instructionExpression & 0x7FE0FFE0) == 0x2A0003E0) {
return printMOVRegisterSimplified(instructionExpression, offset);
}
switch (instructionExpression >> 22 & 0b1011111111) {
case 0x2e5:
return printLRDImmUnsignSimplified(instructionExpression, offset);
case 0xe5:
return printLRDBImmUnsignSimplified(instructionExpression, offset);
}
if ((instructionExpression >> 21 & 0x7FF) == 0x1C2)
return printLDURBSimplified(instructionExpression, offset);
// same to (afterJumpExpression >> 23 & 0x1F9) != 0xA1
switch (instructionExpression >> 22 & 0x1FF){
case 0xA3: // 0b10100011
case 0xA7: // 0b10100111
case 0xA5: // 0b10100101
return printLDPSimplified(instructionExpression, offset);
}
switch ((instructionExpression >> 23 & 0xff)){
case 0xA5:
return printMOVSimplified(instructionExpression, offset);
case 0x22:
return printADDSimplified(instructionExpression, offset);
case 0x62:
if (((instructionExpression & 0x1f) == 0x1f)){
return printCMNSimplified(instructionExpression, offset);
}
case 0xA2:
return printSUBSimplified(instructionExpression, offset);
}
switch (instructionExpression >> 24 & 0xff) {
case 0x34:
case 0xb4:
return printCBZSimplified(instructionExpression, offset);
case 0xb5:
case 0x35:
return printCBNZSimplified(instructionExpression, offset);
case 0x36:
case 0xb6:
return printTBZSimplified(instructionExpression, offset);
case 0x54:
return printBConditionalSimplified(instructionExpression, offset);
}
switch ((instructionExpression >> 26 & 0b111111)) {
case 0x5:
return printBSimplified(instructionExpression, offset);
case 0x25:
return printBLSimplified(instructionExpression, offset);
}
return printUnknownSimplified(instructionExpression, offset);
}
private static String printCBZ(int instructionExpression, int offset){
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
return String.format(ANSI_YELLOW + "sf == 0 ? <Wt> else <Xt>\n" +
"CBZ <?t>, <label> |.....CBZ signature......|\n" +
ANSI_CYAN + " sf 0 1 1 0 1 0 0 |imm19..........................................................||Rd.............|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n\n"+
ANSI_YELLOW + "CBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printCBNZ(int instructionExpression, int offset){
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
return String.format(ANSI_YELLOW + "sf == 0 ? <Wt> else <Xt>\n" +
"CBNZ <?t>, <label> |.....CBZ signature......|\n" +
ANSI_CYAN + " sf 0 1 1 0 1 0 |imm19..........................................................||Rd.............|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n\n"+
ANSI_YELLOW + "CBNZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printCMN(int instructionExpression, int offset){
int Rn = instructionExpression >> 5 & 0x1F;
int imm = instructionExpression >> 10 & 0xFFF;
return String.format(ANSI_YELLOW + "sf == 0 ? <Wt> else <Xt>\n" +
"CMN <?n>, <label> |.....CMN signature...........| |..CMN signature.|\n" +
ANSI_CYAN+" sf 0 1 1 0 0 0 1 0 |imm12......................................||Rn.............| 1 1 1 1 1" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n\n" +
ANSI_YELLOW + "CMN " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
(instructionExpression >> 31 == 0) ? "w" : "x", Rn, imm);
}
private static String printB(int instructionExpression, int offset){
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
return String.format(ANSI_YELLOW+"B <label> |....B signature...|\n" +
" "+ANSI_CYAN+" 0 0 0 1 0 1 |imm26...................................................................................|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
((instructionExpression >> 26 & 0b111111) == 5)?"B":"Some weird stuff",
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
}
private static String printBL(int instructionExpression, int offset){
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
return String.format(ANSI_YELLOW+"BL <label> |...BL signature...|\n" +
" "+ANSI_CYAN+" 1 0 0 1 0 1 |imm26...................................................................................|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
((instructionExpression >> 26 & 0b111111) == 25)?"BL":"Some weird stuff",
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
}
private static String printMOV(int instructionExpression){
int imm16 = instructionExpression >> 5 & 0xFFFF;
int sfHw = (instructionExpression >> 22 & 1);
return String.format(ANSI_YELLOW + "sf == 0 && hw == 0x ? <Wt> else <Xt>\n" +
"MOV <?t>, <label> |.....MOV signature...........|\n" +
ANSI_CYAN +" sf 1 0 1 0 0 1 0 1 |hw...|imm16.................................................||Rd.............|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "MOV " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
(sfHw == 0) ? "w" : "x", (instructionExpression & 0b11111), imm16);
}
private static String printMOVRegister(int instructionExpression){
String sfHw = (instructionExpression >> 31 & 1) == 0 ? "W" : "X";
int Rm = instructionExpression >> 16 & 0xF;
int Rd = instructionExpression & 0xF;
return String.format(ANSI_YELLOW + "sf == 0 && hw == 0x ? <Wt> else <Xt>\n" +
"MOV (register) <?d>, <?m> |.....MOV (register) signature.......|\n" +
ANSI_CYAN +" sf 0 1 0 1 0 1 0 0 0 0 |Rm..............| 0 0 0 0 0 0 1 1 1 1 1 |Rd.............|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "MOV(reg) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "%s%d" + ANSI_RESET + "\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
sfHw, Rm, sfHw, Rd);
}
private static String printNOP(int instructionExpression){
return String.format(
ANSI_YELLOW+"NOP |.....NOP signature..........................................................................................|\n" +
ANSI_CYAN +" 1 1 0 1 0 1 0 1 0 0 0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 " + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n"+
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "%s" + ANSI_RESET + "\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
(instructionExpression == 0xd503201f)?"NOP":"Some weird stuff");
}
private static String printTBZ(int instructionExpression, int offset){
int xwSelector = (instructionExpression >> 31 & 1);
int imm = instructionExpression >> 18 & 0b11111;
int Rt = instructionExpression & 0b11111;
int label = (offset + (instructionExpression >> 5 & 0x3fff) * 4) & 0xfffff;
//System.out.printf("\nInstruction: %x\n", instructionExpression);
return String.format(ANSI_YELLOW + "sf == 0 && hw == 0x ? <Wt> else <Xt>\n" +
"TBZ <?t>,#<imm>, <label> |.....TBZ signature.......|\n" +
ANSI_CYAN+" b5 0 1 1 0 1 1 0 |b40.............|imm14.........................................||Rt.............|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "TBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ", " + ANSI_PURPLE + "%x" + ANSI_RESET + "\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
(xwSelector == 0) ? "w" : "x", Rt, imm, label);
}
private static String printBConditional(int instructionExpression, int offset){
int conditionalJumpLocation = ((instructionExpression >> 4 & 0b1111111111111111111) * 4 + offset) & 0xfffff;
return String.format(
ANSI_YELLOW+"B.%s <label> |...B.cond signature.......|\n" +
ANSI_CYAN+" 0 1 0 1 0 1 0 0 |imm19..........................................................| 0 |.condit...|" + ANSI_RESET + "\n" +
ANSI_GREEN +" 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n" +
ANSI_YELLOW + "B.%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
getBConditionalMarker(instructionExpression & 0xf),
intAsBinString(instructionExpression), intAsHexString(instructionExpression),
getBConditionalMarker(instructionExpression & 0xf),
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printUnknown(int instructionExpression){
return String.format(ANSI_RED + " 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 " + ANSI_RESET + "\n" +
"Instruction (BE) : %s | %s\n",
intAsBinString(instructionExpression), intAsHexString(instructionExpression));
}
private static String getBConditionalMarker(int cond){
switch (cond){
case 0b0000: return "EQ";
case 0b0001: return "NE";
case 0b0010: return "CS";
case 0b0011: return "CC";
case 0b0100: return "MI";
case 0b0101: return "PL";
case 0b0110: return "VS";
case 0b0111: return "VC";
case 0b1000: return "HI";
case 0b1001: return "LS";
case 0b1010: return "GE";
case 0b1011: return "LT";
case 0b1100: return "GT";
case 0b1101: return "LE";
case 0b1110: return "AL";
default: return "??";
}
/*
"__________________CheatSheet_____________________________________\n"+
"0000 | EQ | Z set | equal\n"+
"0001 | NE | Z clear | not equal\n"+
"0010 | CS | C set | unsigned higher or same\n"+
"0011 | CC | C clear | unsigned lower\n"+
"0100 | MI | N set | negative\n"+
"0101 | PL | N clear | positive or zero\n"+
"0110 | VS | V set | overflow\n"+
"0111 | VC | V clear | no overflow\n"+
"1000 | HI | C set & V clear | unsigned higher\n"+
"1001 | LS | C clear or Z set | unsigned lower or same\n"+
"1010 | GE | N equals V | greater or equal\n"+
"1011 | LT | N not equals V | less than\n"+
"1100 | GT | Z clear AND (N equals V) | greater that\n"+
"1101 | LE | Z set OR (N not equals V) | less than or equal\n"+
"1110 | AL | (ignored) | always\n";
*/
}
private static String printCBZSimplified(int instructionExpression, int offset){
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (" + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printCBNZSimplified(int instructionExpression, int offset){
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CBNZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (" + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
(instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printBSimplified(int instructionExpression, int offset){
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " B " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
}
private static String printBLSimplified(int instructionExpression, int offset){
int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " BL " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
}
private static String printMOVSimplified(int instructionExpression, int offset){
int imm16 = instructionExpression >> 5 & 0xFFFF;
int sfHw = (instructionExpression >> 22 & 1);
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " MOV " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
(sfHw == 0) ? "w" : "x", (instructionExpression & 0b11111), imm16);
}
private static String printNOPSimplified(int instructionExpression, int offset){
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " NOP " + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
}
private static String printTBZSimplified(int instructionExpression, int offset){
int xwSelector = (instructionExpression >> 31 & 1);
int imm = instructionExpression >> 18 & 0b11111;
int Rt = instructionExpression & 0b11111;
int label = (offset + (instructionExpression >> 5 & 0x3fff) * 4) & 0xfffff;
//System.out.printf("\nInstruction: %x\n", instructionExpression);
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " TBZ " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ", " + ANSI_PURPLE + "%x" + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
(xwSelector == 0) ? "w" : "x", Rt, imm, label);
}
private static String printBConditionalSimplified(int instructionExpression, int offset){
int conditionalJumpLocation = ((instructionExpression >> 4 & 0b1111111111111111111) * 4 + offset) & 0xfffff;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " B.%s " + ANSI_BLUE + "#0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ")\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
getBConditionalMarker(instructionExpression & 0xf),
conditionalJumpLocation, (conditionalJumpLocation + 0x100));
}
private static String printADDSimplified(int instructionExpression, int offset){ //ADD (immediate)
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " ADD . . . \n"+ ANSI_RESET,
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
}
private static String printLDPSimplified(int instructionExpression, int offset){
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDP . . . \n"+ ANSI_RESET,
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
}
private static String printLDURBSimplified(int instructionExpression, int offset){
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDURB . . . \n"+ ANSI_RESET,
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
}
private static String printSUBSimplified(int instructionExpression, int offset){
String wx = (instructionExpression >> 31 == 0) ? "W" : "X";
int Rt = instructionExpression & 0x1f;
int Rn = instructionExpression >> 5 & 0x1F;
int imm12 = instructionExpression >> 10 & 0xFFF; // unsigned only
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " SUB (imm) " + ANSI_GREEN + "%s%d, " + ANSI_BLUE + "%s%d, #0x%x" + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
wx, Rt, wx, Rn, imm12);
}
private static String printMOVRegisterSimplified(int instructionExpression, int offset){ //ADD (immediate)
String sfHw = (instructionExpression >> 31 & 1) == 0 ? "W" : "X";
int Rm = instructionExpression >> 16 & 0xF;
int Rd = instructionExpression & 0xF;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " MOV (reg) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "%s%d" + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
sfHw, Rm, sfHw, Rd);
}
private static String printCMNSimplified(int instructionExpression, int offset){
int Rn = instructionExpression >> 5 & 0x1F;
int imm = instructionExpression >> 10 & 0xFFF;
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " CMN " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
(instructionExpression >> 31 == 0) ? "w" : "x", Rn, imm);
}
private static String printLRDImmUnsignSimplified(int instructionExpression, int offset){
String wx = (instructionExpression >> 31 == 0) ? "W" : "X";
int Rt = instructionExpression & 0x1f;
int Rn = instructionExpression >> 5 & 0xF;
int imm12 = (instructionExpression >> 10 & 0xFFF) * 8; // unsigned only
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDR(imm) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "[%s%d, #0x%x]" + ANSI_RESET + " (note: unsigned offset)\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
wx, Rt, wx, Rn, imm12);
}
private static String printLRDBImmUnsignSimplified(int instructionExpression, int offset){
String wx = (instructionExpression >> 31 == 0) ? "W" : "X";
int Rt = instructionExpression & 0x1f;
int Rn = instructionExpression >> 5 & 0xF;
int imm12 = (instructionExpression >> 10 & 0xFFF) * 8; // unsigned only
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " LDRB(imm) " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "[%s%d, #0x%x]" + ANSI_RESET + " (note: unsigned offset)\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression,
wx, Rt, wx, Rn, imm12);
}
private static String printUnknownSimplified(int instructionExpression, int offset){
return String.format(
"%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + " ??? 0b"+ANSI_RESET+ Converter.intToBinaryString(Integer.reverseBytes(instructionExpression)) +"\n",
offset, Integer.reverseBytes(instructionExpression), instructionExpression);
}
private static String intAsBinString(int number) {
StringBuilder result = new StringBuilder();
for(int i = 31; i >= 0 ; i--) {
int mask = 1 << i;
result.append((number & mask) != 0 ? "1" : "0");
result.append(" ");
if (i % 4 == 0)
result.append(" ");
}
result.replace(result.length() - 1, result.length(), "");
return result.toString();
}
private static String intAsHexString(int number) {
number = Integer.reverseBytes(number);
StringBuilder result = new StringBuilder();
for(int i = 0; i <= 3 ; i++) {
int mask = 0xff << i*8;
result.append(String.format("%02x", (byte)((number & mask) >> i*8)));
result.append(" ");
}
result.replace(result.length() - 1, result.length(), "");
return result.toString();
}
}

View File

@ -0,0 +1,50 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es;
import libKonogonka.Converter;
import libKonogonka.Tools.NCA.NCAProvider;
import java.util.List;
import java.util.concurrent.Callable;
class EsNcaSearchTask implements Callable<NCAProvider> {
private final List<NCAProvider> ncaProviders;
EsNcaSearchTask(List<NCAProvider> ncaProviders){
this.ncaProviders = ncaProviders;
}
@Override
public NCAProvider call() {
try {
for (NCAProvider ncaProvider : ncaProviders) {
String titleId = Converter.byteArrToHexStringAsLE(ncaProvider.getTitleId());
if (titleId.startsWith("0100000000000033") && ncaProvider.getContentType() == 0) {
return ncaProvider;
}
}
return null;
}
catch (Exception e){
e.printStackTrace();
return null;
}
}
}

View File

@ -0,0 +1,174 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
---
Based on ES-AutoIPS.py patch script made by GBATemp member MrDude.
Taken from: https://gbatemp.net/threads/info-on-sha-256-hashes-on-fs-patches.581550/
*/
package nsusbloader.Utilities.patches.es;
import libKonogonka.Converter;
import libKonogonka.Tools.NCA.NCAProvider;
import libKonogonka.Tools.NSO.NSO0Header;
import libKonogonka.Tools.NSO.NSO0Provider;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import nsusbloader.Utilities.patches.es.finders.HeuristicEsWizard;
import java.io.BufferedOutputStream;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
public class EsPatch {
private final NCAProvider ncaProvider;
private final String saveToLocation;
private final ILogPrinter logPrinter;
private Long fwVersion;
private String buildId;
private byte[] _textSection;
private HeuristicEsWizard wizard;
EsPatch(NCAProvider ncaProvider, String saveToLocation, ILogPrinter logPrinter) throws Exception{
this.ncaProvider = ncaProvider;
this.saveToLocation = saveToLocation + File.separator +
"atmosphere" + File.separator + "exefs_patches" + File.separator + "es_patches";
this.logPrinter = logPrinter;
getPlainFirmwareVersion();
NSO0Provider nso0Provider = new NSO0Provider(ncaProvider.getNCAContentProvider(0).getPfs0().getStreamProducer(0));
getBuildId(nso0Provider);
getTextSection(nso0Provider);
findAllOffsets();
mkDirs();
writeFile();
logPrinter.print(" == Debug information ==\n"+wizard.getDebug(), EMsgType.NULL);
}
private void getPlainFirmwareVersion() throws Exception{
fwVersion = Long.parseLong(""+ncaProvider.getSdkVersion()[3]+ncaProvider.getSdkVersion()[2]
+ncaProvider.getSdkVersion()[1] +ncaProvider.getSdkVersion()[0]);
logPrinter.print("Internal firmware version: "+ncaProvider.getSdkVersion()[3] +"."+ncaProvider.getSdkVersion()[2] +"."+ncaProvider.getSdkVersion()[1] +"."+ncaProvider.getSdkVersion()[0], EMsgType.INFO);
}
private void getBuildId(NSO0Provider nso0Provider) throws Exception{
NSO0Header nso0DecompressedHeader = nso0Provider.getAsDecompressedNSO0().getHeader();
byte[] buildIdBytes = nso0DecompressedHeader.getModuleId();
buildId = Converter.byteArrToHexStringAsLE(buildIdBytes).substring(0, 40).toUpperCase();
logPrinter.print("Build ID: "+buildId, EMsgType.INFO);
}
private void getTextSection(NSO0Provider nso0Provider) throws Exception{
_textSection = nso0Provider.getAsDecompressedNSO0().getTextRaw();
}
private void findAllOffsets() throws Exception{
this.wizard = new HeuristicEsWizard(fwVersion, _textSection);
String errorsAndNotes = wizard.getErrorsAndNotes();
if (errorsAndNotes.length() > 0)
logPrinter.print(errorsAndNotes, EMsgType.WARNING);
}
private void mkDirs(){
File parentFolder = new File(saveToLocation);
parentFolder.mkdirs();
}
private void writeFile() throws Exception{
String patchFileLocation = saveToLocation + File.separator + buildId + ".ips";
int offset1 = wizard.getOffset1();
int offset2 = wizard.getOffset2();
int offset3 = wizard.getOffset3();
ByteBuffer handyEsPatch = ByteBuffer.allocate(0x23).order(ByteOrder.LITTLE_ENDIAN);
handyEsPatch.put(getHeader());
if (offset1 > 0) {
logPrinter.print("Patch component 1 will be used", EMsgType.PASS);
handyEsPatch.put(getPatch1(offset1));
}
if (offset2 > 0) {
logPrinter.print("Patch component 2 will be used", EMsgType.PASS);
handyEsPatch.put(getPatch2(offset2));
}
if (offset3 > 0) {
logPrinter.print("Patch component 3 will be used", EMsgType.PASS);
handyEsPatch.put(getPatch3(offset3));
}
handyEsPatch.put(getFooter());
try (BufferedOutputStream stream = new BufferedOutputStream(
Files.newOutputStream(new File(patchFileLocation).toPath()))){
stream.write(handyEsPatch.array());
}
logPrinter.print("Patch created at "+patchFileLocation, EMsgType.PASS);
}
private byte[] getHeader(){
return "PATCH".getBytes(StandardCharsets.US_ASCII);
}
private byte[] getFooter(){
return "EOF".getBytes(StandardCharsets.US_ASCII);
}
// WE EXPECT TO SEE CBZ (for patch 1) INSTRUCTION RIGHT BEFORE FOUND SEQUENCE (requiredInstructionOffsetInternal)
// IN RESULTING FILE InstructionOffset SHOULD BE INCREMENTED by 0x100 to get real offset
// (because header for decompressed NSO0 size = 0x100; it's fixed alignment produced by libKonogonka)
private byte[] getPatch1(int offset) throws Exception{
int requiredInstructionOffsetInternal = offset - 4;
int requiredInstructionOffsetReal = requiredInstructionOffsetInternal + 0x100;
int instructionExpression = Converter.getLEint(_textSection, requiredInstructionOffsetInternal);
int patch = ((0x14 << 24) | (instructionExpression >> 5) & 0x7FFFF);
logPrinter.print(BinToAsmPrinter.printSimplified(patch, requiredInstructionOffsetInternal), EMsgType.NULL);
// Somehow IPS patches uses offsets written as big_endian (0.o) and bytes dat should be patched as LE.
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
.putInt(requiredInstructionOffsetReal)
.putShort((short) 4)
.putInt(Integer.reverseBytes(patch));
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}
private byte[] getPatch2(int offset) throws Exception{
final int NopExpression = 0x1F2003D5; // reversed
int offsetReal = offset - 4 + 0x100;
logPrinter.print(BinToAsmPrinter.printSimplified(Integer.reverseBytes(NopExpression), offset - 4), EMsgType.NULL);
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
.putInt(offsetReal)
.putShort((short) 4)
.putInt(NopExpression);
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}
private byte[] getPatch3(int offset) throws Exception{
int requiredInstructionOffsetInternal = offset - 4;
int requiredInstructionOffsetReal = requiredInstructionOffsetInternal + 0x100;
int instructionExpression = Converter.getLEint(_textSection, requiredInstructionOffsetInternal);
int patch = ((0x14 << 24) | (instructionExpression >> 5) & 0x7FFFF);
logPrinter.print(BinToAsmPrinter.printSimplified(patch, requiredInstructionOffsetInternal), EMsgType.NULL);
ByteBuffer prePatch = ByteBuffer.allocate(10).order(ByteOrder.BIG_ENDIAN)
.putInt(requiredInstructionOffsetReal)
.putShort((short) 4)
.putInt(Integer.reverseBytes(patch));
return Arrays.copyOfRange(prePatch.array(), 1, 10);
}
}

View File

@ -0,0 +1,187 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es;
import libKonogonka.KeyChainHolder;
import libKonogonka.Tools.NCA.NCAProvider;
import nsusbloader.ModelControllers.CancellableRunnable;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.ModelControllers.Log;
import nsusbloader.NSLDataTypes.EModule;
import nsusbloader.NSLDataTypes.EMsgType;
import java.io.File;
import java.util.*;
import java.util.concurrent.*;
public class EsPatchMaker extends CancellableRunnable {
private int THREADS_POOL_SIZE = 4;
private final ILogPrinter logPrinter;
private final String pathToFirmware;
private final String pathToKeysFile;
private final String saveTo;
private File firmware;
private KeyChainHolder keyChainHolder;
private ExecutorService executorService;
private List<String> ncaFilesList; // inside the folder
private boolean oneLinerStatus = false;
public EsPatchMaker(String pathToFirmware, String pathToKeysFile, String saveTo){
this.logPrinter = Log.getPrinter(EModule.PATCHES); //TODO: UNCOMMENT
/*
this.logPrinter = new ILogPrinter() {
@Override
public void print(String message, EMsgType type) throws InterruptedException {}
@Override
public void updateProgress(Double value) throws InterruptedException {}
@Override
public void update(HashMap<String, File> nspMap, EFileStatus status) {}
@Override
public void update(File file, EFileStatus status) {}
@Override
public void updateOneLinerStatus(boolean status) {}
@Override
public void close() {}
};
*/
this.pathToFirmware = pathToFirmware;
this.pathToKeysFile = pathToKeysFile;
this.saveTo = saveTo;
}
@Override
public void run() {
try {
logPrinter.print("..:: Make ES Patches ::..", EMsgType.INFO);
receiveFirmware();
buildKeyChainHolder();
receiveNcaFileNamesList();
adjustThreadsPoolSize();
createPool();
executePool();
}
catch (Exception e){
e.printStackTrace();
try{
logPrinter.print(e.getMessage(), EMsgType.FAIL);
} catch (Exception ignore){}
}
finally {
logPrinter.updateOneLinerStatus(oneLinerStatus);
logPrinter.close();
}
}
private void receiveFirmware() throws Exception{
logPrinter.print("Looking at firmware", EMsgType.INFO);
this.firmware = new File(pathToFirmware);
}
private void buildKeyChainHolder() throws Exception{
logPrinter.print("Reading keys", EMsgType.INFO);
this.keyChainHolder = new KeyChainHolder(pathToKeysFile, null);
}
private void receiveNcaFileNamesList() throws Exception{
logPrinter.print("Collecting NCA files", EMsgType.INFO);
String[] fileNamesArray = firmware.list((File directory, String file) -> ( ! file.endsWith(".cnmt.nca") && file.endsWith(".nca")));
ncaFilesList = Arrays.asList(Objects.requireNonNull(fileNamesArray));
if (ncaFilesList.size() == 0)
throw new Exception("No NCA files found in firmware folder");
}
private void adjustThreadsPoolSize(){
if (ncaFilesList.size() < 4)
THREADS_POOL_SIZE = ncaFilesList.size();
}
private void createPool() throws Exception{
logPrinter.print("Creating sub-tasks pool", EMsgType.INFO);
this.executorService = Executors.newFixedThreadPool(
THREADS_POOL_SIZE,
runnable -> {
Thread thread = new Thread(runnable);
thread.setDaemon(true);
return thread;
});
}
private void executePool() throws Exception{ //TODO: FIX. Exceptions thrown only by logPrinter
try {
logPrinter.print("Executing sub-tasks pool", EMsgType.INFO);
List<Future<NCAProvider>> futuresResults = executorService.invokeAll(getSubTasksCollection());
for (Future<NCAProvider> future : futuresResults){
NCAProvider ncaProvider = future.get();
if (ncaProvider != null) {
makePatches(ncaProvider);
break;
}
}
executorService.shutdown();
}
catch (InterruptedException ie){
executorService.shutdownNow();
boolean interruptedSuccessfully = false;
try {
interruptedSuccessfully = executorService.awaitTermination(20, TimeUnit.SECONDS);
}
catch (InterruptedException awaitInterrupt){
logPrinter.print("Force interrupting task...", EMsgType.WARNING);
}
logPrinter.print("Task interrupted "+(interruptedSuccessfully?"successfully":"with some issues"), EMsgType.WARNING);
}
catch (Exception e){
e.printStackTrace();
logPrinter.print("Task failed: "+e.getMessage(), EMsgType.FAIL);
}
}
private void makePatches(NCAProvider ncaProvider) throws Exception{
logPrinter.print(String.format("File found: .."+File.separator+"%s"+File.separator+"%s",
ncaProvider.getFile().getParentFile().getName(), ncaProvider.getFile().getName())
, EMsgType.INFO);
new EsPatch(ncaProvider, saveTo, logPrinter);
oneLinerStatus = true;
}
private List<Callable<NCAProvider>> getSubTasksCollection() throws Exception{
logPrinter.print("Forming sub-tasks collection", EMsgType.INFO);
List<Callable<NCAProvider>> subTasks = new ArrayList<>();
int ncaPerThreadAmount = ncaFilesList.size() / THREADS_POOL_SIZE;
Iterator<String> iterator = ncaFilesList.listIterator();
for (int i = 1; i < THREADS_POOL_SIZE; i++){
Callable<NCAProvider> task = new EsNcaSearchTask(getNextSet(iterator, ncaPerThreadAmount));
subTasks.add(task);
}
Callable<NCAProvider> task = new EsNcaSearchTask(getNextSet(iterator,
ncaFilesList.size() % THREADS_POOL_SIZE == 0 ? ncaPerThreadAmount : ncaPerThreadAmount+1));
subTasks.add(task);
return subTasks;
}
private List<NCAProvider> getNextSet(Iterator<String> iterator, int amount) throws Exception{
List<NCAProvider> ncas = new ArrayList<>();
for (int j = 0; j < amount; j++){
String ncaFileName = iterator.next();
File nca = new File(firmware.getAbsolutePath()+File.separator+ncaFileName);
NCAProvider provider = new NCAProvider(nca, keyChainHolder.getRawKeySet());
ncas.add(provider);
}
return ncas;
}
}

View File

@ -0,0 +1,161 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es;
import libKonogonka.Converter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SimplyFind {
private String what;
private final byte[] where;
private Matcher matcherHex;
private Matcher matcherDot;
private final List<Integer> findings = new ArrayList<>();
private final int statementLength;
private final List<SearchBlock> searchBlocks = new ArrayList<>();
/**
* Abstraction layer for searching patterns like "..CAFE..BE" in bytes array.
* It's 'String' combination of hex values and '.' which stands for unknown value.
* Returns offset of the first symbol.
* */
public SimplyFind(String what, byte[] where){
this.where = where;
if (! what.contains(".")){
doKMPSearch(Converter.hexStringToByteArray(what), 0);
this.statementLength = what.length()/2;
return;
}
this.what = what.replaceAll("\\.", "\\.\\.");
this.statementLength = this.what.length()/2;
buildSearchingSequence();
complexSearch();
}
private void buildSearchingSequence(){
Pattern patternHex = Pattern.compile("[0-9]|[A-F]|[a-f]");
Pattern patternDot = Pattern.compile("\\.");
this.matcherHex = patternHex.matcher(what);
this.matcherDot = patternDot.matcher(what);
int nextDotPos = 0;
int nextHexPos;
while(true){
nextHexPos = getNextNumberPosition(nextDotPos);
if (nextHexPos == -1)
break;
nextDotPos = getNextDotPosition(nextHexPos);
if (nextDotPos == -1) {
searchBlocks.add(new SearchBlock(what.substring(nextHexPos), nextHexPos));
break;
}
String searchStatement = what.substring(nextHexPos, nextDotPos);
searchBlocks.add(new SearchBlock(searchStatement, nextHexPos));
}
}
private int getNextNumberPosition(int since){
if (matcherHex.find(since))
return matcherHex.start();
return -1;
}
private int getNextDotPosition(int since){
if (matcherDot.find(since))
return matcherDot.start();
return -1;
}
private void complexSearch(){
SearchBlock block = searchBlocks.get(0);
doKMPSearch(block.statement, block.offsetInStatement);
findings.removeIf(this::searchForward);
}
private boolean searchForward(int offset){
for (int i = 1; i < searchBlocks.size(); i++) {
SearchBlock block = searchBlocks.get(i);
if (! doDumbSearch(block.statement, offset+block.offsetInStatement)){
return true;
}
}
return false;
}
private void doKMPSearch(byte[] subject, int skip){
int whereSize = where.length;
int subjectSize = subject.length;
int[] pf = new int[subjectSize];
int j = 0;
for (int i = 1; i < subjectSize; i++ ) {
while ((j > 0) && (subject[j] != subject[i]))
j = pf[j-1];
if (subject[j] == subject[i])
j++;
pf[i] = j;
}
j = 0;
for (int i = 0; i < whereSize; i++){
while ((j > 0) && (subject[j] != where[i]))
j = pf[j - 1];
if (subject[j] == where[i])
j++;
if (j == subjectSize) {
findings.add(i-j+1-skip);
j = 0;
}
}
}
private boolean doDumbSearch(byte[] subject, int since){
for (int i = 0; i < subject.length; i++) {
if (where[since + i] != subject[i])
return false;
}
return true;
}
public int getStatementLength() {
return statementLength;
}
public List<Integer> getResults(){
return findings;
}
private static class SearchBlock{
byte[] statement;
int offsetInStatement;
SearchBlock(String statement, int offset){
if (statement != null) {
this.statement = Converter.hexStringToByteArray(statement);
}
this.offsetInStatement = offset/2;
}
}
}

View File

@ -0,0 +1,109 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.es.BinToAsmPrinter;
import nsusbloader.Utilities.patches.es.SimplyFind;
import java.util.List;
class HeuristicEs1 implements IHeuristicEs {
private static final String PATTERN = "1F90013128.8052";
private final List<Integer> findings;
private final byte[] where;
HeuristicEs1(byte[] where){
this.where = where;
SimplyFind simplyfind = new SimplyFind(PATTERN, where);
this.findings = simplyfind.getResults();
this.findings.removeIf(this::dropStep1);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep2);
}
// Check ranges
private boolean dropStep1(int offsetOfPatternFound){
return ((offsetOfPatternFound < 0x10000 || offsetOfPatternFound > 0xffffc));
}
// Remove non-CBZ
private boolean dropStep2(int offsetOfPatternFound){
return ((where[offsetOfPatternFound - 1] & (byte) 0b01111111) != 0x34);
}
@Override
public boolean isFound(){
return findings.size() == 1;
}
@Override
public boolean wantLessEntropy(){
return findings.size() > 1;
}
@Override
public int getOffset() throws Exception{
if(findings.isEmpty())
throw new Exception("Nothing found");
if (findings.size() > 1)
throw new Exception("Too many offsets");
return findings.get(0);
}
@Override
public boolean setOffsetsNearby(int offsetNearby) {
findings.removeIf(offset -> {
if (offset > offsetNearby)
return ! (offset < offsetNearby - 0xffff);
return ! (offset > offsetNearby - 0xffff);
});
return isFound();
}
@Override
public String getDetails(){
StringBuilder builder = new StringBuilder();
int cbzOffsetInternal = findings.get(0) - 4;
int instructionExpression = Converter.getLEint(where, cbzOffsetInternal);
int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + cbzOffsetInternal) & 0xfffff;
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
builder.append(BinToAsmPrinter.printSimplified(instructionExpression, cbzOffsetInternal));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+4),
cbzOffsetInternal+4));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+8),
cbzOffsetInternal+8));
builder.append("...\n");
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation+4));
return builder.toString();
}
@Override
public int getId(){
return 1;
}
}

View File

@ -0,0 +1,168 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.es.BinToAsmPrinter;
import nsusbloader.Utilities.patches.es.SimplyFind;
import java.util.ArrayList;
import java.util.List;
class HeuristicEs2 implements IHeuristicEs {
private static final String PATTERN = ".D2.52";
private List<Integer> findings;
private final byte[] where;
HeuristicEs2(byte[] where){
this.where = where;
find();
this.findings.removeIf(this::dropStep1);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep2);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep3);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep4);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep5);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep6);
}
private void find(){
SimplyFind simplyfind = new SimplyFind(PATTERN, where);
findings = new ArrayList<>();
// This approach a bit different. We're looking for pattern we want to patch, not the next one.
// So easier way is just to shift every value and pretend that nothing happened.
for (int offset : simplyfind.getResults())
findings.add(offset+4);
}
// Limit range
private boolean dropStep1(int offsetOfPatternFound){
return ((offsetOfPatternFound < 0x10000 || offsetOfPatternFound > 0xffffc));
}
// Is CBNZ next?
private boolean dropStep2(int offsetOfPatternFound){
return ! isCBNZ(Converter.getLEint(where, offsetOfPatternFound));
}
// Check what's above
private boolean dropStep3(int offsetOfPatternFound){
return ! isMOV(Converter.getLEint(where, offsetOfPatternFound-4));
}
// Check what's beyond or after jump
private boolean dropStep4(int offsetOfPatternFound) {
int nextExpression = Converter.getLEint(where, offsetOfPatternFound + 4);
return ! isLDRB_LDURB(nextExpression); // Drop if not LDRB OR LDURB
}
// Check second after jump if LDR-TBZ
private boolean dropStep5(int offsetOfPatternFound) {
int expression = Converter.getLEint(where, offsetOfPatternFound);
int afterJumpPosition = ((expression >> 5 & 0x7FFFF) * 4 + offsetOfPatternFound) & 0xfffff;
int secondAfterJumpExpression = Converter.getLEint(where, afterJumpPosition+4);
return ! isBL(secondAfterJumpExpression); //Second after jump = BL? No -> Drop
}
// Check second after jump if LDR-TBZ
private boolean dropStep6(int offsetOfPatternFound) {
int expression = Converter.getLEint(where, offsetOfPatternFound);
int afterJumpPosition = ((expression >> 5 & 0x7FFFF) * 4 + offsetOfPatternFound) & 0xfffff;
int forthAfterJumpExpression = Converter.getLEint(where, afterJumpPosition+12);
return ! isBL(forthAfterJumpExpression); //Forth after jump = BL? No -> Drop
}
@Override
public boolean isFound(){
return findings.size() == 1;
}
@Override
public boolean wantLessEntropy(){
return findings.size() > 1;
}
@Override
public int getOffset() throws Exception{
if(findings.isEmpty())
throw new Exception("Nothing found");
if (findings.size() > 1)
throw new Exception("Too many offsets");
return findings.get(0);
}
@Override
public boolean setOffsetsNearby(int offsetNearby) {
findings.removeIf(offset -> {
if (offset > offsetNearby)
return ! (offset < offsetNearby - 0xffff);
return ! (offset > offsetNearby - 0xffff);
});
return isFound();
}
@Override
public String getDetails(){
StringBuilder builder = new StringBuilder();
int secondExpressionOffset = findings.get(0);
int firstExpression = Converter.getLEint(where, secondExpressionOffset-4);
int secondExpression = Converter.getLEint(where, secondExpressionOffset);
int conditionalJumpLocation = 0;
if ((secondExpression >> 24 & 0x7f) == 0x35) {
conditionalJumpLocation = ((secondExpression >> 5 & 0x7FFFF) * 4 + secondExpressionOffset) & 0xfffff;
}
else if ((firstExpression >> 24 & 0x7f) == 0x36) {
conditionalJumpLocation = (secondExpressionOffset-4 + (firstExpression >> 5 & 0x3fff) * 4) & 0xfffff;
}
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation + 4);
int secondExpressionsPairElement3 = Converter.getLEint(where, conditionalJumpLocation + 8);
int secondExpressionsPairElement4 = Converter.getLEint(where, conditionalJumpLocation + 12);
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, secondExpressionOffset-4), secondExpressionOffset-4));
builder.append(BinToAsmPrinter.printSimplified(secondExpression, secondExpressionOffset));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, secondExpressionOffset+4), secondExpressionOffset+4));
builder.append("...\n");
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation + 4));
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement3, conditionalJumpLocation + 8));
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement4, conditionalJumpLocation + 12));
return builder.toString();
}
@Override
public int getId(){
return 2;
}
}

View File

@ -0,0 +1,151 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es.finders;
import libKonogonka.Converter;
import nsusbloader.Utilities.patches.es.BinToAsmPrinter;
import nsusbloader.Utilities.patches.es.SimplyFind;
import java.util.List;
class HeuristicEs3 implements IHeuristicEs {
private static final String PATTERN0 = "..FF97";
private static final String PATTERN1 = "......FF97"; // aka "E0230091..FF97";
private final List<Integer> findings;
private final byte[] where;
HeuristicEs3(long fwVersion, byte[] where){
this.where = where;
String pattern = getPattern(fwVersion);
SimplyFind simplyfind = new SimplyFind(pattern, where);
this.findings = simplyfind.getResults();
this.findings.removeIf(this::dropStep1);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep2);
if(findings.size() < 2)
return;
this.findings.removeIf(this::dropStep3);
}
private String getPattern(long fwVersion){
if (fwVersion < 10400)
return PATTERN0;
return PATTERN1;
}
// Let's focus on CBZ-ONLY statements
private boolean dropStep1(int offsetOfPatternFound){
return ((where[offsetOfPatternFound - 1] & (byte) 0b01111111) != 0x34);
}
private boolean dropStep2(int offsetOfPatternFound){
int conditionalJumpLocation = getCBZConditionalJumpLocation(offsetOfPatternFound - 4);
int afterJumpSecondExpressions = Converter.getLEint(where, conditionalJumpLocation);
int afterJumpThirdExpressions = Converter.getLEint(where, conditionalJumpLocation+4);
// Check first is 'MOV'; second is 'B'
return (! isMOV_REG(afterJumpSecondExpressions)) || ! isB(afterJumpThirdExpressions);
}
private boolean dropStep3(int offsetOfPatternFound){
int conditionalJumpLocation = getCBZConditionalJumpLocation(offsetOfPatternFound-4);
int afterJumpSecondExpressions = Converter.getLEint(where, conditionalJumpLocation+4);
int secondPairConditionalJumpLocation = ((afterJumpSecondExpressions & 0x3ffffff) * 4 + (conditionalJumpLocation+4)) & 0xfffff;
int thirdExpressionsPairElement1 = Converter.getLEint(where, secondPairConditionalJumpLocation);
int thirdExpressionsPairElement2 = Converter.getLEint(where, secondPairConditionalJumpLocation+4);
// Check first is 'ADD'; second is 'BL'
return (! isADD(thirdExpressionsPairElement1)) || (! isBL(thirdExpressionsPairElement2));
}
private int getCBZConditionalJumpLocation(int cbzOffsetInternal){
int cbzExpression = Converter.getLEint(where, cbzOffsetInternal);
return ((cbzExpression >> 5 & 0x7FFFF) * 4 + cbzOffsetInternal) & 0xfffff;
}
@Override
public boolean isFound(){
return findings.size() == 1;
}
@Override
public boolean wantLessEntropy(){
return findings.size() > 1;
}
@Override
public int getOffset() throws Exception{
if(findings.isEmpty())
throw new Exception("Nothing found");
if (findings.size() > 1)
throw new Exception("Too many offsets");
return findings.get(0);
}
@Override
public boolean setOffsetsNearby(int offsetNearby) {
findings.removeIf(offset -> {
if (offset > offsetNearby)
return ! (offset < offsetNearby - 0xffff);
return ! (offset > offsetNearby - 0xffff);
});
return isFound();
}
@Override
public String getDetails(){
StringBuilder builder = new StringBuilder();
int cbzOffsetInternal = findings.get(0) - 4;
int cbzExpression = Converter.getLEint(where, cbzOffsetInternal);
int conditionalJumpLocation = ((cbzExpression >> 5 & 0x7FFFF) * 4 + cbzOffsetInternal) & 0xfffff;
int secondExpressionsPairElement1 = Converter.getLEint(where, conditionalJumpLocation);
int secondExpressionsPairElement2 = Converter.getLEint(where, conditionalJumpLocation+4);
builder.append(BinToAsmPrinter.printSimplified(cbzExpression, cbzOffsetInternal));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+4), cbzOffsetInternal+4));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, cbzOffsetInternal+8), cbzOffsetInternal+8));
builder.append("...\n");
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement1, conditionalJumpLocation));
builder.append(BinToAsmPrinter.printSimplified(secondExpressionsPairElement2, conditionalJumpLocation+4));
if (((secondExpressionsPairElement2 >> 26 & 0b111111) == 0x5)){
builder.append("...\n");
int conditionalJumpLocation2 = ((secondExpressionsPairElement2 & 0x3ffffff) * 4 + (conditionalJumpLocation+4)) & 0xfffff;
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, conditionalJumpLocation2), conditionalJumpLocation2));
builder.append(BinToAsmPrinter.printSimplified(Converter.getLEint(where, conditionalJumpLocation2+4), conditionalJumpLocation2+4));
}
else {
builder.append("NO CONDITIONAL JUMP ON 2nd iteration (HeuristicEs3)");
}
return builder.toString();
}
@Override
public int getId(){
return 3;
}
}

View File

@ -0,0 +1,127 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es.finders;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class HeuristicEsWizard {
private final List<IHeuristicEs> all;
private final List<IHeuristicEs> found;
private final List<IHeuristicEs> wantLessEntropy;
private final StringBuilder errorsAndNotes;
private int offset1 = -1;
private int offset2 = -1;
private int offset3 = -1;
public HeuristicEsWizard(long fwVersion, byte[] where) throws Exception{
this.errorsAndNotes = new StringBuilder();
this.all = Arrays.asList(
new HeuristicEs1(where),
new HeuristicEs2(where),
new HeuristicEs3(fwVersion, where)
);
this.found = all.stream()
.filter(IHeuristicEs::isFound)
.collect(Collectors.toList());
if (found.isEmpty())
throw new Exception("Nothing found!");
this.wantLessEntropy = all.stream()
.filter(IHeuristicEs::wantLessEntropy)
.collect(Collectors.toList());
shareOffsetsWithEachOther();
assignOffset1();
assignOffset2();
assignOffset3();
}
private void shareOffsetsWithEachOther(){
for (IHeuristicEs es : wantLessEntropy) {
if (shareWithNext(es))
return;
}
}
private boolean shareWithNext(IHeuristicEs es){
try {
for (IHeuristicEs foundEs : found) {
if (es.setOffsetsNearby(foundEs.getOffset())) {
found.add(es);
wantLessEntropy.remove(es);
shareOffsetsWithEachOther();
return true;
}
}
}
catch (Exception e){ e.printStackTrace(); }
return false;
}
private void assignOffset1(){
try {
offset1 = all.get(0).getOffset();
}
catch (Exception e){ errorsAndNotes.append(e.getLocalizedMessage()).append("\n"); }
}
private void assignOffset2(){
try {
offset2 = all.get(1).getOffset();
}
catch (Exception e){ errorsAndNotes.append(e.getLocalizedMessage()).append("\n"); }
}
private void assignOffset3(){
try {
offset3 = all.get(2).getOffset();
}
catch (Exception e){ errorsAndNotes.append(e.getLocalizedMessage()).append("\n"); }
}
public String getErrorsAndNotes(){
return errorsAndNotes.toString();
}
public String getDebug(){
StringBuilder builder = new StringBuilder();
if (all.get(0).isFound()){
builder.append("\t\t-=== 1 ===-\n");
builder.append(all.get(0).getDetails());
}
if (all.get(1).isFound()){
builder.append("\t\t-=== 2 ===-\n");
builder.append(all.get(1).getDetails());
}
if (all.get(2).isFound()){
builder.append("\t\t-=== 3 ===-\n");
builder.append(all.get(2).getDetails());
}
return builder.toString();
}
public int getOffset1() { return offset1; }
public int getOffset2() { return offset2; }
public int getOffset3() { return offset3; }
}

View File

@ -0,0 +1,47 @@
/*
Copyright 2018-2022 Dmitry Isaenko
This file is part of NS-USBloader.
NS-USBloader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NS-USBloader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NS-USBloader. If not, see <https://www.gnu.org/licenses/>.
*/
package nsusbloader.Utilities.patches.es.finders;
/**
* Searches instructions (via known patterns) that follows 'specific instruction' we want to patch.
* Returns offset of the pattern. Not offset of the 'specific instruction'.
* */
interface IHeuristicEs {
default boolean isLDR(int expression){ return (expression >> 22 & 0x2FF) == 0x2e5; }// LDR ! Sounds like LDP, don't mess up
default boolean isLDP(int expression){ return (expression >> 22 & 0x1F9) == 0xA1; }// LDP !
default boolean isCBNZ(int expression){ return (expression >> 24 & 0x7f) == 0x35; }
default boolean isMOV(int expression){ return (expression >> 23 & 0xff) == 0xA5; }
default boolean isTBZ(int expression){ return (expression >> 24 & 0x7f) == 0x36; }
default boolean isLDRB_LDURB(int expression){ return (expression >> 21 & 0x7f7) == 0x1c2; }
default boolean isMOV_REG(int expression){ return (expression & 0x7FE0FFE0) == 0x2A0003E0; }
default boolean isB(int expression) { return (expression >> 26 & 0x3f) == 0x5; }
default boolean isBL(int expression){ return (expression >> 26 & 0x3f) == 0x25; }
default boolean isADD(int expression){ return (expression >> 23 & 0xff) == 0x22; }
boolean isFound();
boolean wantLessEntropy();
int getOffset() throws Exception;
String getDetails();
/**
* Should be used if wantLessEntropy() == true
* @return isFound();
* */
boolean setOffsetsNearby(int offsetNearby);
int getId();
}

View File

@ -18,9 +18,12 @@
*/
package nsusbloader.cli;
import nsusbloader.AppPreferences;
import nsusbloader.Main;
import nsusbloader.NSLMain;
import org.apache.commons.cli.*;
import java.time.LocalTime;
import java.util.prefs.Preferences;
public class CommandLineInterface {
@ -32,10 +35,12 @@ public class CommandLineInterface {
}
final Options cliOptions = createCliOptions();
final Options cliOptionsToBeExact =
createCliOptions().addOption(Option.builder().longOpt("gimmegimmegimme").hasArg(false).build());
CommandLineParser cliParser = new DefaultParser();
try{
CommandLine cli = cliParser.parse(cliOptions, args);
CommandLine cli = cliParser.parse(cliOptionsToBeExact, args);
if (cli.hasOption('v') || cli.hasOption("version")){
handleVersion();
return;
@ -75,6 +80,16 @@ public class CommandLineInterface {
return;
}
*/
if (cli.hasOption("gimmegimmegimme")){
if (LocalTime.now().isBefore(LocalTime.parse("09:00:00"))){
AppPreferences.getInstance().give();
AppPreferences.getInstance().setLastOpenedTab("PatchesTabHolder");
System.out.println("=)");
Main.main(new String[]{});
return;
}
throw new ParseException("Unhandled LocalTime() exception;");
}
if (cli.hasOption("s") || cli.hasOption("split")){
final String[] arguments = cli.getOptionValues("split");
new SplitCli(arguments);

View File

@ -15,7 +15,7 @@ Steps to roll NXDT functionality back:
* Set 'Visible' on NXDT Tab selector (SVGPath container)
-->
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NSLMainController">
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.NSLMainController">
<children>
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
@ -47,6 +47,14 @@ Steps to roll NXDT functionality back:
<SVGPath content="M 2.4003906 2 C 1.0683906 2 2.9605947e-16 3.1125 0 4.5 L 0 19.5 A 2.4 2.5 0 0 0 2.4003906 22 L 21.599609 22 A 2.4 2.5 0 0 0 24 19.5 L 24 7 C 24 5.6125 22.919609 4.5 21.599609 4.5 L 12 4.5 L 9.5996094 2 L 2.4003906 2 z M 9 5 L 13 8.5 L 9 12 L 9 10 L 6 10 L 6 7 L 9 7 L 9 5 z M 5 9 L 5 11 L 8 11 L 8 14 L 5 14 L 5 16 L 1 12.5 L 5 9 z M 13.193359 10.962891 C 14.113498 10.962891 14.814236 11.348741 15.296875 12.123047 C 15.779514 12.89388 16.021484 13.935113 16.021484 15.244141 C 16.021484 16.556641 15.779514 17.598741 15.296875 18.373047 C 14.814236 19.14388 14.113498 19.529297 13.193359 19.529297 C 12.276693 19.529297 11.575955 19.14388 11.089844 18.373047 C 10.607205 17.598741 10.365234 16.556641 10.365234 15.244141 C 10.365234 13.935113 10.607205 12.89388 11.089844 12.123047 C 11.575955 11.348741 12.276693 10.962891 13.193359 10.962891 z M 19.589844 10.962891 C 20.509983 10.962891 21.21072 11.348741 21.693359 12.123047 C 22.175998 12.89388 22.417969 13.935113 22.417969 15.244141 C 22.417969 16.556641 22.175998 17.598741 21.693359 18.373047 C 21.21072 19.14388 20.509983 19.529297 19.589844 19.529297 C 18.673177 19.529297 17.970486 19.14388 17.484375 18.373047 C 17.001736 17.598741 16.761719 16.556641 16.761719 15.244141 C 16.761719 13.935113 17.001736 12.89388 17.484375 12.123047 C 17.970486 11.348741 18.673177 10.962891 19.589844 10.962891 z M 13.193359 11.769531 C 12.613498 11.769531 12.173177 12.092448 11.871094 12.738281 C 11.56901 13.380642 11.417969 14.195964 11.417969 15.185547 C 11.417969 15.411241 11.423611 15.655599 11.4375 15.916016 C 11.451389 16.176432 11.511068 16.528212 11.615234 16.972656 L 14.412109 12.591797 C 14.235026 12.26888 14.042318 12.052517 13.833984 11.941406 C 13.629123 11.826823 13.415582 11.769531 13.193359 11.769531 z M 19.589844 11.769531 C 19.009983 11.769531 18.567708 12.092448 18.265625 12.738281 C 17.963542 13.380642 17.8125 14.195964 17.8125 15.185547 C 17.8125 15.411241 17.820095 15.655599 17.833984 15.916016 C 17.847873 16.176432 17.907552 16.528212 18.011719 16.972656 L 20.808594 12.591797 C 20.63151 12.26888 20.438802 12.052517 20.230469 11.941406 C 20.025608 11.826823 19.812066 11.769531 19.589844 11.769531 z M 14.761719 13.556641 L 11.984375 17.962891 C 12.133681 18.216363 12.305556 18.406684 12.5 18.535156 C 12.694444 18.660156 12.91276 18.722656 13.152344 18.722656 C 13.812066 18.722656 14.280816 18.355252 14.558594 17.619141 C 14.836372 16.879557 14.974609 16.059462 14.974609 15.160156 C 14.974609 14.604601 14.90408 14.07053 14.761719 13.556641 z M 21.15625 13.556641 L 18.380859 17.962891 C 18.530165 18.216363 18.70204 18.406684 18.896484 18.535156 C 19.090929 18.660156 19.307292 18.722656 19.546875 18.722656 C 20.206597 18.722656 20.675347 18.355252 20.953125 17.619141 C 21.230903 16.879557 21.371094 16.059462 21.371094 15.160156 C 21.371094 14.604601 21.298611 14.07053 21.15625 13.556641 z" />
</graphic>
</Tab>
<Tab fx:id="PatchesTabHolder" closable="false">
<content>
<fx:include fx:id="PatchesTab" source="PatchesTab.fxml" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" VBox.vgrow="ALWAYS" />
</content>
<graphic>
<SVGPath content="M 5.8828125 0.2109375 C 5.0191331 0.17810553 4.0925755 0.5807669 3.421875 1.3671875 L 0.88671875 4.3398438 C -0.18640328 5.598116 -0.18550892 7.3497981 0.890625 8.2675781 L 4.625 11.451172 L 0.76367188 14.517578 C -0.34380932 15.397272 -0.4055432 17.146472 0.62304688 18.441406 L 3.0527344 21.501953 C 4.0813235 22.796885 5.8007221 23.131646 6.9082031 22.251953 L 12.283203 17.982422 L 17.5 22.431641 C 18.57613 23.34942 20.305782 23.07468 21.378906 21.816406 L 23.914062 18.84375 C 24.987183 17.585475 24.986236 15.833793 23.910156 14.916016 L 20.164062 11.722656 L 24.001953 8.6738281 C 25.109433 7.7941344 25.171167 6.0449323 24.142578 4.75 L 21.712891 1.6914062 C 20.684303 0.39647305 18.964905 0.059759405 17.857422 0.93945312 L 12.505859 5.1914062 L 7.3007812 0.75195312 C 6.8972331 0.40778617 6.4010201 0.23063678 5.8828125 0.2109375 z M 10.304688 5.703125 C 10.467609 5.685648 10.663263 5.7499911 10.828125 5.890625 L 11.210938 6.21875 L 6.5957031 9.8847656 L 10.060547 5.8242188 C 10.120897 5.7534558 10.206934 5.7136111 10.304688 5.703125 z M 14.550781 5.7402344 C 14.6898 5.7328444 14.815451 5.7759495 14.892578 5.8730469 L 18.494141 10.408203 C 18.648395 10.602401 18.552761 10.932817 18.28125 11.148438 L 10.611328 17.238281 C 10.339882 17.453897 9.9980038 17.47154 9.84375 17.277344 L 6.2421875 12.744141 C 6.0879337 12.549944 6.1836297 12.221473 6.4550781 12.005859 L 14.123047 5.9140625 C 14.258772 5.806255 14.411762 5.7476235 14.550781 5.7402344 z M 13.505859 7.1542969 A 0.76761252 0.76761252 0 0 0 13.0625 7.3222656 A 0.76761252 0.76761252 0 0 0 12.943359 8.4023438 A 0.76761252 0.76761252 0 0 0 14.023438 8.5195312 A 0.76761252 0.76761252 0 0 0 14.140625 7.4414062 A 0.76761252 0.76761252 0 0 0 13.505859 7.1542969 z M 16.201172 10.509766 A 0.76742482 0.76742482 0 0 0 15.757812 10.677734 A 0.76742482 0.76742482 0 0 0 15.640625 11.757812 A 0.76742482 0.76742482 0 0 0 16.71875 11.875 A 0.76742482 0.76742482 0 0 0 16.837891 10.796875 A 0.76742482 0.76742482 0 0 0 16.201172 10.509766 z M 12.322266 10.855469 A 0.76742482 0.76742482 0 0 0 11.878906 11.023438 A 0.76742482 0.76742482 0 0 0 11.759766 12.101562 A 0.76742482 0.76742482 0 0 0 12.839844 12.220703 A 0.76742482 0.76742482 0 0 0 12.957031 11.140625 A 0.76742482 0.76742482 0 0 0 12.322266 10.855469 z M 8.4589844 11.199219 A 0.76742482 0.76742482 0 0 0 8.0136719 11.367188 A 0.76742482 0.76742482 0 0 0 7.8964844 12.447266 A 0.76742482 0.76742482 0 0 0 8.9746094 12.566406 A 0.76742482 0.76742482 0 0 0 9.09375 11.486328 A 0.76742482 0.76742482 0 0 0 8.4589844 11.199219 z M 18.248047 13.244141 L 14.707031 17.396484 C 14.546099 17.585183 14.205167 17.555044 13.941406 17.330078 L 13.537109 16.986328 L 18.248047 13.244141 z M 11.15625 14.570312 A 0.76742482 0.76742482 0 0 0 10.712891 14.738281 A 0.76742482 0.76742482 0 0 0 10.595703 15.816406 A 0.76742482 0.76742482 0 0 0 11.671875 15.935547 A 0.76742482 0.76742482 0 0 0 11.791016 14.855469 A 0.76742482 0.76742482 0 0 0 11.15625 14.570312 z" />
</graphic>
</Tab>
<Tab closable="false">
<content>
<fx:include fx:id="SettingsTab" source="SettingsTab.fxml" VBox.vgrow="ALWAYS" />

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.SVGPath?>
<?import javafx.scene.text.Font?>
<ScrollPane fitToWidth="true" onDragDropped="#handleDrop" onDragOver="#handleDragOver" xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nsusbloader.Controllers.PatchesController">
<VBox fx:id="patchesToolPane" spacing="15.0">
<Pane minHeight="-Infinity" prefHeight="10.0" style="-fx-background-color: linear-gradient(from 41px 34px to 50px 50px, reflect, #2cd882 40%, transparent 45%);" />
<HBox alignment="CENTER">
<children>
<Label text="%tabPatches_Lbl_Title">
<font>
<Font name="System Bold" size="15.0" />
</font>
</Label>
</children>
</HBox>
<GridPane>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" />
<ColumnConstraints hgrow="SOMETIMES" percentWidth="90.0" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<rowConstraints>
<RowConstraints vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Separator prefWidth="200.0" styleClass="strangeSeparator" GridPane.columnIndex="1" />
</children>
</GridPane>
<VBox spacing="8.0">
<children>
<VBox spacing="5.0">
<children>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Firmware" wrapText="true" />
<Label fx:id="shortNameFirmwareLbl" textOverrun="LEADING_WORD_ELLIPSIS" />
<Pane HBox.hgrow="ALWAYS" />
<Button fx:id="selFwFolderBtn" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectFirmware" styleClass="buttonSelect" text="%tabSplMrg_Btn_SelectFolder" wrapText="true">
<graphic>
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
</graphic>
</Button>
</children>
</HBox>
<Label fx:id="locationFirmwareLbl" disable="true" textOverrun="LEADING_WORD_ELLIPSIS">
<font>
<Font name="System Italic" size="13.0" />
</font>
</Label>
</children>
</VBox>
<Separator prefWidth="200.0" />
<VBox spacing="5.0">
<children>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabPatches_Lbl_Keys" wrapText="true" />
<Label fx:id="shortNameKeysLbl" />
<Pane HBox.hgrow="ALWAYS" />
<Button fx:id="selProdKeysBtn" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectProdKeys" styleClass="buttonSelect" text="%btn_Select">
<graphic>
<SVGPath content="M22,18V22H18V19H15V16H12L9.74,13.74C9.19,13.91 8.61,14 8,14A6,6 0 0,1 2,8A6,6 0 0,1 8,2A6,6 0 0,1 14,8C14,8.61 13.91,9.19 13.74,9.74L22,18M7,5A2,2 0 0,0 5,7A2,2 0 0,0 7,9A2,2 0 0,0 9,7A2,2 0 0,0 7,5Z" fill="#289de8" />
</graphic>
</Button>
</children>
</HBox>
<Label fx:id="locationKeysLbl" disable="true" textOverrun="LEADING_WORD_ELLIPSIS">
<font>
<Font name="System Italic" size="13.0" />
</font></Label>
</children>
</VBox>
<VBox spacing="5.0">
<children>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minHeight="-Infinity" minWidth="-Infinity" text="%tabSplMrg_Lbl_SaveToLocation" wrapText="true" />
<Label fx:id="saveToLbl" />
<Pane HBox.hgrow="ALWAYS" />
<Button fx:id="selProdKeysBtn1" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" onAction="#selectSaveTo" styleClass="buttonSelect" text="%btn_Select">
<graphic>
<SVGPath content="M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z" fill="#289de8" />
</graphic>
</Button>
</children>
</HBox>
</children>
</VBox>
</children>
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</VBox>
<HBox alignment="CENTER">
<children>
<Label fx:id="statusLbl" />
</children>
</HBox>
<Pane VBox.vgrow="ALWAYS" />
<HBox alignment="CENTER">
<children>
<Button fx:id="makeEsBtn" contentDisplay="TOP" mnemonicParsing="false" styleClass="buttonUp" text="%tabPatches_Btn_MakeEs" />
</children>
</HBox>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</VBox>
</ScrollPane>

View File

@ -79,3 +79,14 @@ windowBodyFilesScanned=Files scanned: %d\nWould be added: %d
tab2_Lbl_AwooBlockTitle=Awoo Installer and compatible
tabRcm_Lbl_Payload=Payload:
tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
tabPatches_Lbl_Firmware=Firmware:
tabPatches_Lbl_Atmo=Atmosphere:
tabPatches_Btn_fromFolder=From folder
tabPatches_Btn_asZipFile=as ZIP file
tabPatches_Lbl_Title=Patches
tabPatches_Lbl_Keys=Keys:
tabPatches_Btn_MakeEs=Make ES
tabPatches_Btn_MakeFs=Make FS
tabPatches_Btn_MakeAtmo=Make Atmo
tabPatches_Btn_MakeAll=Make all
tabPatches_ServiceWindowMessage=Both firmware and keys should be set to generate patches. Otherwise, it's not clear what to patch.

View File

@ -77,5 +77,16 @@ windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u043E\u0432 \u043F\u0440\u043E\u
tab2_Lbl_AwooBlockTitle=Awoo Installer \u0438 \u0441\u043E\u0432\u043C\u0435\u0441\u0442\u0438\u043C\u044B\u0435
tabRcm_Lbl_Payload=Payload:
tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
tabPatches_Btn_asZipFile=\u0432 \u0432\u0438\u0434\u0435 ZIP
tabPatches_Btn_fromFolder=\u0418\u0437 \u043F\u0430\u043F\u043A\u0438
tabPatches_Btn_MakeAll=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0441\u0451
tabPatches_Btn_MakeAtmo=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F Atmo
tabPatches_Btn_MakeEs=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F ES
tabPatches_Btn_MakeFs=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F FS
tabPatches_Lbl_Atmo=Atmosphere:
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0438
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
tabPatches_ServiceWindowMessage=\u0414\u043B\u044F \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043F\u0430\u0442\u0447\u0435\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043A\u0430\u043A \u043F\u0443\u0442\u044C \u043A \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0435, \u0442\u0430\u043A \u0438 \u043F\u0443\u0442\u044C \u043A \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0435\u0439. \u0418\u043D\u0430\u0447\u0435 \u043D\u0435 \u043F\u043E\u043D\u044F\u0442\u043D\u043E \u0447\u0442\u043E \u0436\u0435 \u043F\u0430\u0442\u0447\u0438\u0442\u044C.

View File

@ -77,4 +77,15 @@ windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u0456\u0432 \u043F\u0440\u043E\u
tab2_Lbl_AwooBlockTitle=Awoo Installer \u0442\u0430 \u0441\u0443\u043C\u0456\u0441\u043D\u0456
tabRcm_Lbl_Payload=Payload:
tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM
tabPatches_Btn_asZipFile=\u044F\u043A ZIP
tabPatches_Btn_fromFolder=\u0417 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0456\u0457
tabPatches_Btn_MakeAll=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0432\u0441\u0456
tabPatches_Btn_MakeAtmo=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F Atmo
tabPatches_Btn_MakeEs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F ES
tabPatches_Btn_MakeFs=\u0421\u0442\u0432\u043E\u0440\u0438\u0442\u0438 \u0434\u043B\u044F FS
tabPatches_Lbl_Atmo=Atmosphere:
tabPatches_Lbl_Firmware=\u041F\u0440\u043E\u0448\u0438\u0432\u043A\u0430:
tabPatches_Lbl_Keys=\u041A\u043B\u044E\u0447\u0456
tabPatches_Lbl_Title=\u041F\u0430\u0442\u0447\u0438
tabPatches_ServiceWindowMessage=\u0414\u043B\u044F \u0441\u0442\u0432\u043E\u0440\u0435\u043D\u043D\u044F \u043F\u0430\u0442\u0447\u0456\u0432 \u043D\u0435\u043E\u0431\u0445\u0456\u0434\u043D\u043E \u0432\u043A\u0430\u0437\u0430\u0442\u0438 \u044F\u043A \u0448\u043B\u044F\u0445 \u0434\u043E \u043F\u0440\u043E\u0448\u0438\u0432\u043A\u0438, \u0442\u0430\u043A \u0456 \u0434\u043E \u0444\u0430\u0439\u043B\u0443 \u043A\u043B\u044E\u0447\u0456\u0432. \u0411\u043E \u0456\u043D\u0430\u043A\u0448\u0435 \u043D\u0435 \u0437\u0440\u043E\u0437\u0443\u043C\u0456\u043B\u043E \u0449\u043E \u0436 \u0442\u0440\u0435\u0431\u0430 \u043F\u0430\u0442\u0447\u0438\u0442\u0438.

View File

@ -409,6 +409,13 @@
-fx-min-height: 24;
-fx-min-width: 36;
}
.regionCake{
-fx-shape: "M12,1.5A2.5,2.5 0 0,1 14.5,4A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 9.5,4A2.5,2.5 0 0,1 12,1.5M15.87,5C18,5 20,7 20,9C22.7,9 22.7,13 20,13H4C1.3,13 1.3,9 4,9C4,7 6,5 8.13,5C8.57,6.73 10.14,8 12,8C13.86,8 15.43,6.73 15.87,5M5,15H8L9,22H7L5,15M10,15H14L13,22H11L10,15M16,15H19L17,22H15L16,15Z";
-fx-background-color: #71e016;
-size: 24;
-fx-min-height: -size;
-fx-min-width: -size;
}
.regionDump{
-fx-shape: "M 4.0078125 0 C 1.5078125 0 0 1.4882812 0 3.984375 L 0 15.988281 C 0 18.417969 1.4927148 20 4.0078125 20 L 6.5 20 L 6.5 0 L 4.0078125 0 z M 23.5 0 L 23.5 20 C 24.504057 19.999294 25.159942 20 25.992188 20 C 28.414062 20 30 18.496094 30 15.996094 L 30 3.9765625 C 30 1.5195311 28.508726 0 26.003906 0 L 23.5 0 z M 11.990234 2.8886719 L 11.990234 9.9003906 L 6.9902344 9.9003906 L 14.990234 20 L 22.990234 9.9003906 L 17.990234 9.9003906 C 17.990234 8.2387016 17.9999 3.6538029 18 2.8886719 L 11.990234 2.8886719 z M 3.1015625 2.9570312 C 4.1485235 2.9562481 4.9977514 3.8046013 4.9980469 4.8515625 C 4.998831 5.8992865 4.1492865 6.7488309 3.1015625 6.7480469 C 2.0546013 6.7477509 1.2062483 5.8985235 1.2070312 4.8515625 C 1.2073268 3.8053642 2.0553642 2.9573267 3.1015625 2.9570312 z M 26.865234 11.148438 C 27.912958 11.147652 28.762503 11.997198 28.761719 13.044922 C 28.761423 14.091883 27.912195 14.940236 26.865234 14.939453 C 25.819036 14.939158 24.970999 14.09112 24.970703 13.044922 C 24.96992 11.997961 25.818273 11.148733 26.865234 11.148438 z ";
-fx-background-color: #71e016;

View File

@ -327,6 +327,13 @@
-fx-min-height: 24;
-fx-min-width: 36;
}
.regionCake{
-fx-shape: "M12,1.5A2.5,2.5 0 0,1 14.5,4A2.5,2.5 0 0,1 12,6.5A2.5,2.5 0 0,1 9.5,4A2.5,2.5 0 0,1 12,1.5M15.87,5C18,5 20,7 20,9C22.7,9 22.7,13 20,13H4C1.3,13 1.3,9 4,9C4,7 6,5 8.13,5C8.57,6.73 10.14,8 12,8C13.86,8 15.43,6.73 15.87,5M5,15H8L9,22H7L5,15M10,15H14L13,22H11L10,15M16,15H19L17,22H15L16,15Z";
-fx-background-color: #71e016;
-size: 24;
-fx-min-height: -size;
-fx-min-width: -size;
}
.regionDump{
-fx-shape: "M 4.0078125 0 C 1.5078125 0 0 1.4882812 0 3.984375 L 0 15.988281 C 0 18.417969 1.4927148 20 4.0078125 20 L 6.5 20 L 6.5 0 L 4.0078125 0 z M 23.5 0 L 23.5 20 C 24.504057 19.999294 25.159942 20 25.992188 20 C 28.414062 20 30 18.496094 30 15.996094 L 30 3.9765625 C 30 1.5195311 28.508726 0 26.003906 0 L 23.5 0 z M 11.990234 2.8886719 L 11.990234 9.9003906 L 6.9902344 9.9003906 L 14.990234 20 L 22.990234 9.9003906 L 17.990234 9.9003906 C 17.990234 8.2387016 17.9999 3.6538029 18 2.8886719 L 11.990234 2.8886719 z M 3.1015625 2.9570312 C 4.1485235 2.9562481 4.9977514 3.8046013 4.9980469 4.8515625 C 4.998831 5.8992865 4.1492865 6.7488309 3.1015625 6.7480469 C 2.0546013 6.7477509 1.2062483 5.8985235 1.2070312 4.8515625 C 1.2073268 3.8053642 2.0553642 2.9573267 3.1015625 2.9570312 z M 26.865234 11.148438 C 27.912958 11.147652 28.762503 11.997198 28.761719 13.044922 C 28.761423 14.091883 27.912195 14.940236 26.865234 14.939453 C 25.819036 14.939158 24.970999 14.09112 24.970703 13.044922 C 24.96992 11.997961 25.818273 11.148733 26.865234 11.148438 z ";
-fx-background-color: #71e016;