Compare commits
	
		
			7 commits
		
	
	
		
			6d243a2be1
			...
			db7855765f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						db7855765f | ||
| 
							 | 
						c8efebfcff | ||
| 
							 | 
						0a9883ad2b | ||
| 
							 | 
						02a2200d04 | ||
| 
							 | 
						cf7d54d8af | ||
| 
							 | 
						0ce56eb9b4 | ||
| 
							 | 
						37db634a23 | 
					 20 changed files with 1280 additions and 1209 deletions
				
			
		| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
steps:
 | 
					steps:
 | 
				
			||||||
  - name: test-standard
 | 
					  - name: test-standard
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event: [tag, push]
 | 
					      event: [tag, push, manual]
 | 
				
			||||||
    image: maven:3-openjdk-17
 | 
					    image: maven:3-openjdk-17
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - mvn -B -DskipTests clean package
 | 
					      - mvn -B -DskipTests clean package
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ steps:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: make-windows-installer
 | 
					  - name: make-windows-installer
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event: [tag, push]
 | 
					      event: [tag, push, manual]
 | 
				
			||||||
    image: wheatstalk/makensis:3
 | 
					    image: wheatstalk/makensis:3
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - cp target/NS-USBloader.exe misc/windows/NSIS/
 | 
					      - cp target/NS-USBloader.exe misc/windows/NSIS/
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@ steps:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: emerge-legacy-artifact
 | 
					  - name: emerge-legacy-artifact
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event: [tag, push]
 | 
					      event: [tag, push, manual]
 | 
				
			||||||
    image: maven:3-openjdk-17
 | 
					    image: maven:3-openjdk-17
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - . ./.make_legacy
 | 
					      - . ./.make_legacy
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@ steps:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  - name: make-legacy-windows-installer
 | 
					  - name: make-legacy-windows-installer
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event: [tag, push]
 | 
					      event: [tag, push, manual]
 | 
				
			||||||
    image: wheatstalk/makensis:3
 | 
					    image: wheatstalk/makensis:3
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - cp target/NS-USBloader.exe misc/windows/NSIS/
 | 
					      - cp target/NS-USBloader.exe misc/windows/NSIS/
 | 
				
			||||||
| 
						 | 
					@ -60,7 +60,7 @@ steps:
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  - name: emerge-mac-m1-artifact
 | 
					  - name: emerge-mac-m1-artifact
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event: [tag, push]
 | 
					      event: [tag, push, manual]
 | 
				
			||||||
    image: maven:3-openjdk-17
 | 
					    image: maven:3-openjdk-17
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - . ./.make_m1
 | 
					      - . ./.make_m1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,7 +67,7 @@ Sometimes I add new posts about this project [on my blog page](https://developer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### System requirements
 | 
					### System requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- JDK 11 for macOS and Linux
 | 
					- JDK 17 for macOS and Linux
 | 
				
			||||||
- libusb, if you have a Mac with Apple Silicon (install via `brew install libusb`)
 | 
					- libusb, if you have a Mac with Apple Silicon (install via `brew install libusb`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Supported Goldleaf versions
 | 
					### Supported Goldleaf versions
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,9 @@ Sometimes I add new posts about this project [on my blog page](https://developer
 | 
				
			||||||
| v0.6.1           | v0.6                 |
 | 
					| v0.6.1           | v0.6                 |
 | 
				
			||||||
| v0.7 - 0.7.3     | v0.7+                |
 | 
					| v0.7 - 0.7.3     | v0.7+                |
 | 
				
			||||||
| v0.8 - 0.9       | v1.0+                |
 | 
					| v0.8 - 0.9       | v1.0+                |
 | 
				
			||||||
| v0.10            | v6.0+                |
 | 
					| v0.10 - 1.0.0    | v6.0+                |
 | 
				
			||||||
 | 
					| v1.1.0           | none                 |
 | 
				
			||||||
 | 
					| v1.1.1           | v7.3+                |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
where '+' means 'any next NS-USBloader version'.
 | 
					where '+' means 'any next NS-USBloader version'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							| 
						 | 
					@ -50,7 +50,7 @@
 | 
				
			||||||
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
					        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
				
			||||||
        <maven.build.timestamp.format>yyyyMMdd.HHmmss</maven.build.timestamp.format>
 | 
					        <maven.build.timestamp.format>yyyyMMdd.HHmmss</maven.build.timestamp.format>
 | 
				
			||||||
        <javafx.version>19.0.2.1</javafx.version>
 | 
					        <javafx.version>19.0.2.1</javafx.version>
 | 
				
			||||||
        <maven.compiler.release>11</maven.compiler.release>
 | 
					        <maven.compiler.release>17</maven.compiler.release>
 | 
				
			||||||
    </properties>
 | 
					    </properties>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <issueManagement>
 | 
					    <issueManagement>
 | 
				
			||||||
| 
						 | 
					@ -205,7 +205,7 @@
 | 
				
			||||||
                <artifactId>maven-compiler-plugin</artifactId>
 | 
					                <artifactId>maven-compiler-plugin</artifactId>
 | 
				
			||||||
                <version>3.10.1</version>
 | 
					                <version>3.10.1</version>
 | 
				
			||||||
                <configuration>
 | 
					                <configuration>
 | 
				
			||||||
                    <release>11</release>
 | 
					                    <release>17</release>
 | 
				
			||||||
                </configuration>
 | 
					                </configuration>
 | 
				
			||||||
            </plugin>
 | 
					            </plugin>
 | 
				
			||||||
            <!-- Don't generate default JAR without dependencies -->
 | 
					            <!-- Don't generate default JAR without dependencies -->
 | 
				
			||||||
| 
						 | 
					@ -274,7 +274,7 @@
 | 
				
			||||||
                            <!-- <dontWrapJar>true</dontWrapJar> -->
 | 
					                            <!-- <dontWrapJar>true</dontWrapJar> -->
 | 
				
			||||||
                            <jre>
 | 
					                            <jre>
 | 
				
			||||||
                                <path>%PWD%/jdk</path>
 | 
					                                <path>%PWD%/jdk</path>
 | 
				
			||||||
                                <minVersion>11.0.0</minVersion>
 | 
					                                <minVersion>17.0.0</minVersion>
 | 
				
			||||||
                            </jre>
 | 
					                            </jre>
 | 
				
			||||||
                            <versionInfo>
 | 
					                            <versionInfo>
 | 
				
			||||||
                                <fileVersion>${project.version}.0.0</fileVersion>
 | 
					                                <fileVersion>${project.version}.0.0</fileVersion>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ public class AppPreferences {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private final Preferences preferences;
 | 
					    private final Preferences preferences;
 | 
				
			||||||
    private final Locale locale;
 | 
					    private final Locale locale;
 | 
				
			||||||
    public static final String[] GOLDLEAF_SUPPORTED_VERSIONS = {"v0.5", "v0.7.x", "v0.8-0.9", "v0.10+"};
 | 
					    public static final String[] GOLDLEAF_SUPPORTED_VERSIONS = {"v0.5", "v0.7.x", "v0.8-0.9", "v0.10-1.0.0", "v1.1.1"};
 | 
				
			||||||
    private static final Font DEFAULT_FONT = Font.getDefault();
 | 
					    private static final Font DEFAULT_FONT = Font.getDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private AppPreferences(){
 | 
					    private AppPreferences(){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -352,8 +352,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
 | 
					        int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                (instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
 | 
					                (instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
 | 
				
			||||||
                conditionalJumpLocation, (conditionalJumpLocation + 0x100));
 | 
					                conditionalJumpLocation, (conditionalJumpLocation + 0x100));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -362,8 +362,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
 | 
					        int conditionalJumpLocation = ((instructionExpression >> 5 & 0x7FFFF) * 4 + offset) & 0xfffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                (instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
 | 
					                (instructionExpression >> 31 == 0) ? "w" : "x", (instructionExpression & 0b11111),
 | 
				
			||||||
                conditionalJumpLocation, (conditionalJumpLocation + 0x100));
 | 
					                conditionalJumpLocation, (conditionalJumpLocation + 0x100));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -372,8 +372,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
 | 
					        int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
 | 
					                conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -382,8 +382,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
 | 
					        int conditionalJumpLocationPatch = ((instructionExpression & 0x3ffffff) * 4 + offset) & 0xfffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
 | 
					                conditionalJumpLocationPatch, (conditionalJumpLocationPatch + 0x100));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,15 +392,15 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int sfHw = (instructionExpression >> 22 & 1);
 | 
					        int sfHw = (instructionExpression >> 22 & 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   MOV         " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   MOV         " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                (sfHw == 0) ? "w" : "x", (instructionExpression & 0b11111), imm16);
 | 
					                (sfHw == 0) ? "w" : "x", (instructionExpression & 0b11111), imm16);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static String printNOPSimplified(int instructionExpression, int offset){
 | 
					    private static String printNOPSimplified(int instructionExpression, int offset){
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   NOP           " + ANSI_RESET + "\n",
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   NOP           " + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression);
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static String printTBZSimplified(int instructionExpression, int offset){
 | 
					    private static String printTBZSimplified(int instructionExpression, int offset){
 | 
				
			||||||
| 
						 | 
					@ -410,8 +410,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int label = offset + (instructionExpression >> 5 & 0x3fff) * 4;
 | 
					        int label = offset + (instructionExpression >> 5 & 0x3fff) * 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                (xwSelector == 0) ? "w" : "x", Rt, imm, label);
 | 
					                (xwSelector == 0) ? "w" : "x", Rt, imm, label);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -419,15 +419,15 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int conditionalJumpLocation = ((instructionExpression >> 4 & 0b1111111111111111111) * 4 + offset) & 0xfffff;
 | 
					        int conditionalJumpLocation = ((instructionExpression >> 4 & 0b1111111111111111111) * 4 + offset) & 0xfffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                getBConditionalMarker(instructionExpression & 0xf),
 | 
					                getBConditionalMarker(instructionExpression & 0xf),
 | 
				
			||||||
                conditionalJumpLocation, (conditionalJumpLocation + 0x100));
 | 
					                conditionalJumpLocation, (conditionalJumpLocation + 0x100));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private static String printImTooLazy(String name, int instructionExpression, int offset){
 | 
					    private static String printImTooLazy(String name, int instructionExpression, int offset){
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   "+name+"           . . . \n"+ ANSI_RESET,
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   "+name+"           . . . \n"+ ANSI_RESET,
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression);
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static String printSUBSimplified(int instructionExpression, int offset){
 | 
					    private static String printSUBSimplified(int instructionExpression, int offset){
 | 
				
			||||||
| 
						 | 
					@ -437,8 +437,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int imm12 = instructionExpression >> 10 & 0xFFF; // unsigned only
 | 
					        int imm12 = instructionExpression >> 10 & 0xFFF; // unsigned only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                wx, Rt, wx, Rn, imm12);
 | 
					                wx, Rt, wx, Rn, imm12);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -448,8 +448,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int Rd = instructionExpression & 0x1F;
 | 
					        int Rd = instructionExpression & 0x1F;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   MOV (reg)   " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "%s%d" + ANSI_RESET + "\n",
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   MOV (reg)   " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "%s%d" + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                sfHw, Rm, sfHw, Rd);
 | 
					                sfHw, Rm, sfHw, Rd);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -458,8 +458,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int imm = instructionExpression >> 10 & 0xFFF;
 | 
					        int imm = instructionExpression >> 10 & 0xFFF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   CMN         " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   CMN         " + ANSI_GREEN + "%s%d " + ANSI_BLUE + "#0x%x" + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                (instructionExpression >> 31 == 0) ? "w" : "x", Rn, imm);
 | 
					                (instructionExpression >> 31 == 0) ? "w" : "x", Rn, imm);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -471,8 +471,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                wx, Rt, wx, Rn, imm12);
 | 
					                wx, Rt, wx, Rn, imm12);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private static String printLRDBImmUnsignSimplified(int instructionExpression, int offset){
 | 
					    private static String printLRDBImmUnsignSimplified(int instructionExpression, int offset){
 | 
				
			||||||
| 
						 | 
					@ -482,8 +482,8 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int imm12 = (instructionExpression >> 10 & 0xFFF) * 8; // unsigned only
 | 
					        int imm12 = (instructionExpression >> 10 & 0xFFF) * 8; // unsigned only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        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",
 | 
					                "%06x 7100%06x "+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,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                wx, Rt, wx, Rn, imm12);
 | 
					                wx, Rt, wx, Rn, imm12);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -494,9 +494,9 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        int LSL = (instructionExpression >> 22 & 0b1) == 1 ? 12 : 0;
 | 
					        int LSL = (instructionExpression >> 22 & 0b1) == 1 ? 12 : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   CMP         " + ANSI_GREEN + sf + "%d," +
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   CMP         " + ANSI_GREEN + sf + "%d," +
 | 
				
			||||||
                        ANSI_BLUE + "0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ") " + ANSI_PURPLE + "LSL #%d" + ANSI_RESET + "\n",
 | 
					                        ANSI_BLUE + "0x%x" + ANSI_RESET + " (Real: " + ANSI_BLUE + "#0x%x" + ANSI_RESET + ") " + ANSI_PURPLE + "LSL #%d" + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                Rn,
 | 
					                Rn,
 | 
				
			||||||
                conditionalJumpLocation, (conditionalJumpLocation + 0x100),
 | 
					                conditionalJumpLocation, (conditionalJumpLocation + 0x100),
 | 
				
			||||||
                LSL);
 | 
					                LSL);
 | 
				
			||||||
