/*
* LZ10 quicktool
* is really just a quick UI (by voliol) over compressors/decompressors
* written for other projects by Nick Kraayenbrink and Aurum respectively,
* so they deserve most of the kudos.
* The below licence should be compatible with both sources, and is thus
* what applies to this code.
*/
/*
* Copyright (C) 2022 voliol
*
* LZ10 quicktool 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.
*
* LZ10 quicktool 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 this program. If not, see .
*/
import java.util.ArrayList;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Main extends Application {
private TextArea uncompressedTextArea = new TextArea();
private TextArea compressedTextArea = new TextArea();
private Label feedbackLabel = new Label();
public static void main(String[] args) {
launch();
}
/*
* Returns empty array when the string is non-readable.
*/
private static byte[] hexToBytes(String s) {
ArrayList hexOnly = new ArrayList<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c >= '0' && c <= '9') {
hexOnly.add(c - '0');
} else if (c >= 'A' && c <= 'F') {
hexOnly.add(c - 'A' + 10);
} else if (c >= 'a' && c <= 'f') {
hexOnly.add(c - 'a' + 10);
}
}
if (hexOnly.size() % 2 != 0) {
return new byte[0];
}
byte[] bytes = new byte[hexOnly.size() / 2];
for (int i = 0; i < hexOnly.size() / 2; i++) {
bytes[i] = (byte) ((hexOnly.get(i * 2) << 4) + hexOnly.get(i * 2 + 1));
}
return bytes;
}
/*
* Sourced from:
* https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-
* hex-string-in-java
*/
private static String bytesToHex(byte[] bytes) {
final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[bytes.length * 3];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 3] = HEX_ARRAY[v >>> 4];
hexChars[j * 3 + 1] = HEX_ARRAY[v & 0x0F];
hexChars[j * 3 + 2] = ' ';
}
return new String(hexChars);
}
private static byte[] padBytes(byte[] bytes) {
final int PAD_AMOUNT = 4;
byte[] padded = new byte[bytes.length+PAD_AMOUNT];
for (int i=0; i < bytes.length; i++) {
padded[i] = bytes[i];
}
return padded;
}
@Override
public void start(Stage primaryStage) throws Exception {
Pane mainPane = new Pane();
GridPane grid = setupGrid();
mainPane.getChildren().add(grid);
primaryStage.setScene(new Scene(mainPane));
primaryStage.setTitle("LZ10 quicktool");
primaryStage.show();
}
private GridPane setupGrid() {
GridPane grid = new GridPane();
grid.addRow(0, new Label("Uncompressed:"), new Label("LZ10 Compressed:"));
uncompressedTextArea.setWrapText(true);
compressedTextArea.setWrapText(true);
grid.addRow(1, uncompressedTextArea, compressedTextArea);
Button compressButton = new Button("Compress =>");
compressButton.setOnAction(new CompressHandler());
Button uncompressButton = new Button("<= Decompress");
uncompressButton.setOnAction(new DecompressHandler());
grid.addRow(2, compressButton, uncompressButton);
grid.add(feedbackLabel, 0, 3, 2, 1);
GridPane.setHalignment(feedbackLabel, HPos.CENTER);
return grid;
}
private class CompressHandler implements EventHandler {
@Override
public void handle(ActionEvent event) {
String in = uncompressedTextArea.getText();
byte[] uncompressed = hexToBytes(in);
if (uncompressed.length == 0) {
feedbackLabel.setText("Error: invalid/no hex values in \"Uncompressed\" text field.");
} else {
byte[] compressed = DSCmp.compressLZ10(hexToBytes(in));
compressedTextArea.setText(bytesToHex(compressed));
uncompressedTextArea.setText(bytesToHex(uncompressed));
feedbackLabel.setText("Compression successful!");
}
}
}
private class DecompressHandler implements EventHandler {
@Override
public void handle(ActionEvent event) {
String in = compressedTextArea.getText();
byte[] compressed = hexToBytes(in);
if (compressed.length == 0) {
feedbackLabel.setText("Error: invalid/no hex values in \"Compressed\" text field.");
} else {
try {
// for some reason DSDecmp.Decompress wants some padding at the end of the bytes, this supplies it
byte[] padded = padBytes(hexToBytes(in));
byte[] decompressed = DSDecmp.Decompress(padded);
String out = bytesToHex(decompressed);
uncompressedTextArea.setText(out);
feedbackLabel.setText("Uncompression successful!");
} catch (Exception e) {
feedbackLabel.setText("Error: could not decompress for unknown reason");
}
}
}
}
}