diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..9dce40f --- /dev/null +++ b/.drone.yml @@ -0,0 +1,41 @@ +kind: pipeline +type: docker +name: default + +steps: + - name: test + image: maven:3-jdk-11 + commands: + - mvn -B -DskipTests clean package + - mvn test -B + volumes: + - name: m2 + path: /root/.m2 + + - name: archive-standard-artifact + image: alpine:latest + commands: + - mkdir -p /builds/ns-usbloader + - cp target/ns-usbloader-*jar /builds/ns-usbloader/ + volumes: + - name: builds + path: /builds + + - name: make-store-legacy-artifact + image: maven:3-jdk-11 + commands: + - sed -z -i -e 's/org.usb4java<\/groupId>\n\s*usb4java<\/artifactId>\s*1.3.0<\/version>/org.usb4java<\/groupId>\nusb4java<\/artifactId>\n1.2.0<\/version>/g' pom.xml + - sed -z -i -e 's/${project.artifactId}-${project.version}-${maven.build.timestamp}<\/finalName>/${project.artifactId}-legacy-${project.version}-${maven.build.timestamp}<\/finalName>/g' pom.xml + - mvn -B -DskipTests clean package + - cp target/ns-usbloader-*jar /builds/ns-usbloader/ + volumes: + - name: m2 + path: /root/.m2 + +volumes: + - name: m2 + host: + path: /home/docker/drone/files/m2 + - name: builds + host: + path: /home/www/builds \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 6809359..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,31 +0,0 @@ -pipeline { - agent { - docker { - image 'maven:3-jdk-11' - args '-v /home/docker/jenkins/files/m2:/root/.m2' - } - } - - stages { - stage('Build') { - steps { - sh 'mvn -B -DskipTests clean package' - } - post { - success { - archiveArtifacts artifacts: 'target/*.jar, target/*.exe' - } - } - } - stage('Test') { - steps { - sh 'mvn test' - } - post { - always { - junit 'target/surefire-reports/*.xml' - } - } - } - } -} \ No newline at end of file diff --git a/README.md b/README.md index 205dba0..8f85571 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,6 @@ # NS-USBloader -![License](https://img.shields.io/badge/License-GPLv3-blue.svg) ![Releases](https://img.shields.io/github/downloads/developersu/ns-usbloader/total.svg) ![LatestVer](https://img.shields.io/github/release/developersu/ns-usbloader.svg) ![CI](https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fredrise.ru%2Fjen%2Fjob%2Fns-usbloader%2Fjob%2Fmaster%2F) - -## Mirror: [source code](https://git.redrise.ru/desu/ns-usbloader) | [builds](https://redrise.ru/jen/blue/organizations/jenkins/ns-usbloader/activity) - -[Support author link](#support-this-app) +![License](https://img.shields.io/badge/License-GPLv3-blue.svg) ![Releases](https://img.shields.io/github/downloads/developersu/ns-usbloader/total.svg) ![LatestVer](https://img.shields.io/github/release/developersu/ns-usbloader.svg) [![Build Status](https://ci.redrise.ru/api/badges/desu/ns-usbloader/status.svg)](https://ci.redrise.ru/desu/ns-usbloader) NS-USBloader is: * A PC-side installer for **[Huntereb/Awoo-Installer](https://github.com/Huntereb/Awoo-Installer)** / other compatible installers (USB and Network supported) and **[XorTroll/GoldLeaf](https://github.com/XorTroll/Goldleaf)** (USB) NSP installer. @@ -17,8 +13,14 @@ Alternative to default **usb_install_pc.py**, **remote_install_pc.py**, **GoldTr [Click here for Android version ;)](https://github.com/developersu/ns-usbloader-mobile) With GUI and cookies. Works on Windows, macOS and Linux. +### Let's stay in touch: +#### [→ Independent source code storage](https://git.redrise.ru/desu/ns-usbloader) +#### [→ Mirror, issues tracker, place to send PRs](https://github.com/developersu/ns-usbloader) +#### [→ Nightly builds](https://redrise.ru/builds/ns-usbloader/) -Sometimes I add new posts about this project [on my home page](https://developersu.blogspot.com/search/label/NS-USBloader). +[Support/Donate](#support-this-app) + +Sometimes I add new posts about this project [on my blog page](https://developersu.blogspot.com/search/label/NS-USBloader). ![Application screenshot](screenshots/1.png) screenshot screenshot @@ -45,7 +47,7 @@ Sometimes I add new posts about this project [on my home page](https://developer * Italian by [unbranched](https://github.com/unbranched) * Korean by [DDinghoya](https://github.com/DDinghoya) * Portuguese by [almircanella](https://github.com/almircanella) -* Spanish by [/u/cokimaya007](https://www.reddit.com/u/cokimaya007), Kuziel Alejandro +* Spanish by [/u/cokimaya007](https://www.reddit.com/u/cokimaya007), [Kuziel Alejandro](https://github.com/Uzi-Oni) * Chinese (Simplified) by [Huang YunKun (htynkn)](https://github.com/htynkn), [FFT9 (XXgame Group)](https://www.xxgame.net) * Chinese (Traditional) by [qazrfv1234](https://github.com/qazrfv1234), [FFT9 (XXgame Group)](https://www.xxgame.net) * German by [Swarsele](https://github.com/Swarsele) @@ -68,7 +70,7 @@ JDK 11 for MacOS and Linux | v0.6.1 | v0.6 | | v0.7 - 0.7.3 | v0.7+ | | v0.8 - 0.9 | v1.0+ | -| v0.10 | not supported; TBD | +| v0.10 | v6.0 | where '+' means 'any next NS-USBloader version'. @@ -245,14 +247,19 @@ To convert files of any locale to readable format (and vise-versa) you can use t ## Support this app -If you like this app, just give a star. +If you like this app, just give a star (@ GitHub). -If you want to make a donation*, please see below: +This is non-commercial project. -[yoomoney](https://yoomoney.ru/to/410014301951665) +Nevertheless, I'll be more than happy if you find a chance to make a donation for charity to people I trust: -*Please note: this is non-commercial application. +* BTC → 1YoBdyiL4TTVsCWmJ93TkfU2a1s9UfJcY +* LTC → MEXnCLjwvaAZpaoJ1J4biF4DpoAx86gCkf +* ETH → 0x82Ab0ddE183C12cAa6eD61DF3671675C4bdC42fc +* DOGE → DFfVjsbcs9VfV9EQTSFF3xJVbjZSbmctP3 +* DOT → 13javzN4ixHPmBfR1oZHjAecydvWbEuqRtBWuxrZyKvkUrg3 +* USDT (TRC20) → THhhs883gH1AcvmNb2EVfhR7QNkWnoa1vN -Thanks +Thanks! Appreciate assistance and support of both [Vitaliy](https://github.com/SebastianUA) and [Konstantin](https://github.com/konstantin-kelemen). Without you all this magic would not have happened. diff --git a/pom.xml b/pom.xml index 1465a80..6d40b70 100644 --- a/pom.xml +++ b/pom.xml @@ -8,11 +8,11 @@ NS-USBloader ns-usbloader - 5.2-SNAPSHOT + 6.0 - https://github.com/developersu/ns-usbloader/ + https://redrise.ru - NSP USB loader for Awoo Installer and compatible (USB and Network) and GoldLeaf + NS multi-tool 2019 @@ -42,6 +42,7 @@ UTF-8 + yyyyMMdd.HHmmss @@ -54,7 +55,7 @@ commons-cli commons-cli - 1.4 + 1.5.0 compile @@ -67,21 +68,21 @@ org.openjfx javafx-media - 17 + 18.0.1 linux compile org.openjfx javafx-fxml - 17 + 18.0.1 linux compile org.openjfx javafx-graphics - 17 + 18.0.1 linux compile @@ -89,28 +90,28 @@ org.openjfx javafx-controls - 17 + 18.0.1 win compile org.openjfx javafx-media - 17 + 18.0.1 win compile org.openjfx javafx-fxml - 17 + 18.0.1 win compile org.openjfx javafx-graphics - 17 + 18.0.1 win compile @@ -118,28 +119,28 @@ org.openjfx javafx-controls - 17 + 18.0.1 mac compile org.openjfx javafx-media - 17 + 18.0.1 mac compile org.openjfx javafx-fxml - 17 + 18.0.1 mac compile org.openjfx javafx-graphics - 17 + 18.0.1 mac compile @@ -154,23 +155,35 @@ org.junit.jupiter junit-jupiter-engine - 5.5.2 + 5.8.2 test org.junit.jupiter junit-jupiter-api - 5.5.2 + 5.8.2 test org.junit.jupiter junit-jupiter-params - 5.5.2 + 5.8.2 test + ${project.artifactId}-${project.version}-${maven.build.timestamp} + + + src/main/resources + false + + + src/main/resources-filtered + true + + + @@ -217,6 +230,7 @@ jar-with-dependencies + false diff --git a/src/main/java/nsusbloader/AppPreferences.java b/src/main/java/nsusbloader/AppPreferences.java index 18afe80..7fb69dd 100644 --- a/src/main/java/nsusbloader/AppPreferences.java +++ b/src/main/java/nsusbloader/AppPreferences.java @@ -27,7 +27,7 @@ public class AppPreferences { private final Preferences preferences; private final Locale locale; - public static final String[] goldleafSupportedVersions = {"v0.5", "v0.7.x", "v0.8-0.9"}; + public static final String[] goldleafSupportedVersions = {"v0.5", "v0.7.x", "v0.8-0.9", "v0.10"}; private AppPreferences(){ this.preferences = Preferences.userRoot().node("NS-USBloader"); diff --git a/src/main/java/nsusbloader/NSLMain.java b/src/main/java/nsusbloader/NSLMain.java index c133f72..aa03af7 100644 --- a/src/main/java/nsusbloader/NSLMain.java +++ b/src/main/java/nsusbloader/NSLMain.java @@ -32,7 +32,7 @@ import java.util.ResourceBundle; public class NSLMain extends Application { - public static final String appVersion = "v5.2"; + public static String appVersion; public static boolean isCli; @Override @@ -41,6 +41,7 @@ public class NSLMain extends Application { Locale userLocale = AppPreferences.getInstance().getLocale(); ResourceBundle rb = ResourceBundle.getBundle("locale", userLocale); + NSLMain.appVersion = ResourceBundle.getBundle("app").getString("_version"); loader.setResources(rb); Parent root = loader.load(); diff --git a/src/main/java/nsusbloader/com/usb/GoldLeaf_010.java b/src/main/java/nsusbloader/com/usb/GoldLeaf_010.java new file mode 100644 index 0000000..a5669d2 --- /dev/null +++ b/src/main/java/nsusbloader/com/usb/GoldLeaf_010.java @@ -0,0 +1,1130 @@ +/* + Copyright 2019-2022 Dmitry Isaenko + + This file is part of NS-USBloader. + + NS-USBloader is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + NS-USBloader is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with NS-USBloader. If not, see . +*/ +package nsusbloader.com.usb; + +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 org.usb4java.DeviceHandle; +import org.usb4java.LibUsb; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +/** + * GoldLeaf 0.8 processing + */ +class GoldLeaf_010 extends TransferModule { + private boolean nspFilterForGl; + + // CMD + private final byte[] CMD_GLCO_SUCCESS = new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x00}; // used @ writeToUsb_GLCMD + private final byte[] CMD_GLCO_FAILURE = new byte[]{0x47, 0x4c, 0x43, 0x4F, 0x00, 0x00, (byte) 0xAD, (byte) 0xDE}; // used @ writeToUsb_GLCMD TODO: TEST + + // System.out.println((356 & 0x1FF) | ((1 + 100) & 0x1FFF) << 9); // 52068 // 0x00 0x00 0xCB 0x64 + private final byte[] GL_OBJ_TYPE_FILE = new byte[]{0x01, 0x00, 0x00, 0x00}; + private final byte[] GL_OBJ_TYPE_DIR = new byte[]{0x02, 0x00, 0x00, 0x00}; + + private String recentPath = null; + private String[] recentDirs = null; + private String[] recentFiles = null; + + private String[] nspMapKeySetIndexes; + + private String openReadFileNameAndPath; + private RandomAccessFile randAccessFile; + private NSSplitReader splitReader; + + private HashMap writeFilesMap; + private long virtDriveSize; + private HashMap splitFileSize; + + private final boolean isWindows; + private final String homePath; + // For using in CMD_SelectFile with SPEC:/ prefix + private File selectedFile; + + private final CancellableRunnable task; + + GoldLeaf_010(DeviceHandle handler, + LinkedHashMap nspMap, + CancellableRunnable task, + ILogPrinter logPrinter, + boolean nspFilter) + { + super(handler, nspMap, task, logPrinter); + + this.task = task; + + final byte CMD_GetDriveCount = 1; + final byte CMD_GetDriveInfo = 2; + final byte CMD_StatPath = 3; + final byte CMD_GetFileCount = 4; + final byte CMD_GetFile = 5; + final byte CMD_GetDirectoryCount = 6; + final byte CMD_GetDirectory = 7; + final byte CMD_StartFile = 8; // 1 -open read RAF; 2 open write RAF; 3 open write RAF and seek to EOF (???). + final byte CMD_ReadFile = 9; + final byte CMD_WriteFile = 10; + final byte CMD_EndFile = 11; // 1 - closed read RAF; 2 close write RAF. + final byte CMD_Create = 12; + final byte CMD_Delete = 13; + final byte CMD_Rename = 14; + final byte CMD_GetSpecialPathCount = 15; + final byte CMD_GetSpecialPath = 16; + final byte CMD_SelectFile = 17; + + final byte[] CMD_GLCI = new byte[]{0x47, 0x4c, 0x43, 0x49}; + + this.nspFilterForGl = nspFilter; + + print("=========== GoldLeaf v0.10 ===========\n\t" + + "VIRT:/ equals files added into the application\n\t" + + "HOME:/ equals " + +System.getProperty("user.home"), EMsgType.INFO); + + // Let's collect file names to the array to simplify our life + writeFilesMap = new HashMap<>(); + int i = 0; + nspMapKeySetIndexes = new String[nspMap.size()]; + for (String fileName : nspMap.keySet()) + nspMapKeySetIndexes[i++] = fileName; + + isWindows = System.getProperty("os.name").contains("Windows"); + + homePath = System.getProperty("user.home")+File.separator; + + splitFileSize = new HashMap<>(); + + // Calculate size of VIRT:/ drive + for (File nspFile : nspMap.values()){ + if (nspFile.isDirectory()) { + File[] subFiles = nspFile.listFiles((file, name) -> name.matches("[0-9]{2}")); + 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 + byte[] readByte; + int someLength1, + someLength2; + main_loop: + while (true) { // Till user interrupted process. + readByte = readGL(); + + if (readByte == null) // Issue @ readFromUsbGL method + return; + + //RainbowHexDump.hexDumpUTF16LE(readByte); // DEBUG + //System.out.println("CHOICE: "+readByte[4]); // DEBUG + + if (Arrays.equals(Arrays.copyOfRange(readByte, 0,4), CMD_GLCI)) { + switch (readByte[4]) { + case CMD_GetDriveCount: + if (getDriveCount()) + break main_loop; + break; + case CMD_GetDriveInfo: + if (getDriveInfo(arrToIntLE(readByte,8))) + break main_loop; + break; + case CMD_GetSpecialPathCount: + if (getSpecialPathCount()) + break main_loop; + break; + case CMD_GetSpecialPath: + if (getSpecialPath(arrToIntLE(readByte,8))) + break main_loop; + break; + case CMD_GetDirectoryCount: + someLength1 = arrToIntLE(readByte, 8); + if (getDirectoryOrFileCount(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), true)) + break main_loop; + break; + case CMD_GetFileCount: + someLength1 = arrToIntLE(readByte, 8); + if (getDirectoryOrFileCount(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), false)) + break main_loop; + break; + case CMD_GetDirectory: + someLength1 = arrToIntLE(readByte, 8); + if (getDirectory(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), arrToIntLE(readByte, someLength1+12))) + break main_loop; + break; + case CMD_GetFile: + someLength1 = arrToIntLE(readByte, 8); + if (getFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), arrToIntLE(readByte, someLength1+12))) + break main_loop; + break; + case CMD_StatPath: + someLength1 = arrToIntLE(readByte, 8); + if (statPath(new String(readByte, 12, someLength1, StandardCharsets.UTF_8))) + break main_loop; + break; + case CMD_Rename: + someLength1 = arrToIntLE(readByte, 12); + someLength2 = arrToIntLE(readByte, 16+someLength1); + if (rename(new String(readByte, 16, someLength1, StandardCharsets.UTF_8), + new String(readByte, 16+someLength1+4, someLength2, StandardCharsets.UTF_8))) + break main_loop; + break; + case CMD_Delete: + someLength1 = arrToIntLE(readByte, 12); + if (delete(new String(readByte, 16, someLength1, StandardCharsets.UTF_8))) + break main_loop; + break; + case CMD_Create: + someLength1 = arrToIntLE(readByte, 12); + if (create(new String(readByte, 16, someLength1, StandardCharsets.UTF_8), readByte[8])) + break main_loop; + break; + case CMD_ReadFile: + someLength1 = arrToIntLE(readByte, 8); + if (readFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), + arrToLongLE(readByte, 12+someLength1), + arrToLongLE(readByte, 12+someLength1+8))) + break main_loop; + break; + case CMD_WriteFile: + someLength1 = arrToIntLE(readByte, 8); + //if (writeFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8), arrToLongLE(readByte, 12+someLength1))) + if (writeFile(new String(readByte, 12, someLength1, StandardCharsets.UTF_8))) + break main_loop; + break; + case CMD_SelectFile: + if (selectFile()) + break main_loop; + break; + case CMD_StartFile: + case CMD_EndFile: + if (startOrEndFile()) + break main_loop; + break; + default: + writeGL_FAIL("GL Unknown command: "+readByte[4]+" [it's a very bad sign]"); + } + } + } + // Close (and flush) all opened streams. + if (writeFilesMap.size() != 0){ + for (BufferedOutputStream fBufOutStream: writeFilesMap.values()){ + try{ + fBufOutStream.close(); + }catch (IOException | NullPointerException ignored){} + } + } + closeOpenedReadFilesGl(); + } + + /** + * Close files opened for read/write + */ + private void closeOpenedReadFilesGl(){ + if (openReadFileNameAndPath != null){ // Perfect time to close our opened files + try{ + randAccessFile.close(); + } + catch (IOException | NullPointerException ignored){} + try{ + splitReader.close(); + } + catch (IOException | NullPointerException ignored){} + openReadFileNameAndPath = null; + randAccessFile = null; + splitReader = null; + } + } + /** + * 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 if failed + * false if everything is ok + * */ + private boolean startOrEndFile(){ + if (writeGL_PASS()){ + print("GL Handle 'StartFile' command", EMsgType.FAIL); + return true; + } + return false; + } + /** + * Handle GetDriveCount + * @return true if failed + * false if everything is ok + */ + private boolean getDriveCount(){ + // Let's declare 2 drives + byte[] drivesCnt = intToArrLE(2); //2 + // Write count of drives + if (writeGL_PASS(drivesCnt)) { + print("GL Handle 'ListDrives' command", EMsgType.FAIL); + return true; + } + return false; + } + /** + * Handle GetDriveInfo + * @return true if failed + * false if everything is ok + */ + private boolean getDriveInfo(int driveNo){ + if (driveNo < 0 || driveNo > 1){ + return writeGL_FAIL("GL Handle 'GetDriveInfo' command [no such drive]"); + } + + byte[] driveLabel, + driveLabelLen, + driveLetter, + driveLetterLen, + totalFreeSpace, + totalSize; + long totalSizeLong; + + // 0 == VIRTUAL DRIVE + if (driveNo == 0){ + driveLabel = "Virtual".getBytes(StandardCharsets.UTF_8); + driveLabelLen = intToArrLE(driveLabel.length); + driveLetter = "VIRT".getBytes(StandardCharsets.UTF_8); // TODO: Consider moving to class field declaration + driveLetterLen = intToArrLE(driveLetter.length);// since GL 0.7 + totalFreeSpace = new byte[4]; + totalSizeLong = virtDriveSize; + } + else { //1 == User home dir + driveLabel = "Home".getBytes(StandardCharsets.UTF_8); + driveLabelLen = intToArrLE(driveLabel.length);// since GL 0.7 + driveLetter = "HOME".getBytes(StandardCharsets.UTF_8); + driveLetterLen = intToArrLE(driveLetter.length);// since GL 0.7 + File userHomeDir = new File(System.getProperty("user.home")); + long totalFreeSpaceLong = userHomeDir.getFreeSpace(); + totalFreeSpace = Arrays.copyOfRange(longToArrLE(totalFreeSpaceLong), 0, 4);; + totalSizeLong = userHomeDir.getTotalSpace(); + } + totalSize = Arrays.copyOfRange(longToArrLE(totalSizeLong), 0, 4); + + List command = new LinkedList<>(); + command.add(driveLabelLen); + command.add(driveLabel); + command.add(driveLetterLen); + command.add(driveLetter); + command.add(totalFreeSpace); + command.add(totalSize); + + if (writeGL_PASS(command)) { + print("GL Handle 'GetDriveInfo' command", EMsgType.FAIL); + return true; + } + + return false; + } + /** + * Handle SpecialPathCount + * @return true if failed + * false if everything is ok + * */ + private boolean getSpecialPathCount(){ + // Let's declare nothing =) + byte[] specialPathCnt = intToArrLE(0); + // Write count of special paths + if (writeGL_PASS(specialPathCnt)) { + print("GL Handle 'SpecialPathCount' command", EMsgType.FAIL); + return true; + } + return false; + } + /** + * Handle SpecialPath + * @return true if failed + * false if everything is ok + * */ + private boolean getSpecialPath(int specialPathNo){ + return writeGL_FAIL("GL Handle 'SpecialPath' command [not supported]"); + } + /** + * Handle GetDirectoryCount & GetFileCount + * @return true if failed + * false if everything is ok + * */ + private boolean getDirectoryOrFileCount(String path, boolean isGetDirectoryCount) { + if (path.equals("VIRT:/")) { + if (isGetDirectoryCount){ + if (writeGL_PASS()) { + print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL); + return true; + } + } + else { + if (writeGL_PASS(intToArrLE(nspMap.size()))) { + print("GL Handle 'GetFileCount' command Count = "+nspMap.size(), EMsgType.FAIL); + return true; + } + } + } + else if (path.startsWith("HOME:/")){ + // Let's make it normal path + path = updateHomePath(path); + // Open it + File pathDir = new File(path); + + // Make sure it's exists and it's path + if ((! pathDir.exists() ) || (! pathDir.isDirectory()) ) + return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [doesn't exist or not a folder]"); + // Save recent dir path + this.recentPath = path; + String[] filesOrDirs; + // Now collecting every folder or file inside + if (isGetDirectoryCount){ + filesOrDirs = pathDir.list((current, name) -> { + File dir = new File(current, name); + return (dir.isDirectory() && ! dir.isHidden()); + }); + } + else { + if (nspFilterForGl){ + filesOrDirs = pathDir.list((current, name) -> { + File dir = new File(current, name); + return (! dir.isDirectory() && name.toLowerCase().endsWith(".nsp")); + }); + } + else { + filesOrDirs = pathDir.list((current, name) -> { + File dir = new File(current, name); + return (! dir.isDirectory() && (! dir.isHidden())); + }); + } + } + // If somehow there are no folders, let's say 0; + if (filesOrDirs == null){ + if (writeGL_PASS()) { + print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL); + return true; + } + return false; + } + // 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 + if (writeGL_PASS(intToArrLE(filesOrDirs.length))) { + print("GL Handle 'GetDirectoryOrFileCount' command", EMsgType.FAIL); + return true; + } + } + else if (path.startsWith("SPEC:/")){ + if (isGetDirectoryCount){ // If dir request then 0 dirs + if (writeGL_PASS()) { + print("GL Handle 'GetDirectoryCount' command", EMsgType.FAIL); + return true; + } + } + else if (selectedFile != null){ // Else it's file request, if we have selected then we will report 1. + if (writeGL_PASS(intToArrLE(1))) { + print("GL Handle 'GetFileCount' command Count = 1", EMsgType.FAIL); + return true; + } + } + else + return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] (file) - "+path); + } + else { // If requested drive is not VIRT and not HOME then reply error + return writeGL_FAIL("GL Handle 'GetDirectoryOrFileCount' command [unknown drive request] "+(isGetDirectoryCount?"(dir) - ":"(file) - ")+path); + } + return false; + } + /** + * Handle GetDirectory + * @return true if failed + * false if everything is ok + * */ + private boolean getDirectory(String dirName, int subDirNo){ + if (dirName.startsWith("HOME:/")) { + dirName = updateHomePath(dirName); + + List command = new LinkedList<>(); + + if (dirName.equals(recentPath) && recentDirs != null && recentDirs.length != 0){ + byte[] dirNameBytes = recentDirs[subDirNo].getBytes(StandardCharsets.UTF_8); + + command.add(intToArrLE(dirNameBytes.length)); + command.add(dirNameBytes); + } + else { + File pathDir = new File(dirName); + // Make sure it's exists and it's path + if ((! pathDir.exists() ) || (! pathDir.isDirectory()) ) + return writeGL_FAIL("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((current, name) -> { + File dir = new File(current, name); + return (dir.isDirectory() && ! dir.isHidden()); // TODO: FIX FOR WIN ? + }); + // Check that we still don't have any fuckups + if (this.recentDirs != null && this.recentDirs.length > subDirNo){ + Arrays.sort(recentFiles, String.CASE_INSENSITIVE_ORDER); + byte[] dirBytesName = recentDirs[subDirNo].getBytes(StandardCharsets.UTF_8); + command.add(intToArrLE(dirBytesName.length)); + command.add(dirBytesName); + } + else + return writeGL_FAIL("GL Handle 'GetDirectory' command [doesn't exist or not a folder]"); + } + + if (writeGL_PASS(command)) { + print("GL Handle 'GetDirectory' command.", EMsgType.FAIL); + return true; + } + return false; + } + // VIRT:// and any other + return writeGL_FAIL("GL Handle 'GetDirectory' command for virtual drive [no folders support]"); + } + /** + * Handle GetFile + * @return true if failed + * false if everything is ok + * */ + private boolean getFile(String dirName, int subDirNo){ + List command = new LinkedList<>(); + + if (dirName.startsWith("HOME:/")) { + dirName = updateHomePath(dirName); + + if (dirName.equals(recentPath) && recentFiles != null && recentFiles.length != 0){ + byte[] fileNameBytes = recentFiles[subDirNo].getBytes(StandardCharsets.UTF_8); + + command.add(intToArrLE(fileNameBytes.length)); //Since GL 0.7 + command.add(fileNameBytes); + } + else { + File pathDir = new File(dirName); + // Make sure it's exists and it's path + if ((! pathDir.exists() ) || (! pathDir.isDirectory()) ) + writeGL_FAIL("GL Handle 'GetFile' command [doesn't exist or not a folder]"); + this.recentPath = dirName; + // Now collecting every folder or file inside + if (nspFilterForGl){ + this.recentFiles = pathDir.list((current, name) -> { + File dir = new File(current, name); + return (! dir.isDirectory() && name.toLowerCase().endsWith(".nsp")); // TODO: FIX FOR WIN ? MOVE TO PROD + }); + } + else { + this.recentFiles = pathDir.list((current, name) -> { + File dir = new File(current, name); + return (! dir.isDirectory() && (! dir.isHidden())); // TODO: FIX FOR WIN + }); + } + // Check that we still don't have any fuckups + if (this.recentFiles != null && this.recentFiles.length > subDirNo){ + Arrays.sort(recentFiles, String.CASE_INSENSITIVE_ORDER); // TODO: NOTE: array sorting is an overhead for using poxy loops + byte[] fileNameBytes = recentFiles[subDirNo].getBytes(StandardCharsets.UTF_8); + command.add(intToArrLE(fileNameBytes.length)); //Since GL 0.7 + command.add(fileNameBytes); + } + else + return writeGL_FAIL("GL Handle 'GetFile' command [doesn't exist or not a folder]"); + } + + if (writeGL_PASS(command)) { + print("GL Handle 'GetFile' command.", EMsgType.FAIL); + return true; + } + return false; + } + else if (dirName.equals("VIRT:/")){ + if (nspMap.size() != 0){ // therefore nspMapKeySetIndexes also != 0 + byte[] fileNameBytes = nspMapKeySetIndexes[subDirNo].getBytes(StandardCharsets.UTF_8); + command.add(intToArrLE(fileNameBytes.length)); + command.add(fileNameBytes); + if (writeGL_PASS(command)) { + print("GL Handle 'GetFile' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + else if (dirName.equals("SPEC:/")){ + if (selectedFile != null){ + byte[] fileNameBytes = selectedFile.getName().getBytes(StandardCharsets.UTF_8); + command.add(intToArrLE(fileNameBytes.length)); + command.add(fileNameBytes); + if (writeGL_PASS(command)) { + print("GL Handle 'GetFile' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + // any other cases + return writeGL_FAIL("GL Handle 'GetFile' command for virtual drive [no folders support?]"); + } + /** + * Handle StatPath + * @return true if failed + * false if everything is ok + * */ + private boolean statPath(String filePath){ + List command = new LinkedList<>(); + + if (filePath.startsWith("HOME:/")){ + filePath = updateHomePath(filePath); + + File fileDirElement = new File(filePath); + if (fileDirElement.exists()){ + if (fileDirElement.isDirectory()) + command.add(GL_OBJ_TYPE_DIR); + else { + command.add(GL_OBJ_TYPE_FILE); + command.add(longToArrLE(fileDirElement.length())); + } + if (writeGL_PASS(command)) { + print("GL Handle 'StatPath' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + else if (filePath.startsWith("VIRT:/")) { + filePath = filePath.replaceFirst("VIRT:/", ""); + if (nspMap.containsKey(filePath)){ + command.add(GL_OBJ_TYPE_FILE); // THIS IS INT + if (nspMap.get(filePath).isDirectory()) { + command.add(longToArrLE(splitFileSize.get(filePath))); // YES, THIS IS LONG!; + } + else + command.add(longToArrLE(nspMap.get(filePath).length())); // YES, THIS IS LONG! + + if (writeGL_PASS(command)) { + print("GL Handle 'StatPath' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + else if (filePath.startsWith("SPEC:/")){ + //System.out.println(filePath); + filePath = filePath.replaceFirst("SPEC:/",""); + if (selectedFile.getName().equals(filePath)){ + command.add(GL_OBJ_TYPE_FILE); + command.add(longToArrLE(selectedFile.length())); + if (writeGL_PASS(command)) { + print("GL Handle 'StatPath' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + return writeGL_FAIL("GL Handle 'StatPath' command [no such folder] - "+filePath); + } + /** + * Handle 'Rename' that is actually 'mv' + * @return true if failed + * false if everything is ok + * */ + private boolean rename(String fileName, String newFileName){ + if (fileName.startsWith("HOME:/")){ + // This shit takes too much time to explain, but such behaviour won't let GL to fail + this.recentPath = null; + this.recentFiles = null; + this.recentDirs = null; + fileName = updateHomePath(fileName); + newFileName = updateHomePath(newFileName); + + File currentFile = new File(fileName); + File newFile = new File(newFileName); + if (! newFile.exists()){ // Else, report error + try { + if (currentFile.renameTo(newFile)){ + if (writeGL_PASS()) { + print("GL Handle 'Rename' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + catch (SecurityException ignored){} // Ah, leave it + } + } + // For VIRT:/ and others we don't serve requests + return writeGL_FAIL("GL Handle 'Rename' command [not supported for virtual drive/wrong drive/file with such name already exists/read-only directory]"); + } + /** + * Handle 'Delete' + * @return true if failed + * false if everything is ok + * */ + private boolean delete(String fileName) { + if (fileName.startsWith("HOME:/")) { + fileName = updateHomePath(fileName); + + File fileToDel = new File(fileName); + try { + if (fileToDel.delete()){ + if (writeGL_PASS()) { + print("GL Handle 'Rename' command.", EMsgType.FAIL); + return true; + } + return false; + } + } + catch (SecurityException ignored){} // Ah, leave it + } + // For VIRT:/ and others we don't serve requests + return writeGL_FAIL("GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory]"); + } + /** + * Handle 'Create' + * @param type 1 for file + * 2 for folder + * @param fileName full path including new file name in the end + * @return true if failed + * false if everything is ok + * */ + private boolean create(String fileName, byte type) { + if (fileName.startsWith("HOME:/")) { + fileName = updateHomePath(fileName); + File fileToCreate = new File(fileName); + boolean result = false; + if (type == 1){ + try { + result = fileToCreate.createNewFile(); + } + catch (SecurityException | IOException ignored){} + } + else if (type == 2){ + try { + result = fileToCreate.mkdir(); + } + catch (SecurityException ignored){} + } + if (result){ + if (writeGL_PASS()) { + print("GL Handle 'Create' command.", EMsgType.FAIL); + return true; + } + //print("GL Handle 'Create' command.", EMsgType.PASS); + return false; + } + } + // For VIRT:/ and others we don't serve requests + return writeGL_FAIL("GL Handle 'Delete' command [not supported for virtual drive/wrong drive/read-only directory]"); + } + + /** + * Handle 'ReadFile' + * @param fileName full path including new file name in the end + * @param offset requested offset + * @param size requested size + * @return true if failed + * false if everything is ok + * */ + private boolean readFile(String fileName, long offset, long size) { + //System.out.println("readFile "+fileName+"\t"+offset+"\t"+size+"\n"); + if (fileName.startsWith("VIRT:/")){ + // Let's find out which file requested + String fNamePath = nspMap.get(fileName.substring(6)).getAbsolutePath(); // NOTE: 6 = "VIRT:/".length + // If we don't have this file opened, let's open it + if (openReadFileNameAndPath == null || (! openReadFileNameAndPath.equals(fNamePath))) { + // Try close what opened + if (openReadFileNameAndPath != null){ + try{ + randAccessFile.close(); + }catch (Exception ignored){} + try{ + splitReader.close(); + }catch (Exception ignored){} + } + // Open what has to be opened + try{ + File tempFile = nspMap.get(fileName.substring(6)); + 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("GL Handle 'ReadFile' command\n\t"+ioe.getMessage()); + } + } + } + else { + // Let's find out which file requested + fileName = updateHomePath(fileName); + // If we don't have this file opened, let's open it + if (openReadFileNameAndPath == null || (! openReadFileNameAndPath.equals(fileName))) { + // Try close what opened + if (openReadFileNameAndPath != null){ + try{ + randAccessFile.close(); + }catch (IOException | NullPointerException ignored){} + } + // Open what has to be opened + try{ + randAccessFile = new RandomAccessFile(fileName, "r"); + openReadFileNameAndPath = fileName; + }catch (IOException | NullPointerException ioe){ + return writeGL_FAIL("GL Handle 'ReadFile' command\n\t"+ioe.getMessage()); + } + } + } + //----------------------- Actual transfer chain ------------------------ + try{ + if (randAccessFile == null){ + splitReader.seek(offset); + byte[] chunk = new byte[(int)size]; // WTF MAN? + // Let's find out how much bytes we got + int bytesRead = splitReader.read(chunk); + // Let's check that we read expected size + if (bytesRead != (int)size) + return writeGL_FAIL("GL Handle 'ReadFile' command [CMD]" + + "\n At offset: " + offset + + "\n Requested: " + size + + "\n Received: " + bytesRead); + // Let's tell as a command about our result. + if (writeGL_PASS(longToArrLE(size))) { + print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL); + return true; + } + // Let's bypass bytes we read total + if (writeToUsb(chunk)) { + print("GL Handle 'ReadFile' command", EMsgType.FAIL); + return true; + } + return false; + } + else { + randAccessFile.seek(offset); + byte[] chunk = new byte[(int)size]; // yes, I know, but nothing to do here. + // Let's find out how much bytes we got + int bytesRead = randAccessFile.read(chunk); + // Let's check that we read expected size + if (bytesRead != (int)size) + return writeGL_FAIL("GL Handle 'ReadFile' command [CMD] Requested = "+size+" Read from file = "+bytesRead); + // Let's tell as a command about our result. + if (writeGL_PASS(longToArrLE(size))) { + print("GL Handle 'ReadFile' command [CMD]", EMsgType.FAIL); + return true; + } + // Let's bypass bytes we read total + if (writeToUsb(chunk)) { + print("GL Handle 'ReadFile' command", EMsgType.FAIL); + return true; + } + return false; + } + } + catch (Exception ioe){ + try{ + randAccessFile.close(); + } + catch (NullPointerException ignored){} + catch (IOException ioe_){ + print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING); + } + try{ + splitReader.close(); + } + catch (NullPointerException ignored){} + catch (IOException ioe_){ + print("GL Handle 'ReadFile' command: unable to close: "+openReadFileNameAndPath+"\n\t"+ioe_.getMessage(), EMsgType.WARNING); + } + openReadFileNameAndPath = null; + randAccessFile = null; + splitReader = null; + return writeGL_FAIL("GL Handle 'ReadFile' command\n\t"+ioe.getMessage()); + } + } + /** + * Handle 'WriteFile' + * @param fileName full path including new file name in the end + * + * @return true if failed + * false if everything is ok + * */ + //@param size requested size + //private boolean writeFile(String fileName, long size) { + private boolean writeFile(String fileName) { + if (fileName.startsWith("VIRT:/")){ + return writeGL_FAIL("GL Handle 'WriteFile' command [not supported for virtual drive]"); + } + + fileName = updateHomePath(fileName); + // Check if we didn't see this (or any) file during this session + if (writeFilesMap.size() == 0 || (! writeFilesMap.containsKey(fileName))){ + // Open what we have to open + File writeFile = new File(fileName); + // If this file exists GL will take care + // Otherwise, let's add it + try{ + BufferedOutputStream writeFileBufOutStream = new BufferedOutputStream(new FileOutputStream(writeFile, true)); + writeFilesMap.put(fileName, writeFileBufOutStream); + } catch (IOException ioe){ + return writeGL_FAIL("GL Handle 'WriteFile' command [IOException]\n\t"+ioe.getMessage()); + } + } + // Now we have stream + BufferedOutputStream myStream = writeFilesMap.get(fileName); + + byte[] transferredData; + + if ((transferredData = readGL_file()) == null){ + print("GL Handle 'WriteFile' command [1/1]", EMsgType.FAIL); + return true; + } + try{ + myStream.write(transferredData, 0, transferredData.length); + } + catch (IOException ioe){ + return writeGL_FAIL("GL Handle 'WriteFile' command [1/1]\n\t"+ioe.getMessage()); + } + // Report we're good + if (writeGL_PASS()) { + print("GL Handle 'WriteFile' command", EMsgType.FAIL); + return true; + } + return false; + } + + /** + * Handle 'SelectFile' + * @return true if failed + * false if everything is ok + * */ + private boolean selectFile(){ + File selectedFile = CompletableFuture.supplyAsync(() -> { + FileChooser fChooser = new FileChooser(); + fChooser.setTitle(MediatorControl.getInstance().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("GL Handle 'SelectFile' command: Nothing selected"); + } + + List command = new LinkedList<>(); + byte[] selectedFileNameBytes = ("SPEC:/"+selectedFile.getName()).getBytes(StandardCharsets.UTF_8); + command.add(intToArrLE(selectedFileNameBytes.length)); + command.add(selectedFileNameBytes); + if (writeGL_PASS(command)) { + print("GL Handle 'SelectFile' command", EMsgType.FAIL); + this.selectedFile = null; + return true; + } + this.selectedFile = selectedFile; + return false; + } + + /*----------------------------------------------------*/ + /* GL HELPERS */ + /*----------------------------------------------------*/ + /** + * Convert path received from GL to normal + */ + private String updateHomePath(String glPath){ + if (isWindows) + glPath = glPath.replaceAll("/", "\\\\"); + glPath = homePath+glPath.substring(6); // Do not use replaceAll since it will consider \ as special directive + return glPath; + } + /** + * Convert INT (Little endian) value to bytes-array representation + * */ + private byte[] intToArrLE(int value){ + ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.LITTLE_ENDIAN); + byteBuffer.putInt(value); + return byteBuffer.array(); + } + /** + * Convert LONG (Little endian) value to bytes-array representation + * */ + private byte[] longToArrLE(long value){ + ByteBuffer byteBuffer = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN); + byteBuffer.putLong(value); + return byteBuffer.array(); + } + /** + * Convert bytes-array to INT value (Little endian) + * */ + private int arrToIntLE(byte[] byteArrayWithInt, int intStartPosition){ + return ByteBuffer.wrap(byteArrayWithInt).order(ByteOrder.LITTLE_ENDIAN).getInt(intStartPosition); + } + /** + * Convert bytes-array to LONG value (Little endian) + * */ + private long arrToLongLE(byte[] byteArrayWithLong, int intStartPosition){ + return ByteBuffer.wrap(byteArrayWithLong).order(ByteOrder.LITTLE_ENDIAN).getLong(intStartPosition); + } + + //------------------------------------------------------------------------------------------------------------------ + + /*----------------------------------------------------*/ + /* GL READ/WRITE USB SPECIFIC */ + /*----------------------------------------------------*/ + + private byte[] readGL(){ + ByteBuffer readBuffer; + readBuffer = ByteBuffer.allocateDirect(4096); // GL really? + + IntBuffer readBufTransferred = IntBuffer.allocate(1); + + int result; + + while (! task.isCancelled()) { + result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81 + + switch (result) { + case LibUsb.SUCCESS: + int trans = readBufTransferred.get(); + byte[] receivedBytes = new byte[trans]; + 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: " + + UsbErrorCodes.getErrCode(result) + + "\n GL Execution stopped", EMsgType.FAIL); + return null; + } + } + print("GL Execution interrupted", EMsgType.INFO); + return null; + } + private byte[] readGL_file(){ + ByteBuffer readBuffer = ByteBuffer.allocateDirect(8388608); // Just don't ask.. + IntBuffer readBufTransferred = IntBuffer.allocate(1); + + int result; + + while (! task.isCancelled() ) { + result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81 + + switch (result) { + case LibUsb.SUCCESS: + int trans = readBufTransferred.get(); + byte[] receivedBytes = new byte[trans]; + readBuffer.get(receivedBytes); + return receivedBytes; + case LibUsb.ERROR_TIMEOUT: + continue; + default: + print("GL Data transfer issue [read]\n Returned: " + + UsbErrorCodes.getErrCode(result) + + "\n GL Execution stopped", EMsgType.FAIL); + return null; + } + } + print("GL Execution interrupted", EMsgType.INFO); + return null; + } + /** + * Write new command. Shitty implementation. + * */ + private boolean writeGL_PASS(byte[] message){ + ByteBuffer writeBuffer = ByteBuffer.allocate(4096); + writeBuffer.put(CMD_GLCO_SUCCESS); + writeBuffer.put(message); + return writeToUsb(writeBuffer.array()); + } + private boolean writeGL_PASS(){ + return writeToUsb(Arrays.copyOf(CMD_GLCO_SUCCESS, 4096)); + } + private boolean writeGL_PASS(List messages){ + ByteBuffer writeBuffer = ByteBuffer.allocate(4096); + writeBuffer.put(CMD_GLCO_SUCCESS); + for (byte[] arr : messages) + writeBuffer.put(arr); + return writeToUsb(writeBuffer.array()); + } + + private boolean writeGL_FAIL(String reportToUImsg){ + if (writeToUsb(Arrays.copyOf(CMD_GLCO_FAILURE, 4096))){ + print(reportToUImsg, EMsgType.WARNING); + return true; + } + print(reportToUImsg, 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){ + //System.out.println(">"); + //RainbowHexDump.hexDumpUTF16LE(message); // DEBUG + ByteBuffer writeBuffer = ByteBuffer.allocateDirect(message.length); //writeBuffer.order() equals BIG_ENDIAN; + writeBuffer.put(message); // Don't do writeBuffer.rewind(); + IntBuffer writeBufTransferred = IntBuffer.allocate(1); + int result; + + while (! task.isCancelled()) { + result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 1000); // last one is TIMEOUT. 0 stands for unlimited. 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: " + + UsbErrorCodes.getErrCode(result) + + "\n GL Execution stopped", EMsgType.FAIL); + return true; + } + } + print("GL Execution interrupted", EMsgType.INFO); + return true; + } +} diff --git a/src/main/java/nsusbloader/com/usb/TinFoil.java b/src/main/java/nsusbloader/com/usb/TinFoil.java index d4aa9e4..4b342ab 100644 --- a/src/main/java/nsusbloader/com/usb/TinFoil.java +++ b/src/main/java/nsusbloader/com/usb/TinFoil.java @@ -197,7 +197,7 @@ class TinFoil extends TransferModule { ae.printStackTrace(); return true; } catch (NullPointerException npe){ - print("NullPointerException (in some moment application didn't find something. Something important.):" + + print("Application didn't find something important. Make sure you have enough space on medium!" + "\n "+npe.getMessage(), EMsgType.FAIL); npe.printStackTrace(); return true; diff --git a/src/main/java/nsusbloader/com/usb/UsbCommunications.java b/src/main/java/nsusbloader/com/usb/UsbCommunications.java index 595ede2..1222a55 100644 --- a/src/main/java/nsusbloader/com/usb/UsbCommunications.java +++ b/src/main/java/nsusbloader/com/usb/UsbCommunications.java @@ -49,7 +49,7 @@ public class UsbCommunications extends CancellableRunnable { @Override public void run() { - print("\tStart", EMsgType.INFO); + print("\tStart"); UsbConnect usbConnect = UsbConnect.connectHomebrewMode(logPrinter); @@ -66,6 +66,9 @@ public class UsbCommunications extends CancellableRunnable { case "TinFoil": module = new TinFoil(handler, nspMap, this, logPrinter); break; + case "GoldLeafv0.10": + module = new GoldLeaf_010(handler, nspMap, this, logPrinter, nspFilterForGl); + break; case "GoldLeafv0.8-0.9": module = new GoldLeaf_08(handler, nspMap, this, logPrinter, nspFilterForGl); break; @@ -87,12 +90,12 @@ public class UsbCommunications extends CancellableRunnable { */ private void close(EFileStatus status){ logPrinter.update(nspMap, status); - print("\tEnd", EMsgType.INFO); + print("\tEnd"); logPrinter.close(); } - private void print(String message, EMsgType type){ + private void print(String message){ try { - logPrinter.print(message, type); + logPrinter.print(message, EMsgType.INFO); } catch (InterruptedException ie){ ie.printStackTrace(); diff --git a/src/main/resources-filtered/app.properties b/src/main/resources-filtered/app.properties new file mode 100644 index 0000000..fc2f1ed --- /dev/null +++ b/src/main/resources-filtered/app.properties @@ -0,0 +1 @@ +_version=v${project.version} \ No newline at end of file diff --git a/src/main/resources/locale.properties b/src/main/resources/locale.properties index 8c96082..bfb2ae7 100644 --- a/src/main/resources/locale.properties +++ b/src/main/resources/locale.properties @@ -11,8 +11,9 @@ windowBodyConfirmExit=Data transfer is in progress and closing this application windowTitleConfirmExit=No, don't do this! btn_Stop=Interrupt tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Status tab1_table_Lbl_FileName=File name @@ -77,4 +78,4 @@ windowTitleAddingFiles=Searching for files... windowBodyFilesScanned=Files scanned: %d\nWould be added: %d tab2_Lbl_AwooBlockTitle=Awoo Installer and compatible tabRcm_Lbl_Payload=Payload: -tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM \ No newline at end of file +tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM diff --git a/src/main/resources/locale_ar_AR.properties b/src/main/resources/locale_ar_AR.properties index 2c99a15..1fb7fc0 100644 --- a/src/main/resources/locale_ar_AR.properties +++ b/src/main/resources/locale_ar_AR.properties @@ -9,8 +9,9 @@ windowBodyConfirmExit=\u062C\u0627\u0631\u064A \u0646\u0642\u0644 \u0627\u0644\u windowTitleConfirmExit=\u0644\u0627 , \u0644\u0627 \u062A\u0641\u0639\u0644 \u0630\u0644\u0643! btn_Stop=\u0625\u064A\u0642\u0627\u0641 tab3_Txt_GreetingsMessage2=--\n\ -\u0627\u0644\u0645\u0635\u062F\u0631: https://github.com/developersu/ns-usbloader/\n\ -\u0627\u0644\u0645\u0648\u0642\u0639: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +\u0627\u0644\u0645\u0635\u062F\u0631: https://git.redrise.ru/desu/ns-usbloader/\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +\u0627\u0644\u0645\u0648\u0642\u0639: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=\u0627\u0644\u062D\u0627\u0644\u0629 tab1_table_Lbl_FileName=\u0627\u0633\u0645 \u0627\u0644\u0645\u0644\u0641 @@ -70,3 +71,4 @@ tab2_Cb_GlVersion=\u0625\u0635\u062F\u0627\u0631 \u0628\u0631\u0646\u0627\u0645\ tab2_Cb_GLshowNspOnly=\u0627\u0639\u0631\u0636 \u0641\u0642\u0637 \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0630\u0627\u062A \u0627\u0644\u0625\u0645\u062A\u062F\u0627\u062F "\u0625\u0646 \u0625\u0633 \u0628\u064A" \u0641\u064A \u0628\u0631\u0646\u0627\u0645\u062C \u0627\u0644\u0640 "\u062C\u0648\u0644\u062F \u0644\u064A\u0641". windowBodyPleaseStopOtherProcessFirst=\u0645\u0646 \u0641\u0636\u0644\u0643 \u0642\u0645 \u0628\u0625\u064A\u0642\u0627\u0641 \u0627\u0644\u0639\u0645\u0644\u064A\u0627\u062A \u0627\u0644\u0623\u062E\u0631\u0649 \u0642\u0628\u0644 \u0627\u0644\u0625\u0633\u062A\u0645\u0631\u0627\u0631. + diff --git a/src/main/resources/locale_cs_CZ.properties b/src/main/resources/locale_cs_CZ.properties index c4148c9..03ebe60 100644 --- a/src/main/resources/locale_cs_CZ.properties +++ b/src/main/resources/locale_cs_CZ.properties @@ -9,8 +9,9 @@ windowBodyConfirmExit=Pr\u00E1v\u011B prob\u00EDh\u00E1 p\u0159enos dat a zav\u0 windowTitleConfirmExit=Ne, te\u010F nechci odej\u00EDt! btn_Stop=P\u0159eru\u0161it tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Stav tab1_table_Lbl_FileName=N\u00E1zev souboru @@ -70,3 +71,4 @@ tab2_Cb_GlVersion=GoldLeaf verze tab2_Cb_GLshowNspOnly=Uk\u00E1zat v GoldLeafu pouze *.nsp. windowBodyPleaseStopOtherProcessFirst=Pros\u00EDm, p\u0159ed pokra\u010Dov\u00E1n\u00EDm nejprve zru\u0161te aktivn\u00ED p\u0159enos. + diff --git a/src/main/resources/locale_de_DE.properties b/src/main/resources/locale_de_DE.properties index f028cc3..2e10d92 100644 --- a/src/main/resources/locale_de_DE.properties +++ b/src/main/resources/locale_de_DE.properties @@ -11,8 +11,9 @@ windowBodyConfirmExit=Der Datentransfer ist noch nicht abgeschlossen; das Schlie windowTitleConfirmExit=Nein, mach das nicht! btn_Stop=Unterbrechen tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Status tab1_table_Lbl_FileName=Dateiname @@ -49,3 +50,4 @@ tab2_Cb_GLshowNspOnly=Nur *.nsp in GoldLeaf zeigen. btn_Cancel=Abbrechen + diff --git a/src/main/resources/locale_en_US.properties b/src/main/resources/locale_en_US.properties index f1fd516..62027f7 100644 --- a/src/main/resources/locale_en_US.properties +++ b/src/main/resources/locale_en_US.properties @@ -11,8 +11,9 @@ windowBodyConfirmExit=Data transfer is in progress and closing this application windowTitleConfirmExit=No, don't do this! btn_Stop=Interrupt tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Status tab1_table_Lbl_FileName=File name @@ -76,4 +77,4 @@ tab2_Cb_foldersSelectorForRomsDesc=Changes 'Select files' button behaviour on 'G windowTitleAddingFiles=Searching for files... windowBodyFilesScanned=Files scanned: %d\nWould be added: %d tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM -tabRcm_Lbl_Payload=Payload: \ No newline at end of file +tabRcm_Lbl_Payload=Payload: diff --git a/src/main/resources/locale_es_ES.properties b/src/main/resources/locale_es_ES.properties index b535b7d..f447ef1 100644 --- a/src/main/resources/locale_es_ES.properties +++ b/src/main/resources/locale_es_ES.properties @@ -1,47 +1,81 @@ -btn_OpenFile=Seleccionar los archivos +btn_OpenFile=Seleccionar archivos +btn_OpenFolders=Seleccionar carpeta btn_Upload=Enviar a NS -tab3_Txt_EnteredAsMsg1=Est\u00E1 conectado como: -tab3_Txt_EnteredAsMsg2=Deber\u00EDa ser root o haber configurado las reglas 'udev' de este usuario para evitar problemas. -tab3_Txt_FilesToUploadTitle=Archivos a subir: +btn_OpenFolders_tooltip=Select a folder to be scanned.\nThis folder and all of its subfolders will be scanned.\nAll matching files will be added to the list. +tab3_Txt_EnteredAsMsg1=Est\u00E1s conectado como: +tab3_Txt_EnteredAsMsg2=Debes tener permisos root o haber configurado las reglas 'udev' de este usuario para evitar problemas. +tab3_Txt_FilesToUploadTitle=Archivos a enviar: tab3_Txt_GreetingsMessage=Bienvenido a NS-USBloader -tab3_Txt_NoFolderOrFileSelected=No ha seleccionado ning\u00FAn archivo: Nada se subir\u00E1. -windowBodyConfirmExit=Transferencia de datos en progreso, cerrar la aplicaci\u00F3n lo interrumpir\u00E1.\nNo se recomienda.\nInterrumpir proceso y salir? -windowTitleConfirmExit=No, no haga esto! +tab3_Txt_NoFolderOrFileSelected=Ning\u00FAn archivo seleccionado: No se enviar\u00E1 nada. +windowBodyConfirmExit=Se est\u00E1n transfiriendo archivos y cerrar la aplicaci\u00F3n lo interrumpir\u00E1.\nNo debes hacer esto.\n\u00BFInterrumpir el proceso y salir? +windowTitleConfirmExit=\u00A1No hagas esto! btn_Stop=Interrumpir tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] -tab1_table_Lbl_Status=Estado +tab1_table_Lbl_Status=Estatus tab1_table_Lbl_FileName=Nombre del archivo tab1_table_Lbl_Size=Tama\u00F1o -tab1_table_Lbl_Upload=Enviar? -tab1_table_contextMenu_Btn_BtnDelete=Eliminar -tab1_table_contextMenu_Btn_DeleteAll=Eliminar todo +tab1_table_Lbl_Upload=\u00BFEnviar? +tab1_table_contextMenu_Btn_BtnDelete=Quitar +tab1_table_contextMenu_Btn_DeleteAll=Quitar todos tab2_Lbl_HostIP=IP del host -tab1_Lbl_NSIP=NS IP: -tab2_Cb_ValidateNSHostName=Validar siempre la entrada de IP de la NS. -windowBodyBadIp=Est\u00E1 seguro de que ha introducido la IP de la NS correctamente? -windowTitleBadIp=Es posible que la direcci\u00F3n IP de la NS sea incorrecta -tab2_Cb_ExpertMode=Modo Experto -tab2_Lbl_HostPort=Puerto -tab2_Cb_AutoDetectIp=Detectar IP autom\u00E1ticamente -tab2_Cb_RandSelectPort=Obtener el puerto autom\u00E1ticamente -tab2_Cb_DontServeRequests=No contestar solicitudes -tab2_Lbl_DontServeRequestsDesc=Si habilita esta opci\u00F3n, el ordenador no responder\u00E1 solicitudes de archivos NSP de la NS (en la red), y usar\u00E1 las configuraciones definidas por el host para indicar a Awoo donde se encuentran los archivos -tab2_Lbl_HostExtra=Extra -windowTitleErrorPort=Puerto asignado incorrectamente! -windowBodyErrorPort=El puerto no puede ser 0 o mayor que 65535 -tab2_Cb_AutoCheckForUpdates=Comprobar actualizaciones autom\u00E1ticamente -windowTitleNewVersionAval=Actualizaci\u00F3n disponible -windowTitleNewVersionNOTAval=No hay actualizaciones disponibles -windowTitleNewVersionUnknown=No fue posible encontrar actualizaciones -windowBodyNewVersionUnknown=Algo fall\u00F3\nLa conexi\u00F3n a internet no funciona correctamente, o GitHub est\u00E1 ca\u00EDdo +tab1_Lbl_NSIP=IP del NS: +tab2_Cb_ValidateNSHostName=Siempre verifica el IP del NS. +windowBodyBadIp=\u00BFEst\u00E1s seguro que la direcci\u00F3n IP ingresada es la del NS? +windowTitleBadIp=La IP del NS parece ser incorrecta. +tab2_Cb_ExpertMode=Modo experto (NET setup) +tab2_Lbl_HostPort=puerto +tab2_Cb_AutoDetectIp=Detectar autom\u00E1ticamente la IP +tab2_Cb_RandSelectPort=Obtener puerto aleatoriamente +tab2_Cb_DontServeRequests=No responder solicitudes +tab2_Lbl_DontServeRequestsDesc=Si se activa, esta computadora no responder\u00E1 a las solicitudes de archivos NSP provenientes del NS (en la red) y se usar\u00E1n las configuraciones definidas por el host para decirle a Awoo Installer (o aplicaciones compatibles) donde buscar por los archivos. +tab2_Lbl_HostExtra=extra +windowTitleErrorPort=\u00A1Puerto incorrecto! +windowBodyErrorPort=\u00A1Puerto incorrecto! +tab2_Cb_AutoCheckForUpdates=Buscar actualizaciones autom\u00E1ticamente +windowTitleNewVersionAval=Nueva versi\u00F3n disponible +windowTitleNewVersionNOTAval=No hay ninguna nueva versi\u00F3n disponible +windowTitleNewVersionUnknown=No se pueden buscar actualizaciones +windowBodyNewVersionUnknown=Algo sali\u00F3 mal\nQuiz\u00E1s no tienes conexi\u00F3n a internet, o GitHub est\u00E1 caido windowBodyNewVersionNOTAval=Est\u00E1s usando la \u00FAltima versi\u00F3n -tab2_Cb_AllowXciNszXcz=Permite la selecci\u00F3n de archivos XCI / NSZ / XCZ para Awoo -tab2_Lbl_AllowXciNszXczDesc=Usado por algunas aplicaciones de terceros que soportan XCI/NSZ/XCZ y que utilizan el protocolo de transferencia de Tinfoil. Si no est\u00E1 seguro no cambie la opci\u00F3n. +tab2_Cb_AllowXciNszXcz=Permitir seleccionar archivos XCI / NSZ / XCZ en Awoo +tab2_Lbl_AllowXciNszXczDesc=Usado por aplicaciones que soportan XCI/NSZ/XCZ y utilizan el protocolo de transferencia Awoo (Adubbz/TinFoil). No modificar si no est\u00E1s seguro. Habilitar para Awoo Installer. tab2_Lbl_Language=Idioma -windowBodyRestartToApplyLang=Por favor, reinicie el programa para aplicar los cambios. -tab2_Cb_GLshowNspOnly=Mostrar solo *.nsp en GoldLeaf. +windowBodyRestartToApplyLang=Reinicia la aplicaci\u00F3n para aplicar los cambios. +btn_OpenSplitFile=Seleccionar NSP en partes +tab2_Lbl_ApplicationSettings=Ajustes principales +tabSplMrg_Lbl_SplitNMergeTitle=Herramienta para dividir y fusionar archivos +tabSplMrg_RadioBtn_Split=Dividir +tabSplMrg_RadioBtn_Merge=Fusionar +tabSplMrg_Txt_File=Archivo: +tabSplMrg_Txt_Folder=Archivo dividido (carpeta): +tabSplMrg_Btn_SelectFile=Seleccionar archivo +tabSplMrg_Btn_SelectFolder=Seleccionar carpeta +tabSplMrg_Lbl_SaveToLocation=Guardar en: +tabSplMrg_Btn_ChangeSaveToLocation=Cambiar +tabSplMrg_Btn_Convert=Convertir +windowTitleError=Error +windowBodyPleaseFinishTransfersFirst=No se pueden dividir/fusionar archivos mientras se est\u00E1 realizando otro proceso. Por favor, cancela las operaciones de transferencia activas primero. +done_txt=\u00A1Listo! +failure_txt=Error +btn_Select=Seleccionar +btn_InjectPayloader=Injectar payload +tabNXDT_Btn_Start=\u00A1Iniciar! +tab2_Btn_InstallDrivers=Descargar e instalar controladores +windowTitleDownloadDrivers=Descargar e instalar controladores +windowBodyDownloadDrivers=Descargando controladores (libusbK v3.0.7.0)... btn_Cancel=Cancelar - +btn_Close=Cerrar +tab2_Cb_GlVersion=Versi\u00F3n de GoldLeaf +tab2_Cb_GLshowNspOnly=Mostrar solo *.nsp en GoldLeaf. +windowBodyPleaseStopOtherProcessFirst=Det\u00E9n los dem\u00E1s procesos activos antes de continuar. +tab2_Cb_foldersSelectorForRoms=Seleccionar una carpeta con archivos ROM en lugar de seleccionarlos individualmente. +tab2_Cb_foldersSelectorForRomsDesc=Cambia el comportamiento del bot\u00F3n de 'Seleccionar archivos' en la pesta\u00F1a 'Juegos': en lugar de seleccionar archivos ROM uno por uno puedes seleccionar una carpeta para instalarlos todos a la vez. +windowTitleAddingFiles=Buscando archivos... +windowBodyFilesScanned=Archivos encontrados: %d\nSe a\u00F1adir\u00E1n: %d +tab2_Lbl_AwooBlockTitle=Awoo Installer y compatibles +tabRcm_Lbl_Payload=Payload: +tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM diff --git a/src/main/resources/locale_fr_FR.properties b/src/main/resources/locale_fr_FR.properties index 5fbb3e7..08048b8 100644 --- a/src/main/resources/locale_fr_FR.properties +++ b/src/main/resources/locale_fr_FR.properties @@ -9,8 +9,9 @@ windowBodyConfirmExit=Le transfert de donn\u00E9es est en cours et la fermeture windowTitleConfirmExit=Non, ne faites pas \u00E7a! btn_Stop=Interrompre tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Upload=Envoyer ? tab1_table_Lbl_Size=Taille @@ -44,3 +45,4 @@ tab2_Lbl_Language=La langue btn_Cancel=Annuler + diff --git a/src/main/resources/locale_it_IT.properties b/src/main/resources/locale_it_IT.properties index 8aaad2c..103b64d 100644 --- a/src/main/resources/locale_it_IT.properties +++ b/src/main/resources/locale_it_IT.properties @@ -11,8 +11,9 @@ windowBodyConfirmExit=Il trasferimento dei dati \u00E8 in corso e la chiusura de windowTitleConfirmExit=No, non farlo! btn_Stop=Interrompi tab3_Txt_GreetingsMessage2=--\n\ -Sorgenti: https://github.com/developersu/ns-usbloader/\n\ -Sito: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Sorgenti: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Sito: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Stato tab1_table_Lbl_FileName=Nome file @@ -78,3 +79,4 @@ windowBodyFilesScanned=File scansionati: %d\nVerranno aggiunti: %d tab2_Lbl_AwooBlockTitle=Awoo Installer e compatibili tabRcm_Lbl_Payload=Payload: tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM + diff --git a/src/main/resources/locale_ko_KR.properties b/src/main/resources/locale_ko_KR.properties index 7de4802..8d11a70 100644 --- a/src/main/resources/locale_ko_KR.properties +++ b/src/main/resources/locale_ko_KR.properties @@ -11,8 +11,9 @@ windowBodyConfirmExit=\uB370\uC774\uD130 \uC804\uC1A1\uC774 \uC9C4\uD589 \uC911\ windowTitleConfirmExit=\uC544\uB2C8\uC624, \uC774\uAC83\uC740 \uD558\uC9C0\uB9C8\uC138\uC694! btn_Stop=\uC911\uB2E8 tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=\uC0C1\uD0DC tab1_table_Lbl_FileName=\uD30C\uC77C \uC774\uB984 @@ -78,3 +79,4 @@ windowBodyFilesScanned=\uC2A4\uCE94 \uB41C \uD30C\uC77C: %d\n\uCD94\uAC00 \uB420 tab2_Lbl_AwooBlockTitle=Awoo \uC124\uCE58 \uD504\uB85C\uADF8\uB7A8\uACFC \uD638\uD658\uC131 tabRcm_Lbl_Payload=\uD398\uC774\uB85C\uB4DC: tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM + diff --git a/src/main/resources/locale_pt_BR.properties b/src/main/resources/locale_pt_BR.properties index 551bad0..5b6f5ba 100644 --- a/src/main/resources/locale_pt_BR.properties +++ b/src/main/resources/locale_pt_BR.properties @@ -9,8 +9,9 @@ windowBodyConfirmExit=Transfer\u00EAncia de dados em progresso: Fechar ir\u00E1 windowTitleConfirmExit=N\u00E3o, n\u00E3o fa\u00E7a isso! btn_Stop=Interromper! tab3_Txt_GreetingsMessage2=--\n\ -Fonte: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Fonte: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Status tab1_table_Lbl_FileName=Nome do Arquivo @@ -69,3 +70,4 @@ btn_Close=Fechar tab2_Cb_GlVersion=Vers\u00E3o do GoldLeaf tab2_Cb_GLshowNspOnly=Mostrar apenas *.nsp no GoldLeaf. windowBodyPleaseStopOtherProcessFirst=Por favor, pare outros processos ativos antes de prosseguir + diff --git a/src/main/resources/locale_ro_RO.properties b/src/main/resources/locale_ro_RO.properties index 07be038..6929a64 100644 --- a/src/main/resources/locale_ro_RO.properties +++ b/src/main/resources/locale_ro_RO.properties @@ -11,8 +11,9 @@ windowBodyConfirmExit=Transferul de date este \u00EEn desf\u0103\u0219urare \u02 windowTitleConfirmExit=Nu, nu face asta! btn_Stop=\u00CEntrerupere tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=Status tab1_table_Lbl_FileName=Numele fi\u0219ierului @@ -74,4 +75,4 @@ windowBodyPleaseStopOtherProcessFirst=Te rog opre\u0219te toate cel\u0103lalte p tab2_Cb_foldersSelectorForRoms=Selecteaz\u0103 directorul cu fi\u0219iere ROM \u00EEn loc s\u0103 selectezi fi\u0219iere ROM individual. tab2_Cb_foldersSelectorForRomsDesc=Face ca 'Selecteaz\u0103 fi\u0219ierele' \u00EEn tab-ul 'Games' s\u0103 selecteze toate fi\u0219ierele de-o dat\u0103\u00A0\u00EEn loc de a selecta fi\u0219iere ROM unul c\u00E2te unul. windowTitleAddingFiles=Caut fi\u0219iere... -windowBodyFilesScanned=Fi\u0219iere scanate: %d\nVor fi ad\u0103ugate: %d \ No newline at end of file +windowBodyFilesScanned=Fi\u0219iere scanate: %d\nVor fi ad\u0103ugate: %d diff --git a/src/main/resources/locale_ru_RU.properties b/src/main/resources/locale_ru_RU.properties index bfc8a03..6620554 100644 --- a/src/main/resources/locale_ru_RU.properties +++ b/src/main/resources/locale_ru_RU.properties @@ -9,8 +9,9 @@ windowBodyConfirmExit=\u0421\u0435\u0439\u0447\u0430\u0441 \u043F\u0440\u043E\u0 windowTitleConfirmExit=\u041D\u0435\u0442, \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0441\u044C! btn_Stop=\u041F\u0440\u0435\u0440\u0432\u0430\u0442\u044C tab3_Txt_GreetingsMessage2=--\n\ -\u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u043A\u043E\u0434: https://github.com/developersu/ns-usbloader/\n\ -\u0421\u0430\u0439\u0442: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +\u0418\u0441\u0445\u043E\u0434\u043D\u044B\u0439 \u043A\u043E\u0434: https://git.redrise.ru/desu/ns-usbloader\n\ +\u0417\u0435\u0440\u043A\u0430\u043B\u043E: https://github.com/developersu/ns-usbloader/\n\ +\u0421\u0430\u0439\u0442: https://redrise.ru\n\ \u0418\u0441\u0430\u0435\u043D\u043A\u043E \u0414\u043C\u0438\u0442\u0440\u0438\u0439 [developer.su] tab1_table_Lbl_Upload=\u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C? tab1_table_Lbl_Size=\u0420\u0430\u0437\u043C\u0435\u0440 @@ -77,3 +78,4 @@ tab2_Lbl_AwooBlockTitle=Awoo Installer \u0438 \u0441\u043E\u0432\u043C\u0435\u04 tabRcm_Lbl_Payload=Payload: tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM + diff --git a/src/main/resources/locale_uk_UA.properties b/src/main/resources/locale_uk_UA.properties index 7e88bb5..aad36fc 100644 --- a/src/main/resources/locale_uk_UA.properties +++ b/src/main/resources/locale_uk_UA.properties @@ -9,8 +9,9 @@ windowBodyConfirmExit=\u0417\u0430\u0440\u0430\u0437 \u0432\u0456\u0434\u0431\u0 windowTitleConfirmExit=\u041D\u0456, \u0437\u0443\u043F\u0438\u043D\u0438\u0441\u044C! btn_Stop=\u041F\u0435\u0440\u0435\u0440\u0432\u0430\u0442\u0438 tab3_Txt_GreetingsMessage2=--\n\ -\u0421\u0438\u0440\u0446\u0435\u0432\u0438\u0439 \u043A\u043E\u0434: https://github.com/developersu/ns-usbloader/\n\ -\u0421\u0430\u0439\u0442: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +\u0421\u0438\u0440\u0446\u0435\u0432\u0438\u0439 \u043A\u043E\u0434: https://git.redrise.ru/desu/ns-usbloader\n\ +\u0414\u0437\u0435\u0440\u043A\u0430\u043B\u043E: https://github.com/developersu/ns-usbloader/\n\ +\u0421\u0430\u0439\u0442: https://redrise.ru\n\ \u0418\u0441\u0430\u0454\u043D\u043A\u043E \u0414\u043C\u0438\u0442\u0440\u043E [developer.su] tab1_table_Lbl_Status=\u0421\u0442\u0430\u043D tab1_table_Lbl_FileName=\u0406\u043C'\u044F \u0444\u0430\u0439\u043B\u0443 @@ -76,3 +77,4 @@ windowBodyFilesScanned=\u0424\u0430\u0439\u043B\u0456\u0432 \u043F\u0440\u043E\u tab2_Lbl_AwooBlockTitle=Awoo Installer \u0442\u0430 \u0441\u0443\u043C\u0456\u0441\u043D\u0456 tabRcm_Lbl_Payload=Payload: tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM + diff --git a/src/main/resources/locale_vi_VN.properties b/src/main/resources/locale_vi_VN.properties index cccefce..a8db7dc 100644 --- a/src/main/resources/locale_vi_VN.properties +++ b/src/main/resources/locale_vi_VN.properties @@ -34,7 +34,11 @@ tab3_Txt_EnteredAsMsg1=B\u1EA1n \u0111\u00E3 truy nh\u1EADp d\u01B0\u1EDBi d\u1E tab3_Txt_EnteredAsMsg2=B\u1EA1n n\u00EAn c\u00F3 quy\u1EC1n root ho\u1EB7c c\u1EA5u h\u00ECnh quy\u1EC1n 'udev' cho ng\u01B0\u1EDDi d\u00F9ng n\u00E0y \u0111\u1EC3 tr\u00E1nh c\u00E1c v\u1EA5n \u0111\u1EC1 ph\u00E1t sinh. tab3_Txt_FilesToUploadTitle=T\u1EADp tin s\u1EBD t\u1EA3i l\u00EAn\: tab3_Txt_GreetingsMessage=Ch\u00E0o m\u1EEBng \u0111\u1EBFn NS-USBloader -tab3_Txt_GreetingsMessage2=--\nNgu\u1ED3n\: https\://github.com/developersu/ns-usbloader/\nTrang\: https\://developersu.blogspot.com/search/label/NS-USBloader\nDmitry Isaenko [developer.su] +tab3_Txt_GreetingsMessage2=--\n\ +Ngu\u1ED3n: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Trang: https://redrise.ru\n\ +Dmitry Isaenko [developer.su] tab3_Txt_NoFolderOrFileSelected=Kh\u00F4ng c\u00F3 t\u1EADp tin n\u00E0o \u0111\u01B0\u1EE3c ch\u1ECDn\: kh\u00F4ng c\u00F3 g\u00EC \u0111\u1EC3 t\u1EA3i l\u00EAn. tabSplMrg_Btn_ChangeSaveToLocation=Thay \u0111\u1ED5i tabSplMrg_Btn_Convert=Chuy\u1EC3n \u0111\u1ED5i @@ -62,3 +66,4 @@ windowTitleNewVersionNOTAval=Ch\u01B0a c\u00F3 phi\u00EAn b\u1EA3n m\u1EDBi windowTitleNewVersionUnknown=Kh\u00F4ng th\u1EC3 ki\u1EC3m tra phi\u00EAn b\u1EA3n m\u1EDBi btn_Cancel=H\u1EE7y B\u1ECF + diff --git a/src/main/resources/locale_zh_CN.properties b/src/main/resources/locale_zh_CN.properties index 5262f68..8039b0a 100644 --- a/src/main/resources/locale_zh_CN.properties +++ b/src/main/resources/locale_zh_CN.properties @@ -1,7 +1,7 @@ btn_OpenFile=\u9009\u62E9.NSP\u6587\u4EF6 -btn_OpenFolders=\u9009\u62e9\u76ee\u5f55 +btn_OpenFolders=\u9009\u62E9\u76EE\u5F55 btn_Upload=\u4E0A\u4F20\u5230NS -btn_OpenFolders_tooltip=\u6b63\u5728\u626b\u63cf\u9009\u4e2d\u7684\u76ee\u5f55.\n\u6240\u6709\u7684\u76ee\u5f55\u626b\u63cf\u5b8c\u6210.\n\u7b26\u5408\u7684\u6587\u4ef6\u5df2\u7ecf\u6dfb\u52a0\u5230\u5217\u8868\u4e2d. +btn_OpenFolders_tooltip=\u6B63\u5728\u626B\u63CF\u9009\u4E2D\u7684\u76EE\u5F55.\n\u6240\u6709\u7684\u76EE\u5F55\u626B\u63CF\u5B8C\u6210.\n\u7B26\u5408\u7684\u6587\u4EF6\u5DF2\u7ECF\u6DFB\u52A0\u5230\u5217\u8868\u4E2D. tab3_Txt_EnteredAsMsg1=\u4F60\u6B63\u5728\u4F7F\u7528: tab3_Txt_EnteredAsMsg2=\u4F60\u5E94\u8BE5\u4F7F\u7528root\u8D26\u53F7\u6216\u8005\u4E3A\u5F53\u524D\u7528\u6237\u914D\u7F6E'udev'\u89C4\u5219\u6765\u907F\u514D\u53EF\u80FD\u7684\u95EE\u9898\u3002 tab3_Txt_FilesToUploadTitle=\u8981\u4E0A\u4F20\u7684\u6587\u4EF6: @@ -11,8 +11,9 @@ windowBodyConfirmExit=\u6570\u636E\u6B63\u5728\u4F20\u8F93\u4E2D\uFF0C\u5173\u95 windowTitleConfirmExit=\u4E0D, \u4E0D\u8FDB\u884C\u8FD9\u9879\u64CD\u4F5C\uFF01 btn_Stop=\u4E2D\u65AD tab3_Txt_GreetingsMessage2=--\n\ -\u6E90\u4EE3\u7801: https://github.com/developersu/ns-usbloader/\n\ -\u7F51\u7AD9: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +\u6E90\u4EE3\u7801: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +\u7F51\u7AD9: https://redrise.ru\n\ Dmitry Isaenko [developer.su] tab1_table_Lbl_Status=\u72B6\u6001 tab1_table_Lbl_FileName=\u6587\u4EF6\u540D @@ -71,10 +72,11 @@ btn_Close=\u5173\u95ED tab2_Cb_GlVersion=GoldLeaf\u7248\u672C tab2_Cb_GLshowNspOnly=\u5728GoldLeaf\u5185\u4EC5\u663E\u793A*.nsp\u6587\u4EF6 windowBodyPleaseStopOtherProcessFirst=\u5982\u8981\u6267\u884C\u76EE\u524D\u7684\u64CD\u4F5C\u7A0B\u5E8F,\u8BF7\u5148\u505C\u6B62\u5176\u4ED6\u6B63\u5728\u5904\u7406\u7684\u7A0B\u5E8F. -tab2_Cb_foldersSelectorForRoms=\u9009\u4e2d\u540e\u5207\u6362\u6210\u9009\u62e9\u76ee\u5f55\u6a21\u5f0f -tab2_Cb_foldersSelectorForRomsDesc=\u542f\u7528\u6b64\u529f\u80fd\u540e\uff0c\u5c06\u6539\u53d8\u201c\u6e38\u620f\u6807\u7b7e\u201d\u4e2d\u7684\u201c\u9009\u62e9\u6587\u4ef6\u201d\u6309\u952e\u529f\u80fd\uff1a\u4ece\u9009\u62e9\u4e00\u4e2a\u6587\u4ef6\u66ff\u6362\u4e3a\u9009\u62e9\u4e00\u4e2a\u76ee\u5f55\u3002 -windowTitleAddingFiles=\u641c\u7d22\u6587\u4ef6\u4e2d... -windowBodyFilesScanned=\u626b\u63cf\u6587\u4ef6: %25d\n\u88ab\u6dfb\u52a0: %25d -tab2_Lbl_AwooBlockTitle=awoo installer \u5b8c\u6210 +tab2_Cb_foldersSelectorForRoms=\u9009\u4E2D\u540E\u5207\u6362\u6210\u9009\u62E9\u76EE\u5F55\u6A21\u5F0F +tab2_Cb_foldersSelectorForRomsDesc=\u542F\u7528\u6B64\u529F\u80FD\u540E\uFF0C\u5C06\u6539\u53D8\u201C\u6E38\u620F\u6807\u7B7E\u201D\u4E2D\u7684\u201C\u9009\u62E9\u6587\u4EF6\u201D\u6309\u952E\u529F\u80FD\uFF1A\u4ECE\u9009\u62E9\u4E00\u4E2A\u6587\u4EF6\u66FF\u6362\u4E3A\u9009\u62E9\u4E00\u4E2A\u76EE\u5F55\u3002 +windowTitleAddingFiles=\u641C\u7D22\u6587\u4EF6\u4E2D... +windowBodyFilesScanned=\u626B\u63CF\u6587\u4EF6: %25d\n\u88AB\u6DFB\u52A0: %25d +tab2_Lbl_AwooBlockTitle=awoo installer \u5B8C\u6210 tabRcm_Lbl_Payload=Payload: tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM + diff --git a/src/main/resources/locale_zh_TW.properties b/src/main/resources/locale_zh_TW.properties index 739bedd..615b87f 100644 --- a/src/main/resources/locale_zh_TW.properties +++ b/src/main/resources/locale_zh_TW.properties @@ -1,80 +1,82 @@ -btn_OpenFile=\u9078\u64c7\u6a94\u6848 -btn_OpenFolders=\u9078\u64c7\u8cc7\u6599\u593e -btn_Upload=\u4e0a\u50b3\u81f3NS -btn_OpenFolders_tooltip=\u9078\u64c7\u8981\u6aa2\u67e5\u7684\u8cc7\u6599\u593e.\n\u6703\u6aa2\u67e5\u8cc7\u6599\u593e\u8207\u6240\u6709\u5b50\u76ee\u9304.\n\u6240\u6709\u7b26\u5408\u7684\u6a94\u6848\u90fd\u6703\u52a0\u5165\u4f47\u5217. -tab3_Txt_EnteredAsMsg1=\u76ee\u524d\u767b\u5165\u7684\u4f7f\u7528\u8005: -tab3_Txt_EnteredAsMsg2=\u57f7\u884c\u6b64\u64cd\u4f5c\u6642\u4f60\u5fc5\u9808\u64c1\u6709\u7ba1\u7406\u54e1\u6b0a\u9650,\u6216\u6b64\u767b\u5165\u7684\u4f7f\u7528\u8005\u5e33\u6236\u5df2\u914d\u7f6e'udev'\u898f\u5247,\u4ee5\u907f\u514d\u767c\u751f\u554f\u984c. -tab3_Txt_FilesToUploadTitle=\u4e0a\u50b3\u7684\u6a94\u6848: -tab3_Txt_GreetingsMessage=\u6b61\u8fce\u4f7f\u7528NS-USBloader -tab3_Txt_NoFolderOrFileSelected=\u5c1a\u672a\u9078\u53d6\u6a94\u6848: \u4e0a\u50b3\u4f47\u5217\u6c92\u6709\u9805\u76ee -windowBodyConfirmExit=\u6b64\u6642\u9000\u51fa\u7a0b\u5f0f\u5c07\u6703\u4e2d\u65b7\u6b63\u5728\u50b3\u8f38\u7684\u8cc7\u6599.\n\u518d\u6b21\u50b3\u8f38\u8cc7\u6599\u5c07\u91cd\u8907\u4f54\u7528\u6642\u9593.\n\u662f\u5426\u78ba\u8a8d\u8981\u4e2d\u65b7\u50b3\u8f38\u4e26\u4e14\u7d50\u675f\u7a0b\u5f0f? -windowTitleConfirmExit=\u4e0d,\u8acb\u52ff\u9000\u51fa! -btn_Stop=\u4e2d\u65b7\u64cd\u4f5c +btn_OpenFile=\u9078\u64C7\u6A94\u6848 +btn_OpenFolders=\u9078\u64C7\u8CC7\u6599\u593E +btn_Upload=\u4E0A\u50B3\u81F3NS +btn_OpenFolders_tooltip=\u9078\u64C7\u8981\u6AA2\u67E5\u7684\u8CC7\u6599\u593E.\n\u6703\u6AA2\u67E5\u8CC7\u6599\u593E\u8207\u6240\u6709\u5B50\u76EE\u9304.\n\u6240\u6709\u7B26\u5408\u7684\u6A94\u6848\u90FD\u6703\u52A0\u5165\u4F47\u5217. +tab3_Txt_EnteredAsMsg1=\u76EE\u524D\u767B\u5165\u7684\u4F7F\u7528\u8005: +tab3_Txt_EnteredAsMsg2=\u57F7\u884C\u6B64\u64CD\u4F5C\u6642\u4F60\u5FC5\u9808\u64C1\u6709\u7BA1\u7406\u54E1\u6B0A\u9650,\u6216\u6B64\u767B\u5165\u7684\u4F7F\u7528\u8005\u5E33\u6236\u5DF2\u914D\u7F6E'udev'\u898F\u5247,\u4EE5\u907F\u514D\u767C\u751F\u554F\u984C. +tab3_Txt_FilesToUploadTitle=\u4E0A\u50B3\u7684\u6A94\u6848: +tab3_Txt_GreetingsMessage=\u6B61\u8FCE\u4F7F\u7528NS-USBloader +tab3_Txt_NoFolderOrFileSelected=\u5C1A\u672A\u9078\u53D6\u6A94\u6848: \u4E0A\u50B3\u4F47\u5217\u6C92\u6709\u9805\u76EE +windowBodyConfirmExit=\u6B64\u6642\u9000\u51FA\u7A0B\u5F0F\u5C07\u6703\u4E2D\u65B7\u6B63\u5728\u50B3\u8F38\u7684\u8CC7\u6599.\n\u518D\u6B21\u50B3\u8F38\u8CC7\u6599\u5C07\u91CD\u8907\u4F54\u7528\u6642\u9593.\n\u662F\u5426\u78BA\u8A8D\u8981\u4E2D\u65B7\u50B3\u8F38\u4E26\u4E14\u7D50\u675F\u7A0B\u5F0F? +windowTitleConfirmExit=\u4E0D,\u8ACB\u52FF\u9000\u51FA! +btn_Stop=\u4E2D\u65B7\u64CD\u4F5C tab3_Txt_GreetingsMessage2=--\n\ -Source: https://github.com/developersu/ns-usbloader/\n\ -Site: https://developersu.blogspot.com/search/label/NS-USBloader\n\ +Source: https://git.redrise.ru/desu/ns-usbloader\n\ +Mirror: https://github.com/developersu/ns-usbloader/\n\ +Site: https://redrise.ru\n\ Dmitry Isaenko [developer.su] -tab1_table_Lbl_Status=\u72c0\u614b -tab1_table_Lbl_FileName=\u6a94\u6848\u540d\u7a31 -tab1_table_Lbl_Size=\u6a94\u6848\u5927\u5c0f -tab1_table_Lbl_Upload=\u4e0a\u50b3? -tab1_table_contextMenu_Btn_BtnDelete=\u79fb\u9664 -tab1_table_contextMenu_Btn_DeleteAll=\u5168\u90e8\u79fb\u9664 -tab2_Lbl_HostIP=\u96fb\u8166IP +tab1_table_Lbl_Status=\u72C0\u614B +tab1_table_Lbl_FileName=\u6A94\u6848\u540D\u7A31 +tab1_table_Lbl_Size=\u6A94\u6848\u5927\u5C0F +tab1_table_Lbl_Upload=\u4E0A\u50B3? +tab1_table_contextMenu_Btn_BtnDelete=\u79FB\u9664 +tab1_table_contextMenu_Btn_DeleteAll=\u5168\u90E8\u79FB\u9664 +tab2_Lbl_HostIP=\u96FB\u8166IP tab1_Lbl_NSIP=NS IP: -tab2_Cb_ValidateNSHostName=\u6bcf\u6b21\u8f38\u5165\u5f8c\u90fd\u9a57\u8b49NS IP -windowBodyBadIp=\u4f60\u6240\u8f38\u5165\u7684NS IP\u4f4d\u5740\u662f\u5426\u6b63\u78ba? -windowTitleBadIp=NS IP\u4f4d\u5740\u4e0d\u6b63\u78ba -tab2_Cb_ExpertMode=\u5c08\u5bb6\u6a21\u5f0f (NET \u5b89\u88dd) -tab2_Lbl_HostPort=\u9023\u63a5\u57e0 -tab2_Cb_AutoDetectIp=\u81ea\u52d5\u5075\u6e2cIP -tab2_Cb_RandSelectPort=\u96a8\u6a5f\u9078\u53d6\u9023\u63a5\u57e0 -tab2_Cb_DontServeRequests=\u4e0d\u56de\u61c9NS\u8acb\u6c42 -tab2_Lbl_DontServeRequestsDesc=\u555f\u7528\u6b64\u8a2d\u5b9a\u5f8c,\u6b64\u96fb\u8166\u5c07\u4e0d\u6703\u56de\u61c9\u4f86\u81eaNS(\u900f\u904e\u7db2\u8def)\u7684NSP\u6a94\u6848\u8acb\u6c42,\u4e26\u8b93Awoo(\u6216\u5176\u4ed6\u540c\u985e\u578b\u7a0b\u5f0f)\u5c0b\u627e\u6a94\u6848\u4f86\u6e90\u6642\u4f7f\u7528\u9810\u8a2d\u7684\u4e3b\u6a5f\u8a2d\u5b9a. -tab2_Lbl_HostExtra=\u5176\u4ed6 -windowTitleErrorPort=\u9023\u63a5\u57e0\u8a2d\u5b9a\u4e0d\u6b63\u78ba! -windowBodyErrorPort=\u9023\u63a5\u57e0\u8a2d\u5b9a\u503c\u5fc5\u9808\u4ecb\u65bc0\u523065535\u4e4b\u9593. -tab2_Cb_AutoCheckForUpdates=\u81ea\u52d5\u6aa2\u67e5\u66f4\u65b0 -windowTitleNewVersionAval=\u6709\u53ef\u66f4\u65b0\u7684\u7248\u672c -windowTitleNewVersionNOTAval=\u76ee\u524d\u6c92\u6709\u53ef\u66f4\u65b0\u7684\u7248\u672c -windowTitleNewVersionUnknown=\u76ee\u524d\u7121\u6cd5\u6aa2\u67e5\u6709\u7121\u53ef\u66f4\u65b0\u7248\u672c -windowBodyNewVersionUnknown=\u767c\u751f\u932f\u8aa4\n\u53ef\u80fd\u7db2\u8def\u4e0d\u53ef\u7528\u6216\u8a0a\u865f\u4e0d\u8db3,\u6216\u8005\u7121\u6cd5\u9023\u4e0aGitHub\u5b98\u7db2\u4f3a\u670d\u5668 -windowBodyNewVersionNOTAval=\u76ee\u524d\u4f7f\u7528\u7684\u7a0b\u5f0f\u5df2\u662f\u6700\u65b0\u7248\u672c -tab2_Cb_AllowXciNszXcz=\u5141\u8a31Awoo\u6a21\u5f0f\u6642\u9078\u53d6XCI / NSZ / XCZ \u6a94\u6848\u683c\u5f0f -tab2_Lbl_AllowXciNszXczDesc=\u6b64\u8a2d\u5b9a\u5c08\u70ba\u652f\u63f4XCI/NSZ/XCZ\u6a94\u6848\u683c\u5f0f\u8207Tinfoil\u50b3\u8f38\u5354\u8b70\u7684\u7b2c\u4e09\u65b9\u7a0b\u5f0f\u4f7f\u7528. \u5982\u4e0d\u78ba\u5b9a,\u8acb\u52ff\u8b8a\u66f4\u6b64\u9805\u8a2d\u5b9a. \u4f7f\u7528Awoo Installer\u8acb\u555f\u7528\u6b64\u8a2d\u5b9a. -tab2_Lbl_Language=\u4ecb\u9762\u8a9e\u7cfb -windowBodyRestartToApplyLang=\u8acb\u91cd\u65b0\u555f\u52d5\u7a0b\u5f0f\u4ee5\u5957\u7528\u8b8a\u66f4\u7684\u8a2d\u5b9a. -btn_OpenSplitFile=\u9078\u64c7\u5206\u5272\u7684NSP -tab2_Lbl_ApplicationSettings=\u4e3b\u8981\u8a2d\u5b9a -tabSplMrg_Lbl_SplitNMergeTitle=\u5206\u5272&\u5408\u4f75\u6a94\u6848\u5de5\u5177 -tabSplMrg_RadioBtn_Split=\u5206\u5272&\u5408\u4f75\u6a94\u6848\u5de5\u5177 -tabSplMrg_RadioBtn_Merge=\u5408\u4f75 -tabSplMrg_Txt_File=\u6a94\u6848: -tabSplMrg_Txt_Folder=\u5206\u5272\u6a94\u6848(\u8cc7\u6599\u593e): -tabSplMrg_Btn_SelectFile=\u9078\u64c7\u6a94\u6848 -tabSplMrg_Btn_SelectFolder=\u9078\u64c7\u8cc7\u6599\u593e -tabSplMrg_Lbl_SaveToLocation=\u5132\u5b58\u8def\u5f91: -tabSplMrg_Btn_ChangeSaveToLocation=\u8b8a\u66f4 -tabSplMrg_Btn_Convert=\u8f49\u6a94 -windowTitleError=\u932f\u8aa4 -windowBodyPleaseFinishTransfersFirst=\u7576\u7a0b\u5f0f\u6b63\u5728\u8655\u7406USB/\u7db2\u8def\u5b89\u88dd\u6642\u7121\u6cd5\u540c\u6642\u57f7\u884c\u5206\u5272/\u5408\u4f75\u6a94\u6848. \u5982\u9700\u7e7c\u7e8c,\u5fc5\u9808\u4e2d\u65b7\u76ee\u524d\u7684\u50b3\u8f38. -done_txt=\u5b8c\u6210! +tab2_Cb_ValidateNSHostName=\u6BCF\u6B21\u8F38\u5165\u5F8C\u90FD\u9A57\u8B49NS IP +windowBodyBadIp=\u4F60\u6240\u8F38\u5165\u7684NS IP\u4F4D\u5740\u662F\u5426\u6B63\u78BA? +windowTitleBadIp=NS IP\u4F4D\u5740\u4E0D\u6B63\u78BA +tab2_Cb_ExpertMode=\u5C08\u5BB6\u6A21\u5F0F (NET \u5B89\u88DD) +tab2_Lbl_HostPort=\u9023\u63A5\u57E0 +tab2_Cb_AutoDetectIp=\u81EA\u52D5\u5075\u6E2CIP +tab2_Cb_RandSelectPort=\u96A8\u6A5F\u9078\u53D6\u9023\u63A5\u57E0 +tab2_Cb_DontServeRequests=\u4E0D\u56DE\u61C9NS\u8ACB\u6C42 +tab2_Lbl_DontServeRequestsDesc=\u555F\u7528\u6B64\u8A2D\u5B9A\u5F8C,\u6B64\u96FB\u8166\u5C07\u4E0D\u6703\u56DE\u61C9\u4F86\u81EANS(\u900F\u904E\u7DB2\u8DEF)\u7684NSP\u6A94\u6848\u8ACB\u6C42,\u4E26\u8B93Awoo(\u6216\u5176\u4ED6\u540C\u985E\u578B\u7A0B\u5F0F)\u5C0B\u627E\u6A94\u6848\u4F86\u6E90\u6642\u4F7F\u7528\u9810\u8A2D\u7684\u4E3B\u6A5F\u8A2D\u5B9A. +tab2_Lbl_HostExtra=\u5176\u4ED6 +windowTitleErrorPort=\u9023\u63A5\u57E0\u8A2D\u5B9A\u4E0D\u6B63\u78BA! +windowBodyErrorPort=\u9023\u63A5\u57E0\u8A2D\u5B9A\u503C\u5FC5\u9808\u4ECB\u65BC0\u523065535\u4E4B\u9593. +tab2_Cb_AutoCheckForUpdates=\u81EA\u52D5\u6AA2\u67E5\u66F4\u65B0 +windowTitleNewVersionAval=\u6709\u53EF\u66F4\u65B0\u7684\u7248\u672C +windowTitleNewVersionNOTAval=\u76EE\u524D\u6C92\u6709\u53EF\u66F4\u65B0\u7684\u7248\u672C +windowTitleNewVersionUnknown=\u76EE\u524D\u7121\u6CD5\u6AA2\u67E5\u6709\u7121\u53EF\u66F4\u65B0\u7248\u672C +windowBodyNewVersionUnknown=\u767C\u751F\u932F\u8AA4\n\u53EF\u80FD\u7DB2\u8DEF\u4E0D\u53EF\u7528\u6216\u8A0A\u865F\u4E0D\u8DB3,\u6216\u8005\u7121\u6CD5\u9023\u4E0AGitHub\u5B98\u7DB2\u4F3A\u670D\u5668 +windowBodyNewVersionNOTAval=\u76EE\u524D\u4F7F\u7528\u7684\u7A0B\u5F0F\u5DF2\u662F\u6700\u65B0\u7248\u672C +tab2_Cb_AllowXciNszXcz=\u5141\u8A31Awoo\u6A21\u5F0F\u6642\u9078\u53D6XCI / NSZ / XCZ \u6A94\u6848\u683C\u5F0F +tab2_Lbl_AllowXciNszXczDesc=\u6B64\u8A2D\u5B9A\u5C08\u70BA\u652F\u63F4XCI/NSZ/XCZ\u6A94\u6848\u683C\u5F0F\u8207Tinfoil\u50B3\u8F38\u5354\u8B70\u7684\u7B2C\u4E09\u65B9\u7A0B\u5F0F\u4F7F\u7528. \u5982\u4E0D\u78BA\u5B9A,\u8ACB\u52FF\u8B8A\u66F4\u6B64\u9805\u8A2D\u5B9A. \u4F7F\u7528Awoo Installer\u8ACB\u555F\u7528\u6B64\u8A2D\u5B9A. +tab2_Lbl_Language=\u4ECB\u9762\u8A9E\u7CFB +windowBodyRestartToApplyLang=\u8ACB\u91CD\u65B0\u555F\u52D5\u7A0B\u5F0F\u4EE5\u5957\u7528\u8B8A\u66F4\u7684\u8A2D\u5B9A. +btn_OpenSplitFile=\u9078\u64C7\u5206\u5272\u7684NSP +tab2_Lbl_ApplicationSettings=\u4E3B\u8981\u8A2D\u5B9A +tabSplMrg_Lbl_SplitNMergeTitle=\u5206\u5272&\u5408\u4F75\u6A94\u6848\u5DE5\u5177 +tabSplMrg_RadioBtn_Split=\u5206\u5272&\u5408\u4F75\u6A94\u6848\u5DE5\u5177 +tabSplMrg_RadioBtn_Merge=\u5408\u4F75 +tabSplMrg_Txt_File=\u6A94\u6848: +tabSplMrg_Txt_Folder=\u5206\u5272\u6A94\u6848(\u8CC7\u6599\u593E): +tabSplMrg_Btn_SelectFile=\u9078\u64C7\u6A94\u6848 +tabSplMrg_Btn_SelectFolder=\u9078\u64C7\u8CC7\u6599\u593E +tabSplMrg_Lbl_SaveToLocation=\u5132\u5B58\u8DEF\u5F91: +tabSplMrg_Btn_ChangeSaveToLocation=\u8B8A\u66F4 +tabSplMrg_Btn_Convert=\u8F49\u6A94 +windowTitleError=\u932F\u8AA4 +windowBodyPleaseFinishTransfersFirst=\u7576\u7A0B\u5F0F\u6B63\u5728\u8655\u7406USB/\u7DB2\u8DEF\u5B89\u88DD\u6642\u7121\u6CD5\u540C\u6642\u57F7\u884C\u5206\u5272/\u5408\u4F75\u6A94\u6848. \u5982\u9700\u7E7C\u7E8C,\u5FC5\u9808\u4E2D\u65B7\u76EE\u524D\u7684\u50B3\u8F38. +done_txt=\u5B8C\u6210! failure_txt=\u5931\u6557 -btn_Select=\u9078\u64c7 -btn_InjectPayloader=\u6ce8\u5165payload -tabNXDT_Btn_Start=\u958b\u59cb! -tab2_Btn_InstallDrivers=\u4e0b\u8f09\u4e26\u5b89\u88dd\u9a45\u52d5\u7a0b\u5f0f -windowTitleDownloadDrivers=\u4e0b\u8f09\u4e26\u5b89\u88dd\u9a45\u52d5\u7a0b\u5f0f -windowBodyDownloadDrivers=\u6b63\u5728\u4e0b\u8f09\u9a45\u52d5\u7a0b\u5f0f (libusbK v3.0.7.0)... -btn_Cancel=\u53d6\u6d88 -btn_Close=\u95dc\u9589 -tab2_Cb_GlVersion=GoldLeaf\u7248\u672c -tab2_Cb_GLshowNspOnly=\u5728GoldLeaf\u5167\u50c5\u986f\u793a*.nsp\u6a94\u6848 -windowBodyPleaseStopOtherProcessFirst=\u5982\u8981\u57f7\u884c\u76ee\u524d\u7684\u64cd\u4f5c\u7a0b\u5e8f,\u8acb\u5148\u505c\u6b62\u5176\u4ed6\u6b63\u5728\u8655\u7406\u7684\u7a0b\u5e8f. -tab2_Cb_foldersSelectorForRoms=\u9078\u64c7\u6a94\u6848\u6642\u7531\u539f\u5148\u500b\u5225\u9078\u53d6\u8b8a\u66f4\u70ba\u6307\u5b9a\u8cc7\u6599\u593e\u5167\u7684\u6240\u6709\u7b26\u5408\u6a94\u6848. -tab2_Cb_foldersSelectorForRomsDesc=\u555f\u7528\u6b64\u8a2d\u5b9a\u5f8c,\u5c07\u8b8a\u66f4'\u904a\u6232\u63a7\u5236\u5668'\u5206\u9801\u4e0b\u65b9\u7684'\u9078\u64c7\u6a94\u6848'\u6309\u9215\u529f\u80fd: \u7531\u539f\u5148\u7684\u500b\u5225\u6a94\u6848\u9032\u884c\u9010\u4e00\u9078\u53d6\uff0c\u53d6\u4ee3\u70ba\u4e00\u6b21\u52a0\u5165\u6307\u5b9a\u8cc7\u6599\u593e\u5167\u7b26\u5408\u7684\u6240\u6709\u6a94\u6848. -windowTitleAddingFiles=\u6b63\u5728\u52a0\u5165\u4f47\u5217... -windowBodyFilesScanned=\u6a94\u6848\u5df2\u6383\u63cf:%25d\n \u5df2\u52a0\u5165: %25d -tab2_Lbl_AwooBlockTitle=Awoo Installer \u8207\u540c\u985e\u578b\u7a0b\u5f0f +btn_Select=\u9078\u64C7 +btn_InjectPayloader=\u6CE8\u5165payload +tabNXDT_Btn_Start=\u958B\u59CB! +tab2_Btn_InstallDrivers=\u4E0B\u8F09\u4E26\u5B89\u88DD\u9A45\u52D5\u7A0B\u5F0F +windowTitleDownloadDrivers=\u4E0B\u8F09\u4E26\u5B89\u88DD\u9A45\u52D5\u7A0B\u5F0F +windowBodyDownloadDrivers=\u6B63\u5728\u4E0B\u8F09\u9A45\u52D5\u7A0B\u5F0F (libusbK v3.0.7.0)... +btn_Cancel=\u53D6\u6D88 +btn_Close=\u95DC\u9589 +tab2_Cb_GlVersion=GoldLeaf\u7248\u672C +tab2_Cb_GLshowNspOnly=\u5728GoldLeaf\u5167\u50C5\u986F\u793A*.nsp\u6A94\u6848 +windowBodyPleaseStopOtherProcessFirst=\u5982\u8981\u57F7\u884C\u76EE\u524D\u7684\u64CD\u4F5C\u7A0B\u5E8F,\u8ACB\u5148\u505C\u6B62\u5176\u4ED6\u6B63\u5728\u8655\u7406\u7684\u7A0B\u5E8F. +tab2_Cb_foldersSelectorForRoms=\u9078\u64C7\u6A94\u6848\u6642\u7531\u539F\u5148\u500B\u5225\u9078\u53D6\u8B8A\u66F4\u70BA\u6307\u5B9A\u8CC7\u6599\u593E\u5167\u7684\u6240\u6709\u7B26\u5408\u6A94\u6848. +tab2_Cb_foldersSelectorForRomsDesc=\u555F\u7528\u6B64\u8A2D\u5B9A\u5F8C,\u5C07\u8B8A\u66F4'\u904A\u6232\u63A7\u5236\u5668'\u5206\u9801\u4E0B\u65B9\u7684'\u9078\u64C7\u6A94\u6848'\u6309\u9215\u529F\u80FD: \u7531\u539F\u5148\u7684\u500B\u5225\u6A94\u6848\u9032\u884C\u9010\u4E00\u9078\u53D6\uFF0C\u53D6\u4EE3\u70BA\u4E00\u6B21\u52A0\u5165\u6307\u5B9A\u8CC7\u6599\u593E\u5167\u7B26\u5408\u7684\u6240\u6709\u6A94\u6848. +windowTitleAddingFiles=\u6B63\u5728\u52A0\u5165\u4F47\u5217... +windowBodyFilesScanned=\u6A94\u6848\u5DF2\u6383\u63CF:%25d\n \u5DF2\u52A0\u5165: %25d +tab2_Lbl_AwooBlockTitle=Awoo Installer \u8207\u540C\u985E\u578B\u7A0B\u5F0F tabRcm_Lbl_Payload=Payload: -tabRcm_Lbl_FuseeGelee=Fus\u00e9e Gel\u00e9e RCM +tabRcm_Lbl_FuseeGelee=Fus\u00E9e Gel\u00E9e RCM +