#include #include #include #include /* EXI codec headers */ #include "iso1EXIDatatypes.h" #include "iso1EXIDatatypesDecoder.h" #include "iso1EXIDatatypesEncoder.h" #include "iso2EXIDatatypes.h" #include "iso2EXIDatatypesDecoder.h" #include "iso2EXIDatatypesEncoder.h" #include "dinEXIDatatypes.h" #include "dinEXIDatatypesDecoder.h" #include "dinEXIDatatypesEncoder.h" #include "ByteStream.h" #define BUFFER_SIZE 4096 // Helper function to convert char* string to exi_string_character_t* array static int writeStringToEXIString(char* string, exi_string_character_t* exiString) { int pos = 0; while(string[pos] != '\0') { exiString[pos] = string[pos]; pos++; } return pos; } char* trim_whitespace(char* str) { char* end; while(isspace((unsigned char)*str)) str++; if(*str == 0) return str; end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; end[1] = '\0'; return str; } // Helper function to find XML tag content within a bounded section char* find_tag_in_section(const char* section_start, const char* section_end, const char* tag) { static char result[1024]; char start_tag[256], end_tag[256]; snprintf(start_tag, sizeof(start_tag), "<%s>", tag); snprintf(end_tag, sizeof(end_tag), "", tag); // Search for tag within the bounded section char* tag_start = strstr(section_start, start_tag); if (!tag_start || tag_start >= section_end) { return NULL; } char* content_start = tag_start + strlen(start_tag); if (content_start >= section_end) { return NULL; } char* tag_end = strstr(content_start, end_tag); if (!tag_end || tag_end > section_end) { return NULL; } size_t len = tag_end - content_start; if (len >= sizeof(result)) len = sizeof(result) - 1; strncpy(result, content_start, len); result[len] = '\0'; char* trimmed = trim_whitespace(result); return trimmed; } // Helper function to find XML tag content char* find_tag_content(const char* xml, const char* tag) { static char result[1024]; char start_tag[256], end_tag[256]; snprintf(start_tag, sizeof(start_tag), "<%s>", tag); snprintf(end_tag, sizeof(end_tag), "", tag); char* start = strstr(xml, start_tag); if (!start) return NULL; start += strlen(start_tag); char* end = strstr(start, end_tag); if (!end) return NULL; size_t len = end - start; if (len >= sizeof(result)) len = sizeof(result) - 1; strncpy(result, start, len); result[len] = '\0'; return trim_whitespace(result); } int parse_session_id(const char* hex_str, uint8_t* bytes, size_t* len) { size_t hex_len = strlen(hex_str); if (hex_len % 2 != 0) return -1; *len = hex_len / 2; for (size_t i = 0; i < *len; i++) { unsigned int byte; if (sscanf(&hex_str[i*2], "%2x", &byte) != 1) return -1; bytes[i] = (uint8_t)byte; } return 0; } // Parse PhysicalValue from section bounded XML void parse_physical_value_from_section(const char* section_start, const char* section_end, struct iso1PhysicalValueType* pv) { // Copy the found values to local variables to avoid static buffer overwriting char mult_str[64] = {0}; char unit_str[64] = {0}; char value_str[64] = {0}; char* mult = find_tag_in_section(section_start, section_end, "Multiplier"); if (mult) strncpy(mult_str, mult, sizeof(mult_str)-1); char* unit = find_tag_in_section(section_start, section_end, "Unit"); if (unit) strncpy(unit_str, unit, sizeof(unit_str)-1); char* value = find_tag_in_section(section_start, section_end, "Value"); if (value) strncpy(value_str, value, sizeof(value_str)-1); // Now parse the copied values if (mult) pv->Multiplier = atoi(mult_str); if (unit) pv->Unit = atoi(unit_str); if (value) pv->Value = atoi(value_str); } // Parse XML to ISO1 document for encoding int parse_xml_to_iso1(const char* xml_content, struct iso1EXIDocument* doc) { init_iso1EXIDocument(doc); // Find SessionID char* session_id_str = find_tag_content(xml_content, "SessionID"); if (session_id_str) { size_t len; if (parse_session_id(session_id_str, doc->V2G_Message.Header.SessionID.bytes, &len) == 0) { doc->V2G_Message.Header.SessionID.bytesLen = len; doc->V2G_Message_isUsed = 1; } } // Check for CurrentDemandReq if (strstr(xml_content, "") || strstr(xml_content, "")) { doc->V2G_Message.Body.CurrentDemandReq_isUsed = 1; init_iso1CurrentDemandReqType(&doc->V2G_Message.Body.CurrentDemandReq); // Parse DC_EVStatus char* ev_ready = find_tag_content(xml_content, "EVReady"); if (ev_ready) { doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVReady = (strcmp(ev_ready, "true") == 0); } char* ev_error = find_tag_content(xml_content, "EVErrorCode"); if (ev_error) { if (strcmp(ev_error, "NO_ERROR") == 0) { doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode = 0; } else { doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode = atoi(ev_error); } } char* ev_soc = find_tag_content(xml_content, "EVRESSSOC"); if (ev_soc) { doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVRESSSOC = atoi(ev_soc); } // Parse EVTargetCurrent using bounded section approach char* current_section = strstr(xml_content, ""); if (!current_section) current_section = strstr(xml_content, ""); if (current_section) { char* current_end = strstr(current_section, ""); if (!current_end) current_end = strstr(current_section, ""); if (current_end) { parse_physical_value_from_section(current_section, current_end, &doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent); } } // Parse EVTargetVoltage using bounded section approach char* voltage_section = strstr(xml_content, ""); if (!voltage_section) voltage_section = strstr(xml_content, ""); if (voltage_section) { char* voltage_end = strstr(voltage_section, ""); if (!voltage_end) voltage_end = strstr(voltage_section, ""); if (voltage_end) { parse_physical_value_from_section(voltage_section, voltage_end, &doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage); } } // Parse ChargingComplete char* charging_complete = find_tag_content(xml_content, "ChargingComplete"); if (charging_complete) { doc->V2G_Message.Body.CurrentDemandReq.ChargingComplete = (strcmp(charging_complete, "true") == 0); } // Parse optional fields if present if (strstr(xml_content, "") || strstr(xml_content, "")) { doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit_isUsed = 1; char* max_volt_section = strstr(xml_content, ""); if (!max_volt_section) max_volt_section = strstr(xml_content, ""); char* max_volt_end = strstr(max_volt_section, ""); if (!max_volt_end) max_volt_end = strstr(max_volt_section, ""); if (max_volt_section && max_volt_end) { parse_physical_value_from_section(max_volt_section, max_volt_end, &doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit); } } if (strstr(xml_content, "") || strstr(xml_content, "")) { doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit_isUsed = 1; char* max_curr_section = strstr(xml_content, ""); if (!max_curr_section) max_curr_section = strstr(xml_content, ""); char* max_curr_end = strstr(max_curr_section, ""); if (!max_curr_end) max_curr_end = strstr(max_curr_section, ""); if (max_curr_section && max_curr_end) { parse_physical_value_from_section(max_curr_section, max_curr_end, &doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit); } } if (strstr(xml_content, "") || strstr(xml_content, "")) { doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit_isUsed = 1; char* max_power_section = strstr(xml_content, ""); if (!max_power_section) max_power_section = strstr(xml_content, ""); char* max_power_end = strstr(max_power_section, ""); if (!max_power_end) max_power_end = strstr(max_power_section, ""); if (max_power_section && max_power_end) { parse_physical_value_from_section(max_power_section, max_power_end, &doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit); } } // Parse BulkChargingComplete char* bulk_charging_complete = find_tag_content(xml_content, "BulkChargingComplete"); if (bulk_charging_complete) { doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete_isUsed = 1; doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete = (strcmp(bulk_charging_complete, "true") == 0); } // Parse remaining time fields if (strstr(xml_content, "") || strstr(xml_content, "")) { doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC_isUsed = 1; char* time_section = strstr(xml_content, ""); if (!time_section) time_section = strstr(xml_content, ""); char* time_end = strstr(time_section, ""); if (!time_end) time_end = strstr(time_section, ""); if (time_section && time_end) { parse_physical_value_from_section(time_section, time_end, &doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC); } } if (strstr(xml_content, "") || strstr(xml_content, "")) { doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC_isUsed = 1; char* bulk_time_section = strstr(xml_content, ""); if (!bulk_time_section) bulk_time_section = strstr(xml_content, ""); char* bulk_time_end = strstr(bulk_time_section, ""); if (!bulk_time_end) bulk_time_end = strstr(bulk_time_section, ""); if (bulk_time_section && bulk_time_end) { parse_physical_value_from_section(bulk_time_section, bulk_time_end, &doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC); } } return 0; } return -1; // Unsupported message type } // 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"); if (fp == NULL) { return -1; } *bytes_read = fread(buffer, 1, buffer_size, fp); fclose(fp); if (*bytes_read == 0) { return -1; } return 0; } // Helper functions for Wireshark XML output removed - using numeric values directly void print_xml_header_wireshark() { printf("\n"); printf("\n"); } void print_xml_footer_wireshark() { printf(""); } void print_iso1_xml_wireshark(struct iso1EXIDocument* doc) { print_xml_header_wireshark(); printf(""); for(int i = 0; i < doc->V2G_Message.Header.SessionID.bytesLen; i++) { printf("%02X", doc->V2G_Message.Header.SessionID.bytes[i]); } printf(""); printf(""); if (doc->V2G_Message.Body.CurrentDemandRes_isUsed) { printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.ResponseCode); printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEStatusCode); printf(""); printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Value); printf(""); printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Value); printf(""); printf("%s", doc->V2G_Message.Body.CurrentDemandRes.EVSECurrentLimitAchieved ? "true" : "false"); printf("%s", doc->V2G_Message.Body.CurrentDemandRes.EVSEVoltageLimitAchieved ? "true" : "false"); printf("%s", doc->V2G_Message.Body.CurrentDemandRes.EVSEPowerLimitAchieved ? "true" : "false"); printf("%.*s", doc->V2G_Message.Body.CurrentDemandRes.EVSEID.charactersLen, doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters); printf("%d", doc->V2G_Message.Body.CurrentDemandRes.SAScheduleTupleID); printf(""); } else if (doc->V2G_Message.Body.CurrentDemandReq_isUsed) { printf(""); printf(""); printf("%s", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVReady ? "true" : "false"); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVRESSSOC); printf(""); printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Value); printf(""); printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Value); printf(""); if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit_isUsed) { printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Value); printf(""); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit_isUsed) { printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Value); printf(""); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit_isUsed) { printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Value); printf(""); } if (doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete_isUsed) { printf("%s", doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete ? "true" : "false"); } printf("%s", doc->V2G_Message.Body.CurrentDemandReq.ChargingComplete ? "true" : "false"); if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC_isUsed) { printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Value); printf(""); } if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC_isUsed) { printf(""); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Multiplier); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit); printf("%d", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Value); printf(""); } printf(""); } printf(""); print_xml_footer_wireshark(); } void print_iso1_message(struct iso1EXIDocument* doc) { printf("=== ISO 15118-2 V2G Message Analysis ===\n"); printf("Message Type: ISO1 (2013)\n"); printf("V2G_Message_isUsed: %s\n", doc->V2G_Message_isUsed ? "true" : "false"); if (doc->V2G_Message_isUsed) { printf("\n--- Header ---\n"); printf("SessionID: "); for(int i = 0; i < doc->V2G_Message.Header.SessionID.bytesLen; i++) { printf("%02X", doc->V2G_Message.Header.SessionID.bytes[i]); } printf(" ("); for(int i = 0; i < doc->V2G_Message.Header.SessionID.bytesLen; i++) { if (doc->V2G_Message.Header.SessionID.bytes[i] >= 32 && doc->V2G_Message.Header.SessionID.bytes[i] <= 126) { printf("%c", doc->V2G_Message.Header.SessionID.bytes[i]); } else { printf("."); } } printf(")\n"); printf("\n--- Body ---\n"); if (doc->V2G_Message.Body.CurrentDemandRes_isUsed) { printf("Message Type: CurrentDemandRes\n"); printf("ResponseCode: %d\n", doc->V2G_Message.Body.CurrentDemandRes.ResponseCode); printf("\nDC_EVSEStatus:\n"); printf(" EVSEIsolationStatus: %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEIsolationStatus); printf(" EVSEStatusCode: %d\n", doc->V2G_Message.Body.CurrentDemandRes.DC_EVSEStatus.EVSEStatusCode); printf("\nEVSEPresentVoltage:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentVoltage.Value); printf("\nEVSEPresentCurrent:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPresentCurrent.Value); printf("\nLimit Status:\n"); printf(" CurrentLimitAchieved: %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSECurrentLimitAchieved ? "true" : "false"); printf(" VoltageLimitAchieved: %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEVoltageLimitAchieved ? "true" : "false"); printf(" PowerLimitAchieved: %s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEPowerLimitAchieved ? "true" : "false"); printf("\nEVSEID: %.*s\n", doc->V2G_Message.Body.CurrentDemandRes.EVSEID.charactersLen, doc->V2G_Message.Body.CurrentDemandRes.EVSEID.characters); printf("SAScheduleTupleID: %d\n", doc->V2G_Message.Body.CurrentDemandRes.SAScheduleTupleID); } else if (doc->V2G_Message.Body.CurrentDemandReq_isUsed) { printf("Message Type: CurrentDemandReq\n"); printf("\nDC_EVStatus:\n"); printf(" EVReady: %s\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVReady ? "true" : "false"); printf(" EVErrorCode: %d\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVErrorCode); printf(" EVRESSSOC: %d%%\n", doc->V2G_Message.Body.CurrentDemandReq.DC_EVStatus.EVRESSSOC); printf("\nEVTargetCurrent:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetCurrent.Value); printf("\nEVTargetVoltage:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVTargetVoltage.Value); if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit_isUsed) { printf("\nEVMaximumVoltageLimit:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumVoltageLimit.Value); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit_isUsed) { printf("\nEVMaximumCurrentLimit:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumCurrentLimit.Value); } if (doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit_isUsed) { printf("\nEVMaximumPowerLimit:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.EVMaximumPowerLimit.Value); } if (doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete_isUsed) { printf("\nBulkChargingComplete: %s\n", doc->V2G_Message.Body.CurrentDemandReq.BulkChargingComplete ? "true" : "false"); } printf("ChargingComplete: %s\n", doc->V2G_Message.Body.CurrentDemandReq.ChargingComplete ? "true" : "false"); if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC_isUsed) { printf("\nRemainingTimeToFullSoC:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToFullSoC.Value); } if (doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC_isUsed) { printf("\nRemainingTimeToBulkSoC:\n"); printf(" Multiplier: %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Multiplier); printf(" Unit: %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Unit); printf(" Value: %d\n", doc->V2G_Message.Body.CurrentDemandReq.RemainingTimeToBulkSoC.Value); } } else { printf("Message Type: Other message type (not fully supported)\n"); } } printf("\n"); } int main(int argc, char *argv[]) { int xml_mode = 0; int encode_mode = 0; char *filename = NULL; if (argc == 2) { filename = argv[1]; } else if (argc == 3 && strcmp(argv[1], "-decode") == 0) { xml_mode = 1; filename = argv[2]; } else if (argc == 3 && strcmp(argv[1], "-encode") == 0) { encode_mode = 1; filename = argv[2]; } else { printf("Usage: %s [-decode|-encode] input_file\\n", argv[0]); printf("Enhanced EXI viewer with XML conversion capabilities\\n"); printf(" -decode Convert EXI to Wireshark-style XML format\\n"); printf(" -encode Convert XML to EXI format\\n"); printf(" (default) Analyze EXI with detailed output\\n"); return -1; } uint8_t buffer[BUFFER_SIZE]; bitstream_t stream; size_t pos = 0; int errn = 0; struct iso1EXIDocument iso1Doc; struct iso2EXIDocument iso2Doc; struct dinEXIDocument dinDoc; // Initialize documents init_iso1EXIDocument(&iso1Doc); init_iso2EXIDocument(&iso2Doc); init_dinEXIDocument(&dinDoc); // 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; } // 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"); 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\\n"); free(xml_content); return -1; } free(xml_content); // Encode to EXI pos = 0; stream.size = BUFFER_SIZE; stream.data = buffer; stream.pos = &pos; stream.buffer = 0; stream.capacity = 0; errn = encode_iso1ExiDocument(&stream, &iso1Doc); if (errn != 0) { printf("Error encoding to EXI (error: %d)\\n", errn); return -1; } // Write EXI data to stdout (binary) fwrite(buffer, 1, pos, stdout); 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; } if (!xml_mode) { printf("File: %s (%zu bytes)\\n", filename, pos); printf("Raw hex data: "); for(size_t i = 0; i < (pos > 32 ? 32 : pos); i++) { printf("%02X ", buffer[i]); } if (pos > 32) printf("..."); printf("\\n\\n"); } // Setup stream pos = 0; // reset position for decoding stream.size = BUFFER_SIZE; stream.data = buffer; stream.pos = &pos; stream.buffer = 0; stream.capacity = 0; // Try ISO1 first pos = 0; if (!xml_mode) printf("Trying ISO1 decoder...\\n"); errn = decode_iso1ExiDocument(&stream, &iso1Doc); if (errn == 0) { if (!xml_mode) printf("✓ Successfully decoded as ISO1\\n\\n"); if (xml_mode) { print_iso1_xml_wireshark(&iso1Doc); } else { print_iso1_message(&iso1Doc); } return 0; } else { if (!xml_mode) printf("✗ ISO1 decode failed (error: %d)\\n", errn); } // Try ISO2 pos = 0; if (!xml_mode) printf("Trying ISO2 decoder...\\n"); errn = decode_iso2ExiDocument(&stream, &iso2Doc); if (errn == 0) { if (!xml_mode) printf("✓ Successfully decoded as ISO2\\n\\n"); if (xml_mode) { printf("ISO2 XML output not implemented for Wireshark format\\n"); } else { printf("ISO2 analysis not fully implemented\\n"); } return 0; } else { if (!xml_mode) printf("✗ ISO2 decode failed (error: %d)\\n", errn); } // Try DIN pos = 0; if (!xml_mode) printf("Trying DIN decoder...\\n"); errn = decode_dinExiDocument(&stream, &dinDoc); if (errn == 0) { if (!xml_mode) { printf("✓ Successfully decoded as DIN\\n\\n"); printf("=== DIN V2G Message ===\\n"); // Add DIN message printing as needed } return 0; } else { if (!xml_mode) printf("✗ DIN decode failed (error: %d)\\n", errn); } if (!xml_mode) { printf("\\n❌ Could not decode EXI file with any supported codec\\n"); printf("Supported formats: ISO1, ISO2, DIN\\n"); } return -1; }