- Reorganize project structure: Port/ → DotNet/, VC/, C++/ - Add comprehensive cross-platform build automation - Windows: build_all.bat, build.bat files for all components - Linux/macOS: build_all.sh, build.sh files for all components - Update all build scripts with correct folder paths - Create test automation scripts (test_all.bat/sh) - Update documentation to reflect new structure - Maintain 100% roundtrip accuracy for test5.exi (pure EXI) - Support both Windows MSBuild and Linux GCC compilation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
174 lines
6.7 KiB
C#
174 lines
6.7 KiB
C#
/*
|
|
* Copyright (C) 2007-2024 C# Port
|
|
* Original Copyright (C) 2007-2018 Siemens AG
|
|
*
|
|
* Exact EXI Header implementation - byte-compatible with OpenV2G
|
|
* Matches EXIHeaderDecoder.c and EXIHeaderEncoder.c exactly
|
|
*/
|
|
|
|
using System;
|
|
|
|
namespace V2GDecoderNet.EXI
|
|
{
|
|
/// <summary>
|
|
/// EXI Error codes - exact match to C implementation
|
|
/// </summary>
|
|
public static class EXIErrorCodesExact
|
|
{
|
|
public const int EXI_OK = 0;
|
|
public const int EXI_ERROR_UNEXPECTED_END_OF_STREAM = -1;
|
|
public const int EXI_UNSUPPORTED_HEADER_COOKIE = -2;
|
|
public const int EXI_UNSUPPORTED_HEADER_OPTIONS = -3;
|
|
public const int EXI_ERROR_UNKNOWN_EVENT = -4;
|
|
public const int EXI_ERROR_OUT_OF_BYTE_BUFFER = -5;
|
|
public const int EXI_ERROR_OUT_OF_BOUNDS = -6;
|
|
public const int EXI_ERROR_STRINGVALUES_NOT_SUPPORTED = -7;
|
|
public const int EXI_ERROR_NOT_IMPLEMENTED_YET = -8;
|
|
}
|
|
|
|
/// <summary>
|
|
/// EXI Header decoder - exact implementation of EXIHeaderDecoder.c
|
|
/// </summary>
|
|
public static class EXIHeaderDecoderExact
|
|
{
|
|
/// <summary>
|
|
/// Decode EXI header - exact implementation of decodeEXIHeader()
|
|
/// </summary>
|
|
public static int DecodeHeader(BitInputStreamExact stream, EXIHeaderExact header)
|
|
{
|
|
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
|
if (header == null) throw new ArgumentNullException(nameof(header));
|
|
|
|
// Read the header byte
|
|
int headerByte = stream.ReadBits(8);
|
|
if (headerByte < 0)
|
|
return EXIErrorCodesExact.EXI_ERROR_UNEXPECTED_END_OF_STREAM;
|
|
|
|
byte header_b = (byte)headerByte;
|
|
|
|
// Check for EXI Cookie - not supported in this implementation
|
|
if (header_b == 0x24) // '$' character
|
|
{
|
|
return EXIErrorCodesExact.EXI_UNSUPPORTED_HEADER_COOKIE;
|
|
}
|
|
|
|
// Check presence bit for EXI Options (bit 5, value 0x20)
|
|
if ((header_b & 0x20) != 0)
|
|
{
|
|
return EXIErrorCodesExact.EXI_UNSUPPORTED_HEADER_OPTIONS;
|
|
}
|
|
|
|
// Parse simple header format (distinguishing bits = "1")
|
|
// Bit pattern: 1 | Version[4] | Presence[1] | Format[2]
|
|
|
|
// Extract format version (bits 6-3, mask 0x1E, shift right 1)
|
|
header.FormatVersion = (byte)((header_b & 0x1E) >> 1);
|
|
|
|
// Extract format field (bits 1-0, mask 0x03)
|
|
byte format = (byte)(header_b & 0x03);
|
|
|
|
// Set preservation options based on format field
|
|
switch (format)
|
|
{
|
|
case 0: // Format 00: No preservation
|
|
header.PreserveComments = false;
|
|
header.PreservePIs = false;
|
|
header.PreserveDTD = false;
|
|
header.PreservePrefixes = false;
|
|
break;
|
|
case 1: // Format 01: Preserve comments and PIs
|
|
header.PreserveComments = true;
|
|
header.PreservePIs = true;
|
|
header.PreserveDTD = false;
|
|
header.PreservePrefixes = false;
|
|
break;
|
|
case 2: // Format 10: Preserve DTD and prefixes
|
|
header.PreserveComments = false;
|
|
header.PreservePIs = false;
|
|
header.PreserveDTD = true;
|
|
header.PreservePrefixes = true;
|
|
break;
|
|
case 3: // Format 11: Preserve all
|
|
header.PreserveComments = true;
|
|
header.PreservePIs = true;
|
|
header.PreserveDTD = true;
|
|
header.PreservePrefixes = true;
|
|
break;
|
|
}
|
|
|
|
// Header always has no cookie in this implementation
|
|
header.HasCookie = false;
|
|
|
|
return EXIErrorCodesExact.EXI_OK;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// EXI Header encoder - exact implementation of EXIHeaderEncoder.c
|
|
/// </summary>
|
|
public static class EXIHeaderEncoderExact
|
|
{
|
|
/// <summary>
|
|
/// Encode EXI header - exact implementation of encodeEXIHeader()
|
|
/// Always writes simple header format (0x80 = 128)
|
|
/// </summary>
|
|
public static int EncodeHeader(BitOutputStreamExact stream, EXIHeaderExact header)
|
|
{
|
|
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
|
if (header == null) throw new ArgumentNullException(nameof(header));
|
|
|
|
try
|
|
{
|
|
// Simple header format: always write 128 (0x80)
|
|
// Bit pattern: 1 0000 0 00 = 10000000 = 0x80 = 128
|
|
// - Distinguishing bit: 1
|
|
// - Version: 0000 (format version 0)
|
|
// - Presence bit: 0 (no options)
|
|
// - Format: 00 (no preservation)
|
|
stream.WriteBits(8, EXIConstantsExact.EXI_HEADER_SIMPLE);
|
|
|
|
return EXIErrorCodesExact.EXI_OK;
|
|
}
|
|
catch
|
|
{
|
|
return EXIErrorCodesExact.EXI_ERROR_OUT_OF_BYTE_BUFFER;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// EXI Exception for exact error handling
|
|
/// </summary>
|
|
public class EXIExceptionExact : Exception
|
|
{
|
|
public int ErrorCode { get; }
|
|
|
|
public EXIExceptionExact(int errorCode, string message) : base(message)
|
|
{
|
|
ErrorCode = errorCode;
|
|
}
|
|
|
|
public EXIExceptionExact(int errorCode, string message, Exception innerException)
|
|
: base(message, innerException)
|
|
{
|
|
ErrorCode = errorCode;
|
|
}
|
|
|
|
public static string GetErrorMessage(int errorCode)
|
|
{
|
|
return errorCode switch
|
|
{
|
|
EXIErrorCodesExact.EXI_OK => "No error",
|
|
EXIErrorCodesExact.EXI_ERROR_UNEXPECTED_END_OF_STREAM => "Unexpected end of stream",
|
|
EXIErrorCodesExact.EXI_UNSUPPORTED_HEADER_COOKIE => "EXI header cookie not supported",
|
|
EXIErrorCodesExact.EXI_UNSUPPORTED_HEADER_OPTIONS => "EXI header options not supported",
|
|
EXIErrorCodesExact.EXI_ERROR_UNKNOWN_EVENT => "Unknown EXI event",
|
|
EXIErrorCodesExact.EXI_ERROR_OUT_OF_BYTE_BUFFER => "Output buffer overflow",
|
|
EXIErrorCodesExact.EXI_ERROR_OUT_OF_BOUNDS => "Index out of bounds",
|
|
EXIErrorCodesExact.EXI_ERROR_STRINGVALUES_NOT_SUPPORTED => "String values not supported",
|
|
EXIErrorCodesExact.EXI_ERROR_NOT_IMPLEMENTED_YET => "Feature not implemented",
|
|
_ => $"Unknown error code: {errorCode}"
|
|
};
|
|
}
|
|
}
|
|
} |