| 
						 | 
					@ -527,9 +527,9 @@ public class BinToAsmPrinter {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   CMP (sr)    " + ANSI_GREEN + sf + "%d," +
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   CMP (sr)    " + ANSI_GREEN + sf + "%d," +
 | 
				
			||||||
                        ANSI_BLUE + sf + "%d " + ANSI_BLUE + LSLStr + ANSI_PURPLE + " %d" + ANSI_RESET + "\n",
 | 
					                        ANSI_BLUE + sf + "%d " + ANSI_BLUE + LSLStr + ANSI_PURPLE + " %d" + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression,
 | 
				
			||||||
                Rn, Rm, imm6);
 | 
					                Rn, Rm, imm6);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -544,23 +544,23 @@ public class BinToAsmPrinter {
 | 
				
			||||||
            imm = instructionExpression >> 10 & 0x1fff;
 | 
					            imm = instructionExpression >> 10 & 0x1fff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   AND         " + ANSI_GREEN + sf + "%d, " + ANSI_BLUE +
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   AND         " + ANSI_GREEN + sf + "%d, " + ANSI_BLUE +
 | 
				
			||||||
                        sf + "%d" + ANSI_PURPLE + " # ??? 0b%s " + ANSI_RESET + "\n",
 | 
					                        sf + "%d" + ANSI_PURPLE + " # ??? 0b%s " + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression, Rn, Rd, Converter.intToBinaryString(imm));
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression, Rn, Rd, Converter.intToBinaryString(imm));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static String printRetSimplified(int instructionExpression, int offset){
 | 
					    private static String printRetSimplified(int instructionExpression, int offset){
 | 
				
			||||||
        int Xn = (instructionExpression >> 5) & 0x1F;
 | 
					        int Xn = (instructionExpression >> 5) & 0x1F;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   RET        " + ANSI_GREEN + " X%d" + ANSI_RESET + "\n",
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   RET        " + ANSI_GREEN + " X%d" + ANSI_RESET + "\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression, Xn == 0 ? 30 : Xn);
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression, Xn == 0 ? 30 : Xn);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static String printUnknownSimplified(int instructionExpression, int offset){
 | 
					    private static String printUnknownSimplified(int instructionExpression, int offset){
 | 
				
			||||||
        return String.format(
 | 
					        return String.format(
 | 
				
			||||||
                "%05x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   ???          0b"+ANSI_RESET+ Converter.intToBinaryString(instructionExpression) +"\n",
 | 
					                "%06x 7100%06x "+ANSI_CYAN+"%08x (%08x)"+ANSI_YELLOW + "   ???          0b"+ANSI_RESET+ Converter.intToBinaryString(instructionExpression) +"\n",
 | 
				
			||||||
                offset, Integer.reverseBytes(instructionExpression), instructionExpression);
 | 
					                offset+0x100, offset,Integer.reverseBytes(instructionExpression), instructionExpression);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static String intAsBinString(int number) {
 | 
					    private static String intAsBinString(int number) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,7 +148,7 @@ public class FsPatch {
 | 
				
			||||||
    private void findAllOffsets() throws Exception{
 | 
					    private void findAllOffsets() throws Exception{
 | 
				
			||||||
        this.wizard = new HeuristicFsWizard(_textSection);
 | 
					        this.wizard = new HeuristicFsWizard(_textSection);
 | 
				
			||||||
        String errorsAndNotes = wizard.getErrorsAndNotes();
 | 
					        String errorsAndNotes = wizard.getErrorsAndNotes();
 | 
				
			||||||
        if (errorsAndNotes.length() > 0)
 | 
					        if (! errorsAndNotes.isEmpty())
 | 
				
			||||||
            logPrinter.print(errorsAndNotes, EMsgType.WARNING);
 | 
					            logPrinter.print(errorsAndNotes, EMsgType.WARNING);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    private void mkDirs(){
 | 
					    private void mkDirs(){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
    Copyright 2019-2020 Dmitry Isaenko
 | 
					    Copyright 2019-2025 Dmitry Isaenko
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    This file is part of NS-USBloader.
 | 
					    This file is part of NS-USBloader.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,9 +33,9 @@ import java.util.*;
 | 
				
			||||||
public class PFSProvider {
 | 
					public class PFSProvider {
 | 
				
			||||||
    private static final byte[] PFS0 = new byte[]{0x50, 0x46, 0x53, 0x30};  // PFS0
 | 
					    private static final byte[] PFS0 = new byte[]{0x50, 0x46, 0x53, 0x30};  // PFS0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private String nspFileName;
 | 
					    private final String nspFileName;
 | 
				
			||||||
    private NCAFile[] ncaFiles;
 | 
					    private final NCAFile[] ncaFiles;
 | 
				
			||||||
    private long bodySize;
 | 
					    private final long bodySize;
 | 
				
			||||||
    private int ticketID = -1;
 | 
					    private int ticketID = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public PFSProvider(File nspFile, ILogPrinter logPrinter) throws Exception{
 | 
					    public PFSProvider(File nspFile, ILogPrinter logPrinter) throws Exception{
 | 
				
			||||||
| 
						 | 
					@ -141,7 +141,7 @@ public class PFSProvider {
 | 
				
			||||||
        byte[] b = new byte[1];                 // Temporary
 | 
					        byte[] b = new byte[1];                 // Temporary
 | 
				
			||||||
        for (int i=0; i<filesCount; i++){
 | 
					        for (int i=0; i<filesCount; i++){
 | 
				
			||||||
            ncaFN = new ArrayList<>();
 | 
					            ncaFN = new ArrayList<>();
 | 
				
			||||||
            randAccessFile.seek(filesCount*24+16+ncaNameOffsets.get(i));          // Files cont * 24(bit for each meta-data) + 4 bytes goes after all of them  + 12 bit what were in the beginning
 | 
					            randAccessFile.seek(filesCount*24L+16L+ncaNameOffsets.get(i)); // Files cont * 24(bit for each meta-data) + 4 bytes goes after all of them  + 12 bit what were in the beginning
 | 
				
			||||||
            while ((randAccessFile.read(b)) != -1){
 | 
					            while ((randAccessFile.read(b)) != -1){
 | 
				
			||||||
                if (b[0] == 0x00)
 | 
					                if (b[0] == 0x00)
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,14 +28,20 @@ import java.io.File;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public abstract class TransferModule {
 | 
					public abstract class TransferModule {
 | 
				
			||||||
    EFileStatus status = EFileStatus.UNKNOWN;
 | 
					    protected static final byte IN_EP = (byte) 0x81;
 | 
				
			||||||
 | 
					    protected static final byte OUT_EP = (byte) 0x01;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LinkedHashMap<String, File> nspMap;
 | 
					    protected EFileStatus status = EFileStatus.UNKNOWN;
 | 
				
			||||||
    ILogPrinter logPrinter;
 | 
					 | 
				
			||||||
    DeviceHandle handlerNS;
 | 
					 | 
				
			||||||
    CancellableRunnable task;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    TransferModule(DeviceHandle handler, LinkedHashMap<String, File> nspMap, CancellableRunnable task, ILogPrinter printer){
 | 
					    protected LinkedHashMap<String, File> nspMap;
 | 
				
			||||||
 | 
					    protected ILogPrinter logPrinter;
 | 
				
			||||||
 | 
					    protected DeviceHandle handlerNS;
 | 
				
			||||||
 | 
					    protected CancellableRunnable task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected TransferModule(DeviceHandle handler,
 | 
				
			||||||
 | 
					                             LinkedHashMap<String, File> nspMap,
 | 
				
			||||||
 | 
					                             CancellableRunnable task,
 | 
				
			||||||
 | 
					                             ILogPrinter printer){
 | 
				
			||||||
        this.handlerNS = handler;
 | 
					        this.handlerNS = handler;
 | 
				
			||||||
        this.nspMap = nspMap;
 | 
					        this.nspMap = nspMap;
 | 
				
			||||||
        this.task = task;
 | 
					        this.task = task;
 | 
				
			||||||
| 
						 | 
					@ -78,7 +84,7 @@ public abstract class TransferModule {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    public EFileStatus getStatus(){ return status; }
 | 
					    public EFileStatus getStatus(){ return status; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void print(String message, EMsgType type){
 | 
					    protected void print(String message, EMsgType type){
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            logPrinter.print(message, type);
 | 
					            logPrinter.print(message, type);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
    Copyright 2019-2020 Dmitry Isaenko
 | 
					    Copyright 2019-2025 Dmitry Isaenko
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    This file is part of NS-USBloader.
 | 
					    This file is part of NS-USBloader.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,8 @@ import nsusbloader.ModelControllers.Log;
 | 
				
			||||||
import nsusbloader.NSLDataTypes.EFileStatus;
 | 
					import nsusbloader.NSLDataTypes.EFileStatus;
 | 
				
			||||||
import nsusbloader.NSLDataTypes.EModule;
 | 
					import nsusbloader.NSLDataTypes.EModule;
 | 
				
			||||||
import nsusbloader.NSLDataTypes.EMsgType;
 | 
					import nsusbloader.NSLDataTypes.EMsgType;
 | 
				
			||||||
 | 
					import nsusbloader.com.usb.gl.GoldLeaf_010;
 | 
				
			||||||
 | 
					import nsusbloader.com.usb.gl.GoldLeaf_111;
 | 
				
			||||||
import org.usb4java.*;
 | 
					import org.usb4java.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.*;
 | 
					import java.io.*;
 | 
				
			||||||
| 
						 | 
					@ -66,7 +68,10 @@ public class UsbCommunications extends CancellableRunnable {
 | 
				
			||||||
            case "TinFoil":
 | 
					            case "TinFoil":
 | 
				
			||||||
                module = new TinFoil(handler, nspMap, this, logPrinter);
 | 
					                module = new TinFoil(handler, nspMap, this, logPrinter);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case "GoldLeafv0.10+":
 | 
					            case "GoldLeaf v1.1.1":
 | 
				
			||||||
 | 
					                module = new GoldLeaf_111(handler, nspMap, this, logPrinter, nspFilterForGl);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case "GoldLeaf v0.10-1.0.0":
 | 
				
			||||||
                module = new GoldLeaf_010(handler, nspMap, this, logPrinter, nspFilterForGl);
 | 
					                module = new GoldLeaf_010(handler, nspMap, this, logPrinter, nspFilterForGl);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case "GoldLeaf v0.8-0.9":
 | 
					            case "GoldLeaf v0.8-0.9":
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/main/java/nsusbloader/com/usb/gl/Converters.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/main/java/nsusbloader/com/usb/gl/Converters.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,53 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    Copyright 2019-2025 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.com.usb.gl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					import java.nio.ByteOrder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class Converters {
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Convert INT (Little endian) value to bytes-array representation
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    public static byte[] intToArrLE(int value){
 | 
				
			||||||
 | 
					        return ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.LITTLE_ENDIAN)
 | 
				
			||||||
 | 
					                .putInt(value)
 | 
				
			||||||
 | 
					                .array();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Convert LONG (Little endian) value to bytes-array representation
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    public static byte[] longToArrLE(long value){
 | 
				
			||||||
 | 
					        return ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN)
 | 
				
			||||||
 | 
					                .putLong(value)
 | 
				
			||||||
 | 
					                .array();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Convert bytes-array to INT value (Little endian)
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    public static int arrToIntLE(byte[] byteArrayWithInt, int intStartPosition){
 | 
				
			||||||
 | 
					        return ByteBuffer.wrap(byteArrayWithInt).order(ByteOrder.LITTLE_ENDIAN).getInt(intStartPosition);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Convert bytes-array to LONG value (Little endian)
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    public static long arrToLongLE(byte[] byteArrayWithLong, int intStartPosition){
 | 
				
			||||||
 | 
					        return ByteBuffer.wrap(byteArrayWithLong).order(ByteOrder.LITTLE_ENDIAN).getLong(intStartPosition);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										23
									
								
								src/main/java/nsusbloader/com/usb/gl/GlString.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/main/java/nsusbloader/com/usb/gl/GlString.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    Copyright 2019-2025 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.com.usb.gl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public interface GlString {
 | 
				
			||||||
 | 
					    int length();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								src/main/java/nsusbloader/com/usb/gl/GlString010.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/main/java/nsusbloader/com/usb/gl/GlString010.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    Copyright 2019-2025 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.com.usb.gl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static nsusbloader.com.usb.gl.Converters.arrToIntLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Separated from interface for easier fixes/replacement in future  */
 | 
				
			||||||
 | 
					public class GlString010 implements GlString {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final int length;
 | 
				
			||||||
 | 
					    private final String string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public GlString010(byte[] inputBytes, int startPosition){
 | 
				
			||||||
 | 
					        this.length = arrToIntLE(inputBytes, startPosition);
 | 
				
			||||||
 | 
					        this.string = new String(inputBytes, startPosition+4, length, StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public int length(){
 | 
				
			||||||
 | 
					        return length;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public String toString(){
 | 
				
			||||||
 | 
					        return string;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										897
									
								
								src/main/java/nsusbloader/com/usb/gl/GoldLeaf_010.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										897
									
								
								src/main/java/nsusbloader/com/usb/gl/GoldLeaf_010.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,897 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    Copyright 2019-2025 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.com.usb.gl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javafx.application.Platform;
 | 
				
			||||||
 | 
					import javafx.stage.FileChooser;
 | 
				
			||||||
 | 
					import nsusbloader.MediatorControl;
 | 
				
			||||||
 | 
					import nsusbloader.ModelControllers.CancellableRunnable;
 | 
				
			||||||
 | 
					import nsusbloader.ModelControllers.ILogPrinter;
 | 
				
			||||||
 | 
					import nsusbloader.NSLDataTypes.EMsgType;
 | 
				
			||||||
 | 
					import nsusbloader.com.helpers.NSSplitReader;
 | 
				
			||||||
 | 
					import nsusbloader.com.usb.TransferModule;
 | 
				
			||||||
 | 
					import org.usb4java.DeviceHandle;
 | 
				
			||||||
 | 
					import org.usb4java.LibUsb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.*;
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					import java.nio.IntBuffer;
 | 
				
			||||||
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					import java.util.concurrent.CompletableFuture;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static nsusbloader.com.usb.gl.Converters.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * GoldLeaf v0.10 processing
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class GoldLeaf_010 extends TransferModule {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final static int PACKET_SIZE = 4096;
 | 
				
			||||||
 | 
					    //                     CMD
 | 
				
			||||||
 | 
					    public final static byte[] EXCEPTION_CAUGHT =    Arrays.copyOf(new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, (byte) 0xF1, (byte) 0xBA}, PACKET_SIZE);
 | 
				
			||||||
 | 
					    public final static byte[] INVALID_INDEX =       Arrays.copyOf(new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, (byte) 0xF2, (byte) 0xBA}, PACKET_SIZE);
 | 
				
			||||||
 | 
					    public final static byte[] SELECTION_CANCELLED = Arrays.copyOf(new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, (byte) 0xF4, (byte) 0xBA}, PACKET_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final static byte[] CMD_GLCO_SUCCESS_FLAG = new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final static byte[] CMD_GLCO_SUCCESS =
 | 
				
			||||||
 | 
					            Arrays.copyOf(new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00}, PACKET_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // System.out.println((356 & 0x1FF) | ((1 + 100) & 0x1FFF) << 9); // 52068 // 0x00 0x00 0xCB 0x64
 | 
				
			||||||
 | 
					    private final byte[] GL_OBJECT_TYPE_FILE = new byte[]{0x01, 0x00, 0x00, 0x00};
 | 
				
			||||||
 | 
					    private final byte[] GL_OBJECT_TYPE_DIR = new byte[]{0x02, 0x00, 0x00, 0x00};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final boolean nspFilter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String recentPath;
 | 
				
			||||||
 | 
					    private String[] recentDirs;
 | 
				
			||||||
 | 
					    private String[] recentFiles;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final String[] nspMapKeySetIndexes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected String openReadFileNameAndPath;
 | 
				
			||||||
 | 
					    protected RandomAccessFile randAccessFile;
 | 
				
			||||||
 | 
					    protected NSSplitReader splitReader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final HashMap<String, BufferedOutputStream> writeFilesMap = new HashMap<>();
 | 
				
			||||||
 | 
					    protected long virtDriveSize;
 | 
				
			||||||
 | 
					    private final HashMap<String, Long> splitFileSize = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final boolean isWindows = System.getProperty("os.name").contains("Windows");
 | 
				
			||||||
 | 
					    protected final String homePath = System.getProperty("user.home");
 | 
				
			||||||
 | 
					    // For using in CMD_SelectFile with SPEC:/ prefix
 | 
				
			||||||
 | 
					    protected File selectedFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public GoldLeaf_010(DeviceHandle handler,
 | 
				
			||||||
 | 
					                        LinkedHashMap<String, File> nspMap,
 | 
				
			||||||
 | 
					                        CancellableRunnable task,
 | 
				
			||||||
 | 
					                        ILogPrinter logPrinter,
 | 
				
			||||||
 | 
					                        boolean nspFilter) {
 | 
				
			||||||
 | 
					        super(handler, nspMap, task, logPrinter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.nspFilter = nspFilter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        printWelcomeMessage();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Let's collect file names to the array (simplifies flow)
 | 
				
			||||||
 | 
					        nspMapKeySetIndexes = nspMap.keySet().toArray(new String[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Calculate size of VIRT:/ drive
 | 
				
			||||||
 | 
					        for (File nspFile : nspMap.values()) {
 | 
				
			||||||
 | 
					            if (nspFile.isDirectory()) {
 | 
				
			||||||
 | 
					                var subFiles = nspFile.listFiles((file, name) -> name.matches("[0-9]{2}"));
 | 
				
			||||||
 | 
					                assert subFiles != null;
 | 
				
			||||||
 | 
					                long size = 0;
 | 
				
			||||||
 | 
					                for (File subFile : subFiles)   // Validated by parent class
 | 
				
			||||||
 | 
					                    size += subFile.length();
 | 
				
			||||||
 | 
					                virtDriveSize += size;
 | 
				
			||||||
 | 
					                splitFileSize.put(nspFile.getName(), size);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                virtDriveSize += nspFile.length();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Go parse commands
 | 
				
			||||||
 | 
					        if (workLoop())
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        // Close (and flush) all opened streams.
 | 
				
			||||||
 | 
					        for (var bufferedOutputStream: writeFilesMap.values()){
 | 
				
			||||||
 | 
					            try{
 | 
				
			||||||
 | 
					                bufferedOutputStream.close();
 | 
				
			||||||
 | 
					            } catch (IOException | NullPointerException ignored){}
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        closeOpenedReadFilesGl();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected void printWelcomeMessage(){
 | 
				
			||||||
 | 
					        print("=========== GoldLeaf v0.10-1.0.0 ===========\n\t" +
 | 
				
			||||||
 | 
					                "VIRT:/ equals files added into the application\n\t" +
 | 
				
			||||||
 | 
					                "HOME:/ equals " + homePath, EMsgType.INFO);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected boolean workLoop(){
 | 
				
			||||||
 | 
					        while (true) {                          // Till user interrupted process.
 | 
				
			||||||
 | 
					            GlString glString1;
 | 
				
			||||||
 | 
					            var readByte = readGL();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (readByte == null)              // Issue @ readFromUsbGL method
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //RainbowDump.hexDumpUTF8(readByte);   // DEBUG
 | 
				
			||||||
 | 
					            //print("\t→ "+ GoldleafCmd.get(readByte[4]), EMsgType.INFO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (notGLCI(readByte))
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (GoldleafCmd.get(readByte[4])) {
 | 
				
			||||||
 | 
					                case GetDriveCount:
 | 
				
			||||||
 | 
					                    if (getDriveCount())
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetDriveInfo:
 | 
				
			||||||
 | 
					                    if (getDriveInfo(arrToIntLE(readByte,8)))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetSpecialPathCount:
 | 
				
			||||||
 | 
					                    if (getSpecialPathCount())
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetSpecialPath:
 | 
				
			||||||
 | 
					                    if (getSpecialPath(arrToIntLE(readByte,8)))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetDirectoryCount:
 | 
				
			||||||
 | 
					                    if (getDirectoryOrFileCount(readString(readByte, 8).toString(), true))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetFileCount:
 | 
				
			||||||
 | 
					                    if (getDirectoryOrFileCount(readString(readByte, 8).toString(), false))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetDirectory:
 | 
				
			||||||
 | 
					                    glString1 = readString(readByte, 8);
 | 
				
			||||||
 | 
					                    if (getDirectory(glString1.toString(), arrToIntLE(readByte, glString1.length()+12)))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case GetFile:
 | 
				
			||||||
 | 
					                    glString1 = readString(readByte, 8);
 | 
				
			||||||
 | 
					                    if (getFile(glString1.toString(), arrToIntLE(readByte, glString1.length()+12)))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case StatPath:
 | 
				
			||||||
 | 
					                    if (statPath(readString(readByte, 8).toString()))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case Rename:
 | 
				
			||||||
 | 
					                    glString1 = readString(readByte, 8);
 | 
				
			||||||
 | 
					                    var glString2 = readString(readByte, 12+glString1.length());
 | 
				
			||||||
 | 
					                    if (rename(glString1.toString(), glString2.toString()))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case Delete:
 | 
				
			||||||
 | 
					                    if (delete(readString(readByte, 8).toString()))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case Create:
 | 
				
			||||||
 | 
					                    if (create(readString(readByte, 8).toString(), readByte[8]))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case ReadFile:
 | 
				
			||||||
 | 
					                    glString1 = readString(readByte, 8);
 | 
				
			||||||
 | 
					                    if (readFile(glString1.toString(),
 | 
				
			||||||
 | 
					                            arrToLongLE(readByte, 12+glString1.length()),
 | 
				
			||||||
 | 
					                            arrToLongLE(readByte, 12+glString1.length()+8)))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case WriteFile:
 | 
				
			||||||
 | 
					                    if (writeFile(readString(readByte, 8).toString()))
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case SelectFile:
 | 
				
			||||||
 | 
					                    if (selectFile())
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case StartFile:
 | 
				
			||||||
 | 
					                case EndFile:
 | 
				
			||||||
 | 
					                    if (startOrEndFile())
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case CMD_UNKNOWN:
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    writeGL_FAIL(EXCEPTION_CAUGHT, "GL Unknown command: "+readByte[4]+" [it's a very bad sign]");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected GlString readString(byte[] readByte, int startPosition){
 | 
				
			||||||
 | 
					        return new GlString010(readByte, startPosition);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected boolean notGLCI(byte[] inputBytes){
 | 
				
			||||||
 | 
					        return ! "GLCI".equals(new String(inputBytes, 0, 4, StandardCharsets.US_ASCII));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle StartFile & EndFile
 | 
				
			||||||
 | 
					     * NOTE: It's something internal for GL and used somehow by GL-PC-app, so just ignore this, at least for v0.8.
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean startOrEndFile(){
 | 
				
			||||||
 | 
					        return writeGL_PASS("GL Handle 'StartFile' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle GetDriveCount
 | 
				
			||||||
 | 
					     * 2 drives declared in current implementation
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected boolean getDriveCount(){
 | 
				
			||||||
 | 
					        return writeGL_PASS(intToArrLE(2),"GL Handle 'ListDrives' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle GetDriveInfo
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected boolean getDriveInfo(int driveNo){
 | 
				
			||||||
 | 
					        if (driveNo < 0 || driveNo > 1)
 | 
				
			||||||
 | 
					            return writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetDriveInfo' command [no such drive]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        byte[] driveLabel,
 | 
				
			||||||
 | 
					                driveLabelLen,
 | 
				
			||||||
 | 
					                driveLetter,
 | 
				
			||||||
 | 
					                driveLetterLen,
 | 
				
			||||||
 | 
					                totalFreeSpace;
 | 
				
			||||||
 | 
					        long totalSizeLong;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (driveNo == 0){ // 0 == VIRTUAL DRIVE
 | 
				
			||||||
 | 
					            driveLabel = "Virtual".getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					            driveLabelLen = intToArrLE(driveLabel.length);
 | 
				
			||||||
 | 
					            driveLetter = "VIRT".getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					            driveLetterLen = intToArrLE(driveLetter.length);
 | 
				
			||||||
 | 
					            totalFreeSpace = new byte[4];
 | 
				
			||||||
 | 
					            totalSizeLong = virtDriveSize;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else { //1 == User home dir
 | 
				
			||||||
 | 
					            driveLabel = "Home".getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					            driveLabelLen = intToArrLE(driveLabel.length);
 | 
				
			||||||
 | 
					            driveLetter = "HOME".getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					            driveLetterLen = intToArrLE(driveLetter.length);
 | 
				
			||||||
 | 
					            var userHomeDir = new File(System.getProperty("user.home"));
 | 
				
			||||||
 | 
					            totalFreeSpace = Arrays.copyOfRange(longToArrLE(userHomeDir.getFreeSpace()), 0, 4);;
 | 
				
			||||||
 | 
					            totalSizeLong = userHomeDir.getTotalSpace();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        var totalSize = Arrays.copyOfRange(longToArrLE(totalSizeLong), 0, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var command = Arrays.asList(
 | 
				
			||||||
 | 
					                driveLabelLen,
 | 
				
			||||||
 | 
					                driveLabel,
 | 
				
			||||||
 | 
					                driveLetterLen,
 | 
				
			||||||
 | 
					                driveLetter,
 | 
				
			||||||
 | 
					                totalFreeSpace,
 | 
				
			||||||
 | 
					                totalSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return writeGL_PASS(command, "GL Handle 'GetDriveInfo' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle SpecialPathCount
 | 
				
			||||||
 | 
					     * Let's declare nothing. Write count of special paths
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean getSpecialPathCount(){
 | 
				
			||||||
 | 
					        return writeGL_PASS(intToArrLE(0), "GL Handle 'SpecialPathCount' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle SpecialPath
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean getSpecialPath(int specialPathNo){
 | 
				
			||||||
 | 
					        return writeGL_FAIL(INVALID_INDEX, "GL Handle 'SpecialPath' command [not supported]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle GetDirectoryCount & GetFileCount
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean getDirectoryOrFileCount(String glFileName, boolean isGetDirectoryCount) {
 | 
				
			||||||
 | 
					        if (glFileName.equals("VIRT:/")) {
 | 
				
			||||||
 | 
					            return isGetDirectoryCount ?
 | 
				
			||||||
 | 
					                    writeGL_PASS("GL Handle 'GetDirectoryCount' command") :
 | 
				
			||||||
 | 
					                    writeGL_PASS(intToArrLE(nspMap.size()), "GL Handle 'GetFileCount' command Count = " + nspMap.size());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (glFileName.startsWith("HOME:/")){
 | 
				
			||||||
 | 
					            var path = decodeGlPath(glFileName);
 | 
				
			||||||
 | 
					            var pathDir = new File(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (notExistsOrDirectory(pathDir))
 | 
				
			||||||
 | 
					                return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'GetDirectoryOrFileCount' command [doesn't exist or not a folder] "+ pathDir);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.recentPath = path; // Save recent dir path
 | 
				
			||||||
 | 
					            var filesOrDirs = isGetDirectoryCount ?
 | 
				
			||||||
 | 
					                    pathDir.list(this::isDirectoryAndNotHidden) :
 | 
				
			||||||
 | 
					                    pathDir.list(this::isFileAndNotHidden);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // If no folders, let's say 0;
 | 
				
			||||||
 | 
					            if (filesOrDirs == null)
 | 
				
			||||||
 | 
					                return writeGL_PASS("GL Handle 'GetDirectoryOrFileCount' command");
 | 
				
			||||||
 | 
					            // Sorting is mandatory NOTE: Proxy tail
 | 
				
			||||||
 | 
					            Arrays.sort(filesOrDirs, String.CASE_INSENSITIVE_ORDER);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (isGetDirectoryCount)
 | 
				
			||||||
 | 
					                this.recentDirs = filesOrDirs;
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                this.recentFiles = filesOrDirs;
 | 
				
			||||||
 | 
					            // Otherwise, let's tell how may folders are in there
 | 
				
			||||||
 | 
					            return writeGL_PASS(intToArrLE(filesOrDirs.length), "GL Handle 'GetDirectoryOrFileCount' command");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (glFileName.startsWith("SPEC:/")){
 | 
				
			||||||
 | 
					            if (isGetDirectoryCount)        // If dir request then 0 dirs
 | 
				
			||||||
 | 
					                return writeGL_PASS("GL Handle 'GetDirectoryCount' command");
 | 
				
			||||||
 | 
					            else if (selectedFile != null)  // Else it's file request, if we have selected then we will report 1.
 | 
				
			||||||
 | 
					                return writeGL_PASS(intToArrLE(1), "GL Handle 'GetFileCount' command Count = 1");
 | 
				
			||||||
 | 
					            return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] (file) - "+glFileName);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // If requested drive is not VIRT and not HOME then reply error
 | 
				
			||||||
 | 
					        return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] "+(isGetDirectoryCount?"(dir) - ":"(file) - ")+glFileName);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle GetDirectory
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean getDirectory(String dirName, int subDirNo){
 | 
				
			||||||
 | 
					        if (dirName.startsWith("HOME:/")) {
 | 
				
			||||||
 | 
					            dirName = decodeGlPath(dirName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var command = new ArrayList<byte[]>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (dirName.equals(recentPath) && recentDirs != null && recentDirs.length != 0){
 | 
				
			||||||
 | 
					                var dirNameBytes = recentDirs[subDirNo].getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                command.add(intToArrLE(dirNameBytes.length));
 | 
				
			||||||
 | 
					                command.add(dirNameBytes);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                var pathDir = new File(dirName);
 | 
				
			||||||
 | 
					                // Make sure it's exists and it's path
 | 
				
			||||||
 | 
					                if (notExistsOrDirectory(pathDir))
 | 
				
			||||||
 | 
					                    return writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetDirectory' command [doesn't exist or not a folder]");
 | 
				
			||||||
 | 
					                this.recentPath = dirName;
 | 
				
			||||||
 | 
					                // Now collecting every folder or file inside
 | 
				
			||||||
 | 
					                this.recentDirs = pathDir.list(this::isDirectoryAndNotHidden);
 | 
				
			||||||
 | 
					                // Check that we still don't have any fuckups
 | 
				
			||||||
 | 
					                if (this.recentDirs != null && this.recentDirs.length > subDirNo){
 | 
				
			||||||
 | 
					                    Arrays.sort(recentFiles, String.CASE_INSENSITIVE_ORDER);
 | 
				
			||||||
 | 
					                    var dirBytesName = recentDirs[subDirNo].getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                    command.add(intToArrLE(dirBytesName.length));
 | 
				
			||||||
 | 
					                    command.add(dirBytesName);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    return writeGL_FAIL(INVALID_INDEX,"GL Handle 'GetDirectory' command [doesn't exist or not a folder]");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return writeGL_PASS(command, "GL Handle 'GetDirectory' command.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // VIRT:// and any other
 | 
				
			||||||
 | 
					        return writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetDirectory' command for virtual drive [no folders support]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle GetFile
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean getFile(String glDirName, int subDirNo){
 | 
				
			||||||
 | 
					        var command = new LinkedList<byte[]>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (glDirName.startsWith("HOME:/")) {
 | 
				
			||||||
 | 
					            var dirName = decodeGlPath(glDirName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (dirName.equals(recentPath) && recentFiles != null && recentFiles.length != 0){
 | 
				
			||||||
 | 
					                var fileNameBytes = recentFiles[subDirNo].getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                command.add(intToArrLE(fileNameBytes.length));
 | 
				
			||||||
 | 
					                command.add(fileNameBytes);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                var pathDir = new File(dirName);
 | 
				
			||||||
 | 
					                if (notExistsOrDirectory(pathDir))
 | 
				
			||||||
 | 
					                    writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetFile' command [doesn't exist or not a folder]");
 | 
				
			||||||
 | 
					                this.recentPath = dirName;
 | 
				
			||||||
 | 
					                this.recentFiles = pathDir.list(this::isFileAndNotHidden);
 | 
				
			||||||
 | 
					                // Check that we still don't have any fuckups
 | 
				
			||||||
 | 
					                if (this.recentFiles != null && this.recentFiles.length > subDirNo){
 | 
				
			||||||
 | 
					                    Arrays.sort(recentFiles, String.CASE_INSENSITIVE_ORDER);
 | 
				
			||||||
 | 
					                    var fileNameBytes = recentFiles[subDirNo].getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                    command.add(intToArrLE(fileNameBytes.length));
 | 
				
			||||||
 | 
					                    command.add(fileNameBytes);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    return writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetFile' command [doesn't exist or not a folder]");
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return writeGL_PASS(command, "GL Handle 'GetFile' command.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (glDirName.equals("VIRT:/") && (! nspMap.isEmpty())){ // thus nspMapKeySetIndexes also != 0
 | 
				
			||||||
 | 
					            var fileNameBytes = nspMapKeySetIndexes[subDirNo].getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					            command.add(intToArrLE(fileNameBytes.length));
 | 
				
			||||||
 | 
					            command.add(fileNameBytes);
 | 
				
			||||||
 | 
					            return writeGL_PASS(command, "GL Handle 'GetFile' command.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (glDirName.equals("SPEC:/") && (selectedFile != null)){
 | 
				
			||||||
 | 
					            var fileNameBytes = selectedFile.getName().getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					            command.add(intToArrLE(fileNameBytes.length));
 | 
				
			||||||
 | 
					            command.add(fileNameBytes);
 | 
				
			||||||
 | 
					            return writeGL_PASS(command, "GL Handle 'GetFile' command.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //  any other cases
 | 
				
			||||||
 | 
					        return writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetFile' command for virtual drive [no folders support?]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle StatPath
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean statPath(String glFileName){
 | 
				
			||||||
 | 
					        var command = new ArrayList<byte[]>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (glFileName.startsWith("HOME:/")){
 | 
				
			||||||
 | 
					            var fileDirElement = new File(decodeGlPath(glFileName));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (fileDirElement.exists()){
 | 
				
			||||||
 | 
					                if (fileDirElement.isDirectory())
 | 
				
			||||||
 | 
					                    command.add(GL_OBJECT_TYPE_DIR);
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    command.add(GL_OBJECT_TYPE_FILE);
 | 
				
			||||||
 | 
					                    command.add(longToArrLE(fileDirElement.length()));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return writeGL_PASS(command, "GL Handle 'StatPath' command for "+glFileName);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (glFileName.startsWith("VIRT:/")) {
 | 
				
			||||||
 | 
					            var fileName = glFileName.replaceFirst("^.*?:/", "");
 | 
				
			||||||
 | 
					            if (nspMap.containsKey(fileName)){
 | 
				
			||||||
 | 
					                command.add(GL_OBJECT_TYPE_FILE);                              // THIS IS INT
 | 
				
			||||||
 | 
					                if (nspMap.get(fileName).isDirectory())
 | 
				
			||||||
 | 
					                    command.add(longToArrLE(splitFileSize.get(fileName)));    // YES, THIS IS LONG!;
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    command.add(longToArrLE(nspMap.get(fileName).length()));    // YES, THIS IS LONG!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return writeGL_PASS(command, "GL Handle 'StatPath' command for "+glFileName);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (glFileName.startsWith("SPEC:/")){
 | 
				
			||||||
 | 
					            var fileName = glFileName.replaceFirst("^.*?:/", "");
 | 
				
			||||||
 | 
					            if (selectedFile.getName().equals(fileName)){
 | 
				
			||||||
 | 
					                command.add(GL_OBJECT_TYPE_FILE);
 | 
				
			||||||
 | 
					                command.add(longToArrLE(selectedFile.length()));
 | 
				
			||||||
 | 
					                return writeGL_PASS(command, "GL Handle 'StatPath' command for "+glFileName);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'StatPath' command [no such path]: "+glFileName);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle 'Rename' that is actually 'mv'
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean rename(String glFileName, String glNewFileName){
 | 
				
			||||||
 | 
					        if (glFileName.startsWith("HOME:/")){
 | 
				
			||||||
 | 
					            // Prevent GL failures
 | 
				
			||||||
 | 
					            this.recentPath = null;
 | 
				
			||||||
 | 
					            this.recentFiles = null;
 | 
				
			||||||
 | 
					            this.recentDirs = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var fileName = decodeGlPath(glFileName);
 | 
				
			||||||
 | 
					            var newFile = new File(decodeGlPath(glNewFileName));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                if (new File(fileName).renameTo(newFile)){
 | 
				
			||||||
 | 
					                    return writeGL_PASS("GL Handle 'Rename' command.");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (SecurityException se){
 | 
				
			||||||
 | 
					                return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'Rename' command failed:\n\t" +se.getMessage());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // For VIRT:/ and others we don't serve requests
 | 
				
			||||||
 | 
					        return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'Rename' command is not supported for virtual drive, selected files," +
 | 
				
			||||||
 | 
					                " if file with such name already exists in folder, read-only directories");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle 'Delete'
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean delete(String glFileName) {
 | 
				
			||||||
 | 
					        if (! glFileName.startsWith("HOME:/"))
 | 
				
			||||||
 | 
					            return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory] "+glFileName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var file = new File(decodeGlPath(glFileName));
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            if (file.delete())
 | 
				
			||||||
 | 
					                return writeGL_PASS("GL Handle 'Rename' command.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (SecurityException ignored){} // Ah, leave it
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'Create' command [unknown drive/read-only directory]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle 'Create'
 | 
				
			||||||
 | 
					     * @param type 1 → file,  2 → folder
 | 
				
			||||||
 | 
					     * @param glFileName full path including new file name in the end
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean create(String glFileName, byte type) {
 | 
				
			||||||
 | 
					        if (! glFileName.startsWith("HOME:/"))    // For VIRT:/ and others we don't serve requests
 | 
				
			||||||
 | 
					            return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'Create' command [not supported for virtual drive/wrong drive/read-only directory]"+glFileName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var file = new File(decodeGlPath(glFileName));
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            boolean result = switch (type) {
 | 
				
			||||||
 | 
					                case 1 -> file.createNewFile();
 | 
				
			||||||
 | 
					                case 2 -> file.mkdir();
 | 
				
			||||||
 | 
					                default -> false;
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (result)
 | 
				
			||||||
 | 
					                return writeGL_PASS("GL Handle 'Create' command.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (SecurityException | IOException ignored){}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'Create' command [unknown drive/read-only directory]");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle 'ReadFile'
 | 
				
			||||||
 | 
					     * @param glFileName full path including new file name in the end in format of Goldleaf
 | 
				
			||||||
 | 
					     * @param offset requested offset
 | 
				
			||||||
 | 
					     * @param size requested size
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean readFile(String glFileName, long offset, long size) {
 | 
				
			||||||
 | 
					        var fileName = glFileName.replaceFirst("^.*?:/", "");
 | 
				
			||||||
 | 
					        if (glFileName.startsWith("VIRT:/")){                                              // Could have split-file
 | 
				
			||||||
 | 
					            // Let's find out which file requested
 | 
				
			||||||
 | 
					            var fNamePath = nspMap.get(fileName).getAbsolutePath(); // NOTE: 6 = "VIRT:/".length
 | 
				
			||||||
 | 
					            // If we don't have this file opened, let's open it
 | 
				
			||||||
 | 
					            if (openReadFileNameAndPath == null || (! openReadFileNameAndPath.equals(fNamePath))) {
 | 
				
			||||||
 | 
					                if (openReadFileNameAndPath != null)                                      // (Try to) close what opened
 | 
				
			||||||
 | 
					                    closeRAFandSplitReader();
 | 
				
			||||||
 | 
					                try{                                                                      // And open the rest
 | 
				
			||||||
 | 
					                    var tempFile = nspMap.get(fileName);
 | 
				
			||||||
 | 
					                    if (tempFile.isDirectory()) {
 | 
				
			||||||
 | 
					                        randAccessFile = null;
 | 
				
			||||||
 | 
					                        splitReader = new NSSplitReader(tempFile, 0);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        splitReader = null;
 | 
				
			||||||
 | 
					                        randAccessFile = new RandomAccessFile(tempFile, "r");
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    openReadFileNameAndPath = fNamePath;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (IOException | NullPointerException ioe){
 | 
				
			||||||
 | 
					                    return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'ReadFile' command\n\t"+ioe.getMessage());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else { // SPEC:/ & HOME:/
 | 
				
			||||||
 | 
					            String filePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (glFileName.startsWith("SPEC:/")) {
 | 
				
			||||||
 | 
					                if (! fileName.equals(selectedFile.getName())) {
 | 
				
			||||||
 | 
					                    return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'ReadFile' command\n\trequested != selected:\n\t"
 | 
				
			||||||
 | 
					                            + glFileName + "\n\t" + selectedFile);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                filePath = selectedFile.getAbsolutePath();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                filePath = decodeGlPath(glFileName); // What requested?
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            // If we don't have this file opened, let's open it
 | 
				
			||||||
 | 
					            if (openReadFileNameAndPath == null || (! openReadFileNameAndPath.equals(filePath))) {
 | 
				
			||||||
 | 
					                if (openReadFileNameAndPath != null) // Try close what opened
 | 
				
			||||||
 | 
					                    closeRAF();
 | 
				
			||||||
 | 
					                try{                                   // Open what has to be opened
 | 
				
			||||||
 | 
					                    randAccessFile = new RandomAccessFile(filePath, "r");
 | 
				
			||||||
 | 
					                    openReadFileNameAndPath = filePath;
 | 
				
			||||||
 | 
					                }catch (IOException | NullPointerException ioe){
 | 
				
			||||||
 | 
					                    return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'ReadFile' command\n\t"+ioe.getMessage());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        //----------------------- Actual transfer chain ------------------------
 | 
				
			||||||
 | 
					        try{
 | 
				
			||||||
 | 
					            var chunk = new byte[(int)size];
 | 
				
			||||||
 | 
					            int bytesRead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (randAccessFile == null){
 | 
				
			||||||
 | 
					                splitReader.seek(offset);
 | 
				
			||||||
 | 
					                bytesRead = splitReader.read(chunk);   // How many bytes we got?
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                randAccessFile.seek(offset);
 | 
				
			||||||
 | 
					                bytesRead = randAccessFile.read(chunk); // How many bytes we got?
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (bytesRead != (int) size)    // Let's check that we read expected size
 | 
				
			||||||
 | 
					                return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'ReadFile' command [CMD]" +
 | 
				
			||||||
 | 
					                        "\n         At offset: " + offset +
 | 
				
			||||||
 | 
					                        "\n         Requested: " + size +
 | 
				
			||||||
 | 
					                        "\n         Received:  " + bytesRead);
 | 
				
			||||||
 | 
					            if (writeGL_PASS(longToArrLE(size), "GL Handle 'ReadFile' command [CMD]")) { // Reporting result
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (writeToUsb(chunk)) {    // Bypassing bytes we read total // FIXME: move failure message into method
 | 
				
			||||||
 | 
					                print("GL Handle 'ReadFile' command", EMsgType.FAIL);
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ioe){
 | 
				
			||||||
 | 
					            closeOpenedReadFilesGl();
 | 
				
			||||||
 | 
					            return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'ReadFile' transfer chain\n\t"+ioe.getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle 'WriteFile'
 | 
				
			||||||
 | 
					     * @param glFileName full path including new file name in the end
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    boolean writeFile(String glFileName) {
 | 
				
			||||||
 | 
					        if (glFileName.startsWith("VIRT:/"))
 | 
				
			||||||
 | 
					            return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'WriteFile' command [not supported for virtual drive]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        glFileName = decodeGlPath(glFileName);
 | 
				
			||||||
 | 
					        // Check if this file being used during this session
 | 
				
			||||||
 | 
					        if (! writeFilesMap.containsKey(glFileName)){
 | 
				
			||||||
 | 
					            try{                                     // If this file exists GL will take care; Otherwise, let's add it
 | 
				
			||||||
 | 
					                writeFilesMap.put(glFileName,
 | 
				
			||||||
 | 
					                        new BufferedOutputStream(new FileOutputStream(glFileName, true))); // Open what we have to open
 | 
				
			||||||
 | 
					            } catch (IOException ioe){
 | 
				
			||||||
 | 
					                return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'WriteFile' command [IOException]\n\t"+ioe.getMessage());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var transferredData = readGL_file();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (transferredData == null){
 | 
				
			||||||
 | 
					            print("GL Handle 'WriteFile' command [1/1]", EMsgType.FAIL);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        try{
 | 
				
			||||||
 | 
					            writeFilesMap.get(glFileName).write(transferredData, 0, transferredData.length);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (IOException ioe){
 | 
				
			||||||
 | 
					            return writeGL_FAIL(EXCEPTION_CAUGHT, "GL Handle 'WriteFile' command [1/1]\n\t"+ioe.getMessage());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Report we're good
 | 
				
			||||||
 | 
					        return writeGL_PASS("GL Handle 'WriteFile' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Handle 'SelectFile'
 | 
				
			||||||
 | 
					     * @return true - failed, false - passed
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean selectFile(){
 | 
				
			||||||
 | 
					        var selectedFile = CompletableFuture.supplyAsync(() -> {
 | 
				
			||||||
 | 
					            var fChooser = new FileChooser();
 | 
				
			||||||
 | 
					            fChooser.setTitle(MediatorControl.INSTANCE.getResourceBundle().getString("btn_OpenFile"));   // TODO: FIX BAD IMPLEMENTATION
 | 
				
			||||||
 | 
					            fChooser.setInitialDirectory(new File(System.getProperty("user.home")));                         // TODO: Consider fixing; not a priority.
 | 
				
			||||||
 | 
					            fChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("*", "*"));
 | 
				
			||||||
 | 
					            return fChooser.showOpenDialog(null);    // Leave as is for now.
 | 
				
			||||||
 | 
					        }, Platform::runLater).join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (selectedFile == null){    // Nothing selected
 | 
				
			||||||
 | 
					            this.selectedFile = null;
 | 
				
			||||||
 | 
					            return writeGL_FAIL(SELECTION_CANCELLED, "GL Handle 'SelectFile' command: Nothing selected");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var selectedFileNameBytes = ("SPEC:/"+selectedFile.getName()).getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					        var command = Arrays.asList(
 | 
				
			||||||
 | 
					                intToArrLE(selectedFileNameBytes.length),
 | 
				
			||||||
 | 
					                selectedFileNameBytes);
 | 
				
			||||||
 | 
					        if (writeGL_PASS(command, "GL Handle 'SelectFile' command")) {
 | 
				
			||||||
 | 
					            this.selectedFile = null;
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.selectedFile = selectedFile;
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*--------------------------------*/
 | 
				
			||||||
 | 
					    /*           GL HELPERS           */
 | 
				
			||||||
 | 
					    /*--------------------------------*/
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Convert path received from GL to host-default structure
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected String decodeGlPath(String glPath){
 | 
				
			||||||
 | 
					        if (isWindows)
 | 
				
			||||||
 | 
					            glPath = glPath.replace('/', '\\');
 | 
				
			||||||
 | 
					        return homePath + glPath.substring(5);     // e.g. HOME:/some/file/
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private boolean isFileAndNotHidden(File parent, String child){
 | 
				
			||||||
 | 
					            var entry = new File(parent, child);
 | 
				
			||||||
 | 
					            return (! entry.isDirectory()) && (nspFilter ?
 | 
				
			||||||
 | 
					                                                child.toLowerCase().endsWith(".nsp") :
 | 
				
			||||||
 | 
					                                                ! entry.isHidden());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private boolean isDirectoryAndNotHidden(File parent, String child){
 | 
				
			||||||
 | 
					        var dir = new File(parent, child);
 | 
				
			||||||
 | 
					        return (dir.isDirectory() && ! dir.isHidden());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private boolean notExistsOrDirectory(File pathDir){
 | 
				
			||||||
 | 
					        return (! pathDir.exists() ) || (! pathDir.isDirectory());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Close files opened for read/write
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected void closeOpenedReadFilesGl(){
 | 
				
			||||||
 | 
					        if (openReadFileNameAndPath != null){
 | 
				
			||||||
 | 
					            closeRAFandSplitReader();
 | 
				
			||||||
 | 
					            openReadFileNameAndPath = null;
 | 
				
			||||||
 | 
					            randAccessFile = null;
 | 
				
			||||||
 | 
					            splitReader = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    protected void closeRAFandSplitReader(){
 | 
				
			||||||
 | 
					        closeRAF();
 | 
				
			||||||
 | 
					        try{
 | 
				
			||||||
 | 
					            splitReader.close();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (IOException ioe_){
 | 
				
			||||||
 | 
					            print("Unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ignored){}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    protected void closeRAF(){
 | 
				
			||||||
 | 
					        try{
 | 
				
			||||||
 | 
					            randAccessFile.close();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (IOException ioe_){
 | 
				
			||||||
 | 
					            print("Unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (Exception ignored){}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /*----------------------------------------------------*/
 | 
				
			||||||
 | 
					    /*           GL READ/WRITE USB SPECIFIC               */
 | 
				
			||||||
 | 
					    /*----------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected byte[] readGL(){
 | 
				
			||||||
 | 
					        var readBuffer = ByteBuffer.allocateDirect(PACKET_SIZE);
 | 
				
			||||||
 | 
					        var readBufTransferred = IntBuffer.allocate(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (! task.isCancelled()) {
 | 
				
			||||||
 | 
					            int result = LibUsb.bulkTransfer(handlerNS, IN_EP, readBuffer, readBufTransferred, 1000);  // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (result) {
 | 
				
			||||||
 | 
					                case LibUsb.SUCCESS:
 | 
				
			||||||
 | 
					                    var receivedBytes = new byte[readBufTransferred.get()];
 | 
				
			||||||
 | 
					                    readBuffer.get(receivedBytes);
 | 
				
			||||||
 | 
					                    return receivedBytes;
 | 
				
			||||||
 | 
					                case LibUsb.ERROR_TIMEOUT:
 | 
				
			||||||
 | 
					                    closeOpenedReadFilesGl();       // Could be a problem if GL glitches and slow down process. Or if user has extra-slow SD card. TODO: refactor?
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    print("GL Data transfer issue [read]\n         Returned: " +
 | 
				
			||||||
 | 
					                            LibUsb.errorName(result) +
 | 
				
			||||||
 | 
					                            "\n         GL Execution stopped", EMsgType.FAIL);
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        print("GL Execution interrupted", EMsgType.INFO);
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    private byte[] readGL_file(){
 | 
				
			||||||
 | 
					        var readBuffer = ByteBuffer.allocateDirect(8388608); // Just don't ask..
 | 
				
			||||||
 | 
					        var readBufTransferred = IntBuffer.allocate(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (! task.isCancelled() ) {
 | 
				
			||||||
 | 
					            int result = LibUsb.bulkTransfer(handlerNS, IN_EP, readBuffer, readBufTransferred, 1000);  // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (result) {
 | 
				
			||||||
 | 
					                case LibUsb.SUCCESS:
 | 
				
			||||||
 | 
					                    var receivedBytes = new byte[readBufTransferred.get()];
 | 
				
			||||||
 | 
					                    readBuffer.get(receivedBytes);
 | 
				
			||||||
 | 
					                    return receivedBytes;
 | 
				
			||||||
 | 
					                case LibUsb.ERROR_TIMEOUT:
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    print("GL Data transfer issue [read]\n         Returned: " +
 | 
				
			||||||
 | 
					                            LibUsb.errorName(result) +
 | 
				
			||||||
 | 
					                            "\n         GL Execution stopped", EMsgType.FAIL);
 | 
				
			||||||
 | 
					                    return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        print("GL Execution interrupted", EMsgType.INFO);
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Write new command
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    protected boolean writeGL_PASS(String onFailureText){
 | 
				
			||||||
 | 
					        if (writeToUsb(CMD_GLCO_SUCCESS)){
 | 
				
			||||||
 | 
					            print(onFailureText, EMsgType.FAIL);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    protected boolean writeGL_PASS(byte[] message, String onFailureText){
 | 
				
			||||||
 | 
					        var result = writeToUsb(ByteBuffer.allocate(PACKET_SIZE)
 | 
				
			||||||
 | 
					                .put(CMD_GLCO_SUCCESS_FLAG)
 | 
				
			||||||
 | 
					                .put(message)
 | 
				
			||||||
 | 
					                .array());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(result){
 | 
				
			||||||
 | 
					            print(onFailureText, EMsgType.FAIL);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    protected boolean writeGL_PASS(List<byte[]> messages, String onFailureText){
 | 
				
			||||||
 | 
					        var writeBuffer = ByteBuffer.allocate(PACKET_SIZE)
 | 
				
			||||||
 | 
					                .put(CMD_GLCO_SUCCESS_FLAG);
 | 
				
			||||||
 | 
					        messages.forEach(writeBuffer::put);
 | 
				
			||||||
 | 
					        if (writeToUsb(writeBuffer.array())){
 | 
				
			||||||
 | 
					            print(onFailureText, EMsgType.FAIL);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected boolean writeGL_FAIL(byte[] failurePacket, String failureMessage){
 | 
				
			||||||
 | 
					        if (writeToUsb(failurePacket)){
 | 
				
			||||||
 | 
					            print(failureMessage, EMsgType.WARNING);
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        print(failureMessage, EMsgType.FAIL);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sending any byte array to USB device
 | 
				
			||||||
 | 
					     * @return 'false' if no issues
 | 
				
			||||||
 | 
					     *          'true' if errors happened
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					    private boolean writeToUsb(byte[] message){
 | 
				
			||||||
 | 
					        //RainbowHexDump.hexDumpUTF16LE(message);   // DEBUG
 | 
				
			||||||
 | 
					        var writeBufTransferred = IntBuffer.allocate(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (! task.isCancelled()) {
 | 
				
			||||||
 | 
					            int result = LibUsb.bulkTransfer(handlerNS,
 | 
				
			||||||
 | 
					                    OUT_EP,
 | 
				
			||||||
 | 
					                    ByteBuffer.allocateDirect(message.length).put(message), // order -> BIG_ENDIAN; Don't writeBuffer.rewind();
 | 
				
			||||||
 | 
					                    writeBufTransferred,
 | 
				
			||||||
 | 
					                    1000);  // TIMEOUT. 0 stands for infinite. Endpoint OUT = 0x01
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            switch (result){
 | 
				
			||||||
 | 
					                case LibUsb.SUCCESS:
 | 
				
			||||||
 | 
					                    if (writeBufTransferred.get() == message.length)
 | 
				
			||||||
 | 
					                        return false;
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        print("GL Data transfer issue [write]\n         Requested: " +
 | 
				
			||||||
 | 
					                                message.length +
 | 
				
			||||||
 | 
					                                "\n         Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
 | 
				
			||||||
 | 
					                        return true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                case LibUsb.ERROR_TIMEOUT:
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    print("GL Data transfer issue [write]\n         Returned: " +
 | 
				
			||||||
 | 
					                            LibUsb.errorName(result) +
 | 
				
			||||||
 | 
					                            "\n         GL Execution stopped", EMsgType.FAIL);
 | 
				
			||||||
 | 
					                    return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        print("GL Execution interrupted", EMsgType.INFO);
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										118
									
								
								src/main/java/nsusbloader/com/usb/gl/GoldLeaf_111.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/main/java/nsusbloader/com/usb/gl/GoldLeaf_111.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,118 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    Copyright 2019-2025 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.com.usb.gl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import nsusbloader.ModelControllers.CancellableRunnable;
 | 
				
			||||||
 | 
					import nsusbloader.ModelControllers.ILogPrinter;
 | 
				
			||||||
 | 
					import nsusbloader.NSLDataTypes.EMsgType;
 | 
				
			||||||
 | 
					import org.usb4java.DeviceHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.*;
 | 
				
			||||||
 | 
					import java.nio.charset.StandardCharsets;
 | 
				
			||||||
 | 
					import java.util.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static nsusbloader.com.usb.gl.Converters.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * GoldLeaf 1.1.1 processing
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class GoldLeaf_111 extends GoldLeaf_010{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public GoldLeaf_111(DeviceHandle handler, LinkedHashMap<String, File> nspMap,
 | 
				
			||||||
 | 
					                        CancellableRunnable task,
 | 
				
			||||||
 | 
					                        ILogPrinter logPrinter,
 | 
				
			||||||
 | 
					                        boolean nspFilter) {
 | 
				
			||||||
 | 
					        super(handler, nspMap, task, logPrinter, nspFilter);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected void printWelcomeMessage(){
 | 
				
			||||||
 | 
					        print("=========== GoldLeaf v1.1.1 ===========\n\t" +
 | 
				
			||||||
 | 
					                "VIRT:/ equals files added into the application\n\t" +
 | 
				
			||||||
 | 
					                "HOME:/ equals " + homePath + "\n\t" +
 | 
				
			||||||
 | 
					                "BE CAREFUL!\n\t" +
 | 
				
			||||||
 | 
					                "Due to some strange behaviour with Goldleaf v1.1.1, you will see last menu entry " +
 | 
				
			||||||
 | 
					                "'Do not click (crashes Atmosphere)'\n\t" +
 | 
				
			||||||
 | 
					                "You should better not clicking on it", EMsgType.INFO);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Fixes issues with incorrect request for 'Home' & 'Virtual'. Forces both to return 'HOME:/'
 | 
				
			||||||
 | 
					     * v1.1.1 specific fix
 | 
				
			||||||
 | 
					     * Otherwise v.1.1.1 returns 'HOME:/' once 'Virtual' requested and ':/' once requested 'Home'
 | 
				
			||||||
 | 
					     * */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected boolean getDriveCount(){
 | 
				
			||||||
 | 
					        return writeGL_PASS(intToArrLE(3),"GL Handle 'ListDrives' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    protected boolean getDriveInfo(int driveNo){
 | 
				
			||||||
 | 
					        if (driveNo < 0 || driveNo > 2)
 | 
				
			||||||
 | 
					            return writeGL_FAIL(INVALID_INDEX, "GL Handle 'GetDriveInfo' command [no such drive]");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        byte[] driveLabel,
 | 
				
			||||||
 | 
					                driveLabelLen,
 | 
				
			||||||
 | 
					                driveLetter,
 | 
				
			||||||
 | 
					                driveLetterLen,
 | 
				
			||||||
 | 
					                totalFreeSpace;
 | 
				
			||||||
 | 
					        long totalSizeLong;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (driveNo){
 | 
				
			||||||
 | 
					            case 0:
 | 
				
			||||||
 | 
					                driveLabel = "Home".getBytes(StandardCharsets.UTF_8); // yes, it's hotfix
 | 
				
			||||||
 | 
					                driveLabelLen = intToArrLE(driveLabel.length);
 | 
				
			||||||
 | 
					                driveLetter = "VIRT".getBytes(StandardCharsets.UTF_8); // and this is fine
 | 
				
			||||||
 | 
					                driveLetterLen = intToArrLE(driveLetter.length);
 | 
				
			||||||
 | 
					                totalFreeSpace = new byte[4];
 | 
				
			||||||
 | 
					                totalSizeLong = virtDriveSize;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 1:
 | 
				
			||||||
 | 
					                driveLabel = "Virtual".getBytes(StandardCharsets.UTF_8); // here as well
 | 
				
			||||||
 | 
					                driveLabelLen = intToArrLE(driveLabel.length);
 | 
				
			||||||
 | 
					                driveLetter = "HOME".getBytes(StandardCharsets.UTF_8); // and here
 | 
				
			||||||
 | 
					                driveLetterLen = intToArrLE(driveLetter.length);
 | 
				
			||||||
 | 
					                var userHomeDir = new File(System.getProperty("user.home"));
 | 
				
			||||||
 | 
					                totalFreeSpace = Arrays.copyOfRange(longToArrLE(userHomeDir.getFreeSpace()), 0, 4);;
 | 
				
			||||||
 | 
					                totalSizeLong = userHomeDir.getTotalSpace();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                driveLabel = "Do not click (crashes Atmosphere)".getBytes(StandardCharsets.UTF_8); // and this one is necessary too
 | 
				
			||||||
 | 
					                driveLabelLen = intToArrLE(driveLabel.length);
 | 
				
			||||||
 | 
					                driveLetter = "VIRT".getBytes(StandardCharsets.UTF_8);
 | 
				
			||||||
 | 
					                driveLetterLen = intToArrLE(driveLetter.length);
 | 
				
			||||||
 | 
					                totalFreeSpace = new byte[4];
 | 
				
			||||||
 | 
					                totalSizeLong = virtDriveSize;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var totalSize = Arrays.copyOfRange(longToArrLE(totalSizeLong), 0, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var command = Arrays.asList(
 | 
				
			||||||
 | 
					                driveLabelLen,
 | 
				
			||||||
 | 
					                driveLabel,
 | 
				
			||||||
 | 
					                driveLetterLen,
 | 
				
			||||||
 | 
					                driveLetter,
 | 
				
			||||||
 | 
					                totalFreeSpace,
 | 
				
			||||||
 | 
					                totalSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return writeGL_PASS(command, "GL Handle 'GetDriveInfo' command");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										54
									
								
								src/main/java/nsusbloader/com/usb/gl/GoldleafCmd.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/main/java/nsusbloader/com/usb/gl/GoldleafCmd.java
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,54 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					    Copyright 2019-2025 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.com.usb.gl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public enum GoldleafCmd {
 | 
				
			||||||
 | 
					    GetDriveCount((byte) 1),
 | 
				
			||||||
 | 
					    GetDriveInfo((byte) 2),
 | 
				
			||||||
 | 
					    StatPath((byte) 3),
 | 
				
			||||||
 | 
					    GetFileCount((byte) 4),
 | 
				
			||||||
 | 
					    GetFile((byte) 5),
 | 
				
			||||||
 | 
					    GetDirectoryCount((byte) 6),
 | 
				
			||||||
 | 
					    GetDirectory((byte) 7),
 | 
				
			||||||
 | 
					    StartFile((byte) 8),
 | 
				
			||||||
 | 
					    ReadFile((byte) 9),
 | 
				
			||||||
 | 
					    WriteFile((byte) 10),
 | 
				
			||||||
 | 
					    EndFile((byte) 11),
 | 
				
			||||||
 | 
					    Create((byte) 12),
 | 
				
			||||||
 | 
					    Delete((byte) 13),
 | 
				
			||||||
 | 
					    Rename((byte) 14),
 | 
				
			||||||
 | 
					    GetSpecialPathCount((byte) 15),
 | 
				
			||||||
 | 
					    GetSpecialPath((byte) 16),
 | 
				
			||||||
 | 
					    SelectFile((byte) 17),
 | 
				
			||||||
 | 
					    CMD_UNKNOWN((byte) 255);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final byte id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    GoldleafCmd(byte id) {
 | 
				
			||||||
 | 
					        this.id = id;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static GoldleafCmd get(byte id) {
 | 
				
			||||||
 | 
					        for(GoldleafCmd cmd : values()) {
 | 
				
			||||||
 | 
					            if(cmd.id == id)
 | 
				
			||||||
 | 
					                return cmd;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return CMD_UNKNOWN;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -22,18 +22,17 @@ public class EsIntegrationTest {
 | 
				
			||||||
        pathToKeysFile = environment.getProdkeysLocation();
 | 
					        pathToKeysFile = environment.getProdkeysLocation();
 | 
				
			||||||
        saveTo = environment.getSaveToLocation() + File.separator + "ES_LPR";
 | 
					        saveTo = environment.getSaveToLocation() + File.separator + "ES_LPR";
 | 
				
			||||||
        pathToFirmwares = environment.getFirmwaresLocation();
 | 
					        pathToFirmwares = environment.getFirmwaresLocation();
 | 
				
			||||||
        pathToFirmware = environment.getFirmwaresLocation() + File.separator + "Firmware 17.0.0";
 | 
					        pathToFirmware = environment.getFirmwaresLocation() + File.separator + "Firmware 19.0.1";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @DisplayName("ES Integration validation - everything")
 | 
					    @DisplayName("ES Integration validation - everything")
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    void makeEss() throws Exception{
 | 
					    void makeEss() throws Exception{
 | 
				
			||||||
        File[] fwDirs = new File(pathToFirmwares).listFiles((file, s) -> {
 | 
					        File[] fwDirs = new File(pathToFirmwares).listFiles((file, s) ->
 | 
				
			||||||
            return s.matches("^Firmware (9\\.|[0-9][0-9]\\.).*");
 | 
					                s.matches("^Firmware (9\\.|[0-9][0-9]\\.).*"));
 | 
				
			||||||
            //return s.matches("^Firmware 10.0.1.*");
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        assert fwDirs != null;
 | 
					        assert fwDirs != null;
 | 
				
			||||||
        Arrays.sort(fwDirs);
 | 
					        Arrays.sort(fwDirs);
 | 
				
			||||||
 | 
					        Arrays.stream(fwDirs).forEach(System.out::println);
 | 
				
			||||||
        for (File dir : fwDirs){
 | 
					        for (File dir : fwDirs){
 | 
				
			||||||
            EsPatchMaker esPatchMaker = new EsPatchMaker(dir.getAbsolutePath(), pathToKeysFile, saveTo);
 | 
					            EsPatchMaker esPatchMaker = new EsPatchMaker(dir.getAbsolutePath(), pathToKeysFile, saveTo);
 | 
				
			||||||
            Thread workThread = new Thread(esPatchMaker);
 | 
					            Thread workThread = new Thread(esPatchMaker);
 | 
				
			||||||
| 
						 | 
					@ -42,6 +41,7 @@ public class EsIntegrationTest {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Disabled
 | 
				
			||||||
    @DisplayName("ES Integration validation - one particular firmware")
 | 
					    @DisplayName("ES Integration validation - one particular firmware")
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    void makeEs() throws Exception{
 | 
					    void makeEs() throws Exception{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,19 +25,17 @@ public class FsIntegrationTest {
 | 
				
			||||||
        pathToKeysFile = environment.getProdkeysLocation();
 | 
					        pathToKeysFile = environment.getProdkeysLocation();
 | 
				
			||||||
        saveTo = environment.getSaveToLocation() + File.separator + "FS_LPR";
 | 
					        saveTo = environment.getSaveToLocation() + File.separator + "FS_LPR";
 | 
				
			||||||
        pathToFirmwares = environment.getFirmwaresLocation();
 | 
					        pathToFirmwares = environment.getFirmwaresLocation();
 | 
				
			||||||
        pathToFirmware = environment.getFirmwaresLocation() + File.separator + "Firmware 17.0.0";
 | 
					        pathToFirmware = environment.getFirmwaresLocation() + File.separator + "Firmware 15.0.0";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @DisplayName("FS Integration validation - everything")
 | 
					    @DisplayName("FS Integration validation - everything")
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    void makeFss() throws Exception{
 | 
					    void makeFss() throws Exception{
 | 
				
			||||||
        File[] fwDirs = new File(pathToFirmwares).listFiles((file, s) -> {
 | 
					        File[] fwDirs = new File(pathToFirmwares).listFiles((file, s) ->
 | 
				
			||||||
            return (s.matches("^Firmware (9\\.|[0-9][0-9]\\.).*") && ! s.endsWith(".zip"));
 | 
					                s.matches("^Firmware (9\\.|[0-9][0-9]\\.).*") && ! s.endsWith(".zip"));
 | 
				
			||||||
            //return s.matches("^Firmware 10.0.1.*");
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        assert fwDirs != null;
 | 
					        assert fwDirs != null;
 | 
				
			||||||
        Arrays.sort(fwDirs);
 | 
					        Arrays.sort(fwDirs);
 | 
				
			||||||
 | 
					        Arrays.stream(fwDirs).forEach(System.out::println);
 | 
				
			||||||
        for (File dir : fwDirs){
 | 
					        for (File dir : fwDirs){
 | 
				
			||||||
            System.out.println("\n\t\t\t"+dir.getName());
 | 
					            System.out.println("\n\t\t\t"+dir.getName());
 | 
				
			||||||
            FsPatchMaker fsPatchMaker = new FsPatchMaker(dir.getAbsolutePath(), pathToKeysFile, saveTo);
 | 
					            FsPatchMaker fsPatchMaker = new FsPatchMaker(dir.getAbsolutePath(), pathToKeysFile, saveTo);
 | 
				
			||||||
| 
						 | 
					@ -47,6 +45,7 @@ public class FsIntegrationTest {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Disabled
 | 
				
			||||||
    @DisplayName("FS Integration validation - one particular firmware")
 | 
					    @DisplayName("FS Integration validation - one particular firmware")
 | 
				
			||||||
    @Test
 | 
					    @Test
 | 
				
			||||||
    void makeFs() throws Exception{
 | 
					    void makeFs() throws Exception{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue