mirror of
https://github.com/sirjonasxx/G-Earth.git
synced 2024-11-23 08:50:52 +01:00
packetlogger hexadecimal packet options
This commit is contained in:
parent
c968a24e8d
commit
87fdca03ac
@ -204,6 +204,11 @@
|
|||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>2.10.0</version>
|
<version>2.10.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>at.favre.lib</groupId>
|
||||||
|
<artifactId>bytes</artifactId>
|
||||||
|
<version>1.5.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package gearth.services.internal_extensions.uilogger;
|
package gearth.services.internal_extensions.uilogger;
|
||||||
|
|
||||||
|
import at.favre.lib.bytes.Bytes;
|
||||||
import gearth.misc.Cacher;
|
import gearth.misc.Cacher;
|
||||||
|
import gearth.services.internal_extensions.uilogger.hexdumper.Hexdump;
|
||||||
import gearth.services.packet_info.PacketInfo;
|
import gearth.services.packet_info.PacketInfo;
|
||||||
import gearth.services.packet_info.PacketInfoManager;
|
import gearth.services.packet_info.PacketInfoManager;
|
||||||
import gearth.protocol.HMessage;
|
import gearth.protocol.HMessage;
|
||||||
@ -16,7 +18,8 @@ import javafx.scene.layout.FlowPane;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.fxmisc.flowless.VirtualizedScrollPane;
|
import org.fxmisc.flowless.VirtualizedScrollPane;
|
||||||
import org.fxmisc.richtext.StyleClassedTextArea;
|
import org.fxmisc.richtext.StyleClassedTextArea;
|
||||||
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
import org.fxmisc.richtext.StyledTextArea;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpansBuilder;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -43,6 +46,7 @@ public class UiLoggerController implements Initializable {
|
|||||||
public CheckMenuItem chkSkipBigPackets;
|
public CheckMenuItem chkSkipBigPackets;
|
||||||
public CheckMenuItem chkMessageName;
|
public CheckMenuItem chkMessageName;
|
||||||
public CheckMenuItem chkMessageHash;
|
public CheckMenuItem chkMessageHash;
|
||||||
|
public CheckMenuItem chkMessageId;
|
||||||
public Label lblPacketInfo;
|
public Label lblPacketInfo;
|
||||||
public CheckMenuItem chkUseNewStructures;
|
public CheckMenuItem chkUseNewStructures;
|
||||||
public CheckMenuItem chkAlwaysOnTop;
|
public CheckMenuItem chkAlwaysOnTop;
|
||||||
@ -66,6 +70,11 @@ public class UiLoggerController implements Initializable {
|
|||||||
public Label lblFiltered;
|
public Label lblFiltered;
|
||||||
public CheckMenuItem chkTimestamp;
|
public CheckMenuItem chkTimestamp;
|
||||||
|
|
||||||
|
public RadioMenuItem chkReprLegacy;
|
||||||
|
public RadioMenuItem chkReprHex;
|
||||||
|
public RadioMenuItem chkReprRawHex;
|
||||||
|
public RadioMenuItem chkReprNone;
|
||||||
|
|
||||||
private Map<Integer, LinkedList<Long>> filterTimestamps = new HashMap<>();
|
private Map<Integer, LinkedList<Long>> filterTimestamps = new HashMap<>();
|
||||||
|
|
||||||
private StyleClassedTextArea area;
|
private StyleClassedTextArea area;
|
||||||
@ -123,10 +132,10 @@ public class UiLoggerController implements Initializable {
|
|||||||
public void initialize(URL arg0, ResourceBundle arg1) {
|
public void initialize(URL arg0, ResourceBundle arg1) {
|
||||||
allMenuItems.addAll(Arrays.asList(
|
allMenuItems.addAll(Arrays.asList(
|
||||||
chkViewIncoming, chkViewOutgoing, chkDisplayStructure, chkAutoscroll,
|
chkViewIncoming, chkViewOutgoing, chkDisplayStructure, chkAutoscroll,
|
||||||
chkSkipBigPackets, chkMessageName, chkMessageHash, chkUseNewStructures,
|
chkSkipBigPackets, chkMessageName, chkMessageHash, chkMessageId, chkUseNewStructures,
|
||||||
chkOpenOnConnect, chkResetOnConnect, chkHideOnDisconnect, chkResetOnDisconnect,
|
chkOpenOnConnect, chkResetOnConnect, chkHideOnDisconnect, chkResetOnDisconnect,
|
||||||
chkAntiSpam_none, chkAntiSpam_low, chkAntiSpam_medium, chkAntiSpam_high, chkAntiSpam_ultra,
|
chkAntiSpam_none, chkAntiSpam_low, chkAntiSpam_medium, chkAntiSpam_high, chkAntiSpam_ultra,
|
||||||
chkTimestamp
|
chkTimestamp, chkReprHex, chkReprLegacy, chkReprRawHex, chkReprNone
|
||||||
));
|
));
|
||||||
loadAllMenuItems();
|
loadAllMenuItems();
|
||||||
|
|
||||||
@ -218,6 +227,9 @@ public class UiLoggerController implements Initializable {
|
|||||||
|
|
||||||
boolean packetInfoAvailable = uiLogger.getPacketInfoManager().getPacketInfoList().size() > 0;
|
boolean packetInfoAvailable = uiLogger.getPacketInfoManager().getPacketInfoList().size() > 0;
|
||||||
|
|
||||||
|
|
||||||
|
boolean addedSomeMessageInfo = false;
|
||||||
|
|
||||||
if ((chkMessageName.isSelected() || chkMessageHash.isSelected()) && packetInfoAvailable) {
|
if ((chkMessageName.isSelected() || chkMessageHash.isSelected()) && packetInfoAvailable) {
|
||||||
List<PacketInfo> messages = uiLogger.getPacketInfoManager().getAllPacketInfoFromHeaderId(
|
List<PacketInfo> messages = uiLogger.getPacketInfoManager().getAllPacketInfoFromHeaderId(
|
||||||
(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER),
|
(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER),
|
||||||
@ -228,60 +240,61 @@ public class UiLoggerController implements Initializable {
|
|||||||
List<String> hashes = messages.stream().map(PacketInfo::getHash)
|
List<String> hashes = messages.stream().map(PacketInfo::getHash)
|
||||||
.filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
.filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||||
|
|
||||||
boolean addedSomething = false;
|
|
||||||
if (chkMessageName.isSelected() && names.size() > 0) {
|
if (chkMessageName.isSelected() && names.size() > 0) {
|
||||||
for (String name : names) {elements.add(new Element("["+name+"]", "messageinfo")); }
|
for (String name : names) {elements.add(new Element("["+name+"]", "messageinfo")); }
|
||||||
addedSomething = true;
|
addedSomeMessageInfo = true;
|
||||||
}
|
}
|
||||||
if (chkMessageHash.isSelected() && hashes.size() > 0) {
|
if (chkMessageHash.isSelected() && hashes.size() > 0) {
|
||||||
for (String hash : hashes) {elements.add(new Element("["+hash+"]", "messageinfo")); }
|
for (String hash : hashes) {elements.add(new Element("["+hash+"]", "messageinfo")); }
|
||||||
addedSomething = true;
|
addedSomeMessageInfo = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addedSomething) {
|
if (chkMessageId.isSelected()) {
|
||||||
|
elements.add(new Element(String.format("[%d]", packet.headerId()), "messageinfo"));
|
||||||
|
addedSomeMessageInfo = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addedSomeMessageInfo) {
|
||||||
elements.add(new Element("\n", ""));
|
elements.add(new Element("\n", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBlocked) elements.add(new Element("[Blocked]\n", "blocked"));
|
if (isBlocked) elements.add(new Element("[Blocked]\n", "blocked"));
|
||||||
else if (isReplaced) elements.add(new Element("[Replaced]\n", "replaced"));
|
else if (isReplaced) elements.add(new Element("[Replaced]\n", "replaced"));
|
||||||
|
|
||||||
if (isIncoming) {
|
if (!chkReprNone.isSelected()) {
|
||||||
// handle skipped eventually
|
boolean isSkipped = chkSkipBigPackets.isSelected() && (packet.length() > 4000 || (packet.length() > 1000 && chkReprHex.isSelected()));
|
||||||
elements.add(new Element("Incoming[", "incoming"));
|
String packetRepresentation = chkReprHex.isSelected() ?
|
||||||
elements.add(new Element(String.valueOf(packet.headerId()), ""));
|
Hexdump.hexdump(packet.toBytes()) :
|
||||||
elements.add(new Element("]", "incoming"));
|
(chkReprRawHex.isSelected() ? Bytes.wrap(packet.toBytes()).encodeHex() : packet.toString());
|
||||||
|
|
||||||
elements.add(new Element(" <- ", ""));
|
String type = isIncoming ? "Incoming" : "Outgoing";
|
||||||
if (chkSkipBigPackets.isSelected() && packet.length() > 4000) {
|
|
||||||
elements.add(new Element("<packet skipped>", "skipped"));
|
if (!chkReprHex.isSelected()) {
|
||||||
}
|
elements.add(new Element(String.format("%s[", type), type.toLowerCase()));
|
||||||
else {
|
|
||||||
elements.add(new Element(packet.toString(), "incoming"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
elements.add(new Element("Outgoing[", "outgoing"));
|
|
||||||
elements.add(new Element(String.valueOf(packet.headerId()), ""));
|
elements.add(new Element(String.valueOf(packet.headerId()), ""));
|
||||||
elements.add(new Element("]", "outgoing"));
|
elements.add(new Element("]", type.toLowerCase()));
|
||||||
|
|
||||||
elements.add(new Element(" -> ", ""));
|
elements.add(new Element(" -> ", ""));
|
||||||
|
}
|
||||||
|
|
||||||
if (chkSkipBigPackets.isSelected() && packet.length() > 4000) {
|
if (isSkipped) {
|
||||||
elements.add(new Element("<packet skipped>", "skipped"));
|
elements.add(new Element("<packet skipped>", "skipped"));
|
||||||
|
} else
|
||||||
|
elements.add(new Element(packetRepresentation, String.format(chkReprHex.isSelected() ? "%sHex": "%s", type.toLowerCase())));
|
||||||
|
elements.add(new Element("\n", ""));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
elements.add(new Element(packet.toString(), "outgoing"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet.length() <= 2000) {
|
if (packet.length() <= 2000) {
|
||||||
try {
|
try {
|
||||||
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER, uiLogger.getPacketInfoManager(), chkUseNewStructures.isSelected());
|
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER, uiLogger.getPacketInfoManager(), chkUseNewStructures.isSelected());
|
||||||
String cleaned = cleanTextContent(expr);
|
String cleaned = cleanTextContent(expr);
|
||||||
if (cleaned.equals(expr)) {
|
if (cleaned.equals(expr)) {
|
||||||
if (!expr.equals("") && chkDisplayStructure.isSelected())
|
if (!expr.equals("") && chkDisplayStructure.isSelected()) {
|
||||||
elements.add(new Element("\n" + cleanTextContent(expr), "structure"));
|
elements.add(new Element(cleanTextContent(expr), "structure"));
|
||||||
|
elements.add(new Element("\n", ""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
@ -292,7 +305,7 @@ public class UiLoggerController implements Initializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
elements.add(new Element("\n--------------------\n", ""));
|
elements.add(new Element("--------------------\n", ""));
|
||||||
|
|
||||||
synchronized (appendLater) {
|
synchronized (appendLater) {
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
|
@ -0,0 +1,129 @@
|
|||||||
|
package gearth.services.internal_extensions.uilogger.hexdumper;
|
||||||
|
|
||||||
|
// https://github.com/zuckel/hexdump
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for generating hexdumps from byte arrays. Mostly for debugging purposes.
|
||||||
|
*/
|
||||||
|
public final class Hexdump {
|
||||||
|
|
||||||
|
private static final char[] HEX =
|
||||||
|
new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
||||||
|
|
||||||
|
public static final char NON_PRINTABLE = '\u25a1'; // WHITE SQUARE □
|
||||||
|
|
||||||
|
private Hexdump() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Create human-readable hexdump for a byte array.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This method is not thread-safe in the sense that bytes will be read more than once, thus possibly producing inconsistent
|
||||||
|
* output if the byte array is mutated concurrently.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param bytes array to be rendered
|
||||||
|
* @return human-readable formatted hexdump as a String
|
||||||
|
*/
|
||||||
|
public static String hexdump(byte[] bytes) {
|
||||||
|
if (bytes == null) {
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
if (bytes.length == 0) {
|
||||||
|
return "empty";
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
|
||||||
|
for (int offset = 0; offset < bytes.length; offset += 16) {
|
||||||
|
appendLine(bytes, offset, out);
|
||||||
|
}
|
||||||
|
appendOffset(bytes.length, out);
|
||||||
|
// out.append('\n');
|
||||||
|
|
||||||
|
return out.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 00000000 2f 2e 63 6c 61 73 73 70 61 74 68 0a 2f 2e 70 72 |/.classpath¶/.pr|
|
||||||
|
// offset first block second block | displayChars|
|
||||||
|
private static void appendLine(byte[] bytes, int firstBlockStart, StringBuilder out) {
|
||||||
|
int firstBlockEnd = Math.min(bytes.length, firstBlockStart + 8);
|
||||||
|
int secondBlockEnd = Math.min(bytes.length, firstBlockStart + 16);
|
||||||
|
|
||||||
|
appendOffset(firstBlockStart, out);
|
||||||
|
out.append(' ');
|
||||||
|
out.append(' ');
|
||||||
|
|
||||||
|
appendHexBytes(bytes, firstBlockStart, firstBlockEnd, out);
|
||||||
|
out.append(' ');
|
||||||
|
|
||||||
|
appendHexBytes(bytes, firstBlockStart + 8, secondBlockEnd, out);
|
||||||
|
padMissingBytes(firstBlockStart, secondBlockEnd, out);
|
||||||
|
out.append(' ');
|
||||||
|
|
||||||
|
out.append('|');
|
||||||
|
appendDisplayChars(bytes, firstBlockStart, secondBlockEnd, out);
|
||||||
|
out.append('|');
|
||||||
|
out.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// visible for testing
|
||||||
|
static void appendOffset(int offset, StringBuilder out) {
|
||||||
|
appendHexChars((byte) ((offset & 0xFF000000) >> 24), out);
|
||||||
|
appendHexChars((byte) ((offset & 0x00FF0000) >> 16), out);
|
||||||
|
appendHexChars((byte) ((offset & 0x0000FF00) >> 8), out);
|
||||||
|
appendHexChars((byte) ((offset & 0x000000FF) >> 0), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendHexBytes(byte[] bytes, int offset, int limit, StringBuilder out) {
|
||||||
|
for (int i = offset; i < limit; i++) {
|
||||||
|
appendHexChars(bytes[i], out);
|
||||||
|
out.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendHexChars(byte b, StringBuilder out) {
|
||||||
|
out.append(HEX[(b >> 4) & 0x0F]); // 4 high bits
|
||||||
|
out.append(HEX[b & 0x0F]); // 4 low bits
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void padMissingBytes(int firstByte, int lastByte, StringBuilder out) {
|
||||||
|
int charsPerByte = 3;
|
||||||
|
int maxBytesPerLine = 16;
|
||||||
|
int bytesWritten = lastByte - firstByte;
|
||||||
|
|
||||||
|
int charsMissing = charsPerByte * (maxBytesPerLine - bytesWritten);
|
||||||
|
for (int i = 0; i < charsMissing; i++) {
|
||||||
|
out.append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendDisplayChars(byte[] bytes, int offset, int blockEnd, StringBuilder out) {
|
||||||
|
for (int i = offset; i < blockEnd; i++) {
|
||||||
|
appendDisplayChar(bytes[i], out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendDisplayChar(byte b, StringBuilder out) {
|
||||||
|
switch (b) {
|
||||||
|
case 0x20:
|
||||||
|
out.append("\u2423"); // SPACE ␣
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
out.append('\u2192'); // TAB →
|
||||||
|
break;
|
||||||
|
case 0x0a:
|
||||||
|
out.append('\u00b6'); // LF ¶
|
||||||
|
break;
|
||||||
|
case 0x0d:
|
||||||
|
out.append('\u00a4'); // CR ¤
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out.append((32 <= b && b <= 126) ? (char) b : NON_PRINTABLE); // ' ' to '~', non-printable is WHITE SQUARE □
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -47,9 +47,26 @@
|
|||||||
<items>
|
<items>
|
||||||
<Menu mnemonicParsing="false" text="Display Details">
|
<Menu mnemonicParsing="false" text="Display Details">
|
||||||
<items>
|
<items>
|
||||||
|
<Menu mnemonicParsing="false" text="Byte representation">
|
||||||
|
<items>
|
||||||
|
<RadioMenuItem fx:id="chkReprLegacy" mnemonicParsing="false" selected="true" text="Legacy">
|
||||||
|
<toggleGroup>
|
||||||
|
<ToggleGroup fx:id="byterepr" />
|
||||||
|
</toggleGroup>
|
||||||
|
</RadioMenuItem>
|
||||||
|
<RadioMenuItem fx:id="chkReprHex" mnemonicParsing="false" text="Hexdump" toggleGroup="$byterepr" />
|
||||||
|
<RadioMenuItem fx:id="chkReprRawHex" mnemonicParsing="false" text="Raw hex" toggleGroup="$byterepr" />
|
||||||
|
<RadioMenuItem fx:id="chkReprNone" mnemonicParsing="false" text="None" toggleGroup="$byterepr" />
|
||||||
|
</items>
|
||||||
|
</Menu>
|
||||||
|
<Menu mnemonicParsing="false" text="Message">
|
||||||
|
<items>
|
||||||
|
<CheckMenuItem fx:id="chkMessageName" mnemonicParsing="false" selected="true" text="Name" />
|
||||||
|
<CheckMenuItem fx:id="chkMessageHash" mnemonicParsing="false" text="Hash" />
|
||||||
|
<CheckMenuItem fx:id="chkMessageId" mnemonicParsing="false" text="Id" />
|
||||||
|
</items>
|
||||||
|
</Menu>
|
||||||
<CheckMenuItem fx:id="chkDisplayStructure" mnemonicParsing="false" selected="true" text="Structure" />
|
<CheckMenuItem fx:id="chkDisplayStructure" mnemonicParsing="false" selected="true" text="Structure" />
|
||||||
<CheckMenuItem fx:id="chkMessageName" mnemonicParsing="false" selected="true" text="Message Name" />
|
|
||||||
<CheckMenuItem fx:id="chkMessageHash" mnemonicParsing="false" text="Message Hash" />
|
|
||||||
<CheckMenuItem fx:id="chkUseNewStructures" mnemonicParsing="false" selected="true" text="New structures" />
|
<CheckMenuItem fx:id="chkUseNewStructures" mnemonicParsing="false" selected="true" text="New structures" />
|
||||||
<CheckMenuItem fx:id="chkTimestamp" mnemonicParsing="false" text="Timestamp" />
|
<CheckMenuItem fx:id="chkTimestamp" mnemonicParsing="false" text="Timestamp" />
|
||||||
</items>
|
</items>
|
||||||
@ -69,6 +86,11 @@
|
|||||||
</Menu>
|
</Menu>
|
||||||
<CheckMenuItem fx:id="chkSkipBigPackets" mnemonicParsing="false" selected="true" text="Skip big packets" />
|
<CheckMenuItem fx:id="chkSkipBigPackets" mnemonicParsing="false" selected="true" text="Skip big packets" />
|
||||||
<MenuItem mnemonicParsing="false" onAction="#exportAll" text="Export all" />
|
<MenuItem mnemonicParsing="false" onAction="#exportAll" text="Export all" />
|
||||||
|
<Menu mnemonicParsing="false" text="Unspecified Menu">
|
||||||
|
<items>
|
||||||
|
<MenuItem mnemonicParsing="false" text="Action 1" />
|
||||||
|
</items>
|
||||||
|
</Menu>
|
||||||
</items>
|
</items>
|
||||||
</Menu>
|
</Menu>
|
||||||
</MenuBar>
|
</MenuBar>
|
||||||
|
@ -19,10 +19,20 @@
|
|||||||
-fx-fill: #b22222;
|
-fx-fill: #b22222;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.incomingHex {
|
||||||
|
-fx-fill: #f06262;
|
||||||
|
-fx-font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
.outgoing {
|
.outgoing {
|
||||||
-fx-fill: #0066cc;
|
-fx-fill: #0066cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.outgoingHex {
|
||||||
|
-fx-fill: #4fb7f7;
|
||||||
|
-fx-font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
.structure, .skipped {
|
.structure, .skipped {
|
||||||
-fx-fill: cyan;
|
-fx-fill: cyan;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user