diff --git a/README.md b/README.md
index 2d269d1..876eeff 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
![License](https://img.shields.io/badge/License-GPLv3-blue.svg) [![Build Status](https://ci.redrise.ru/api/badges/desu/libKonogonka/status.svg)](https://ci.redrise.ru/desu/libKonogonka)
-Library to work with NS-specific files / filesystem images. Ex-backend of [konogonka](https://github.com/developersu/konogonka) ([independent source location](https://git.redrise.ru/desu/konogonka))
+Library made to work with NS-specific files / filesystem images. Separated backend of [konogonka](https://github.com/developersu/konogonka) ([independent source location](https://git.redrise.ru/desu/konogonka))
### Let's stay in touch
@@ -20,8 +20,8 @@ You can get this application from independent source location: [https://git.redr
#### Thanks
-* Switch brew wiki
-* Original ScriesM software
+* [Switch brew](https://switchbrew.org) wiki
+* Original [ScriesM software](https://github.com/SciresM/)
* roothorick, [shchmue](https://github.com/shchmue/), He, other Team AtlasNX discord members for their advices, notes and examples!
### System requirements
@@ -30,4 +30,8 @@ JRE/JDK 8u60 or higher.
### Build
-See .drone.yml
\ No newline at end of file
+See .drone.yml
+
+### Install on local host (local maven repo)
+
+`# mvn instal`
\ No newline at end of file
diff --git a/misc/logo.svg b/misc/logo.svg
index dfff516..d1f8abd 100644
--- a/misc/logo.svg
+++ b/misc/logo.svg
@@ -25,13 +25,13 @@
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="2.8284272"
- inkscape:cx="378.30212"
- inkscape:cy="70.5339"
- inkscape:window-width="2266"
- inkscape:window-height="1414"
- inkscape:window-x="1305"
- inkscape:window-y="546"
- inkscape:window-maximized="0"
+ inkscape:cx="378.65567"
+ inkscape:cy="71.06423"
+ inkscape:window-width="3754"
+ inkscape:window-height="2127"
+ inkscape:window-x="1166"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
inkscape:current-layer="layer1"
showguides="false" />
- libKonogonka
+
+
+
+
+
+
+
+
+
+
+
+
+
+
2.19.0
compile
+
+
+ org.lz4
+ lz4-pure-java
+ 1.8.0
+ compile
+
org.junit.jupiter
@@ -89,11 +96,7 @@
5.9.0
test
-
- org.lz4
- lz4-pure-java
- 1.8.0
-
+
${project.artifactId}-${project.version}-${maven.build.timestamp}
diff --git a/src/main/java/libKonogonka/RainbowDump.java b/src/main/java/libKonogonka/RainbowDump.java
index dba4ffb..a2e8bd3 100644
--- a/src/main/java/libKonogonka/RainbowDump.java
+++ b/src/main/java/libKonogonka/RainbowDump.java
@@ -22,7 +22,11 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.nio.charset.StandardCharsets;
-
+/* ANSI_BLACK = "\u001B[30m";
+ ANSI_YELLOW = "\u001B[33m";
+ ANSI_PURPLE = "\u001B[35m";
+ ANSI_CYAN = "\u001B[36m";
+ ANSI_WHITE = "\u001B[37m"; */
/**
* Debug tool like hexdump <3
*/
@@ -30,14 +34,9 @@ public class RainbowDump {
private final static Logger log = LogManager.getLogger(Converter.class);
private static final String ANSI_RESET = "\u001B[0m";
- private static final String ANSI_BLACK = "\u001B[30m";
private static final String ANSI_RED = "\u001B[31m";
private static final String ANSI_GREEN = "\u001B[32m";
- private static final String ANSI_YELLOW = "\u001B[33m";
private static final String ANSI_BLUE = "\u001B[34m";
- private static final String ANSI_PURPLE = "\u001B[35m";
- private static final String ANSI_CYAN = "\u001B[36m";
- private static final String ANSI_WHITE = "\u001B[37m";
private static StringBuilder stringBuilder;
public static void hexDumpUTF8(byte[] byteArray){
@@ -80,7 +79,13 @@ public class RainbowDump {
}
private static void printChars(byte[] byteArray, int pointer){
- for (int j = pointer-16; j < pointer; j++){
+ int j;
+ if (pointer < 16)
+ j = 0;
+ else
+ j = pointer-16;
+
+ for (; j < pointer; j++){
if ((byteArray[j] > 21) && (byteArray[j] < 126)) // man ascii
stringBuilder.append((char) byteArray[j]);
else if (byteArray[j] == 0x0a)
@@ -92,18 +97,22 @@ public class RainbowDump {
}
}
-
public static void hexDumpUTF8Legacy(byte[] byteArray){
+ StringBuilder stringBuilderLegacy = new StringBuilder("HexDumpUTF8Legacy");
+ stringBuilderLegacy.append(ANSI_BLUE);
+
if (byteArray == null || byteArray.length == 0)
return;
- System.out.print(ANSI_BLUE);
+
for (int i=0; i < byteArray.length; i++)
- System.out.printf("%02d-", i%100);
- System.out.println(">"+ANSI_RED+byteArray.length+ANSI_RESET);
+ stringBuilderLegacy.append(String.format("%02d-", i%100));
+ stringBuilderLegacy.append(">" + ANSI_RED).append(byteArray.length).append(ANSI_RESET).append("\n");
for (byte b: byteArray)
- System.out.printf("%02x ", b);
- System.out.println();
- System.out.print(new String(byteArray, StandardCharsets.UTF_8)+"\n");
+ stringBuilderLegacy.append(String.format("%02x ", b));
+ stringBuilderLegacy.append("\n")
+ .append(new String(byteArray, StandardCharsets.UTF_8))
+ .append("\n");
+ log.debug(stringBuilderLegacy.toString());
}
public static void binDumpInt(int value){
@@ -111,7 +120,7 @@ public class RainbowDump {
}
public static void binDumpLong(long value){
- System.out.println(String.format("%64s", Long.toBinaryString( value )).replace(' ', '0')+" | "+value);
+ log.debug(String.format("%64s", Long.toBinaryString( value )).replace(' ', '0')+" | "+value);
}
public static String formatDecHexString(long value){
diff --git a/src/main/java/libKonogonka/Tools/NPDM/KernelAccessControlProvider.java b/src/main/java/libKonogonka/Tools/NPDM/KernelAccessControlProvider.java
index cbe7f37..2f3cb97 100644
--- a/src/main/java/libKonogonka/Tools/NPDM/KernelAccessControlProvider.java
+++ b/src/main/java/libKonogonka/Tools/NPDM/KernelAccessControlProvider.java
@@ -19,6 +19,8 @@
package libKonogonka.Tools.NPDM;
import libKonogonka.Converter;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -73,6 +75,7 @@ for (byte i = 0; i < 16; i++){
*/
public class KernelAccessControlProvider {
+ private final static Logger log = LogManager.getLogger(KernelAccessControlProvider.class);
private static final int KERNELFLAGS = 3,
SYSCALLMASK = 4,
@@ -85,7 +88,7 @@ public class KernelAccessControlProvider {
DEBUGFLAGS = 16;
// RAW data
- private LinkedList rawData;
+ private final LinkedList rawData;
// Kernel flags
private boolean kernelFlagsAvailable;
private int kernelFlagCpuIdHi,
@@ -93,13 +96,13 @@ public class KernelAccessControlProvider {
kernelFlagThreadPrioHi,
kernelFlagThreadPrioLo;
// Syscall Masks as index | mask - order AS IS. [0] = bit5; [1] = bit6
- private LinkedHashMap syscallMasks; // Index, Mask
+ private final LinkedHashMap syscallMasks; // Index, Mask
// MapIoOrNormalRange
- private LinkedHashMap mapIoOrNormalRange; // alt page+num, RO flag
+ private final LinkedHashMap mapIoOrNormalRange; // alt page+num, RO flag
// MapNormalPage (RW)
private byte[] mapNormalPage; // TODO: clarify is possible to have multiple
// InterruptPair
- private LinkedHashMap interruptPairs; // Number; irq0, irq2
+ private final LinkedHashMap interruptPairs; // Number; irq0, irq2
// Application type
private int applicationType;
// KernelReleaseVersion
@@ -142,42 +145,42 @@ public class KernelAccessControlProvider {
kernelFlagCpuIdLo = block >> 16 & 0b11111111;
kernelFlagThreadPrioHi = block >> 10 & 0b111111;
kernelFlagThreadPrioLo = block >> 4 & 0b111111;
- //System.out.println("KERNELFLAGS "+kernelFlagCpuIdHi+" "+kernelFlagCpuIdLo+" "+kernelFlagThreadPrioHi+" "+kernelFlagThreadPrioLo);
+ //log.debug("KERNELFLAGS "+kernelFlagCpuIdHi+" "+kernelFlagCpuIdLo+" "+kernelFlagThreadPrioHi+" "+kernelFlagThreadPrioLo);
break;
case SYSCALLMASK:
byte maskTableIndex = (byte) (block >> 29 & 0b111); // declared as byte; max value could be 7; min - 0;
byte[] mask = new byte[24]; // Consider as bit.
- //System.out.println("SYSCALLMASK ind: "+maskTableIndex);
+ //log.debug("SYSCALLMASK ind: "+maskTableIndex);
for (int k = 28; k >= 5; k--) {
mask[k-5] = (byte) (block >> k & 1); // Only 1 or 0 possible
- //System.out.print(mask[k-5]);
+ //log.debug(" " + mask[k-5]);
}
- //System.out.println();
+ //log.debug();
syscallMasks.put(maskTableIndex, mask);
break;
case MAPIOORNORMALRANGE:
byte[] altStPgNPgNum = new byte[24];
- //System.out.println("MAPIOORNORMALRANGE Flag: "+((block >> 31 & 1) != 0));
+ //log.debug("MAPIOORNORMALRANGE Flag: "+((block >> 31 & 1) != 0));
for (int k = 30; k >= 7; k--){
altStPgNPgNum[k-7] = (byte) (block >> k & 1); // Only 1 or 0 possible
- //System.out.print(altStPgNPgNum[k-7]);
+ //log.debug(" " + altStPgNPgNum[k-7]);
}
mapIoOrNormalRange.put(altStPgNPgNum, (block >> 31 & 1) != 0);
- //System.out.println();
+ //log.debug();
break;
case MAPNORMALPAGE_RW:
- //System.out.println("MAPNORMALPAGE_RW\t");
+ //log.debug("MAPNORMALPAGE_RW\t");
mapNormalPage = new byte[24];
for (int k = 31; k >= 8; k--){
mapNormalPage[k-8] = (byte) (block >> k & 1);
- //System.out.print(mapNormalPage[k-8]);
+ //log.debug(" " + mapNormalPage[k-8]);
}
- //System.out.println();
+ //log.debug();
break;
case INTERRUPTPAIR:
- //System.out.println("INTERRUPTPAIR");
+ //log.debug("INTERRUPTPAIR");
//RainbowHexDump.octDumpInt(block);
byte[][] pair = new byte[2][];
byte[] irq0 = new byte[10];
@@ -193,26 +196,26 @@ public class KernelAccessControlProvider {
break;
case APPLICATIONTYPE:
applicationType = block >> 14 & 0b111;
- //System.out.println("APPLICATIONTYPE "+applicationType);
+ //log.debug("APPLICATIONTYPE "+applicationType);
break;
case KERNELRELEASEVERSION:
- //System.out.println("KERNELRELEASEVERSION\t"+(block >> 19 & 0b111111111111)+"."+(block >> 15 & 0b1111)+".X");
+ //log.debug("KERNELRELEASEVERSION\t"+(block >> 19 & 0b111111111111)+"."+(block >> 15 & 0b1111)+".X");
isKernelRelVersionAvailable = true;
kernelRelVersionMajor = (block >> 19 & 0b111111111111);
kernelRelVersionMinor = (block >> 15 & 0b1111);
break;
case HANDLETABLESIZE:
handleTableSize = block >> 16 & 0b1111111111;
- //System.out.println("HANDLETABLESIZE "+handleTableSize);
+ //log.debug("HANDLETABLESIZE "+handleTableSize);
break;
case DEBUGFLAGS:
debugFlagsAvailable = true;
canBeDebugged = (block >> 17 & 1) != 0;
canDebugOthers = (block >> 18 & 1) != 0;
- //System.out.println("DEBUGFLAGS "+canBeDebugged+" "+canDebugOthers);
+ //log.debug("DEBUGFLAGS "+canBeDebugged+" "+canDebugOthers);
break;
default:
- System.out.println("UNKNOWN\t\t"+block+" "+type);
+ log.error("UNKNOWN\t\t"+block+" "+type);
}
}
}
diff --git a/src/main/java/libKonogonka/Tools/NSO/NSO0Header.java b/src/main/java/libKonogonka/Tools/NSO/NSO0Header.java
new file mode 100644
index 0000000..dd5af64
--- /dev/null
+++ b/src/main/java/libKonogonka/Tools/NSO/NSO0Header.java
@@ -0,0 +1,174 @@
+/*
+ Copyright 2018-2022 Dmitry Isaenko
+
+ This file is part of libKonogonka.
+
+ libKonogonka 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.
+
+ libKonogonka 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 libKonogonka. If not, see .
+ */
+package libKonogonka.Tools.NSO;
+
+import libKonogonka.Converter;
+import libKonogonka.RainbowDump;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import static libKonogonka.Converter.getLEint;
+
+public class NSO0Header {
+ private final static Logger log = LogManager.getLogger(NSO0Header.class);
+
+ private String magic;
+ private int version;
+ private byte[] upperReserved;
+ private int flags;
+ private SegmentHeader textSegmentHeader;
+ private int moduleNameOffset; // note: could be unsigned int; consider 'long'
+ private SegmentHeader rodataSegmentHeader;
+ private int moduleNameSize;
+ private SegmentHeader dataSegmentHeader;
+ private int bssSize; // note: could be unsigned int; consider 'long'
+ private byte[] moduleId;
+ private int textCompressedSize;
+ private int rodataCompressedSize;
+ private int dataCompressedSize;
+ private byte[] bottomReserved;
+ private SegmentHeaderRelative _api_infoRelative;
+ private SegmentHeaderRelative _dynstrRelative;
+ private SegmentHeaderRelative _dynsymRelative;
+ private byte[] textHash;
+ private byte[] rodataHash;
+ private byte[] dataHash;
+
+ public NSO0Header(byte[] headerBytes) throws Exception{
+ if (headerBytes.length < 0x100)
+ throw new Exception("Incorrect NSO0 header size");
+ parse(headerBytes);
+ }
+
+ private void parse(byte[] knownStartingBytes) throws Exception{
+ this.magic = new String(knownStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
+ if (! magic.equals("NSO0")){
+ throw new Exception("Bad magic");
+ }
+
+ this.version = getLEint(knownStartingBytes, 0x4);
+ this.upperReserved = Arrays.copyOfRange(knownStartingBytes, 0x8, 0xC);
+ this.flags = getLEint(knownStartingBytes, 0xC);
+ this.textSegmentHeader = new SegmentHeader(knownStartingBytes, 0x10);
+ this.moduleNameOffset = Converter.getLEint(knownStartingBytes, 0x1C);
+ this.rodataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x20);
+ this.moduleNameSize = Converter.getLEint(knownStartingBytes, 0x2C);
+ this.dataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x30);
+ this.bssSize = Converter.getLEint(knownStartingBytes, 0x3C);
+ this.moduleId = Arrays.copyOfRange(knownStartingBytes, 0x40, 0x60);
+ this.textCompressedSize = Converter.getLEint(knownStartingBytes, 0x60);
+ this.rodataCompressedSize = Converter.getLEint(knownStartingBytes, 0x64);
+ this.dataCompressedSize = Converter.getLEint(knownStartingBytes, 0x68);
+ this.bottomReserved = Arrays.copyOfRange(knownStartingBytes, 0x6C, 0x88);
+ this._api_infoRelative = new SegmentHeaderRelative(knownStartingBytes, 0x88);
+ this._dynstrRelative = new SegmentHeaderRelative(knownStartingBytes, 0x90);
+ this._dynsymRelative = new SegmentHeaderRelative(knownStartingBytes, 0x98);
+ this.textHash = Arrays.copyOfRange(knownStartingBytes, 0xA0, 0xC0);
+ this.rodataHash = Arrays.copyOfRange(knownStartingBytes, 0xC0, 0xE0);
+ this.dataHash = Arrays.copyOfRange(knownStartingBytes, 0xE0, 0x100);
+ }
+
+ /* API */
+ public String getMagic() { return magic; }
+ public int getVersion() {return version; }
+ public byte[] getUpperReserved() { return upperReserved; }
+ public int getFlags() { return flags; }
+ public boolean isTextCompressFlag(){ return (flags & 0b000001) == 1; }
+ public boolean isRoCompressFlag(){ return (flags & 0b000010) >> 1 == 1; }
+ public boolean isDataCompressFlag(){ return (flags & 0b000100 ) >> 2 == 1; }
+ public boolean isTextHashFlag(){ return (flags & 0b001000 ) >> 3 == 1; }
+ public boolean isRoHashFlag(){ return (flags & 0b010000 ) >> 4 == 1; }
+ public boolean isDataHashFlag(){ return (flags & 0b100000 ) >> 5 == 1; }
+ public SegmentHeader getTextSegmentHeader() { return textSegmentHeader; }
+ public int getModuleNameOffset() { return moduleNameOffset; }
+ public SegmentHeader getRodataSegmentHeader() { return rodataSegmentHeader; }
+ public int getModuleNameSize() { return moduleNameSize; }
+ public SegmentHeader getDataSegmentHeader() { return dataSegmentHeader; }
+ public int getBssSize() { return bssSize; }
+ public byte[] getModuleId() { return moduleId; }
+ public int getTextCompressedSize() { return textCompressedSize; }
+ public int getRodataCompressedSize() { return rodataCompressedSize; }
+ public int getDataCompressedSize() { return dataCompressedSize; }
+ public byte[] getBottomReserved() { return bottomReserved; }
+ public SegmentHeaderRelative get_api_infoRelative() { return _api_infoRelative; }
+ public SegmentHeaderRelative get_dynstrRelative() { return _dynstrRelative; }
+ public SegmentHeaderRelative get_dynsymRelative() { return _dynsymRelative; }
+ public byte[] getTextHash() { return textHash; }
+ public byte[] getRodataHash() { return rodataHash; }
+ public byte[] getDataHash() { return dataHash; }
+
+ public void printDebug(){
+ log.debug(".:: NSO0 Provider ::.\n" +
+ " ============================================================= \n" +
+ "Magic \"NSO0\" " + magic + "\n" +
+ "Version (always 0) " + version + "\n" +
+ "Reserved " + Converter.byteArrToHexString(upperReserved) + "\n" +
+ "Flags " + Converter.intToBinaryString(flags) + "\n" +
+ " |- 0. .text Compress " + isTextCompressFlag() + "\n" +
+ " |- 1. .rodata Compress " + isRoCompressFlag() + "\n" +
+ " |- 2. .data Compress " + isDataCompressFlag() + "\n" +
+ " |- 3. .text Hash " + isTextHashFlag() + "\n" +
+ " |- 4. .rodata Hash " + isRoHashFlag() + "\n" +
+ " |- 5. .data Hash " + isDataHashFlag() + "\n" +
+ " +++\n"+
+ "SegmentHeader for .text\n" +
+ " |- File Offset - - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSegmentOffset()) + "\n" +
+ " |- Memory Offset - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getMemoryOffset()) + "\n" +
+ " |- Size As Decompressed - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSizeAsDecompressed()) + "\n" +
+ "ModuleNameOffset (calculated by sizeof(header)) " + RainbowDump.formatDecHexString(moduleNameOffset) + "\n" +
+ " +++\n"+
+ "SegmentHeader for .rodata\n" +
+ " |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSegmentOffset()) + "\n" +
+ " |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getMemoryOffset()) + "\n" +
+ " |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSizeAsDecompressed()) + "\n" +
+ "ModuleNameSize " + RainbowDump.formatDecHexString(moduleNameSize) + "\n" +
+ " +++\n"+
+ "SegmentHeader for .data\n" +
+ " |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSegmentOffset()) + "\n" +
+ " |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getMemoryOffset()) + "\n" +
+ " |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSizeAsDecompressed()) + "\n" +
+ " .bss Size " + RainbowDump.formatDecHexString(bssSize) + "\n" + // Block Started by Symbol
+ "Module ID (aka Build ID) " + Converter.byteArrToHexString(moduleId) + "\n" +
+ " .text Size (compressed) " + RainbowDump.formatDecHexString(textCompressedSize) + "\n" +
+ " .rodata Size (compressed) " + RainbowDump.formatDecHexString(rodataCompressedSize) + "\n" +
+ " .data Size (compressed) " + RainbowDump.formatDecHexString(dataCompressedSize) + "\n" +
+ "Reserved " + Converter.byteArrToHexString(bottomReserved) + "\n" +
+ " xxx\n"+
+ "SegmentHeaderRelative for .api_info\n" +
+ " |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getOffset()) + "\n" +
+ " |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getSize()) + "\n" +
+ " xxx\n"+
+ "SegmentHeaderRelative for .dynstr\n" +
+ " |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getOffset()) + "\n" +
+ " |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getSize()) + "\n" +
+ " xxx\n"+
+ "SegmentHeaderRelative for .dynsym\n" +
+ " |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getOffset()) + "\n" +
+ " |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getSize()) + "\n" +
+ " xxx\n"+
+ ".text decompressed' SHA-256 hash " + Converter.byteArrToHexString(textHash) + "\n" +
+ ".rodata decompressed' SHA-256 hash " + Converter.byteArrToHexString(rodataHash) + "\n" +
+ ".data decompressed' SHA-256 hash " + Converter.byteArrToHexString(dataHash) + "\n" +
+ " ============================================================= "
+ );
+ }
+}
diff --git a/src/main/java/libKonogonka/Tools/NSO/NSO0Provider.java b/src/main/java/libKonogonka/Tools/NSO/NSO0Provider.java
index 0c9fba7..9c91779 100644
--- a/src/main/java/libKonogonka/Tools/NSO/NSO0Provider.java
+++ b/src/main/java/libKonogonka/Tools/NSO/NSO0Provider.java
@@ -18,45 +18,15 @@
*/
package libKonogonka.Tools.NSO;
-import libKonogonka.Converter;
-import libKonogonka.RainbowDump;
import libKonogonka.ctraes.InFileStreamProducer;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
import java.io.BufferedInputStream;
import java.io.File;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-
-import static libKonogonka.Converter.getLEint;
public class NSO0Provider {
- private final static Logger log = LogManager.getLogger(NSO0Provider.class);
-
private final InFileStreamProducer producer;
- private String magic;
- private int version;
- private byte[] upperReserved;
- private int flags;
- private SegmentHeader textSegmentHeader;
- private int moduleNameOffset; // note: could be unsigned int; consider 'long'
- private SegmentHeader rodataSegmentHeader;
- private int moduleNameSize;
- private SegmentHeader dataSegmentHeader;
- private int bssSize; // note: could be unsigned int; consider 'long'
- private byte[] moduleId;
- private int textCompressedSize;
- private int rodataCompressedSize;
- private int dataCompressedSize;
- private byte[] bottomReserved;
- private SegmentHeaderRelative _api_infoRelative;
- private SegmentHeaderRelative _dynstrRelative;
- private SegmentHeaderRelative _dynsymRelative;
- private byte[] textHash;
- private byte[] rodataHash;
- private byte[] dataHash;
+ private final NSO0Header header;
/* Encrypted */
public NSO0Provider(InFileStreamProducer producer) throws Exception {
@@ -65,7 +35,7 @@ public class NSO0Provider {
byte[] knownStartingBytes = new byte[0x100];
if (0x100 != stream.read(knownStartingBytes))
throw new Exception("Reading stream suddenly ended while trying to read starting 0x100 bytes");
- parse(knownStartingBytes);
+ this.header = new NSO0Header(knownStartingBytes);
}
}
@@ -82,123 +52,26 @@ public class NSO0Provider {
byte[] knownStartingBytes = new byte[0x100];
if (0x100 != stream.read(knownStartingBytes))
throw new Exception("Reading stream suddenly ended while trying to read starting 0x100 bytes");
- parse(knownStartingBytes);
+ this.header = new NSO0Header(knownStartingBytes);
}
}
- private void parse(byte[] knownStartingBytes) throws Exception{
- this.magic = new String(knownStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
- if (! magic.equals("NSO0")){
- throw new Exception("Bad magic");
- }
- this.version = getLEint(knownStartingBytes, 0x4);
- this.upperReserved = Arrays.copyOfRange(knownStartingBytes, 0x8, 0xC);
- this.flags = getLEint(knownStartingBytes, 0xC);
- this.textSegmentHeader = new SegmentHeader(knownStartingBytes, 0x10);
- this.moduleNameOffset = Converter.getLEint(knownStartingBytes, 0x1C);
- this.rodataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x20);
- this.moduleNameSize = Converter.getLEint(knownStartingBytes, 0x2C);
- this.dataSegmentHeader = new SegmentHeader(knownStartingBytes, 0x30);
- this.bssSize = Converter.getLEint(knownStartingBytes, 0x3C);
- this.moduleId = Arrays.copyOfRange(knownStartingBytes, 0x40, 0x60);
- this.textCompressedSize = Converter.getLEint(knownStartingBytes, 0x60);
- this.rodataCompressedSize = Converter.getLEint(knownStartingBytes, 0x64);
- this.dataCompressedSize = Converter.getLEint(knownStartingBytes, 0x68);
- this.bottomReserved = Arrays.copyOfRange(knownStartingBytes, 0x6C, 0x88);
- this._api_infoRelative = new SegmentHeaderRelative(knownStartingBytes, 0x88);
- this._dynstrRelative = new SegmentHeaderRelative(knownStartingBytes, 0x90);
- this._dynsymRelative = new SegmentHeaderRelative(knownStartingBytes, 0x98);
- this.textHash = Arrays.copyOfRange(knownStartingBytes, 0xA0, 0xC0);
- this.rodataHash = Arrays.copyOfRange(knownStartingBytes, 0xC0, 0xE0);
- this.dataHash = Arrays.copyOfRange(knownStartingBytes, 0xE0, 0x100);
+ public NSO0Header getHeader() {
+ return header;
}
public void exportAsDecompressedNSO0(String saveToLocation) throws Exception{
- NSO0Unpacker.unpack(this, producer, saveToLocation);
+ NSO0Unpacker.unpack(header, producer, saveToLocation);
}
- /* API */
- public String getMagic() { return magic; }
- public int getVersion() {return version; }
- public byte[] getUpperReserved() { return upperReserved; }
- public int getFlags() { return flags; }
- public boolean isTextCompressFlag(){ return (flags & 0b000001) == 1; }
- public boolean isRoCompressFlag(){ return (flags & 0b000010) >> 1 == 1; }
- public boolean isDataCompressFlag(){ return (flags & 0b000100 ) >> 2 == 1; }
- public boolean isTextHashFlag(){ return (flags & 0b001000 ) >> 3 == 1; }
- public boolean isRoHashFlag(){ return (flags & 0b010000 ) >> 4 == 1; }
- public boolean isDataHashFlag(){ return (flags & 0b100000 ) >> 5 == 1; }
- public SegmentHeader getTextSegmentHeader() { return textSegmentHeader; }
- public int getModuleNameOffset() { return moduleNameOffset; }
- public SegmentHeader getRodataSegmentHeader() { return rodataSegmentHeader; }
- public int getModuleNameSize() { return moduleNameSize; }
- public SegmentHeader getDataSegmentHeader() { return dataSegmentHeader; }
- public int getBssSize() { return bssSize; }
- public byte[] getModuleId() { return moduleId; }
- public int getTextCompressedSize() { return textCompressedSize; }
- public int getRodataCompressedSize() { return rodataCompressedSize; }
- public int getDataCompressedSize() { return dataCompressedSize; }
- public byte[] getBottomReserved() { return bottomReserved; }
- public SegmentHeaderRelative get_api_infoRelative() { return _api_infoRelative; }
- public SegmentHeaderRelative get_dynstrRelative() { return _dynstrRelative; }
- public SegmentHeaderRelative get_dynsymRelative() { return _dynsymRelative; }
- public byte[] getTextHash() { return textHash; }
- public byte[] getRodataHash() { return rodataHash; }
- public byte[] getDataHash() { return dataHash; }
+ public NSO0Raw getAsDecompressedNSO0() throws Exception{
+ return NSO0Unpacker.getNSO0Raw(header, producer);
+ }
+ /**
+ * Prints header.printDebug()
+ * */
public void printDebug(){
- log.debug(".:: NSO0 Provider ::.\n" +
- " ============================================================= \n" +
- "Magic \"NSO0\" " + magic + "\n" +
- "Version (always 0) " + version + "\n" +
- "Reserved " + Converter.byteArrToHexString(upperReserved) + "\n" +
- "Flags " + Converter.intToBinaryString(flags) + "\n" +
- " |- 0. .text Compress " + isTextCompressFlag() + "\n" +
- " |- 1. .rodata Compress " + isRoCompressFlag() + "\n" +
- " |- 2. .data Compress " + isDataCompressFlag() + "\n" +
- " |- 3. .text Hash " + isTextHashFlag() + "\n" +
- " |- 4. .rodata Hash " + isRoHashFlag() + "\n" +
- " |- 5. .data Hash " + isDataHashFlag() + "\n" +
- " +++\n"+
- "SegmentHeader for .text\n" +
- " |- File Offset - - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSegmentOffset()) + "\n" +
- " |- Memory Offset - - - - - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getMemoryOffset()) + "\n" +
- " |- Size As Decompressed - - - - - - - - - "+ RainbowDump.formatDecHexString(textSegmentHeader.getSizeAsDecompressed()) + "\n" +
- "ModuleNameOffset (calculated by sizeof(header)) " + RainbowDump.formatDecHexString(moduleNameOffset) + "\n" +
- " +++\n"+
- "SegmentHeader for .rodata\n" +
- " |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSegmentOffset()) + "\n" +
- " |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getMemoryOffset()) + "\n" +
- " |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(rodataSegmentHeader.getSizeAsDecompressed()) + "\n" +
- "ModuleNameSize " + RainbowDump.formatDecHexString(moduleNameSize) + "\n" +
- " +++\n"+
- "SegmentHeader for .data\n" +
- " |- File Offset - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSegmentOffset()) + "\n" +
- " |- Memory Offset - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getMemoryOffset()) + "\n" +
- " |- Size As Decompressed - - - - - - - - - " + RainbowDump.formatDecHexString(dataSegmentHeader.getSizeAsDecompressed()) + "\n" +
- " .bss Size " + RainbowDump.formatDecHexString(bssSize) + "\n" + // Block Started by Symbol
- "Module ID (aka Build ID) " + Converter.byteArrToHexString(moduleId) + "\n" +
- " .text Size (compressed) " + RainbowDump.formatDecHexString(textCompressedSize) + "\n" +
- " .rodata Size (compressed) " + RainbowDump.formatDecHexString(rodataCompressedSize) + "\n" +
- " .data Size (compressed) " + RainbowDump.formatDecHexString(dataCompressedSize) + "\n" +
- "Reserved " + Converter.byteArrToHexString(bottomReserved) + "\n" +
- " xxx\n"+
- "SegmentHeaderRelative for .api_info\n" +
- " |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getOffset()) + "\n" +
- " |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_api_infoRelative.getSize()) + "\n" +
- " xxx\n"+
- "SegmentHeaderRelative for .dynstr\n" +
- " |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getOffset()) + "\n" +
- " |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynstrRelative.getSize()) + "\n" +
- " xxx\n"+
- "SegmentHeaderRelative for .dynsym\n" +
- " |- Offset - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getOffset()) + "\n" +
- " |- Size - - - - - - - - - - - - - - - - - " + RainbowDump.formatDecHexString(_dynsymRelative.getSize()) + "\n" +
- " xxx\n"+
- ".text decompressed' SHA-256 hash " + Converter.byteArrToHexString(textHash) + "\n" +
- ".rodata decompressed' SHA-256 hash " + Converter.byteArrToHexString(rodataHash) + "\n" +
- ".data decompressed' SHA-256 hash " + Converter.byteArrToHexString(dataHash) + "\n" +
- " ============================================================= "
- );
+ header.printDebug();
}
}
diff --git a/src/main/java/libKonogonka/Tools/NSO/NSO0Raw.java b/src/main/java/libKonogonka/Tools/NSO/NSO0Raw.java
new file mode 100644
index 0000000..97304e8
--- /dev/null
+++ b/src/main/java/libKonogonka/Tools/NSO/NSO0Raw.java
@@ -0,0 +1,47 @@
+/*
+ Copyright 2018-2022 Dmitry Isaenko
+
+ This file is part of libKonogonka.
+
+ libKonogonka 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.
+
+ libKonogonka 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 libKonogonka. If not, see .
+ */
+package libKonogonka.Tools.NSO;
+
+public class NSO0Raw {
+ private NSO0Header headerObject;
+ private final byte[] header;
+ private final byte[] _textDecompressedSection;
+ private final byte[] _rodataDecompressedSection;
+ private final byte[] _dataDecompressedSection;
+
+ NSO0Raw(byte[] header,
+ byte[] _textDecompressedSection,
+ byte[] _rodataDecompressedSection,
+ byte[] _dataDecompressedSection){
+ this.header = header;
+ this._textDecompressedSection = _textDecompressedSection;
+ this. _rodataDecompressedSection = _rodataDecompressedSection;
+ this._dataDecompressedSection = _dataDecompressedSection;
+ try {
+ this.headerObject = new NSO0Header(header);
+ }
+ catch (Exception e){ e.printStackTrace(); } //never happens
+ }
+
+ public NSO0Header getHeader() { return headerObject; }
+ public byte[] getHeaderRaw() {return header;}
+ public byte[] getTextRaw() {return _textDecompressedSection;}
+ public byte[] getRodataRaw() {return _rodataDecompressedSection;}
+ public byte[] getDataRaw() {return _dataDecompressedSection;}
+}
diff --git a/src/main/java/libKonogonka/Tools/NSO/NSO0Unpacker.java b/src/main/java/libKonogonka/Tools/NSO/NSO0Unpacker.java
index 1e61e66..8d81cc7 100644
--- a/src/main/java/libKonogonka/Tools/NSO/NSO0Unpacker.java
+++ b/src/main/java/libKonogonka/Tools/NSO/NSO0Unpacker.java
@@ -29,15 +29,14 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
-public class NSO0Unpacker {
+class NSO0Unpacker {
private static final String DECOMPRESSED_FILE_NAME = "main_decompressed";
private final MessageDigest digest = MessageDigest.getInstance("SHA-256");
- private NSO0Provider provider;
- private InFileStreamProducer producer;
+ private final NSO0Header nso0Header;
+ private final InFileStreamProducer producer;
private byte[] _textDecompressedSection;
private byte[] _rodataDecompressedSection;
@@ -47,19 +46,29 @@ public class NSO0Unpacker {
private int rodataFileOffsetNew;
private int dataFileOffsetNew;
- private NSO0Unpacker() throws NoSuchAlgorithmException { }
+ private NSO0Unpacker(NSO0Header nso0Header, InFileStreamProducer producer) throws Exception {
+ this.nso0Header = nso0Header;
+ this.producer = producer;
- public static void unpack(NSO0Provider provider, InFileStreamProducer producer, String saveToLocation) throws Exception{
- if (! provider.isTextCompressFlag() && ! provider.isRoCompressFlag() && ! provider.isDataCompressFlag())
+ decompressSections();
+ validateHashes();
+ makeHeader();
+ }
+
+ static NSO0Raw getNSO0Raw(NSO0Header nso0Header, InFileStreamProducer producer) throws Exception{
+ NSO0Unpacker instance = new NSO0Unpacker(nso0Header, producer);
+
+ return new NSO0Raw(instance.header,
+ instance._textDecompressedSection,
+ instance._rodataDecompressedSection,
+ instance._dataDecompressedSection);
+ }
+
+ static void unpack(NSO0Header nso0Header, InFileStreamProducer producer, String saveToLocation) throws Exception{
+ if (! nso0Header.isTextCompressFlag() && ! nso0Header.isRoCompressFlag() && ! nso0Header.isDataCompressFlag())
throw new Exception("This file is not compressed");
+ NSO0Unpacker instance = new NSO0Unpacker(nso0Header, producer);
- NSO0Unpacker instance = new NSO0Unpacker();
- instance.provider = provider;
- instance.producer = producer;
-
- instance.decompressSections();
- instance.validateHashes();
- instance.makeHeader();
instance.writeFile(saveToLocation);
}
@@ -69,22 +78,22 @@ public class NSO0Unpacker {
decompressDataSection();
}
private void decompressTextSection() throws Exception{
- if (provider.isTextCompressFlag())
- _textDecompressedSection = decompressSection(provider.getTextSegmentHeader(), provider.getTextCompressedSize());
+ if (nso0Header.isTextCompressFlag())
+ _textDecompressedSection = decompressSection(nso0Header.getTextSegmentHeader(), nso0Header.getTextCompressedSize());
else
- _textDecompressedSection = duplicateSection(provider.getTextSegmentHeader());
+ _textDecompressedSection = duplicateSection(nso0Header.getTextSegmentHeader());
}
private void decompressRodataSection() throws Exception{
- if (provider.isRoCompressFlag())
- _rodataDecompressedSection = decompressSection(provider.getRodataSegmentHeader(), provider.getRodataCompressedSize());
+ if (nso0Header.isRoCompressFlag())
+ _rodataDecompressedSection = decompressSection(nso0Header.getRodataSegmentHeader(), nso0Header.getRodataCompressedSize());
else
- _rodataDecompressedSection = duplicateSection(provider.getRodataSegmentHeader());
+ _rodataDecompressedSection = duplicateSection(nso0Header.getRodataSegmentHeader());
}
private void decompressDataSection() throws Exception{
- if (provider.isDataCompressFlag())
- _dataDecompressedSection = decompressSection(provider.getDataSegmentHeader(), provider.getDataCompressedSize());
+ if (nso0Header.isDataCompressFlag())
+ _dataDecompressedSection = decompressSection(nso0Header.getDataSegmentHeader(), nso0Header.getDataCompressedSize());
else
- _dataDecompressedSection = duplicateSection(provider.getDataSegmentHeader());
+ _dataDecompressedSection = duplicateSection(nso0Header.getDataSegmentHeader());
}
private byte[] decompressSection(SegmentHeader segmentHeader, int compressedSectionSize) throws Exception{
@@ -126,13 +135,13 @@ public class NSO0Unpacker {
}
private void validateHashes() throws Exception{
- if ( ! Arrays.equals(provider.getTextHash(), digest.digest(_textDecompressedSection)) ) {
+ if ( ! Arrays.equals(nso0Header.getTextHash(), digest.digest(_textDecompressedSection)) ) {
throw new Exception(".text hash mismatch for .text section");
}
- if ( ! Arrays.equals(provider.getRodataHash(), digest.digest(_rodataDecompressedSection)) ) {
+ if ( ! Arrays.equals(nso0Header.getRodataHash(), digest.digest(_rodataDecompressedSection)) ) {
throw new Exception(".rodata hash mismatch for .text section");
}
- if ( ! Arrays.equals(provider.getDataHash(), digest.digest(_dataDecompressedSection)) ) {
+ if ( ! Arrays.equals(nso0Header.getDataHash(), digest.digest(_dataDecompressedSection)) ) {
throw new Exception(".data hash mismatch for .text section");
}
}
@@ -163,41 +172,41 @@ public class NSO0Unpacker {
header = resultingHeader.array();
*/
- textFileOffsetNew = provider.getTextSegmentHeader().getMemoryOffset()+0x100;
- rodataFileOffsetNew = provider.getRodataSegmentHeader().getMemoryOffset()+0x100;
- dataFileOffsetNew = provider.getDataSegmentHeader().getMemoryOffset()+0x100;
+ textFileOffsetNew = nso0Header.getTextSegmentHeader().getMemoryOffset()+0x100;
+ rodataFileOffsetNew = nso0Header.getRodataSegmentHeader().getMemoryOffset()+0x100;
+ dataFileOffsetNew = nso0Header.getDataSegmentHeader().getMemoryOffset()+0x100;
ByteBuffer resultingHeader = ByteBuffer.allocate(0x100).order(ByteOrder.LITTLE_ENDIAN);
resultingHeader.put("NSO0".getBytes(StandardCharsets.US_ASCII))
- .putInt(provider.getVersion())
- .put(provider.getUpperReserved())
- .putInt(provider.getFlags() & 0b111000)
+ .putInt(nso0Header.getVersion())
+ .put(nso0Header.getUpperReserved())
+ .putInt(nso0Header.getFlags() & 0b111000)
.putInt(textFileOffsetNew)
- .putInt(provider.getTextSegmentHeader().getMemoryOffset())
- .putInt(provider.getTextSegmentHeader().getSizeAsDecompressed())
+ .putInt(nso0Header.getTextSegmentHeader().getMemoryOffset())
+ .putInt(nso0Header.getTextSegmentHeader().getSizeAsDecompressed())
.putInt(0x100)
.putInt(rodataFileOffsetNew)
- .putInt(provider.getRodataSegmentHeader().getMemoryOffset())
- .putInt(provider.getRodataSegmentHeader().getSizeAsDecompressed())
+ .putInt(nso0Header.getRodataSegmentHeader().getMemoryOffset())
+ .putInt(nso0Header.getRodataSegmentHeader().getSizeAsDecompressed())
.putInt(0)
.putInt(dataFileOffsetNew)
- .putInt(provider.getDataSegmentHeader().getMemoryOffset())
- .putInt(provider.getDataSegmentHeader().getSizeAsDecompressed())
- .putInt(provider.getBssSize())
- .put(provider.getModuleId())
- .putInt(provider.getTextSegmentHeader().getSizeAsDecompressed())
- .putInt(provider.getRodataSegmentHeader().getSizeAsDecompressed())
- .putInt(provider.getDataSegmentHeader().getSizeAsDecompressed())
- .put(provider.getBottomReserved())
- .putInt(provider.get_api_infoRelative().getOffset())
- .putInt(provider.get_api_infoRelative().getSize())
- .putInt(provider.get_dynstrRelative().getOffset())
- .putInt(provider.get_dynstrRelative().getSize())
- .putInt(provider.get_dynsymRelative().getOffset())
- .putInt(provider.get_dynsymRelative().getSize())
- .put(provider.getTextHash())
- .put(provider.getRodataHash())
- .put(provider.getDataHash());
+ .putInt(nso0Header.getDataSegmentHeader().getMemoryOffset())
+ .putInt(nso0Header.getDataSegmentHeader().getSizeAsDecompressed())
+ .putInt(nso0Header.getBssSize())
+ .put(nso0Header.getModuleId())
+ .putInt(nso0Header.getTextSegmentHeader().getSizeAsDecompressed())
+ .putInt(nso0Header.getRodataSegmentHeader().getSizeAsDecompressed())
+ .putInt(nso0Header.getDataSegmentHeader().getSizeAsDecompressed())
+ .put(nso0Header.getBottomReserved())
+ .putInt(nso0Header.get_api_infoRelative().getOffset())
+ .putInt(nso0Header.get_api_infoRelative().getSize())
+ .putInt(nso0Header.get_dynstrRelative().getOffset())
+ .putInt(nso0Header.get_dynstrRelative().getSize())
+ .putInt(nso0Header.get_dynsymRelative().getOffset())
+ .putInt(nso0Header.get_dynsymRelative().getSize())
+ .put(nso0Header.getTextHash())
+ .put(nso0Header.getRodataHash())
+ .put(nso0Header.getDataHash());
header = resultingHeader.array();
}
diff --git a/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java b/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java
index b2f5e14..75877c2 100644
--- a/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java
+++ b/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java
@@ -184,7 +184,7 @@ public class FileSystemEntry {
nextHashTableBucketFileOffset = Converter.getLEint(filesMetadataTable, i);
/*
if (nextHashTableBucketFileOffset < 0) {
- System.out.println("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
+ log.debug("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
}
//*/
i += 4;
diff --git a/src/main/java/libKonogonka/Tools/XCI/HFS0Provider.java b/src/main/java/libKonogonka/Tools/XCI/HFS0Provider.java
index 9713a38..44ff19e 100644
--- a/src/main/java/libKonogonka/Tools/XCI/HFS0Provider.java
+++ b/src/main/java/libKonogonka/Tools/XCI/HFS0Provider.java
@@ -19,6 +19,8 @@
package libKonogonka.Tools.XCI;
import libKonogonka.Tools.ISuperProvider;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.io.*;
import java.nio.charset.StandardCharsets;
@@ -31,6 +33,8 @@ import static libKonogonka.Converter.*;
* HFS0
* */
public class HFS0Provider implements ISuperProvider {
+ private final static Logger log = LogManager.getLogger(HFS0Provider.class);
+
private final String magic;
private final int filesCount;
private final byte[] padding;
@@ -136,7 +140,7 @@ public class HFS0Provider implements ISuperProvider {
PipedInputStream streamIn = new PipedInputStream(streamOut);
workerThread = new Thread(() -> {
- System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Executing thread");
+ log.trace("HFS0Provider -> getHfs0FilePipedInpStream(): Executing thread");
try{
long subFileRealPosition = rawFileDataStart + hfs0Files[subFileNumber].getOffset();
BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
@@ -164,10 +168,10 @@ public class HFS0Provider implements ISuperProvider {
streamOut.close();
}
catch (Exception ioe){
- System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to provide stream");
+ log.error("HFS0Provider -> getHfs0FilePipedInpStream(): Unable to provide stream");
ioe.printStackTrace();
}
- System.out.println("HFS0Provider -> getHfs0FilePipedInpStream(): Thread died");
+ log.trace("HFS0Provider -> getHfs0FilePipedInpStream(): Thread died");
});
workerThread.start();
return streamIn;
diff --git a/src/main/java/libKonogonka/Tools/XCI/XCIGamecardCert.java b/src/main/java/libKonogonka/Tools/XCI/XCIGamecardCert.java
index 7d5451f..4bcfa76 100644
--- a/src/main/java/libKonogonka/Tools/XCI/XCIGamecardCert.java
+++ b/src/main/java/libKonogonka/Tools/XCI/XCIGamecardCert.java
@@ -18,20 +18,26 @@
*/
package libKonogonka.Tools.XCI;
+import libKonogonka.Converter;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
import java.util.Arrays;
/**
* Gamecard Cert
* */
public class XCIGamecardCert {
- private byte[] rsa2048PKCS1sig;
- private byte[] magicCert;
- private byte[] unknown1;
- private byte kekIndex;
- private byte[] unknown2;
- private byte[] deviceID;
- private byte[] unknown3;
- private byte[] encryptedData;
+ private final static Logger log = LogManager.getLogger(XCIGamecardCert.class);
+
+ private final byte[] rsa2048PKCS1sig;
+ private final byte[] magicCert;
+ private final byte[] unknown1;
+ private final byte kekIndex;
+ private final byte[] unknown2;
+ private final byte[] deviceID;
+ private final byte[] unknown3;
+ private final byte[] encryptedData;
XCIGamecardCert(byte[] certBytes) throws Exception{
if (certBytes.length != 512)
@@ -44,16 +50,6 @@ public class XCIGamecardCert {
deviceID = Arrays.copyOfRange(certBytes, 272, 288);
unknown3 = Arrays.copyOfRange(certBytes, 288, 298);
encryptedData = Arrays.copyOfRange(certBytes, 298, 512);
- /*
- RainbowHexDump.hexDumpUTF8(rsa2048PKCS1sig);
- RainbowHexDump.hexDumpUTF8(magicCert);
- RainbowHexDump.hexDumpUTF8(unknown1);
- System.out.println(kekIndex);
- RainbowHexDump.hexDumpUTF8(unknown2);
- RainbowHexDump.hexDumpUTF8(deviceID);
- RainbowHexDump.hexDumpUTF8(unknown3);
- RainbowHexDump.hexDumpUTF8(encryptedData);
- */
}
public byte[] getRsa2048PKCS1sig() { return rsa2048PKCS1sig; }
public byte[] getMagicCert() { return magicCert; }
@@ -64,4 +60,17 @@ public class XCIGamecardCert {
public byte[] getDeviceID() { return deviceID; }
public byte[] getUnknown3() { return unknown3; }
public byte[] getEncryptedData() { return encryptedData; }
+
+ public void printDebug(){
+ log.debug("== XCIGamecardCert ==\n" +
+ "rsa2048PKCS1sig " + Converter.byteArrToHexString(rsa2048PKCS1sig) + "\n" +
+ "magicCert " + Converter.byteArrToHexString(magicCert) + "\n" +
+ "unknown1 " + Converter.byteArrToHexString(unknown1) + "\n" +
+ "kekIndex " + kekIndex + "\n" +
+ "unknown2 " + Converter.byteArrToHexString(unknown2) + "\n" +
+ "deviceID " + Converter.byteArrToHexString(deviceID) + "\n" +
+ "unknown3 " + Converter.byteArrToHexString(unknown3) + "\n" +
+ "encryptedData " + Converter.byteArrToHexString(encryptedData) + "\n"
+ );
+ }
}
diff --git a/src/main/java/libKonogonka/Tools/XCI/XCIGamecardInfo.java b/src/main/java/libKonogonka/Tools/XCI/XCIGamecardInfo.java
index 569971d..11c924e 100644
--- a/src/main/java/libKonogonka/Tools/XCI/XCIGamecardInfo.java
+++ b/src/main/java/libKonogonka/Tools/XCI/XCIGamecardInfo.java
@@ -30,6 +30,7 @@ import static libKonogonka.Converter.getLElong;
* Gamecard Info
* */
public class XCIGamecardInfo{
+ //private final static Logger log = LogManager.getLogger(XCIGamecardInfo.class);
private long fwVersion;
private byte[] accessCtrlFlags; // 0x00A10011 for 25MHz access or 0x00A10010 for 50MHz access
@@ -73,12 +74,12 @@ public class XCIGamecardInfo{
cupID = Arrays.copyOfRange(decrypted, 48, 56);
emptyPadding2 = Arrays.copyOfRange(decrypted, 56, 112);
/*
- System.out.println(fwVersion);
+ log.debug(fwVersion);
RainbowHexDump.hexDumpUTF8(accessCtrlFlags);
- System.out.println(readWaitTime1);
- System.out.println(readWaitTime2);
- System.out.println(writeWaitTime1);
- System.out.println(writeWaitTime2);
+ log.debug(readWaitTime1);
+ log.debug(readWaitTime2);
+ log.debug(writeWaitTime1);
+ log.debug(writeWaitTime2);
RainbowHexDump.hexDumpUTF8(fwMode);
RainbowHexDump.hexDumpUTF8(cupVersion);
RainbowHexDump.hexDumpUTF8(emptyPadding1);
diff --git a/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java b/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java
index 45eddf3..7a88237 100644
--- a/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java
+++ b/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java
@@ -88,7 +88,7 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
//1
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesFromFirstBlock);
//2
- System.out.println("\n"+bytesFromFirstBlock+"\n"+ middleBlocksCount+" = "+(middleBlocksCount*0x200)+" bytes\n"+ bytesFromEnd+"\n");
+ //log.debug("\n"+bytesFromFirstBlock+"\n"+ middleBlocksCount+" = "+(middleBlocksCount*0x200)+" bytes\n"+ bytesFromEnd+"\n");
for (int i = 0; i < middleBlocksCount; i++) {
fillDecryptedCache();
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+i*0x200, 0x200);
diff --git a/src/test/java/libKonogonka/RomFsDecrypted/NSOTest.java b/src/test/java/libKonogonka/RomFsDecrypted/NSOTest.java
index bf6b276..e0c9a24 100644
--- a/src/test/java/libKonogonka/RomFsDecrypted/NSOTest.java
+++ b/src/test/java/libKonogonka/RomFsDecrypted/NSOTest.java
@@ -30,7 +30,6 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.*;
-import java.nio.file.Files;
public class NSOTest {
private static final String keysFileLocation = "./FilesForTests/prod.keys";
@@ -116,6 +115,7 @@ public class NSOTest {
NSO0Provider nso0Provider = new NSO0Provider(pfs0Provider.getStreamProducer(0));
nso0Provider.printDebug();
+ nso0Provider.exportAsDecompressedNSO0("./tmp");
// NPDMProvider npdmProvider = new NPDMProvider(pfs0Provider.getProviderSubFilePipedInpStream(1));