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>
|
||||
<version>2.10.0</version>
|
||||
</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;
|
||||
|
||||
import at.favre.lib.bytes.Bytes;
|
||||
import gearth.misc.Cacher;
|
||||
import gearth.services.internal_extensions.uilogger.hexdumper.Hexdump;
|
||||
import gearth.services.packet_info.PacketInfo;
|
||||
import gearth.services.packet_info.PacketInfoManager;
|
||||
import gearth.protocol.HMessage;
|
||||
@ -16,7 +18,8 @@ import javafx.scene.layout.FlowPane;
|
||||
import javafx.stage.Stage;
|
||||
import org.fxmisc.flowless.VirtualizedScrollPane;
|
||||
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.File;
|
||||
@ -43,6 +46,7 @@ public class UiLoggerController implements Initializable {
|
||||
public CheckMenuItem chkSkipBigPackets;
|
||||
public CheckMenuItem chkMessageName;
|
||||
public CheckMenuItem chkMessageHash;
|
||||
public CheckMenuItem chkMessageId;
|
||||
public Label lblPacketInfo;
|
||||
public CheckMenuItem chkUseNewStructures;
|
||||
public CheckMenuItem chkAlwaysOnTop;
|
||||
@ -66,6 +70,11 @@ public class UiLoggerController implements Initializable {
|
||||
public Label lblFiltered;
|
||||
public CheckMenuItem chkTimestamp;
|
||||
|
||||
public RadioMenuItem chkReprLegacy;
|
||||
public RadioMenuItem chkReprHex;
|
||||
public RadioMenuItem chkReprRawHex;
|
||||
public RadioMenuItem chkReprNone;
|
||||
|
||||
private Map<Integer, LinkedList<Long>> filterTimestamps = new HashMap<>();
|
||||
|
||||
private StyleClassedTextArea area;
|
||||
@ -123,10 +132,10 @@ public class UiLoggerController implements Initializable {
|
||||
public void initialize(URL arg0, ResourceBundle arg1) {
|
||||
allMenuItems.addAll(Arrays.asList(
|
||||
chkViewIncoming, chkViewOutgoing, chkDisplayStructure, chkAutoscroll,
|
||||
chkSkipBigPackets, chkMessageName, chkMessageHash, chkUseNewStructures,
|
||||
chkSkipBigPackets, chkMessageName, chkMessageHash, chkMessageId, chkUseNewStructures,
|
||||
chkOpenOnConnect, chkResetOnConnect, chkHideOnDisconnect, chkResetOnDisconnect,
|
||||
chkAntiSpam_none, chkAntiSpam_low, chkAntiSpam_medium, chkAntiSpam_high, chkAntiSpam_ultra,
|
||||
chkTimestamp
|
||||
chkTimestamp, chkReprHex, chkReprLegacy, chkReprRawHex, chkReprNone
|
||||
));
|
||||
loadAllMenuItems();
|
||||
|
||||
@ -218,6 +227,9 @@ public class UiLoggerController implements Initializable {
|
||||
|
||||
boolean packetInfoAvailable = uiLogger.getPacketInfoManager().getPacketInfoList().size() > 0;
|
||||
|
||||
|
||||
boolean addedSomeMessageInfo = false;
|
||||
|
||||
if ((chkMessageName.isSelected() || chkMessageHash.isSelected()) && packetInfoAvailable) {
|
||||
List<PacketInfo> messages = uiLogger.getPacketInfoManager().getAllPacketInfoFromHeaderId(
|
||||
(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER),
|
||||
@ -228,60 +240,61 @@ public class UiLoggerController implements Initializable {
|
||||
List<String> hashes = messages.stream().map(PacketInfo::getHash)
|
||||
.filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||
|
||||
boolean addedSomething = false;
|
||||
if (chkMessageName.isSelected() && names.size() > 0) {
|
||||
for (String name : names) {elements.add(new Element("["+name+"]", "messageinfo")); }
|
||||
addedSomething = true;
|
||||
addedSomeMessageInfo = true;
|
||||
}
|
||||
if (chkMessageHash.isSelected() && hashes.size() > 0) {
|
||||
for (String hash : hashes) {elements.add(new Element("["+hash+"]", "messageinfo")); }
|
||||
addedSomething = true;
|
||||
addedSomeMessageInfo = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (addedSomething) {
|
||||
elements.add(new Element("\n", ""));
|
||||
}
|
||||
if (chkMessageId.isSelected()) {
|
||||
elements.add(new Element(String.format("[%d]", packet.headerId()), "messageinfo"));
|
||||
addedSomeMessageInfo = true;
|
||||
}
|
||||
|
||||
if (addedSomeMessageInfo) {
|
||||
elements.add(new Element("\n", ""));
|
||||
}
|
||||
|
||||
if (isBlocked) elements.add(new Element("[Blocked]\n", "blocked"));
|
||||
else if (isReplaced) elements.add(new Element("[Replaced]\n", "replaced"));
|
||||
|
||||
if (isIncoming) {
|
||||
// handle skipped eventually
|
||||
elements.add(new Element("Incoming[", "incoming"));
|
||||
elements.add(new Element(String.valueOf(packet.headerId()), ""));
|
||||
elements.add(new Element("]", "incoming"));
|
||||
if (!chkReprNone.isSelected()) {
|
||||
boolean isSkipped = chkSkipBigPackets.isSelected() && (packet.length() > 4000 || (packet.length() > 1000 && chkReprHex.isSelected()));
|
||||
String packetRepresentation = chkReprHex.isSelected() ?
|
||||
Hexdump.hexdump(packet.toBytes()) :
|
||||
(chkReprRawHex.isSelected() ? Bytes.wrap(packet.toBytes()).encodeHex() : packet.toString());
|
||||
|
||||
elements.add(new Element(" <- ", ""));
|
||||
if (chkSkipBigPackets.isSelected() && packet.length() > 4000) {
|
||||
String type = isIncoming ? "Incoming" : "Outgoing";
|
||||
|
||||
if (!chkReprHex.isSelected()) {
|
||||
elements.add(new Element(String.format("%s[", type), type.toLowerCase()));
|
||||
elements.add(new Element(String.valueOf(packet.headerId()), ""));
|
||||
elements.add(new Element("]", type.toLowerCase()));
|
||||
|
||||
elements.add(new Element(" -> ", ""));
|
||||
}
|
||||
|
||||
if (isSkipped) {
|
||||
elements.add(new Element("<packet skipped>", "skipped"));
|
||||
}
|
||||
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("]", "outgoing"));
|
||||
|
||||
elements.add(new Element(" -> ", ""));
|
||||
|
||||
if (chkSkipBigPackets.isSelected() && packet.length() > 4000) {
|
||||
elements.add(new Element("<packet skipped>", "skipped"));
|
||||
}
|
||||
else {
|
||||
elements.add(new Element(packet.toString(), "outgoing"));
|
||||
}
|
||||
} else
|
||||
elements.add(new Element(packetRepresentation, String.format(chkReprHex.isSelected() ? "%sHex": "%s", type.toLowerCase())));
|
||||
elements.add(new Element("\n", ""));
|
||||
}
|
||||
|
||||
|
||||
if (packet.length() <= 2000) {
|
||||
try {
|
||||
String expr = packet.toExpression(isIncoming ? HMessage.Direction.TOCLIENT : HMessage.Direction.TOSERVER, uiLogger.getPacketInfoManager(), chkUseNewStructures.isSelected());
|
||||
String cleaned = cleanTextContent(expr);
|
||||
if (cleaned.equals(expr)) {
|
||||
if (!expr.equals("") && chkDisplayStructure.isSelected())
|
||||
elements.add(new Element("\n" + cleanTextContent(expr), "structure"));
|
||||
if (!expr.equals("") && chkDisplayStructure.isSelected()) {
|
||||
elements.add(new Element(cleanTextContent(expr), "structure"));
|
||||
elements.add(new Element("\n", ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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>
|
||||
<Menu mnemonicParsing="false" text="Display Details">
|
||||
<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="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="chkTimestamp" mnemonicParsing="false" text="Timestamp" />
|
||||
</items>
|
||||
@ -69,6 +86,11 @@
|
||||
</Menu>
|
||||
<CheckMenuItem fx:id="chkSkipBigPackets" mnemonicParsing="false" selected="true" text="Skip big packets" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#exportAll" text="Export all" />
|
||||
<Menu mnemonicParsing="false" text="Unspecified Menu">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="Action 1" />
|
||||
</items>
|
||||
</Menu>
|
||||
</items>
|
||||
</Menu>
|
||||
</MenuBar>
|
||||
|
@ -19,10 +19,20 @@
|
||||
-fx-fill: #b22222;
|
||||
}
|
||||
|
||||
.incomingHex {
|
||||
-fx-fill: #f06262;
|
||||
-fx-font-family: monospace;
|
||||
}
|
||||
|
||||
.outgoing {
|
||||
-fx-fill: #0066cc;
|
||||
}
|
||||
|
||||
.outgoingHex {
|
||||
-fx-fill: #4fb7f7;
|
||||
-fx-font-family: monospace;
|
||||
}
|
||||
|
||||
.structure, .skipped {
|
||||
-fx-fill: cyan;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user