From 643f09fd9e86dc69446136baa5cd372b63bb8bbd Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Mon, 19 Aug 2019 04:55:42 +0300 Subject: [PATCH] PFSEncryptedProvider could provide pipe with content data --- .../konogonka/Tools/NCA/NCAContentPFS0.java | 60 +++- .../Tools/PFS0/PFS0EncryptedProvider.java | 312 ++++++++++-------- .../konogonka/Tools/PFS0/PFS0Provider.java | 2 +- .../konogonka/Workers/NspXciExtractor.java | 5 + .../konogonka/ctraes/AesCtrDecryptSimple.java | 2 +- .../java/konogonka/xtsaes/XTSAESCipher.java | 2 +- src/main/java/konogonka/xtsaes/XTSCore.java | 2 +- src/main/java/konogonka/xtsaes/XTSTweak.java | 2 +- src/main/resources/locale.properties | 4 +- src/main/resources/locale_fra.properties | 4 +- src/main/resources/locale_rus.properties | 4 +- src/main/resources/locale_ukr.properties | 4 +- src/main/resources/res/app_light.css | 18 +- 13 files changed, 237 insertions(+), 184 deletions(-) diff --git a/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java b/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java index 6f012d1..64e8102 100644 --- a/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java +++ b/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java @@ -44,7 +44,7 @@ public class NCAContentPFS0 { // Get pfs0 pfs0 = new PFS0Provider(file, pfs0Location); } - // If encrypted (regular) + // If encrypted regular [ 0x03 ] else if (ncaSectionBlock.getCryptoType() == 0x03){ new CryptoSection03(file, offsetPosition, @@ -59,7 +59,7 @@ public class NCAContentPFS0 { } } else if (ncaSectionBlock.getSuperBlockIVFC() != null){ - // TODO + // TODO } else { return; // TODO: FIX THIS STUFF @@ -105,7 +105,13 @@ public class NCAContentPFS0 { streamInp, ncaSectionBlock.getSuperBlockPFS0().getPfs0offset(), ncaSectionBlock.getSuperBlockPFS0().getHashTableOffset(), - ncaSectionBlock.getSuperBlockPFS0().getHashTableSize() + ncaSectionBlock.getSuperBlockPFS0().getHashTableSize(), + offsetPosition, + file, + decryptedKey, + ncaSectionBlock.getSectionCTR(), + mediaStartOffset, + mediaEndOffset )); pThread.start(); // Decrypt data @@ -126,18 +132,6 @@ public class NCAContentPFS0 { pThread.join(); streamOut.close(); raf.close(); - // TODO: re-write - if (pfs0 != null){ - PFS0EncryptedProvider pfs0enc = (PFS0EncryptedProvider)pfs0; - pfs0enc.setMeta( - offsetPosition, - file, - decryptedKey, - ncaSectionBlock.getSectionCTR(), - mediaStartOffset, - mediaEndOffset - ); - } //****************************************___DEBUG___******************************************************* /* File contentFile = new File("/tmp/decryptedNCA0block_"+offsetPosition+".pfs0"); @@ -180,13 +174,39 @@ public class NCAContentPFS0 { long hashTableRecordsCount; long pfs0offset; + private long MetaOffsetPositionInFile; + private File MetaFileWithEncPFS0; + private byte[] MetaKey; + private byte[] MetaSectionCTR; + private long MetaMediaStartOffset; + private long MetaMediaEndOffset; - ParseThread(PipedInputStream pipedInputStream, long pfs0offset, long hashTableOffset, long hashTableSize){ + + ParseThread(PipedInputStream pipedInputStream, + long pfs0offset, + long hashTableOffset, + long hashTableSize, + + long MetaOffsetPositionInFile, + File MetaFileWithEncPFS0, + byte[] MetaKey, + byte[] MetaSectionCTR, + long MetaMediaStartOffset, + long MetaMediaEndOffset + ){ this.pipedInputStream = pipedInputStream; this.hashTableOffset = hashTableOffset; this.hashTableSize = hashTableSize; this.hashTableRecordsCount = hashTableSize / 0x20; this.pfs0offset = pfs0offset; + + this.MetaOffsetPositionInFile = MetaOffsetPositionInFile; + this.MetaFileWithEncPFS0 = MetaFileWithEncPFS0; + this.MetaKey = MetaKey; + this.MetaSectionCTR = MetaSectionCTR; + this.MetaMediaStartOffset = MetaMediaStartOffset; + this.MetaMediaEndOffset = MetaMediaEndOffset; + } @Override @@ -223,7 +243,13 @@ public class NCAContentPFS0 { counter += toSkip; } //--------------------------------------------------------- - pfs0 = new PFS0EncryptedProvider(pipedInputStream, counter); + pfs0 = new PFS0EncryptedProvider(pipedInputStream, counter, + MetaOffsetPositionInFile, + MetaFileWithEncPFS0, + MetaKey, + MetaSectionCTR, + MetaMediaStartOffset, + MetaMediaEndOffset); pipedInputStream.close(); } catch (Exception e){ diff --git a/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java b/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java index 31159b7..2634bc1 100644 --- a/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java +++ b/src/main/java/konogonka/Tools/PFS0/PFS0EncryptedProvider.java @@ -9,7 +9,7 @@ import java.util.Arrays; import static konogonka.LoperConverter.*; public class PFS0EncryptedProvider implements IPFS0Provider{ - private long rawFileDataStart; // For this class is pointing to data start position relative to media block start + private long rawFileDataStart; // Always -1 @ PFS0EncryptedProvider private String magic; private int filesCount; @@ -21,138 +21,28 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ private long rawBlockDataStart; - private PFS0DecryptedStreamProvider pfs0DecryptedStreamProvider; + private long offsetPositionInFile; + private File file; + private byte[] key; + private byte[] sectionCTR; + private long mediaStartOffset; + private long mediaEndOffset; - // Let's do some fuck - private class PFS0DecryptedStreamProvider{ - private long mediaStartOffset; // * 0x200 - private long mediaEndOffset; - - - private RandomAccessFile raf; - private PipedOutputStream streamOut; - private PipedInputStream streamInp; - private AesCtrDecryptSimple aesCtrDecryptSimple; // if null, then exception happened. - - public PipedInputStream getPipedInputStream(){ return streamInp; } - - - public void getStarted(PFS0subFile subFile) throws Exception{ - - System.out.println("rawBlockDataStart (PFS0 Start): "+rawBlockDataStart); - System.out.println("Skip blocks: "+rawBlockDataStart/0x200); // aesCtrDecryptSimple.skip(THIS) - System.out.println("Skip bytes: "+ (rawBlockDataStart-(rawBlockDataStart/0x200)*0x200)); // write to stream after skiping THIS - - // DBG START - File contentFile = new File("/tmp/pfs0-NCA0block.pfs0"); - BufferedOutputStream extractedFileOS = new BufferedOutputStream(new FileOutputStream(contentFile)); - // DBG END - long mediaBlockSize = mediaEndOffset - mediaStartOffset; - byte[] encryptedBlock; - byte[] dectyptedBlock; - - // Skip full-size blocks of 512 bytes that we don't need and start decryption from required one - long startFromBlock = rawBlockDataStart/0x200; - if (startFromBlock > 0) { - aesCtrDecryptSimple.skipNext(startFromBlock); - raf.seek(raf.getFilePointer() + (startFromBlock*0x200)); - } - // Since our data could be located in position with some offset from the decrypted block, let's skip bytes left - int skipBytes = (int)(rawBlockDataStart-(rawBlockDataStart/0x200)*0x200); - if (skipBytes > 0){ - encryptedBlock = new byte[0x200]; - if (raf.read(encryptedBlock) != -1){ - dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); - try { - // DBG START - extractedFileOS.write(dectyptedBlock, skipBytes, 0x200-skipBytes); - // DBG END - //streamOut.write(dectyptedBlock, skipBytes, 0x200); - } - catch (IOException e){ - System.out.println("Exception @extract 1st bock"); - } - } - startFromBlock++; - } - - for (long i = startFromBlock; i < mediaBlockSize; i++){ - encryptedBlock = new byte[0x200]; - if (raf.read(encryptedBlock) != -1){ - //dectyptedBlock = aesCtr.decrypt(encryptedBlock); - dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); - // Writing decrypted data to pipe - try { - // DBG START - extractedFileOS.write(dectyptedBlock); - // DBG END - //streamOut.write(dectyptedBlock); - } - catch (IOException e){ - System.out.println("Exception @extract"); - break; - } - } - } - - // DBG START - extractedFileOS.close(); - // DBG END - } - - PFS0DecryptedStreamProvider(File file, - long rawBlockDataStart, - long offsetPositionInFile, - byte[] key, - byte[] sectionCTR, - long mediaStartOffset, - long mediaEndOffset - ){ - this.mediaStartOffset = mediaStartOffset; - this.mediaEndOffset = mediaEndOffset; - - try { - this.raf = new RandomAccessFile(file, "r"); - this.raf.seek(offsetPositionInFile + (mediaStartOffset * 0x200)); - this.aesCtrDecryptSimple = new AesCtrDecryptSimple(key, sectionCTR, mediaStartOffset * 0x200); - - this.streamOut = new PipedOutputStream(); - this.streamInp = new PipedInputStream(streamOut); - } - catch (Exception e) { - e.printStackTrace(); - } - } - } - // TODO: simplify - public void setMeta( - long offsetPositionInFile, - File fileWithEncPFS0, - byte[] key, - byte[] sectionCTR, - long mediaStartOffset, - long mediaEndOffset - ){ - this.pfs0DecryptedStreamProvider = new PFS0DecryptedStreamProvider( - fileWithEncPFS0, - rawBlockDataStart, - offsetPositionInFile, - key, - sectionCTR, - mediaStartOffset, - mediaEndOffset - ); - try{ - pfs0DecryptedStreamProvider.getStarted(pfs0subFiles[0]); - } - catch (Exception e){ - e.printStackTrace(); - } - } - //--------------------------------------- - public PFS0EncryptedProvider(PipedInputStream pipedInputStream, - long pfs0offsetPosition + public PFS0EncryptedProvider(PipedInputStream pipedInputStream, long pfs0offsetPosition, + long offsetPositionInFile, + File fileWithEncPFS0, + byte[] key, + byte[] sectionCTR, + long mediaStartOffset, + long mediaEndOffset ) throws Exception{ + // Populate 'meta' data that is needed for getProviderSubFilePipedInpStream() + this.offsetPositionInFile = offsetPositionInFile; + this.file = fileWithEncPFS0; + this.key = key; + this.sectionCTR = sectionCTR; + this.mediaStartOffset = mediaStartOffset; + this.mediaEndOffset = mediaEndOffset; // pfs0offsetPosition is a position relative to Media block. Lets add pfs0 'header's' bytes count and get raw data start position in media block rawFileDataStart = -1; // Set -1 for PFS0EncryptedProvider // Detect raw data start position using next var @@ -164,7 +54,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ for (int i = 0; i < 0x10; i++){ int currentByte = pipedInputStream.read(); if (currentByte == -1) { - throw new Exception("PFS0: Reading stream suddenly ended while trying to read starting 0x10 bytes"); + throw new Exception("PFS0EncryptedProvider: Reading stream suddenly ended while trying to read starting 0x10 bytes"); } fileStartingBytes[i] = (byte)currentByte; } @@ -173,17 +63,17 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ // Check PFS0Provider magic = new String(fileStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII); if (! magic.equals("PFS0")){ - throw new Exception("PFS0Provider: Bad magic"); + throw new Exception("PFS0EncryptedProvider: Bad magic"); } // Get files count filesCount = getLEint(fileStartingBytes, 0x4); if (filesCount <= 0 ) { - throw new Exception("PFS0Provider: Files count is too small"); + throw new Exception("PFS0EncryptedProvider: Files count is too small"); } // Get string table stringTableSize = getLEint(fileStartingBytes, 0x8); if (stringTableSize <= 0 ){ - throw new Exception("PFS0Provider: String table is too small"); + throw new Exception("PFS0EncryptedProvider: String table is too small"); } padding = Arrays.copyOfRange(fileStartingBytes, 0xc, 0x10); //--------------------------------------------------------------------------------------------------------- @@ -199,7 +89,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ for (int j = 0; j < 0x18; j++){ int currentByte = pipedInputStream.read(); if (currentByte == -1) { - throw new Exception("PFS0: Reading stream suddenly ended while trying to read File Entry Table #"+i); + throw new Exception("PFS0EncryptedProvider: Reading stream suddenly ended while trying to read File Entry Table #"+i); } fileEntryTable[j] = (byte)currentByte; } @@ -218,7 +108,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ for (int i = 0; i < stringTableSize; i++){ int currentByte = pipedInputStream.read(); if (currentByte == -1) { - throw new Exception("PFS0: Reading stream suddenly ended while trying to read string table"); + throw new Exception("PFS0EncryptedProvider: Reading stream suddenly ended while trying to read string table"); } stringTbl[i] = (byte)currentByte; } @@ -239,7 +129,6 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ zeroBytes[i] ); } - } @Override @@ -257,15 +146,148 @@ public class PFS0EncryptedProvider implements IPFS0Provider{ @Override public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; } - @Override - public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) { - //TODO - return null; - } - @Override public PipedInputStream getProviderSubFilePipedInpStream(int subFileNumber) { - //TODO + if (subFileNumber >= pfs0subFiles.length) { + System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Requested sub file doesn't exists"); + return null; + } + /*/------------------------------------------------------------------ + System.out.println("Raw Block Data Start (PFS0 Start): " + rawBlockDataStart); + System.out.println("Skipped blocks: " + rawBlockDataStart/0x200); // aesCtrDecryptSimple.skip(THIS) + System.out.println("Skip bytes: " + (rawBlockDataStart-(rawBlockDataStart/0x200)*0x200)); // write to stream after skiping THIS + *///----------------------------------------------------------------- + Thread workerThread; + PipedOutputStream streamOut = new PipedOutputStream(); + + try{ + PipedInputStream streamIn = new PipedInputStream(streamOut); + workerThread = new Thread(() -> { + System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Executing thread"); + try { + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + // Let's store what we're about to skip + int skipBytes = (int) (offsetPositionInFile + (mediaStartOffset * 0x200)); + // Check if skip was successful + if (bis.skip(skipBytes) != skipBytes) { + System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipBytes); + return; + } + + AesCtrDecryptSimple aesCtrDecryptSimple = new AesCtrDecryptSimple(key, sectionCTR, mediaStartOffset * 0x200); + + byte[] encryptedBlock; + byte[] dectyptedBlock; + + //----------------------------- Pre-set: skip non-necessary data -------------------------------- + + long startBlock = (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) / 0x200; // <- pointing to place where actual data starts + + if (startBlock > 0) { + aesCtrDecryptSimple.skipNext(startBlock); + skipBytes = (int)(startBlock * 0x200); + if (bis.skip(skipBytes) != skipBytes) { + System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipBytes); + return; + } + } + + //----------------------------- Step 1: get starting bytes from the end of the junk block -------------------------------- + + // Since our data could be located in position with some offset from the decrypted block, let's skip bytes left. Considering the case when data is not aligned to block + skipBytes = (int) ( (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) - startBlock * 0x200); // <- How much bytes shall we skip to reach requested data start of sub-file + + if (skipBytes > 0) { + encryptedBlock = new byte[0x200]; + if (bis.read(encryptedBlock) == 0x200) { + dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); + // If we have extra-small file that is less then a block and even more + if ((0x200 - skipBytes) > pfs0subFiles[subFileNumber].getSize()){ + streamOut.write(dectyptedBlock, skipBytes, (int) pfs0subFiles[subFileNumber].getSize()); // safe cast + return; + } + else + streamOut.write(dectyptedBlock, skipBytes, 0x200 - skipBytes); + } + else { + System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); + return; + } + startBlock++; + } + + long endBlock = pfs0subFiles[subFileNumber].getSize() / 0x200 + startBlock; // <- pointing to place where any data related to this media-block ends + + //----------------------------- Step 2: Detect if we have junk data on the end of the final block -------------------------------- + int extraData = (int)(rawBlockDataStart+pfs0subFiles[subFileNumber].getOffset()+pfs0subFiles[subFileNumber].getSize() - (endBlock*0x200)); // safe cast + if (extraData < 0){ + endBlock--; + } + //----------------------------- Step 3: Read main part of data -------------------------------- + // Here we're reading main amount of bytes. We can read only less bytes. + while ( startBlock < endBlock) { + encryptedBlock = new byte[0x200]; + if (bis.read(encryptedBlock) == 0x200) { + //dectyptedBlock = aesCtr.decrypt(encryptedBlock); + dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); + // Writing decrypted data to pipe + streamOut.write(dectyptedBlock); + } + else { + System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from bock"); + return; + } + startBlock++; + } + //----------------------------- Step 4: Read what's left -------------------------------- + // Now we have to find out if data overlaps to one more extra block + if (extraData > 0){ // In case we didn't get what we want + encryptedBlock = new byte[0x200]; + if (bis.read(encryptedBlock) == 0x200) { + dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); + streamOut.write(dectyptedBlock, 0, extraData); + } + else { + System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); + return; + } + } + else if (extraData < 0){ // In case we can get more than we need + encryptedBlock = new byte[0x200]; + if (bis.read(encryptedBlock) == 0x200) { + dectyptedBlock = aesCtrDecryptSimple.dectyptNext(encryptedBlock); + streamOut.write(dectyptedBlock, 0, 0x200 + extraData); + } + else { + System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): Unable to get 512 bytes from 1st bock"); + return; + } + } + bis.close(); + streamOut.close(); + } + catch (Exception e){ + System.out.println("PFS0EncryptedProvider -> getProviderSubFilePipedInpStream(): "+e.getMessage()); + e.printStackTrace(); + } + System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Thread died"); + + + }); + workerThread.start(); + return streamIn; + } + catch (IOException ioe){ + System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to provide stream"); + return null; + } + } + @Override + public PipedInputStream getProviderSubFilePipedInpStream(String subFileName) { + for (int i = 0; i < pfs0subFiles.length; i++){ + if (pfs0subFiles[i].getName().equals(subFileName)) + return getProviderSubFilePipedInpStream(i); + } return null; } } diff --git a/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java b/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java index cbdcf36..bb200fc 100644 --- a/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java +++ b/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java @@ -10,7 +10,7 @@ import java.util.Arrays; import static konogonka.LoperConverter.*; public class PFS0Provider implements IPFS0Provider{ - private long rawFileDataStart; // If -1 then this PFS0 located @ encrypted region + private long rawFileDataStart; // Where data starts, excluding header, string table etc. private String magic; private int filesCount; diff --git a/src/main/java/konogonka/Workers/NspXciExtractor.java b/src/main/java/konogonka/Workers/NspXciExtractor.java index 1b2f4aa..b63af2f 100644 --- a/src/main/java/konogonka/Workers/NspXciExtractor.java +++ b/src/main/java/konogonka/Workers/NspXciExtractor.java @@ -54,6 +54,11 @@ public class NspXciExtractor extends Task { } //*** PROGRESS BAR DECORCATIONS END } + try { + logPrinter.updateProgress(1.0); + }catch (InterruptedException ie){ + getException().printStackTrace(); // TODO: Do something with this + } extractedFileBOS.close(); } catch (IOException ioe) { logPrinter.print("\tRead/Write error\n\t" + ioe.getMessage(), EMsgType.INFO); diff --git a/src/main/java/konogonka/ctraes/AesCtrDecryptSimple.java b/src/main/java/konogonka/ctraes/AesCtrDecryptSimple.java index de2067b..b43a2f9 100644 --- a/src/main/java/konogonka/ctraes/AesCtrDecryptSimple.java +++ b/src/main/java/konogonka/ctraes/AesCtrDecryptSimple.java @@ -38,7 +38,7 @@ public class AesCtrDecryptSimple { private void updateIV(long offset){ offset >>= 4; for (int i = 0; i < 0x8; i++){ - IVarray[0x10-i-1] = (byte)(offset & 0xff); // Note: issues could be here + IVarray[0x10-i-1] = (byte)(offset & 0xff); // Note: issues could be here offset >>= 8; } } diff --git a/src/main/java/konogonka/xtsaes/XTSAESCipher.java b/src/main/java/konogonka/xtsaes/XTSAESCipher.java index b75d09e..3e72d50 100644 --- a/src/main/java/konogonka/xtsaes/XTSAESCipher.java +++ b/src/main/java/konogonka/xtsaes/XTSAESCipher.java @@ -34,7 +34,7 @@ import java.util.function.LongFunction; * XTS-AES cipher with arbitrary (non 128-bit aligned) data unit lengths. * * @author Ahseya - * @author Dmitry Isaenko (updates for special usage) + * (updates for special usage by Dmitry Isaenko) */ @NotThreadSafe public class XTSAESCipher { diff --git a/src/main/java/konogonka/xtsaes/XTSCore.java b/src/main/java/konogonka/xtsaes/XTSCore.java index 32f7a84..bd81c9a 100644 --- a/src/main/java/konogonka/xtsaes/XTSCore.java +++ b/src/main/java/konogonka/xtsaes/XTSCore.java @@ -36,7 +36,7 @@ import java.util.Objects; * XTS core functions. * * @author Ahseya - * @author Dmitry Isaenko (updates for special usage) + * (updates for special usage by Dmitry Isaenko) */ @NotThreadSafe class XTSCore { diff --git a/src/main/java/konogonka/xtsaes/XTSTweak.java b/src/main/java/konogonka/xtsaes/XTSTweak.java index 3765c12..8aa4c5c 100644 --- a/src/main/java/konogonka/xtsaes/XTSTweak.java +++ b/src/main/java/konogonka/xtsaes/XTSTweak.java @@ -38,7 +38,7 @@ import java.util.function.LongFunction; * XTS tweak with pluggable tweak function. * * @author Ahseya - * @author Dmitry Isaenko (updates for special usage) + * (updates for special usage by Dmitry Isaenko) */ @NotThreadSafe class XTSTweak { diff --git a/src/main/resources/locale.properties b/src/main/resources/locale.properties index 9226f1b..bdbb7e2 100644 --- a/src/main/resources/locale.properties +++ b/src/main/resources/locale.properties @@ -3,9 +3,9 @@ btnAnalyze=Analyze lblNoFileSelected=No files selected. tableNumberLbl=# tableFileNameLbl=File name -tableSizeLbl=Size (kB) +tableSizeLbl=Size (b) tableUploadLbl=Extract? -tableOffsetLbl=Offset (kB) +tableOffsetLbl=Offset (B) btnExtract=Extract files btnLogShow=Log settings_SettingsName=Settings diff --git a/src/main/resources/locale_fra.properties b/src/main/resources/locale_fra.properties index 0af7755..4964468 100644 --- a/src/main/resources/locale_fra.properties +++ b/src/main/resources/locale_fra.properties @@ -2,10 +2,10 @@ btnFileOpen=Selectionner NSP/XCI/NCA btnAnalyze=Analyser lblNoFileSelected=Aucuns fichiers s\u00E9lectionn\u00E9s. tableUploadLbl=Extraire ? -tableSizeLbl=Taille (kB) +tableSizeLbl=Taille (b) tableFileNameLbl=Nom de fichier tableNumberLbl=# -tableOffsetLbl=D\u00E9calage (kB) +tableOffsetLbl=D\u00E9calage (B) btnExtract=Extraire les fichiers btnLogShow=B\u00FBche settings_SettingsName=R\u00E9glages diff --git a/src/main/resources/locale_rus.properties b/src/main/resources/locale_rus.properties index 9fcdaa4..c1280f8 100644 --- a/src/main/resources/locale_rus.properties +++ b/src/main/resources/locale_rus.properties @@ -2,10 +2,10 @@ btnFileOpen=\u0412\u044B\u0431\u0440\u0430\u0442\u044C NSP/XCI/NCA btnAnalyze=\u0410\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C lblNoFileSelected=\u0424\u0430\u0439\u043B\u044B \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B. tableUploadLbl=\u0420\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u0442\u044C? -tableSizeLbl=\u0420\u0430\u0437\u043C\u0435\u0440 (\u043A\u0411) +tableSizeLbl=\u0420\u0430\u0437\u043C\u0435\u0440 (\u0411) tableFileNameLbl=\u0418\u043C\u044F \u0444\u0430\u0439\u043B\u0430 tableNumberLbl=\u2116 -tableOffsetLbl=\u0421\u043C\u0435\u0449\u0435\u043D\u0438\u0435 (\u043A\u0411) +tableOffsetLbl=\u0421\u043C\u0435\u0449\u0435\u043D\u0438\u0435 (\u0411) btnExtract=\u0420\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B btnLogShow=\u041B\u043E\u0433 settings_SettingsName=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 diff --git a/src/main/resources/locale_ukr.properties b/src/main/resources/locale_ukr.properties index 9115495..356c1b8 100644 --- a/src/main/resources/locale_ukr.properties +++ b/src/main/resources/locale_ukr.properties @@ -3,9 +3,9 @@ btnAnalyze=\u0410\u043D\u0430\u043B\u0456\u0437\u0443\u0432\u0430\u0442\u0438 lblNoFileSelected=\u0424\u0430\u0439\u043B\u0438 \u043D\u0435 \u0432\u0438\u0431\u0440\u0430\u043D\u0456. tableNumberLbl=\u2116 tableFileNameLbl=\u0406\u043C'\u044F \u0444\u0430\u0439\u043B\u0443 -tableSizeLbl=\u0420\u043E\u0437\u043C\u0456\u0440 (\u043A\u0411) +tableSizeLbl=\u0420\u043E\u0437\u043C\u0456\u0440 (\u0411) tableUploadLbl=\u0420\u043E\u0437\u043F\u0430\u043A\u043E\u0432\u0443\u0432\u0430\u0442\u0438? -tableOffsetLbl=\u0417\u043C\u0456\u0449\u0435\u043D\u043D\u044F (\u043A\u0411) +tableOffsetLbl=\u0417\u043C\u0456\u0449\u0435\u043D\u043D\u044F (\u0411) btnExtract=\u0420\u043E\u0437\u043F\u0430\u043A\u0443\u0432\u0430\u0442\u0438 \u0444\u0430\u0439\u043B\u0438 btnLogShow=\u041B\u043E\u0433 settings_SettingsName=\u041D\u0430\u043B\u0430\u0448\u0442\u0443\u0432\u0430\u043D\u043D\u044F diff --git a/src/main/resources/res/app_light.css b/src/main/resources/res/app_light.css index 72f1e1a..3dbf1d0 100644 --- a/src/main/resources/res/app_light.css +++ b/src/main/resources/res/app_light.css @@ -17,7 +17,7 @@ -fx-border-color: #0d98ba; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #2c2c2c; } @@ -30,7 +30,7 @@ -fx-border-color: #959595; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #bbbbbb; } @@ -39,7 +39,7 @@ -fx-border-color: #0d98ba; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #ffffff; } .button:focused, .choice-box:focused{ @@ -47,7 +47,7 @@ -fx-border-color: #0d98ba; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #2c2c2c; } @@ -56,7 +56,7 @@ -fx-border-color: #007cad; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #ffffff; } // -========================+ Button RED =====================- @@ -68,7 +68,7 @@ -fx-border-color: #e34234; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #2c2c2c; } @@ -77,7 +77,7 @@ -fx-border-color: #e34234; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #ffffff; } .buttonRed:focused{ @@ -85,7 +85,7 @@ -fx-border-color: #cc0605; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #2c2c2c; } @@ -94,7 +94,7 @@ -fx-border-color: #cc0605; -fx-background-radius: 5; -fx-border-radius: 5; - -fx-border-width: 2; + -fx-border-width: 1; -fx-text-fill: #ffffff; } // -========================+ TextArea =====================-