feat: Add stdin support for both encode and decode in VC2022 C version

- 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 <noreply@anthropic.com>
This commit is contained in:
ChiKyun Kim
2025-09-10 17:33:07 +09:00
parent 5afcce7a17
commit 5a7b57f90c

View File

@@ -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); 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 // Helper function to read EXI file
int readEXIFile(char* file, uint8_t* buffer, size_t buffer_size, size_t *bytes_read) { int readEXIFile(char* file, uint8_t* buffer, size_t buffer_size, size_t *bytes_read) {
FILE *fp = fopen(file, "rb"); FILE *fp = fopen(file, "rb");
@@ -1099,7 +1146,17 @@ int main(int argc, char *argv[]) {
char *filename = NULL; char *filename = NULL;
if (argc == 2) { 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) { } else if (argc == 3 && strcmp(argv[1], "-decode") == 0) {
xml_mode = 1; xml_mode = 1;
filename = argv[2]; filename = argv[2];
@@ -1108,9 +1165,13 @@ int main(int argc, char *argv[]) {
filename = argv[2]; filename = argv[2];
} else { } else {
printf("Usage: %s [-decode|-encode] input_file\\n", argv[0]); 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("Enhanced EXI viewer with XML conversion capabilities\\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 | %s -decode)\\n", argv[0]);
printf(" -encode Convert XML to EXI format\\n"); 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"); printf(" (default) Analyze EXI with detailed output\\n");
return -1; return -1;
} }
@@ -1131,29 +1192,62 @@ int main(int argc, char *argv[]) {
// Handle encode mode (XML to EXI) // Handle encode mode (XML to EXI)
if (encode_mode) { if (encode_mode) {
// Read XML file FILE* xml_file;
FILE* xml_file = fopen(filename, "r"); char* xml_content;
if (!xml_file) { long xml_size;
printf("Error opening XML file: %s\\n", filename);
return -1;
}
// Read entire XML content // Check if reading from stdin or file
fseek(xml_file, 0, SEEK_END); if (strcmp(filename, "-") == 0) {
long xml_size = ftell(xml_file); // Read from stdin
fseek(xml_file, 0, SEEK_SET); xml_file = stdin;
char* xml_content = malloc(xml_size + 1); // Read all content from stdin
if (!xml_content) { size_t capacity = 4096;
printf("Error allocating memory for XML content\\n"); 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); 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 // Parse XML to ISO1 document structure
if (parse_xml_to_iso1(xml_content, &iso1Doc) != 0) { if (parse_xml_to_iso1(xml_content, &iso1Doc) != 0) {
printf("Error parsing XML file - no supported message type found\\n"); printf("Error parsing XML file - no supported message type found\\n");
@@ -1221,11 +1315,37 @@ int main(int argc, char *argv[]) {
return 0; return 0;
} }
// Read EXI file for decode/analysis mode // Read EXI data for decode/analysis mode
errn = readEXIFile(filename, buffer, BUFFER_SIZE, &pos); if (strcmp(filename, "-") == 0 && xml_mode) {
if (errn != 0) { // Read hex string from stdin for decode mode
printf("Error reading file: %s\\n", filename); char hex_input[BUFFER_SIZE * 2 + 1]; // Hex string can be up to 2x binary size
return -1; 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) { if (!xml_mode) {