Port to .NET Framework 4.8 with C# 9.0 compatibility
- Change target framework from net6.0 to net48 with LangVersion 9.0 - Remove nullable reference types for .NET Framework compatibility - Replace Convert.FromHexString/ToHexString with custom implementations - Fix switch pattern matching to use traditional case statements - Replace range operators with LINQ Take/Skip and Array.Copy - Replace Math.Log2 with Math.Log(p)/Math.Log(2) formula - Fix Contains method calls to use ToLower() instead of StringComparison 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
57
Program.cs
57
Program.cs
@@ -7,6 +7,23 @@ namespace V2GProtocol
|
||||
{
|
||||
class Program
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static string ToHexString(byte[] bytes)
|
||||
{
|
||||
return BitConverter.ToString(bytes).Replace("-", "");
|
||||
}
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Only show header for help or analysis mode (not for encode/decode operations)
|
||||
@@ -63,13 +80,16 @@ namespace V2GProtocol
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case "--decode" or "-d":
|
||||
case "--decode":
|
||||
case "-d":
|
||||
HandleDecodeCommand(args);
|
||||
break;
|
||||
case "--encode" or "-e":
|
||||
case "--encode":
|
||||
case "-e":
|
||||
HandleEncodeCommand(args);
|
||||
break;
|
||||
case "--help" or "-h":
|
||||
case "--help":
|
||||
case "-h":
|
||||
ShowUsage();
|
||||
break;
|
||||
default:
|
||||
@@ -172,7 +192,7 @@ namespace V2GProtocol
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
static string? GetOutputFilename(string[] args)
|
||||
static string GetOutputFilename(string[] args)
|
||||
{
|
||||
for (int i = 0; i < args.Length - 1; i++)
|
||||
{
|
||||
@@ -188,7 +208,7 @@ namespace V2GProtocol
|
||||
{
|
||||
string input;
|
||||
byte[] exiBytes;
|
||||
string? outputFile = GetOutputFilename(args);
|
||||
string outputFile = GetOutputFilename(args);
|
||||
|
||||
// Check if we have sufficient arguments for file/string input
|
||||
if (args.Length >= 2)
|
||||
@@ -264,7 +284,7 @@ namespace V2GProtocol
|
||||
{
|
||||
// Plain hex
|
||||
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
|
||||
exiBytes = Convert.FromHexString(fileContent);
|
||||
exiBytes = FromHexString(fileContent);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -272,7 +292,7 @@ namespace V2GProtocol
|
||||
// Unknown extension, try as plain hex
|
||||
string fileContent = File.ReadAllText(input).Trim();
|
||||
fileContent = fileContent.Replace(" ", "").Replace("-", "").Replace("0x", "").Replace("\n", "").Replace("\r", "");
|
||||
exiBytes = Convert.FromHexString(fileContent);
|
||||
exiBytes = FromHexString(fileContent);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -286,7 +306,7 @@ namespace V2GProtocol
|
||||
return;
|
||||
}
|
||||
|
||||
exiBytes = Convert.FromHexString(exiHexString);
|
||||
exiBytes = FromHexString(exiHexString);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -312,7 +332,7 @@ namespace V2GProtocol
|
||||
}
|
||||
}
|
||||
|
||||
static byte[]? ExtractV2GMessageFromHexDump(byte[] data)
|
||||
static byte[] ExtractV2GMessageFromHexDump(byte[] data)
|
||||
{
|
||||
// Find V2G Transfer Protocol signature (0x01FE)
|
||||
for (int i = 0; i < data.Length - 8; i++)
|
||||
@@ -338,7 +358,7 @@ namespace V2GProtocol
|
||||
{
|
||||
string xmlInput;
|
||||
string xmlContent;
|
||||
string? outputFile = GetOutputFilename(args);
|
||||
string outputFile = GetOutputFilename(args);
|
||||
|
||||
// Check if we have sufficient arguments for file/string input
|
||||
if (args.Length >= 2)
|
||||
@@ -386,13 +406,13 @@ namespace V2GProtocol
|
||||
Console.WriteLine($"Encoded binary saved to: {outputFile} ({exiBytes.Length} bytes)");
|
||||
|
||||
// Also show hex string on console for reference
|
||||
var exiHexString = Convert.ToHexString(exiBytes);
|
||||
var exiHexString = ToHexString(exiBytes);
|
||||
Console.WriteLine($"Hex: {exiHexString}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Output hex string to console
|
||||
var exiHexString = Convert.ToHexString(exiBytes);
|
||||
var exiHexString = ToHexString(exiBytes);
|
||||
Console.WriteLine(exiHexString);
|
||||
}
|
||||
}
|
||||
@@ -485,8 +505,8 @@ namespace V2GProtocol
|
||||
{
|
||||
// 이더넷 헤더 분석 (14 bytes)
|
||||
Console.WriteLine("Ethernet Header:");
|
||||
Console.WriteLine($" Destination MAC: {string.Join(":", data[0..6].Select(b => b.ToString("X2")))}");
|
||||
Console.WriteLine($" Source MAC: {string.Join(":", data[6..12].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.Skip(6).Take(6).Select(b => b.ToString("X2")))}");
|
||||
Console.WriteLine($" EtherType: 0x{(data[12] << 8 | data[13]):X4}");
|
||||
|
||||
ushort etherType = (ushort)(data[12] << 8 | data[13]);
|
||||
@@ -508,8 +528,10 @@ namespace V2GProtocol
|
||||
Console.WriteLine($" Hop Limit: {hopLimit}");
|
||||
|
||||
// IPv6 주소는 16바이트씩
|
||||
var srcAddr = data[(ipv6Offset + 8)..(ipv6Offset + 24)];
|
||||
var dstAddr = data[(ipv6Offset + 24)..(ipv6Offset + 40)];
|
||||
byte[] srcAddr = new byte[16];
|
||||
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($" Destination Address: {string.Join(":", Enumerable.Range(0, 8).Select(i => $"{dstAddr[i*2]:X2}{dstAddr[i*2+1]:X2}"))}");
|
||||
@@ -539,7 +561,8 @@ namespace V2GProtocol
|
||||
if (tcpDataOffset < data.Length)
|
||||
{
|
||||
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 메시지 찾기
|
||||
if (tcpPayload.Length > 8 && tcpPayload[0] == 0x01 && tcpPayload[1] == 0xFE)
|
||||
|
||||
@@ -8,6 +8,18 @@ namespace V2GProtocol
|
||||
{
|
||||
public class V2GDecoder
|
||||
{
|
||||
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;
|
||||
}
|
||||
private const byte V2G_TP_VERSION = 0x01;
|
||||
private const byte V2G_TP_INVERSE_VERSION = 0xFE;
|
||||
|
||||
@@ -420,7 +432,7 @@ namespace V2GProtocol
|
||||
if (byteCounts[i] > 0)
|
||||
{
|
||||
double p = (double)byteCounts[i] / totalBytes;
|
||||
entropy -= p * Math.Log2(p);
|
||||
entropy -= p * (Math.Log(p) / Math.Log(2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +459,7 @@ namespace V2GProtocol
|
||||
|
||||
foreach (var keyword in v2gKeywords)
|
||||
{
|
||||
if (text.Contains(keyword, StringComparison.OrdinalIgnoreCase))
|
||||
if (text.ToLower().Contains(keyword.ToLower()))
|
||||
xmlIndicators += 2;
|
||||
}
|
||||
|
||||
@@ -488,7 +500,7 @@ namespace V2GProtocol
|
||||
|
||||
foreach (var keyword in keywords)
|
||||
{
|
||||
if (dataAsString.Contains(keyword, StringComparison.OrdinalIgnoreCase))
|
||||
if (dataAsString.ToLower().Contains(keyword.ToLower()))
|
||||
{
|
||||
found.Add(keyword);
|
||||
}
|
||||
@@ -1057,7 +1069,7 @@ namespace V2GProtocol
|
||||
var sessionId = ExtractValueFromXML(xmlContent, "SessionID");
|
||||
if (!string.IsNullOrEmpty(sessionId) && sessionId.Length == 16) // 8 bytes as hex
|
||||
{
|
||||
var sessionBytes = Convert.FromHexString(sessionId);
|
||||
var sessionBytes = FromHexString(sessionId);
|
||||
foreach (byte b in sessionBytes)
|
||||
{
|
||||
if (b >= 0x30 && b <= 0x5A) // ASCII range
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<AssemblyName>V2GDecoder</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user