- Port core EXI encoding/decoding functionality to C# - Implement V2G protocol parsing and analysis - Add simplified decoder/encoder for roundtrip testing - Create comprehensive error handling with EXI exceptions - Support both byte array and file stream operations - Include packet structure analysis for V2GTP data - Successfully builds and runs basic functionality tests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
198 lines
6.7 KiB
C#
198 lines
6.7 KiB
C#
/*
|
|
* Copyright (C) 2007-2024 C# Port
|
|
* Original Copyright (C) 2007-2018 Siemens AG
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
using System.IO;
|
|
|
|
namespace V2GDecoderNet.EXI
|
|
{
|
|
/// <summary>
|
|
/// Byte Stream utilities for file operations
|
|
/// </summary>
|
|
public static class ByteStream
|
|
{
|
|
/// <summary>
|
|
/// Write bytes to file
|
|
/// </summary>
|
|
/// <param name="data">byte array</param>
|
|
/// <param name="filename">File name</param>
|
|
/// <returns>Error-Code != 0 on failure</returns>
|
|
public static int WriteBytesToFile(byte[] data, string filename)
|
|
{
|
|
try
|
|
{
|
|
if (data == null)
|
|
return EXIErrorCodes.EXI_ERROR_OUT_OF_BYTE_BUFFER;
|
|
|
|
if (string.IsNullOrEmpty(filename))
|
|
return EXIErrorCodes.EXI_ERROR_OUTPUT_FILE;
|
|
|
|
File.WriteAllBytes(filename, data);
|
|
return 0; // Success
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_OUTPUT_FILE;
|
|
}
|
|
catch (DirectoryNotFoundException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_OUTPUT_FILE;
|
|
}
|
|
catch (IOException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_OUTPUT_FILE;
|
|
}
|
|
catch
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_OUTPUT_FILE;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read bytes from file
|
|
/// </summary>
|
|
/// <param name="filename">File name</param>
|
|
/// <param name="data">Output byte array</param>
|
|
/// <param name="bytesRead">Number of bytes actually read</param>
|
|
/// <returns>Error-Code != 0 on failure</returns>
|
|
public static int ReadBytesFromFile(string filename, out byte[] data, out int bytesRead)
|
|
{
|
|
data = Array.Empty<byte>();
|
|
bytesRead = 0;
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(filename))
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
|
|
if (!File.Exists(filename))
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
|
|
data = File.ReadAllBytes(filename);
|
|
bytesRead = data.Length;
|
|
return 0; // Success
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch (DirectoryNotFoundException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch (FileNotFoundException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch (IOException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Read bytes from file with buffer size limit
|
|
/// </summary>
|
|
/// <param name="filename">File name</param>
|
|
/// <param name="maxSize">Maximum buffer size</param>
|
|
/// <param name="data">Output byte array</param>
|
|
/// <param name="bytesRead">Number of bytes actually read</param>
|
|
/// <returns>Error-Code != 0 on failure</returns>
|
|
public static int ReadBytesFromFile(string filename, int maxSize, out byte[] data, out int bytesRead)
|
|
{
|
|
data = Array.Empty<byte>();
|
|
bytesRead = 0;
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(filename))
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
|
|
if (!File.Exists(filename))
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
|
|
using var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
|
|
var fileSize = (int)fileStream.Length;
|
|
|
|
if (fileSize > maxSize)
|
|
return EXIErrorCodes.EXI_ERROR_OUT_OF_BYTE_BUFFER;
|
|
|
|
data = new byte[fileSize];
|
|
bytesRead = fileStream.Read(data, 0, fileSize);
|
|
|
|
return 0; // Success
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch (DirectoryNotFoundException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch (FileNotFoundException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch (IOException)
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
catch
|
|
{
|
|
return EXIErrorCodes.EXI_ERROR_INPUT_FILE_HANDLE;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert hex string to byte array
|
|
/// </summary>
|
|
/// <param name="hex">Hex string</param>
|
|
/// <returns>Byte array</returns>
|
|
public static byte[] HexStringToByteArray(string hex)
|
|
{
|
|
if (string.IsNullOrEmpty(hex))
|
|
return Array.Empty<byte>();
|
|
|
|
// Remove any whitespace or separators
|
|
hex = hex.Replace(" ", "").Replace("-", "").Replace(":", "");
|
|
|
|
if (hex.Length % 2 != 0)
|
|
throw new ArgumentException("Hex string must have even number of characters");
|
|
|
|
var result = new byte[hex.Length / 2];
|
|
for (int i = 0; i < result.Length; i++)
|
|
{
|
|
if (!byte.TryParse(hex.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber, null, out result[i]))
|
|
throw new ArgumentException($"Invalid hex characters at position {i * 2}");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Convert byte array to hex string
|
|
/// </summary>
|
|
/// <param name="data">Byte array</param>
|
|
/// <param name="uppercase">Use uppercase hex digits</param>
|
|
/// <returns>Hex string</returns>
|
|
public static string ByteArrayToHexString(byte[] data, bool uppercase = true)
|
|
{
|
|
if (data == null || data.Length == 0)
|
|
return string.Empty;
|
|
|
|
var format = uppercase ? "X2" : "x2";
|
|
return string.Concat(data.Select(b => b.ToString(format)));
|
|
}
|
|
}
|
|
} |