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:
2025-09-07 20:02:22 +09:00
parent 4f2f6a99d7
commit e09c63080e
3 changed files with 58 additions and 24 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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>