Compare commits
	
		
			3 Commits
		
	
	
		
			fdfab0c666
			...
			7ba42fe215
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7ba42fe215 | |||
| e09c63080e | |||
| 4f2f6a99d7 | 
							
								
								
									
										38
									
								
								Helper.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Helper.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | using System; | ||||||
|  |  | ||||||
|  | namespace V2GProtocol | ||||||
|  | { | ||||||
|  |     /// <summary> | ||||||
|  |     /// 헥스 문자열 변환 헬퍼 클래스 | ||||||
|  |     /// </summary> | ||||||
|  |     public static class Helper | ||||||
|  |     { | ||||||
|  |         /// <summary> | ||||||
|  |         /// 헥스 문자열을 바이트 배열로 변환 | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name="hexString">헥스 문자열</param> | ||||||
|  |         /// <returns>바이트 배열</returns> | ||||||
|  |         public static byte[] FromHexString(string hexString) | ||||||
|  |         { | ||||||
|  |             if (hexString.Length % 2 != 0) | ||||||
|  |                 throw new ArgumentException("Invalid hex string length"); | ||||||
|  |                  | ||||||
|  |             byte[] bytes = new byte[hexString.Length / 2]; | ||||||
|  |             for (int i = 0; i < bytes.Length; i++) | ||||||
|  |             { | ||||||
|  |                 bytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); | ||||||
|  |             } | ||||||
|  |             return bytes; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         /// <summary> | ||||||
|  |         /// 바이트 배열을 헥스 문자열로 변환 | ||||||
|  |         /// </summary> | ||||||
|  |         /// <param name="bytes">바이트 배열</param> | ||||||
|  |         /// <returns>헥스 문자열</returns> | ||||||
|  |         public static string ToHexString(byte[] bytes) | ||||||
|  |         { | ||||||
|  |             return BitConverter.ToString(bytes).Replace("-", ""); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										140
									
								
								Program.cs
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								Program.cs
									
									
									
									
									
								
							| @@ -9,7 +9,7 @@ namespace V2GProtocol | |||||||
|     { |     { | ||||||
|         static void Main(string[] args) |         static void Main(string[] args) | ||||||
|         { |         { | ||||||
|             // Only show header for help or analysis mode (not for encode/decode operations) |             // 헤더는 도움말 또는 분석 모드에서만 표시 (인코드/디코드 작업에서는 표시하지 않음) | ||||||
|             bool showHeader = false; |             bool showHeader = false; | ||||||
|              |              | ||||||
|             if (args.Length == 0) |             if (args.Length == 0) | ||||||
| @@ -20,18 +20,18 @@ namespace V2GProtocol | |||||||
|             { |             { | ||||||
|                 string firstArg = args[0].ToLower(); |                 string firstArg = args[0].ToLower(); | ||||||
|                  |                  | ||||||
|                 // Check if it's help command |                 // 도움말 명령인지 확인 | ||||||
|                 if (firstArg == "--help" || firstArg == "-h") |                 if (firstArg == "--help" || firstArg == "-h") | ||||||
|                 { |                 { | ||||||
|                     showHeader = true; |                     showHeader = true; | ||||||
|                 } |                 } | ||||||
|                 // Check if it's a file for analysis mode (only .dump/.txt without options) |                 // 분석 모드용 파일인지 확인 (옵션 없이 .dump/.txt만) | ||||||
|                 else if (File.Exists(args[0]) && args.Length == 1) |                 else if (File.Exists(args[0]) && args.Length == 1) | ||||||
|                 { |                 { | ||||||
|                     string extension = Path.GetExtension(args[0]).ToLower(); |                     string extension = Path.GetExtension(args[0]).ToLower(); | ||||||
|                      |                      | ||||||
|                     // Only show header for analysis mode (.dump/.txt) |                     // 분석 모드에서만 헤더 표시 (.dump/.txt) | ||||||
|                     // NOT for auto-conversion (.hex, .xml) |                     // 자동 변환에서는 표시하지 않음 (.hex, .xml) | ||||||
|                     if (extension == ".dump" || extension == ".txt") |                     if (extension == ".dump" || extension == ".txt") | ||||||
|                     { |                     { | ||||||
|                         showHeader = true; |                         showHeader = true; | ||||||
| @@ -42,8 +42,9 @@ namespace V2GProtocol | |||||||
|  |  | ||||||
|             if (showHeader) |             if (showHeader) | ||||||
|             { |             { | ||||||
|                 Console.WriteLine("=== V2G Transfer Protocol Decoder/Encoder ==="); |                 Console.WriteLine("=== V2G Transfer Protocol Decoder/Encoder"); | ||||||
|                 Console.WriteLine("ISO 15118-2 / DIN SPEC 70121 / SAP Protocol"); |                 Console.WriteLine("=== ISO 15118-2 / DIN SPEC 70121 / SAP Protocol"); | ||||||
|  |                 Console.WriteLine("=== made by [tindevil82@gmail.com]"); | ||||||
|                 Console.WriteLine(); |                 Console.WriteLine(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -62,13 +63,16 @@ namespace V2GProtocol | |||||||
|                 { |                 { | ||||||
|                     switch (command) |                     switch (command) | ||||||
|                     { |                     { | ||||||
|                         case "--decode" or "-d": |                         case "--decode": | ||||||
|  |                         case "-d": | ||||||
|                             HandleDecodeCommand(args); |                             HandleDecodeCommand(args); | ||||||
|                             break; |                             break; | ||||||
|                         case "--encode" or "-e": |                         case "--encode": | ||||||
|  |                         case "-e": | ||||||
|                             HandleEncodeCommand(args); |                             HandleEncodeCommand(args); | ||||||
|                             break; |                             break; | ||||||
|                         case "--help" or "-h": |                         case "--help": | ||||||
|  |                         case "-h": | ||||||
|                             ShowUsage(); |                             ShowUsage(); | ||||||
|                             break; |                             break; | ||||||
|                         default: |                         default: | ||||||
| @@ -97,35 +101,35 @@ namespace V2GProtocol | |||||||
|                 // 파일명만 전달된 경우 (분석 모드) |                 // 파일명만 전달된 경우 (분석 모드) | ||||||
|                 else if (File.Exists(args[0])) |                 else if (File.Exists(args[0])) | ||||||
|                 { |                 { | ||||||
|                     // Check file extension to determine default action |                     // 파일 확장자를 확인하여 기본 동작 결정 | ||||||
|                     string extension = Path.GetExtension(args[0]).ToLower(); |                     string extension = Path.GetExtension(args[0]).ToLower(); | ||||||
|                      |                      | ||||||
|                     if (extension == ".dump" || extension == ".txt") |                     if (extension == ".dump" || extension == ".txt") | ||||||
|                     { |                     { | ||||||
|                         // Hex dump files - use full analysis mode |                         // 헥스 덤프 파일 - 전체 분석 모드 사용 | ||||||
|                         AnalyzeFile(args[0]); |                         AnalyzeFile(args[0]); | ||||||
|                     } |                     } | ||||||
|                     else if (extension == ".hex") |                     else if (extension == ".hex") | ||||||
|                     { |                     { | ||||||
|                         // .hex files - automatically decode to XML |                         // .hex 파일 - 자동으로 XML로 디코드 | ||||||
|                         var autoArgs = new List<string> { "--decode", args[0] }; |                         var autoArgs = new List<string> { "--decode", args[0] }; | ||||||
|                         // Add remaining args (like -out) |                         // 나머지 인자 추가 (-out 등) | ||||||
|                         for (int i = 1; i < args.Length; i++) |                         for (int i = 1; i < args.Length; i++) | ||||||
|                             autoArgs.Add(args[i]); |                             autoArgs.Add(args[i]); | ||||||
|                         HandleDecodeCommand(autoArgs.ToArray()); |                         HandleDecodeCommand(autoArgs.ToArray()); | ||||||
|                     } |                     } | ||||||
|                     else if (extension == ".xml") |                     else if (extension == ".xml") | ||||||
|                     { |                     { | ||||||
|                         // .xml files - automatically encode to EXI |                         // .xml 파일 - 자동으로 EXI로 인코드 | ||||||
|                         var autoArgs = new List<string> { "--encode", args[0] }; |                         var autoArgs = new List<string> { "--encode", args[0] }; | ||||||
|                         // Add remaining args (like -out) |                         // 나머지 인자 추가 (-out 등) | ||||||
|                         for (int i = 1; i < args.Length; i++) |                         for (int i = 1; i < args.Length; i++) | ||||||
|                             autoArgs.Add(args[i]); |                             autoArgs.Add(args[i]); | ||||||
|                         HandleEncodeCommand(autoArgs.ToArray()); |                         HandleEncodeCommand(autoArgs.ToArray()); | ||||||
|                     } |                     } | ||||||
|                     else |                     else | ||||||
|                     { |                     { | ||||||
|                         // Unknown extension - require explicit option |                         // 알 수 없는 확장자 - 명시적 옵션 필요 | ||||||
|                         Console.WriteLine($"Error: Unknown file extension '{extension}'. Please specify operation:"); |                         Console.WriteLine($"Error: Unknown file extension '{extension}'. Please specify operation:"); | ||||||
|                         Console.WriteLine($"  {Path.GetFileName(args[0])} --decode   # To decode as EXI to XML"); |                         Console.WriteLine($"  {Path.GetFileName(args[0])} --decode   # To decode as EXI to XML"); | ||||||
|                         Console.WriteLine($"  {Path.GetFileName(args[0])} --encode   # To encode as XML to EXI"); |                         Console.WriteLine($"  {Path.GetFileName(args[0])} --encode   # To encode as XML to EXI"); | ||||||
| @@ -136,7 +140,7 @@ namespace V2GProtocol | |||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     Console.WriteLine($"Error: Unknown option or file not found: {args[0]}"); |                     Console.WriteLine($"Error: Unknown option or file not found: {args[0]}"); | ||||||
|                     ShowUsage(); |                     //ShowUsage(); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             catch (Exception ex) |             catch (Exception ex) | ||||||
| @@ -166,19 +170,12 @@ namespace V2GProtocol | |||||||
|             Console.WriteLine("Pipe Usage:"); |             Console.WriteLine("Pipe Usage:"); | ||||||
|             Console.WriteLine("  type file.xml | V2GDecoder.exe --encode        # Pipe XML file to encode"); |             Console.WriteLine("  type file.xml | V2GDecoder.exe --encode        # Pipe XML file to encode"); | ||||||
|             Console.WriteLine("  echo \"hex_string\" | V2GDecoder.exe --decode   # Pipe hex string to decode"); |             Console.WriteLine("  echo \"hex_string\" | V2GDecoder.exe --decode   # Pipe hex string to decode"); | ||||||
|  |             Console.WriteLine("Example:"); | ||||||
|  |             Console.WriteLine("V2GDecoder.exe 01FE80010000001E809802104142423030303831908C0C0C0E0C51E020256968C0C0C0C0C080 --decode"); | ||||||
|             Console.WriteLine(); |             Console.WriteLine(); | ||||||
|             Console.WriteLine("Examples:"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe data/dump2.dump                # Full analysis of hex dump"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe data/test.hex                  # Auto-decode hex to XML"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe data/encode0.xml               # Auto-encode XML to EXI"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe -d \"8098021050908C0C0C0E0C5211003200\"  # Decode hex string"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe data/test.dat --decode         # Decode unknown file type"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe data/data0.xml -out data0.hex  # Encode to binary file"); |  | ||||||
|             Console.WriteLine("  V2GDecoder.exe --decode data.hex -out out.xml # Decode to XML file"); |  | ||||||
|             Console.WriteLine("  type data\\encode0.xml | V2GDecoder.exe -e     # Pipe XML to encode"); |  | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         static string? GetOutputFilename(string[] args) |         static string GetOutputFilename(string[] args) | ||||||
|         { |         { | ||||||
|             for (int i = 0; i < args.Length - 1; i++) |             for (int i = 0; i < args.Length - 1; i++) | ||||||
|             { |             { | ||||||
| @@ -194,24 +191,24 @@ namespace V2GProtocol | |||||||
|         { |         { | ||||||
|             string input; |             string input; | ||||||
|             byte[] exiBytes; |             byte[] exiBytes; | ||||||
|             string? outputFile = GetOutputFilename(args); |             string outputFile = GetOutputFilename(args); | ||||||
|              |              | ||||||
|             // Check if we have sufficient arguments for file/string input |             // 파일/문자열 입력을 위한 충분한 인자가 있는지 확인 | ||||||
|             if (args.Length >= 2) |             if (args.Length >= 2) | ||||||
|             { |             { | ||||||
|                 // We have command line arguments, use them |                 // 명령줄 인자가 있으므로 사용 | ||||||
|                 input = args[1]; |                 input = args[1]; | ||||||
|             } |             } | ||||||
|             else if (Console.IsInputRedirected) |             else if (Console.IsInputRedirected) | ||||||
|             { |             { | ||||||
|                 // No sufficient arguments, check if input is coming from stdin (pipe) |                 // 충분한 인자가 없으므로 stdin(파이프)에서 입력이 오는지 확인 | ||||||
|                 input = Console.In.ReadToEnd().Trim(); |                 input = Console.In.ReadToEnd().Trim(); | ||||||
|                 if (string.IsNullOrEmpty(input)) |                 if (string.IsNullOrEmpty(input)) | ||||||
|                 { |                 { | ||||||
|                     Console.WriteLine("Error: No input data received from stdin"); |                     Console.WriteLine("Error: No input data received from stdin"); | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 outputFile = null; // Force console output for stdin |                 outputFile = null; // stdin의 경우 콘솔 출력 강제 | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
| @@ -220,18 +217,18 @@ namespace V2GProtocol | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             // Check if input is a file |             // 입력이 파일인지 확인 | ||||||
|             if (File.Exists(input)) |             if (File.Exists(input)) | ||||||
|             { |             { | ||||||
|                 // Handle different file extensions |                 // 다양한 파일 확장자 처리 | ||||||
|                 string extension = Path.GetExtension(input).ToLower(); |                 string extension = Path.GetExtension(input).ToLower(); | ||||||
|                  |                  | ||||||
|                 if (extension == ".dump") |                 if (extension == ".dump") | ||||||
|                 { |                 { | ||||||
|                     // Hex dump file format with arrows (→) |                     // 화살표(→)가 있는 헥스 덤프 파일 형식 | ||||||
|                     byte[] rawData = V2GDecoder.ParseHexFile(input); |                     byte[] rawData = V2GDecoder.ParseHexFile(input); | ||||||
|                      |                      | ||||||
|                     // Find V2G message in the hex dump |                     // 헥스 덤프에서 V2G 메시지 찾기 | ||||||
|                     var v2gMessage = ExtractV2GMessageFromHexDump(rawData); |                     var v2gMessage = ExtractV2GMessageFromHexDump(rawData); | ||||||
|                     if (v2gMessage != null) |                     if (v2gMessage != null) | ||||||
|                     { |                     { | ||||||
| @@ -239,24 +236,22 @@ namespace V2GProtocol | |||||||
|                     } |                     } | ||||||
|                     else |                     else | ||||||
|                     { |                     { | ||||||
|                         // Try to decode the raw data directly (might be pure EXI without V2G header) |                         // 원시 데이터를 직접 디코드 시도 (V2G 헤더 없는 순수 EXI일 수 있음) | ||||||
|                         exiBytes = rawData; |                         exiBytes = rawData; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 else if (extension == ".hex") |                 else if (extension == ".hex") | ||||||
|                 { |                 { | ||||||
|                     // Plain hex file (pure hex string) |                     // 바이너리 hex 파일 | ||||||
|                     string fileContent = File.ReadAllText(input).Trim(); |                     exiBytes = File.ReadAllBytes(input); | ||||||
|                     fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); |  | ||||||
|                     exiBytes = Convert.FromHexString(fileContent); |  | ||||||
|                 } |                 } | ||||||
|                 else if (extension == ".txt") |                 else if (extension == ".txt") | ||||||
|                 { |                 { | ||||||
|                     // Legacy support for .txt files - check content format |                     // .txt 파일에 대한 레거시 지원 - 컨텐츠 형식 확인 | ||||||
|                     string fileContent = File.ReadAllText(input).Trim(); |                     string fileContent = File.ReadAllText(input).Trim(); | ||||||
|                     if (fileContent.Contains("→")) |                     if (fileContent.Contains("→")) | ||||||
|                     { |                     { | ||||||
|                         // Hex dump format |                         // 헥스 덤프 형식 | ||||||
|                         byte[] rawData = V2GDecoder.ParseHexFile(input); |                         byte[] rawData = V2GDecoder.ParseHexFile(input); | ||||||
|                         var v2gMessage = ExtractV2GMessageFromHexDump(rawData); |                         var v2gMessage = ExtractV2GMessageFromHexDump(rawData); | ||||||
|                         if (v2gMessage != null) |                         if (v2gMessage != null) | ||||||
| @@ -270,22 +265,22 @@ namespace V2GProtocol | |||||||
|                     } |                     } | ||||||
|                     else |                     else | ||||||
|                     { |                     { | ||||||
|                         // Plain hex |                         // 순수 헥스 | ||||||
|                         fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); |                         fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); | ||||||
|                         exiBytes = Convert.FromHexString(fileContent); |                         exiBytes = Helper.FromHexString(fileContent); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     // Unknown extension, try as plain hex |                     // 알 수 없는 확장자, 순수 헥스로 시도 | ||||||
|                     string fileContent = File.ReadAllText(input).Trim(); |                     string fileContent = File.ReadAllText(input).Trim(); | ||||||
|                     fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); |                     fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", ""); | ||||||
|                     exiBytes = Convert.FromHexString(fileContent); |                     exiBytes = Helper.FromHexString(fileContent); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 // Direct hex string input |                 // 직접 헥스 문자열 입력 | ||||||
|                 string exiHexString = input.Replace(" ", "").Replace("-", "").Replace("0x", ""); |                 string exiHexString = input.Replace(" ", "").Replace("-", "").Replace("0x", ""); | ||||||
|                  |                  | ||||||
|                 if (exiHexString.Length % 2 != 0) |                 if (exiHexString.Length % 2 != 0) | ||||||
| @@ -294,23 +289,23 @@ namespace V2GProtocol | |||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                  |                  | ||||||
|                 exiBytes = Convert.FromHexString(exiHexString); |                 exiBytes = Helper.FromHexString(exiHexString); | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 // Decode EXI to XML - output only the XML |                 // EXI를 XML로 디코드 - XML만 출력 | ||||||
|                 var decodedXml = V2GDecoder.DecodeEXIToXML(exiBytes); |                 var decodedXml = V2GDecoder.DecodeEXIToXML(exiBytes); | ||||||
|                  |                  | ||||||
|                 if (outputFile != null) |                 if (outputFile != null) | ||||||
|                 { |                 { | ||||||
|                     // Save to file |                     // 파일로 저장 | ||||||
|                     File.WriteAllText(outputFile, decodedXml); |                     File.WriteAllText(outputFile, decodedXml); | ||||||
|                     Console.WriteLine($"Decoded XML saved to: {outputFile}"); |                     Console.WriteLine($"Decoded XML saved to: {outputFile}"); | ||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     // Output to console |                     // 콘솔로 출력 | ||||||
|                     Console.WriteLine(decodedXml); |                     Console.WriteLine(decodedXml); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -320,17 +315,17 @@ namespace V2GProtocol | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         static byte[]? ExtractV2GMessageFromHexDump(byte[] data) |         static byte[] ExtractV2GMessageFromHexDump(byte[] data) | ||||||
|         { |         { | ||||||
|             // Find V2G Transfer Protocol signature (0x01FE) |             // V2G Transfer Protocol 시그니처 찾기 (0x01FE) | ||||||
|             for (int i = 0; i < data.Length - 8; i++) |             for (int i = 0; i < data.Length - 8; i++) | ||||||
|             { |             { | ||||||
|                 if (data[i] == 0x01 && data[i + 1] == 0xFE) |                 if (data[i] == 0x01 && data[i + 1] == 0xFE) | ||||||
|                 { |                 { | ||||||
|                     // Get payload length |                     // 페이로드 길이 가져오기 | ||||||
|                     uint payloadLength = (uint)((data[i + 4] << 24) | (data[i + 5] << 16) | (data[i + 6] << 8) | data[i + 7]); |                     uint payloadLength = (uint)((data[i + 4] << 24) | (data[i + 5] << 16) | (data[i + 6] << 8) | data[i + 7]); | ||||||
|                      |                      | ||||||
|                     // Extract EXI payload |                     // EXI 페이로드 추출 | ||||||
|                     if (i + 8 + payloadLength <= data.Length) |                     if (i + 8 + payloadLength <= data.Length) | ||||||
|                     { |                     { | ||||||
|                         byte[] exiPayload = new byte[payloadLength]; |                         byte[] exiPayload = new byte[payloadLength]; | ||||||
| @@ -346,15 +341,15 @@ namespace V2GProtocol | |||||||
|         { |         { | ||||||
|             string xmlInput; |             string xmlInput; | ||||||
|             string xmlContent; |             string xmlContent; | ||||||
|             string? outputFile = GetOutputFilename(args); |             string outputFile = GetOutputFilename(args); | ||||||
|              |              | ||||||
|             // Check if we have sufficient arguments for file/string input |             // 파일/문자열 입력을 위한 충분한 인자가 있는지 확인 | ||||||
|             if (args.Length >= 2) |             if (args.Length >= 2) | ||||||
|             { |             { | ||||||
|                 // We have command line arguments, use them |                 // 명령줄 인자가 있으므로 사용 | ||||||
|                 xmlInput = args[1]; |                 xmlInput = args[1]; | ||||||
|                  |                  | ||||||
|                 // Check if input is a file |                 // 입력이 파일인지 확인 | ||||||
|                 if (File.Exists(xmlInput)) |                 if (File.Exists(xmlInput)) | ||||||
|                 { |                 { | ||||||
|                     xmlContent = File.ReadAllText(xmlInput); |                     xmlContent = File.ReadAllText(xmlInput); | ||||||
| @@ -366,14 +361,14 @@ namespace V2GProtocol | |||||||
|             } |             } | ||||||
|             else if (Console.IsInputRedirected) |             else if (Console.IsInputRedirected) | ||||||
|             { |             { | ||||||
|                 // No sufficient arguments, check if input is coming from stdin (pipe) |                 // 충분한 인자가 없으므로 stdin(파이프)에서 입력이 오는지 확인 | ||||||
|                 xmlContent = Console.In.ReadToEnd().Trim(); |                 xmlContent = Console.In.ReadToEnd().Trim(); | ||||||
|                 if (string.IsNullOrEmpty(xmlContent)) |                 if (string.IsNullOrEmpty(xmlContent)) | ||||||
|                 { |                 { | ||||||
|                     Console.WriteLine("Error: No input data received from stdin"); |                     Console.WriteLine("Error: No input data received from stdin"); | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 outputFile = null; // Force console output for stdin |                 outputFile = null; // stdin의 경우 콘솔 출력 강제 | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
| @@ -384,7 +379,7 @@ namespace V2GProtocol | |||||||
|              |              | ||||||
|             try |             try | ||||||
|             { |             { | ||||||
|                 // Encode XML to EXI |                 // XML을 EXI로 인코드 | ||||||
|                 var exiBytes = V2GDecoder.EncodeXMLToEXI(xmlContent); |                 var exiBytes = V2GDecoder.EncodeXMLToEXI(xmlContent); | ||||||
|                  |                  | ||||||
|                 if (outputFile != null) |                 if (outputFile != null) | ||||||
| @@ -394,13 +389,13 @@ namespace V2GProtocol | |||||||
|                     Console.WriteLine($"Encoded binary saved to: {outputFile} ({exiBytes.Length} bytes)"); |                     Console.WriteLine($"Encoded binary saved to: {outputFile} ({exiBytes.Length} bytes)"); | ||||||
|                      |                      | ||||||
|                     // Also show hex string on console for reference |                     // Also show hex string on console for reference | ||||||
|                     var exiHexString = Convert.ToHexString(exiBytes); |                     var exiHexString = Helper.ToHexString(exiBytes); | ||||||
|                     Console.WriteLine($"Hex: {exiHexString}"); |                     Console.WriteLine($"Hex: {exiHexString}"); | ||||||
|                 } |                 } | ||||||
|                 else |                 else | ||||||
|                 { |                 { | ||||||
|                     // Output hex string to console |                     // Output hex string to console | ||||||
|                     var exiHexString = Convert.ToHexString(exiBytes); |                     var exiHexString = Helper.ToHexString(exiBytes); | ||||||
|                     Console.WriteLine(exiHexString); |                     Console.WriteLine(exiHexString); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -493,8 +488,8 @@ namespace V2GProtocol | |||||||
|             { |             { | ||||||
|                 // 이더넷 헤더 분석 (14 bytes) |                 // 이더넷 헤더 분석 (14 bytes) | ||||||
|                 Console.WriteLine("Ethernet Header:"); |                 Console.WriteLine("Ethernet Header:"); | ||||||
|                 Console.WriteLine($"  Destination MAC: {string.Join(":", data[0..6].Select(b => b.ToString("X2")))}"); |                 Console.WriteLine($"  Destination MAC: {string.Join(":", data.Take(6).Select(b => b.ToString("X2")))}"); | ||||||
|                 Console.WriteLine($"  Source MAC: {string.Join(":", data[6..12].Select(b => b.ToString("X2")))}"); |                 Console.WriteLine($"  Source MAC: {string.Join(":", data.Skip(6).Take(6).Select(b => b.ToString("X2")))}"); | ||||||
|                 Console.WriteLine($"  EtherType: 0x{(data[12] << 8 | data[13]):X4}"); |                 Console.WriteLine($"  EtherType: 0x{(data[12] << 8 | data[13]):X4}"); | ||||||
|                  |                  | ||||||
|                 ushort etherType = (ushort)(data[12] << 8 | data[13]); |                 ushort etherType = (ushort)(data[12] << 8 | data[13]); | ||||||
| @@ -516,8 +511,10 @@ namespace V2GProtocol | |||||||
|                     Console.WriteLine($"  Hop Limit: {hopLimit}"); |                     Console.WriteLine($"  Hop Limit: {hopLimit}"); | ||||||
|                      |                      | ||||||
|                     // IPv6 주소는 16바이트씩 |                     // IPv6 주소는 16바이트씩 | ||||||
|                     var srcAddr = data[(ipv6Offset + 8)..(ipv6Offset + 24)]; |                     byte[] srcAddr = new byte[16]; | ||||||
|                     var dstAddr = data[(ipv6Offset + 24)..(ipv6Offset + 40)]; |                     byte[] dstAddr = new byte[16]; | ||||||
|  |                     Array.Copy(data, ipv6Offset + 8, srcAddr, 0, 16); | ||||||
|  |                     Array.Copy(data, ipv6Offset + 24, dstAddr, 0, 16); | ||||||
|                      |                      | ||||||
|                     Console.WriteLine($"  Source Address: {string.Join(":", Enumerable.Range(0, 8).Select(i => $"{srcAddr[i*2]:X2}{srcAddr[i*2+1]:X2}"))}"); |                     Console.WriteLine($"  Source Address: {string.Join(":", Enumerable.Range(0, 8).Select(i => $"{srcAddr[i*2]:X2}{srcAddr[i*2+1]:X2}"))}"); | ||||||
|                     Console.WriteLine($"  Destination Address: {string.Join(":", Enumerable.Range(0, 8).Select(i => $"{dstAddr[i*2]:X2}{dstAddr[i*2+1]:X2}"))}"); |                     Console.WriteLine($"  Destination Address: {string.Join(":", Enumerable.Range(0, 8).Select(i => $"{dstAddr[i*2]:X2}{dstAddr[i*2+1]:X2}"))}"); | ||||||
| @@ -547,7 +544,8 @@ namespace V2GProtocol | |||||||
|                             if (tcpDataOffset < data.Length) |                             if (tcpDataOffset < data.Length) | ||||||
|                             { |                             { | ||||||
|                                 Console.WriteLine($"\nTCP Payload (starting at offset 0x{tcpDataOffset:X4}):"); |                                 Console.WriteLine($"\nTCP Payload (starting at offset 0x{tcpDataOffset:X4}):"); | ||||||
|                                 byte[] tcpPayload = data[tcpDataOffset..]; |                                 byte[] tcpPayload = new byte[data.Length - tcpDataOffset]; | ||||||
|  |                                 Array.Copy(data, tcpDataOffset, tcpPayload, 0, tcpPayload.Length); | ||||||
|                                  |                                  | ||||||
|                                 // TCP 페이로드에서 V2G 메시지 찾기 |                                 // TCP 페이로드에서 V2G 메시지 찾기 | ||||||
|                                 if (tcpPayload.Length > 8 && tcpPayload[0] == 0x01 && tcpPayload[1] == 0xFE) |                                 if (tcpPayload.Length > 8 && tcpPayload[0] == 0x01 && tcpPayload[1] == 0xFE) | ||||||
|   | |||||||
| @@ -420,7 +420,7 @@ namespace V2GProtocol | |||||||
|                 if (byteCounts[i] > 0) |                 if (byteCounts[i] > 0) | ||||||
|                 { |                 { | ||||||
|                     double p = (double)byteCounts[i] / totalBytes; |                     double p = (double)byteCounts[i] / totalBytes; | ||||||
|                     entropy -= p * Math.Log2(p); |                     entropy -= p * (Math.Log(p) / Math.Log(2)); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|              |              | ||||||
| @@ -447,7 +447,7 @@ namespace V2GProtocol | |||||||
|              |              | ||||||
|             foreach (var keyword in v2gKeywords) |             foreach (var keyword in v2gKeywords) | ||||||
|             { |             { | ||||||
|                 if (text.Contains(keyword, StringComparison.OrdinalIgnoreCase)) |                 if (text.ToLower().Contains(keyword.ToLower())) | ||||||
|                     xmlIndicators += 2; |                     xmlIndicators += 2; | ||||||
|             } |             } | ||||||
|              |              | ||||||
| @@ -488,7 +488,7 @@ namespace V2GProtocol | |||||||
|              |              | ||||||
|             foreach (var keyword in keywords) |             foreach (var keyword in keywords) | ||||||
|             { |             { | ||||||
|                 if (dataAsString.Contains(keyword, StringComparison.OrdinalIgnoreCase)) |                 if (dataAsString.ToLower().Contains(keyword.ToLower())) | ||||||
|                 { |                 { | ||||||
|                     found.Add(keyword); |                     found.Add(keyword); | ||||||
|                 } |                 } | ||||||
| @@ -1057,7 +1057,7 @@ namespace V2GProtocol | |||||||
|             var sessionId = ExtractValueFromXML(xmlContent, "SessionID"); |             var sessionId = ExtractValueFromXML(xmlContent, "SessionID"); | ||||||
|             if (!string.IsNullOrEmpty(sessionId) && sessionId.Length == 16) // 8 bytes as hex |             if (!string.IsNullOrEmpty(sessionId) && sessionId.Length == 16) // 8 bytes as hex | ||||||
|             { |             { | ||||||
|                 var sessionBytes = Convert.FromHexString(sessionId); |                 var sessionBytes = Helper.FromHexString(sessionId); | ||||||
|                 foreach (byte b in sessionBytes) |                 foreach (byte b in sessionBytes) | ||||||
|                 { |                 { | ||||||
|                     if (b >= 0x30 && b <= 0x5A) // ASCII range |                     if (b >= 0x30 && b <= 0x5A) // ASCII range | ||||||
|   | |||||||
| @@ -2,9 +2,8 @@ | |||||||
|  |  | ||||||
|   <PropertyGroup> |   <PropertyGroup> | ||||||
|     <OutputType>Exe</OutputType> |     <OutputType>Exe</OutputType> | ||||||
|     <TargetFramework>net6.0</TargetFramework> |     <TargetFramework>net48</TargetFramework> | ||||||
|     <ImplicitUsings>enable</ImplicitUsings> |     <LangVersion>9.0</LangVersion> | ||||||
|     <Nullable>enable</Nullable> |  | ||||||
|     <AssemblyName>V2GDecoder</AssemblyName> |     <AssemblyName>V2GDecoder</AssemblyName> | ||||||
|   </PropertyGroup> |   </PropertyGroup> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user