From 5a7b57f90cfe4d3a27ee6b9e84e9933e1a622ebd Mon Sep 17 00:00:00 2001 From: ChiKyun Kim Date: Wed, 10 Sep 2025 17:33:07 +0900 Subject: [PATCH] feat: Add stdin support for both encode and decode in VC2022 C version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added stdin support for XML encoding: V2GDecoder.exe -encode (reads XML from stdin) - Added stdin support for hex decoding: V2GDecoder.exe -decode (reads hex string from stdin) - Implemented hexStringToBinary() function for hex string to binary conversion - Enhanced main() argument parsing to support stdin mode with filename "-" - Updated help messages to show new pipe support options - Cross-validated with original C program - 100% identical results for both encoding and decoding - Enables pipeline usage: echo hex | V2GDecoder.exe -decode and type file.xml | V2GDecoder.exe -encode 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- csharp/vc2022/V2GDecoder.c | 170 +++++++++++++++++++++++++++++++------ 1 file changed, 145 insertions(+), 25 deletions(-) diff --git a/csharp/vc2022/V2GDecoder.c b/csharp/vc2022/V2GDecoder.c index 7de0a8c..2b064d5 100644 --- a/csharp/vc2022/V2GDecoder.c +++ b/csharp/vc2022/V2GDecoder.c @@ -829,6 +829,53 @@ void dump_iso1_document_to_file(const struct iso1EXIDocument* doc, const char* f printf("✓ Structure dump saved to %s\n", filename); } +// Helper function to convert hex string to binary +int hexStringToBinary(const char* hex_string, uint8_t* buffer, size_t buffer_size, size_t* bytes_written) { + size_t hex_len = strlen(hex_string); + + // Remove any whitespace and newlines + char* cleaned_hex = malloc(hex_len + 1); + if (!cleaned_hex) { + return -1; + } + + size_t clean_pos = 0; + for (size_t i = 0; i < hex_len; i++) { + char c = hex_string[i]; + if (isxdigit(c)) { + cleaned_hex[clean_pos++] = toupper(c); + } + } + cleaned_hex[clean_pos] = '\0'; + + // Check if hex string length is even + if (clean_pos % 2 != 0) { + free(cleaned_hex); + return -1; // Invalid hex string length + } + + size_t binary_len = clean_pos / 2; + if (binary_len > buffer_size) { + free(cleaned_hex); + return -2; // Buffer too small + } + + // Convert hex pairs to bytes + for (size_t i = 0; i < binary_len; i++) { + char hex_byte[3] = {cleaned_hex[i*2], cleaned_hex[i*2+1], '\0'}; + unsigned int byte_val; + if (sscanf(hex_byte, "%X", &byte_val) != 1) { + free(cleaned_hex); + return -3; // Invalid hex character + } + buffer[i] = (uint8_t)byte_val; + } + + *bytes_written = binary_len; + free(cleaned_hex); + return 0; +} + // Helper function to read EXI file int readEXIFile(char* file, uint8_t* buffer, size_t buffer_size, size_t *bytes_read) { FILE *fp = fopen(file, "rb"); @@ -1099,7 +1146,17 @@ int main(int argc, char *argv[]) { char *filename = NULL; if (argc == 2) { - filename = argv[1]; + if (strcmp(argv[1], "-encode") == 0) { + // Special case: -encode without filename reads from stdin + encode_mode = 1; + filename = "-"; // Use "-" to indicate stdin + } else if (strcmp(argv[1], "-decode") == 0) { + // Special case: -decode without filename reads from stdin + xml_mode = 1; + filename = "-"; // Use "-" to indicate stdin + } else { + filename = argv[1]; + } } else if (argc == 3 && strcmp(argv[1], "-decode") == 0) { xml_mode = 1; filename = argv[2]; @@ -1108,9 +1165,13 @@ int main(int argc, char *argv[]) { filename = argv[2]; } else { printf("Usage: %s [-decode|-encode] input_file\\n", argv[0]); + printf(" %s -encode (read XML from stdin)\\n", argv[0]); + printf(" %s -decode (read hex string from stdin)\\n", argv[0]); printf("Enhanced EXI viewer with XML conversion capabilities\\n"); printf(" -decode Convert EXI to Wireshark-style XML format\\n"); + printf(" -decode Read hex string from stdin (echo hex | %s -decode)\\n", argv[0]); printf(" -encode Convert XML to EXI format\\n"); + printf(" -encode Read XML from stdin (type file.xml | %s -encode)\\n", argv[0]); printf(" (default) Analyze EXI with detailed output\\n"); return -1; } @@ -1131,29 +1192,62 @@ int main(int argc, char *argv[]) { // Handle encode mode (XML to EXI) if (encode_mode) { - // Read XML file - FILE* xml_file = fopen(filename, "r"); - if (!xml_file) { - printf("Error opening XML file: %s\\n", filename); - return -1; - } + FILE* xml_file; + char* xml_content; + long xml_size; - // Read entire XML content - fseek(xml_file, 0, SEEK_END); - long xml_size = ftell(xml_file); - fseek(xml_file, 0, SEEK_SET); - - char* xml_content = malloc(xml_size + 1); - if (!xml_content) { - printf("Error allocating memory for XML content\\n"); + // Check if reading from stdin or file + if (strcmp(filename, "-") == 0) { + // Read from stdin + xml_file = stdin; + + // Read all content from stdin + size_t capacity = 4096; + xml_content = malloc(capacity); + if (!xml_content) { + printf("Error allocating memory for XML content\\n"); + return -1; + } + + xml_size = 0; + int ch; + while ((ch = fgetc(stdin)) != EOF) { + if (xml_size >= capacity - 1) { + capacity *= 2; + xml_content = realloc(xml_content, capacity); + if (!xml_content) { + printf("Error reallocating memory for XML content\\n"); + return -1; + } + } + xml_content[xml_size++] = ch; + } + xml_content[xml_size] = '\0'; + } else { + // Read XML file + xml_file = fopen(filename, "r"); + if (!xml_file) { + printf("Error opening XML file: %s\\n", filename); + return -1; + } + + // Read entire XML content + fseek(xml_file, 0, SEEK_END); + xml_size = ftell(xml_file); + fseek(xml_file, 0, SEEK_SET); + + xml_content = malloc(xml_size + 1); + if (!xml_content) { + printf("Error allocating memory for XML content\\n"); + fclose(xml_file); + return -1; + } + + fread(xml_content, 1, xml_size, xml_file); + xml_content[xml_size] = '\0'; fclose(xml_file); - return -1; } - fread(xml_content, 1, xml_size, xml_file); - xml_content[xml_size] = '\0'; - fclose(xml_file); - // Parse XML to ISO1 document structure if (parse_xml_to_iso1(xml_content, &iso1Doc) != 0) { printf("Error parsing XML file - no supported message type found\\n"); @@ -1221,11 +1315,37 @@ int main(int argc, char *argv[]) { return 0; } - // Read EXI file for decode/analysis mode - errn = readEXIFile(filename, buffer, BUFFER_SIZE, &pos); - if (errn != 0) { - printf("Error reading file: %s\\n", filename); - return -1; + // Read EXI data for decode/analysis mode + if (strcmp(filename, "-") == 0 && xml_mode) { + // Read hex string from stdin for decode mode + char hex_input[BUFFER_SIZE * 2 + 1]; // Hex string can be up to 2x binary size + size_t hex_len = 0; + + // Read hex string from stdin + int ch; + while ((ch = fgetc(stdin)) != EOF && hex_len < sizeof(hex_input) - 1) { + hex_input[hex_len++] = ch; + } + hex_input[hex_len] = '\0'; + + // Convert hex string to binary + errn = hexStringToBinary(hex_input, buffer, BUFFER_SIZE, &pos); + if (errn != 0) { + printf("Error converting hex string to binary (error: %d)\\n", errn); + printf("Make sure input is a valid hex string like: 8098021050908C0C0C0E0C50E001993206002040C40C203030C014000603DA98B3E60C0008\\n"); + return -1; + } + + if (!xml_mode) { + printf("Hex string from stdin (%zu bytes converted to %zu binary bytes)\\n", hex_len, pos); + } + } else { + // Read from file + errn = readEXIFile(filename, buffer, BUFFER_SIZE, &pos); + if (errn != 0) { + printf("Error reading file: %s\\n", filename); + return -1; + } } if (!xml_mode) {