feat: Add automatic file type detection and enhanced analysis
- Auto-detect XML files for encoding, other files for decoding/analysis - Enhanced structure analysis for both .NET and VC versions - Added V2GTP header analysis and EXI structure breakdown - Added message type prediction based on body choice patterns - Improved SessionID analysis with ASCII decoding - Updated usage messages to reflect auto-detection capabilities 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,17 @@ namespace V2GDecoderNet
|
|||||||
if (args.Length == 1)
|
if (args.Length == 1)
|
||||||
{
|
{
|
||||||
filename = args[0];
|
filename = args[0];
|
||||||
|
// 자동으로 확장자를 감지하여 모드 결정
|
||||||
|
string extension = Path.GetExtension(filename).ToLower();
|
||||||
|
if (extension == ".xml")
|
||||||
|
{
|
||||||
|
encodeMode = true;
|
||||||
|
Console.WriteLine($"Auto-detected XML file: encoding to EXI");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Auto-detected binary file: analyzing structure");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (args.Length == 2 && args[0] == "-decode")
|
else if (args.Length == 2 && args[0] == "-decode")
|
||||||
{
|
{
|
||||||
@@ -55,9 +66,11 @@ namespace V2GDecoderNet
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: V2GDecoderNet [-decode|-encode] input_file");
|
Console.Error.WriteLine("Usage: V2GDecoderNet [-decode|-encode] input_file");
|
||||||
|
Console.Error.WriteLine(" V2GDecoderNet filename (auto-detect by extension)");
|
||||||
Console.Error.WriteLine(" V2GDecoderNet -encode (read XML from stdin)");
|
Console.Error.WriteLine(" V2GDecoderNet -encode (read XML from stdin)");
|
||||||
Console.Error.WriteLine(" V2GDecoderNet -decode (read hex string from stdin)");
|
Console.Error.WriteLine(" V2GDecoderNet -decode (read hex string from stdin)");
|
||||||
Console.Error.WriteLine("Enhanced EXI viewer with XML conversion capabilities");
|
Console.Error.WriteLine("Enhanced EXI viewer with XML conversion capabilities");
|
||||||
|
Console.Error.WriteLine(" filename Auto-detect: .xml files are encoded, others are decoded/analyzed");
|
||||||
Console.Error.WriteLine(" -decode Convert EXI to Wireshark-style XML format");
|
Console.Error.WriteLine(" -decode Convert EXI to Wireshark-style XML format");
|
||||||
Console.Error.WriteLine(" -decode Read hex string from stdin (echo hex | V2GDecoderNet -decode)");
|
Console.Error.WriteLine(" -decode Read hex string from stdin (echo hex | V2GDecoderNet -decode)");
|
||||||
Console.Error.WriteLine(" -encode Convert XML to EXI format");
|
Console.Error.WriteLine(" -encode Convert XML to EXI format");
|
||||||
@@ -234,35 +247,171 @@ namespace V2GDecoderNet
|
|||||||
Console.WriteLine($"First 4 bytes: 0x{firstFourBytes:X8}");
|
Console.WriteLine($"First 4 bytes: 0x{firstFourBytes:X8}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for EXI start pattern
|
// Determine protocol type and analyze
|
||||||
for (int i = 0; i <= buffer.Length - 2; i++)
|
|
||||||
{
|
|
||||||
ushort pattern = (ushort)((buffer[i] << 8) | buffer[i + 1]);
|
|
||||||
if (pattern == EXI_START_PATTERN)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"EXI start pattern (0x{EXI_START_PATTERN:X4}) found at offset: {i}");
|
|
||||||
Console.WriteLine($"EXI payload size: {buffer.Length - i} bytes");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine protocol type
|
|
||||||
if (buffer.Length >= 8 && buffer[0] == V2G_PROTOCOL_VERSION && buffer[1] == V2G_INV_PROTOCOL_VERSION)
|
if (buffer.Length >= 8 && buffer[0] == V2G_PROTOCOL_VERSION && buffer[1] == V2G_INV_PROTOCOL_VERSION)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Protocol: V2G Transfer Protocol detected");
|
Console.WriteLine("Protocol: V2G Transfer Protocol detected");
|
||||||
|
AnalyzeV2GTPHeader(buffer);
|
||||||
}
|
}
|
||||||
else if (buffer.Length >= 2 && ((buffer[0] << 8) | buffer[1]) == EXI_START_PATTERN)
|
else if (buffer.Length >= 2 && ((buffer[0] << 8) | buffer[1]) == EXI_START_PATTERN)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Protocol: Direct EXI format");
|
Console.WriteLine("Protocol: Direct EXI format");
|
||||||
|
AnalyzeEXIStructure(buffer, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("Protocol: Unknown or Direct EXI");
|
Console.WriteLine("Protocol: Unknown format - attempting EXI detection");
|
||||||
|
// Check for EXI start pattern anywhere in the buffer
|
||||||
|
for (int i = 0; i <= buffer.Length - 2; i++)
|
||||||
|
{
|
||||||
|
ushort pattern = (ushort)((buffer[i] << 8) | buffer[i + 1]);
|
||||||
|
if (pattern == EXI_START_PATTERN)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"EXI start pattern (0x{EXI_START_PATTERN:X4}) found at offset: {i}");
|
||||||
|
AnalyzeEXIStructure(buffer, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void AnalyzeV2GTPHeader(byte[] buffer)
|
||||||
|
{
|
||||||
|
if (buffer.Length < 8) return;
|
||||||
|
|
||||||
|
Console.WriteLine("\n--- V2G Transfer Protocol Header ---");
|
||||||
|
Console.WriteLine($"Version: 0x{buffer[0]:X2}");
|
||||||
|
Console.WriteLine($"Inverse Version: 0x{buffer[1]:X2}");
|
||||||
|
|
||||||
|
ushort payloadType = (ushort)((buffer[2] << 8) | buffer[3]);
|
||||||
|
Console.WriteLine($"Payload Type: 0x{payloadType:X4} ({GetPayloadTypeDescription(payloadType)})");
|
||||||
|
|
||||||
|
uint payloadLength = (uint)((buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]);
|
||||||
|
Console.WriteLine($"Payload Length: {payloadLength} bytes");
|
||||||
|
|
||||||
|
if (8 + payloadLength == buffer.Length)
|
||||||
|
{
|
||||||
|
Console.WriteLine("✓ V2GTP header is valid (payload length matches)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"⚠ V2GTP header mismatch (expected {8 + payloadLength}, got {buffer.Length})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze EXI payload if present
|
||||||
|
if (buffer.Length > 8)
|
||||||
|
{
|
||||||
|
AnalyzeEXIStructure(buffer, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AnalyzeEXIStructure(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
if (offset + 4 > buffer.Length) return;
|
||||||
|
|
||||||
|
Console.WriteLine("\n--- EXI Structure Analysis ---");
|
||||||
|
Console.WriteLine($"EXI data starts at offset: {offset}");
|
||||||
|
Console.WriteLine($"EXI payload size: {buffer.Length - offset} bytes");
|
||||||
|
|
||||||
|
// EXI Header analysis
|
||||||
|
if (offset + 4 <= buffer.Length)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"EXI Magic: 0x{buffer[offset]:X2} (expected 0x80)");
|
||||||
|
Console.WriteLine($"Document Choice: 0x{buffer[offset + 1]:X2}");
|
||||||
|
Console.WriteLine($"Grammar State: 0x{buffer[offset + 2]:X2} 0x{buffer[offset + 3]:X2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionID analysis (if present after EXI header)
|
||||||
|
if (offset + 12 <= buffer.Length)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\n--- SessionID Analysis ---");
|
||||||
|
Console.Write("SessionID bytes: ");
|
||||||
|
for (int i = offset + 4; i < offset + 12 && i < buffer.Length; i++)
|
||||||
|
{
|
||||||
|
Console.Write($"{buffer[i]:X2} ");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
// Try to decode SessionID as ASCII if reasonable
|
||||||
|
if (IsReadableAscii(buffer, offset + 4, 8))
|
||||||
|
{
|
||||||
|
string sessionId = System.Text.Encoding.ASCII.GetString(buffer, offset + 4, 8);
|
||||||
|
Console.WriteLine($"SessionID (ASCII): \"{sessionId}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Predict message type based on patterns
|
||||||
|
PredictMessageType(buffer, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PredictMessageType(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\n--- Message Type Prediction ---");
|
||||||
|
|
||||||
|
// Look for body choice pattern (around offset 12-16 typically)
|
||||||
|
for (int i = offset + 8; i < Math.Min(offset + 20, buffer.Length); i++)
|
||||||
|
{
|
||||||
|
byte b = buffer[i];
|
||||||
|
// Body choice is typically encoded in specific patterns
|
||||||
|
if ((b & 0xF0) == 0xD0) // Common pattern for body choices
|
||||||
|
{
|
||||||
|
int bodyChoice = (b >> 1) & 0x1F; // Extract 5-bit choice
|
||||||
|
Console.WriteLine($"Possible Body Choice at offset {i}: {bodyChoice} ({GetMessageTypeDescription(bodyChoice)})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsReadableAscii(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length && offset + i < buffer.Length; i++)
|
||||||
|
{
|
||||||
|
byte b = buffer[offset + i];
|
||||||
|
if (b < 32 || b > 126) // Not printable ASCII
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetPayloadTypeDescription(ushort payloadType)
|
||||||
|
{
|
||||||
|
return payloadType switch
|
||||||
|
{
|
||||||
|
V2G_PAYLOAD_ISO_DIN_SAP => "ISO 15118-2/DIN/SAP",
|
||||||
|
V2G_PAYLOAD_ISO2 => "ISO 15118-20",
|
||||||
|
_ => "Unknown"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetMessageTypeDescription(int bodyChoice)
|
||||||
|
{
|
||||||
|
return bodyChoice switch
|
||||||
|
{
|
||||||
|
0 => "SessionSetupReq",
|
||||||
|
1 => "SessionSetupRes",
|
||||||
|
2 => "ServiceDiscoveryReq",
|
||||||
|
3 => "ServiceDiscoveryRes",
|
||||||
|
4 => "ServiceDetailReq",
|
||||||
|
5 => "ServiceDetailRes",
|
||||||
|
6 => "PaymentServiceSelectionReq",
|
||||||
|
7 => "PaymentServiceSelectionRes",
|
||||||
|
8 => "AuthorizationReq",
|
||||||
|
9 => "AuthorizationRes",
|
||||||
|
10 => "ChargeParameterDiscoveryReq",
|
||||||
|
11 => "ChargeParameterDiscoveryRes",
|
||||||
|
12 => "PowerDeliveryReq",
|
||||||
|
13 => "CurrentDemandReq",
|
||||||
|
14 => "CurrentDemandRes",
|
||||||
|
15 => "PowerDeliveryRes",
|
||||||
|
16 => "ChargingStatusReq",
|
||||||
|
17 => "ChargingStatusRes",
|
||||||
|
18 => "SessionStopReq",
|
||||||
|
19 => "SessionStopRes",
|
||||||
|
_ => $"Unknown ({bodyChoice})"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] ExtractExiBody(byte[] inputData)
|
private static byte[] ExtractExiBody(byte[] inputData)
|
||||||
{
|
{
|
||||||
if (inputData.Length < 8)
|
if (inputData.Length < 8)
|
||||||
|
|||||||
150
VC/V2GDecoder.c
150
VC/V2GDecoder.c
@@ -122,6 +122,122 @@ const char* get_payload_type_name(uint16_t payload_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void analyze_v2gtp_header(uint8_t* data, size_t size) {
|
||||||
|
if (size < 8) return;
|
||||||
|
|
||||||
|
printf("\n--- V2G Transfer Protocol Header ---\n");
|
||||||
|
printf("Version: 0x%02X\n", data[0]);
|
||||||
|
printf("Inverse Version: 0x%02X\n", data[1]);
|
||||||
|
|
||||||
|
uint16_t payload_type = (data[2] << 8) | data[3];
|
||||||
|
printf("Payload Type: 0x%04X (%s)\n", payload_type, get_payload_type_name(payload_type));
|
||||||
|
|
||||||
|
uint32_t payload_length = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
|
||||||
|
printf("Payload Length: %u bytes\n", payload_length);
|
||||||
|
|
||||||
|
if (8 + payload_length == size) {
|
||||||
|
printf("✓ V2GTP header is valid (payload length matches)\n");
|
||||||
|
} else {
|
||||||
|
printf("⚠ V2GTP header mismatch (expected %u, got %zu)\n", (unsigned)(8 + payload_length), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze EXI payload if present
|
||||||
|
if (size > 8) {
|
||||||
|
analyze_exi_structure(data, size, 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void analyze_exi_structure(uint8_t* data, size_t size, size_t offset) {
|
||||||
|
if (offset + 4 > size) return;
|
||||||
|
|
||||||
|
printf("\n--- EXI Structure Analysis ---\n");
|
||||||
|
printf("EXI data starts at offset: %zu\n", offset);
|
||||||
|
printf("EXI payload size: %zu bytes\n", size - offset);
|
||||||
|
|
||||||
|
// EXI Header analysis
|
||||||
|
if (offset + 4 <= size) {
|
||||||
|
printf("EXI Magic: 0x%02X (expected 0x80)\n", data[offset]);
|
||||||
|
printf("Document Choice: 0x%02X\n", data[offset + 1]);
|
||||||
|
printf("Grammar State: 0x%02X 0x%02X\n", data[offset + 2], data[offset + 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionID analysis (if present after EXI header)
|
||||||
|
if (offset + 12 <= size) {
|
||||||
|
printf("\n--- SessionID Analysis ---\n");
|
||||||
|
printf("SessionID bytes: ");
|
||||||
|
for (size_t i = offset + 4; i < offset + 12 && i < size; i++) {
|
||||||
|
printf("%02X ", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Try to decode SessionID as ASCII if reasonable
|
||||||
|
if (is_readable_ascii(data, offset + 4, 8)) {
|
||||||
|
printf("SessionID (ASCII): \"");
|
||||||
|
for (size_t i = offset + 4; i < offset + 12 && i < size; i++) {
|
||||||
|
printf("%c", data[i]);
|
||||||
|
}
|
||||||
|
printf("\"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Predict message type based on patterns
|
||||||
|
predict_message_type(data, size, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_readable_ascii(uint8_t* data, size_t offset, size_t length) {
|
||||||
|
for (size_t i = 0; i < length && offset + i < length; i++) {
|
||||||
|
uint8_t b = data[offset + i];
|
||||||
|
if (b < 32 || b > 126) // Not printable ASCII
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void predict_message_type(uint8_t* data, size_t size, size_t offset) {
|
||||||
|
printf("\n--- Message Type Prediction ---\n");
|
||||||
|
|
||||||
|
// Look for body choice pattern (around offset 12-16 typically)
|
||||||
|
for (size_t i = offset + 8; i < offset + 20 && i < size; i++) {
|
||||||
|
uint8_t b = data[i];
|
||||||
|
// Body choice is typically encoded in specific patterns
|
||||||
|
if ((b & 0xF0) == 0xD0) { // Common pattern for body choices
|
||||||
|
int body_choice = (b >> 1) & 0x1F; // Extract 5-bit choice
|
||||||
|
printf("Possible Body Choice at offset %zu: %d (%s)\n",
|
||||||
|
i, body_choice, get_message_type_description(body_choice));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_message_type_description(int body_choice) {
|
||||||
|
switch(body_choice) {
|
||||||
|
case 0: return "SessionSetupReq";
|
||||||
|
case 1: return "SessionSetupRes";
|
||||||
|
case 2: return "ServiceDiscoveryReq";
|
||||||
|
case 3: return "ServiceDiscoveryRes";
|
||||||
|
case 4: return "ServiceDetailReq";
|
||||||
|
case 5: return "ServiceDetailRes";
|
||||||
|
case 6: return "PaymentServiceSelectionReq";
|
||||||
|
case 7: return "PaymentServiceSelectionRes";
|
||||||
|
case 8: return "AuthorizationReq";
|
||||||
|
case 9: return "AuthorizationRes";
|
||||||
|
case 10: return "ChargeParameterDiscoveryReq";
|
||||||
|
case 11: return "ChargeParameterDiscoveryRes";
|
||||||
|
case 12: return "PowerDeliveryReq";
|
||||||
|
case 13: return "CurrentDemandReq";
|
||||||
|
case 14: return "CurrentDemandRes";
|
||||||
|
case 15: return "PowerDeliveryRes";
|
||||||
|
case 16: return "ChargingStatusReq";
|
||||||
|
case 17: return "ChargingStatusRes";
|
||||||
|
case 18: return "SessionStopReq";
|
||||||
|
case 19: return "SessionStopRes";
|
||||||
|
default: {
|
||||||
|
static char unknown_msg[32];
|
||||||
|
snprintf(unknown_msg, sizeof(unknown_msg), "Unknown (%d)", body_choice);
|
||||||
|
return unknown_msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Function to analyze complete packet structure
|
// Function to analyze complete packet structure
|
||||||
void analyze_data_structure(uint8_t* data, size_t size) {
|
void analyze_data_structure(uint8_t* data, size_t size) {
|
||||||
printf("=== Data Structure Analysis ===\n");
|
printf("=== Data Structure Analysis ===\n");
|
||||||
@@ -237,15 +353,23 @@ void analyze_data_structure(uint8_t* data, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for EXI pattern
|
// Check protocol type and analyze
|
||||||
for (size_t i = 0; i <= size - 2; i++) {
|
if (size >= 8 && data[0] == V2G_PROTOCOL_VERSION && data[1] == V2G_INV_PROTOCOL_VERSION) {
|
||||||
uint16_t pattern = (data[i] << 8) | data[i + 1];
|
printf("Protocol: V2G Transfer Protocol detected\n");
|
||||||
if (pattern == EXI_START_PATTERN) {
|
analyze_v2gtp_header(data, size);
|
||||||
printf("EXI start pattern (0x8098) found at offset: %zu\n", i);
|
} else if (size >= 2 && ((data[0] << 8) | data[1]) == EXI_START_PATTERN) {
|
||||||
if (i >= offset) {
|
printf("Protocol: Direct EXI format\n");
|
||||||
printf("EXI payload size: %zu bytes\n", size - i);
|
analyze_exi_structure(data, size, 0);
|
||||||
|
} else {
|
||||||
|
printf("Protocol: Unknown format - attempting EXI detection\n");
|
||||||
|
// Look for EXI pattern
|
||||||
|
for (size_t i = 0; i <= size - 2; i++) {
|
||||||
|
uint16_t pattern = (data[i] << 8) | data[i + 1];
|
||||||
|
if (pattern == EXI_START_PATTERN) {
|
||||||
|
printf("EXI start pattern (0x8098) found at offset: %zu\n", i);
|
||||||
|
analyze_exi_structure(data, size, i);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -1453,6 +1577,14 @@ int main(int argc, char *argv[]) {
|
|||||||
filename = "-"; // Use "-" to indicate stdin
|
filename = "-"; // Use "-" to indicate stdin
|
||||||
} else {
|
} else {
|
||||||
filename = argv[arg_index];
|
filename = argv[arg_index];
|
||||||
|
// 자동으로 확장자를 감지하여 모드 결정
|
||||||
|
char* ext = strrchr(filename, '.');
|
||||||
|
if (ext && _stricmp(ext, ".xml") == 0) {
|
||||||
|
encode_mode = 1;
|
||||||
|
printf("Auto-detected XML file: encoding to EXI\n");
|
||||||
|
} else {
|
||||||
|
printf("Auto-detected binary file: analyzing structure\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (argc == 3 && strcmp(argv[arg_index], "-decode") == 0) {
|
} else if (argc == 3 && strcmp(argv[arg_index], "-decode") == 0) {
|
||||||
xml_mode = 1;
|
xml_mode = 1;
|
||||||
@@ -1462,9 +1594,11 @@ int main(int argc, char *argv[]) {
|
|||||||
filename = argv[arg_index + 1];
|
filename = argv[arg_index + 1];
|
||||||
} else {
|
} else {
|
||||||
printf("Usage: V2GDecoder [-debug] [-decode|-encode] input_file\\n");
|
printf("Usage: V2GDecoder [-debug] [-decode|-encode] input_file\\n");
|
||||||
|
printf(" V2GDecoder [-debug] filename (auto-detect by extension)\\n");
|
||||||
printf(" V2GDecoder [-debug] -encode (read XML from stdin)\\n");
|
printf(" V2GDecoder [-debug] -encode (read XML from stdin)\\n");
|
||||||
printf(" V2GDecoder [-debug] -decode (read hex string from stdin)\\n");
|
printf(" V2GDecoder [-debug] -decode (read hex string from stdin)\\n");
|
||||||
printf("Enhanced EXI viewer with XML conversion capabilities\\n");
|
printf("Enhanced EXI viewer with XML conversion capabilities\\n");
|
||||||
|
printf(" filename Auto-detect: .xml files are encoded, others are decoded/analyzed\\n");
|
||||||
printf(" -debug Enable detailed bit-level encoding/decoding output\\n");
|
printf(" -debug Enable detailed bit-level encoding/decoding output\\n");
|
||||||
printf(" -decode Convert EXI to Wireshark-style XML format\\n");
|
printf(" -decode Convert EXI to Wireshark-style XML format\\n");
|
||||||
printf(" -decode Read hex string from stdin (echo hex | V2GDecoder -decode)\\n");
|
printf(" -decode Read hex string from stdin (echo hex | V2GDecoder -decode)\\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user