- 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>
275 lines
9.8 KiB
C#
275 lines
9.8 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 V2GDecoderNet.EXI;
|
|
using System.Xml;
|
|
|
|
namespace V2GDecoderNet.V2G
|
|
{
|
|
/// <summary>
|
|
/// EXI Encoder for converting XML to EXI binary data
|
|
/// </summary>
|
|
public class EXIEncoder
|
|
{
|
|
private readonly EXIConfig _config;
|
|
|
|
public EXIEncoder(EXIConfig? config = null)
|
|
{
|
|
_config = config ?? new EXIConfig();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encode XML string to EXI binary data
|
|
/// </summary>
|
|
/// <param name="xmlString">XML string to encode</param>
|
|
/// <returns>EXI binary data</returns>
|
|
public byte[] EncodeFromXml(string xmlString)
|
|
{
|
|
if (string.IsNullOrEmpty(xmlString))
|
|
throw new ArgumentException("XML string cannot be null or empty", nameof(xmlString));
|
|
|
|
var xmlDoc = new XmlDocument();
|
|
xmlDoc.LoadXml(xmlString);
|
|
|
|
return EncodeFromXmlDocument(xmlDoc);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encode XmlDocument to EXI binary data
|
|
/// </summary>
|
|
/// <param name="xmlDoc">XmlDocument to encode</param>
|
|
/// <returns>EXI binary data</returns>
|
|
public byte[] EncodeFromXmlDocument(XmlDocument xmlDoc)
|
|
{
|
|
if (xmlDoc == null)
|
|
throw new ArgumentNullException(nameof(xmlDoc));
|
|
|
|
var outputStream = new BitOutputStream();
|
|
|
|
try
|
|
{
|
|
// Write EXI header
|
|
WriteHeader(outputStream);
|
|
|
|
// Encode document
|
|
EncodeDocument(xmlDoc, outputStream);
|
|
|
|
return outputStream.ToArray();
|
|
}
|
|
catch (EXIException)
|
|
{
|
|
throw;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new EXIException(EXIErrorCodes.EXI_ERROR_UNKOWN_EVENT,
|
|
"Error during EXI encoding", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write EXI header with options
|
|
/// </summary>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
private void WriteHeader(BitOutputStream outputStream)
|
|
{
|
|
// Write EXI cookie ($EXI)
|
|
outputStream.WriteBytes(new byte[] { (byte)'$', (byte)'E', (byte)'X', (byte)'I' });
|
|
|
|
// Format version (4 bits) - currently 0
|
|
outputStream.WriteBits(0, 4);
|
|
|
|
// Options presence flag (1 bit) - false for simplicity
|
|
outputStream.WriteBit(0);
|
|
|
|
// Align to byte boundary
|
|
outputStream.AlignToByteBank();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encode XML document content
|
|
/// </summary>
|
|
/// <param name="xmlDoc">XML document</param>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
private void EncodeDocument(XmlDocument xmlDoc, BitOutputStream outputStream)
|
|
{
|
|
// Write START_DOCUMENT event
|
|
WriteEventCode(outputStream, EXIEvent.START_DOCUMENT);
|
|
|
|
// Encode root element and its children
|
|
if (xmlDoc.DocumentElement != null)
|
|
{
|
|
EncodeElement(xmlDoc.DocumentElement, outputStream);
|
|
}
|
|
|
|
// Write END_DOCUMENT event
|
|
WriteEventCode(outputStream, EXIEvent.END_DOCUMENT);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encode XML element
|
|
/// </summary>
|
|
/// <param name="element">XML element</param>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
private void EncodeElement(XmlElement element, BitOutputStream outputStream)
|
|
{
|
|
// Write START_ELEMENT event
|
|
WriteEventCode(outputStream, EXIEvent.START_ELEMENT);
|
|
|
|
// Write element name (simplified - in real implementation would use string tables)
|
|
WriteElementName(outputStream, element.Name);
|
|
|
|
// Encode attributes
|
|
EncodeAttributes(element, outputStream);
|
|
|
|
// Encode child nodes
|
|
foreach (XmlNode child in element.ChildNodes)
|
|
{
|
|
switch (child.NodeType)
|
|
{
|
|
case XmlNodeType.Element:
|
|
EncodeElement((XmlElement)child, outputStream);
|
|
break;
|
|
|
|
case XmlNodeType.Text:
|
|
case XmlNodeType.CDATA:
|
|
EncodeTextContent(child.Value ?? string.Empty, outputStream);
|
|
break;
|
|
|
|
case XmlNodeType.Comment:
|
|
if (_config != null) // Preserve comments if configured
|
|
{
|
|
// Skip for simplicity
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Write END_ELEMENT event
|
|
WriteEventCode(outputStream, EXIEvent.END_ELEMENT);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encode element attributes
|
|
/// </summary>
|
|
/// <param name="element">XML element</param>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
private void EncodeAttributes(XmlElement element, BitOutputStream outputStream)
|
|
{
|
|
foreach (XmlAttribute attr in element.Attributes)
|
|
{
|
|
// Write ATTRIBUTE event
|
|
WriteEventCode(outputStream, EXIEvent.ATTRIBUTE);
|
|
|
|
// Write attribute name and value (simplified)
|
|
WriteAttributeName(outputStream, attr.Name);
|
|
WriteAttributeValue(outputStream, attr.Value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Encode text content
|
|
/// </summary>
|
|
/// <param name="text">Text content</param>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
private void EncodeTextContent(string text, BitOutputStream outputStream)
|
|
{
|
|
if (!string.IsNullOrEmpty(text))
|
|
{
|
|
// Write CHARACTERS event
|
|
WriteEventCode(outputStream, EXIEvent.CHARACTERS);
|
|
|
|
// Write text content
|
|
WriteCharacters(outputStream, text);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write event code to stream
|
|
/// </summary>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
/// <param name="eventType">Event type</param>
|
|
private void WriteEventCode(BitOutputStream outputStream, EXIEvent eventType)
|
|
{
|
|
// Simplified event code writing - in real implementation,
|
|
// this would be based on current grammar state
|
|
uint code = eventType switch
|
|
{
|
|
EXIEvent.START_DOCUMENT => 0,
|
|
EXIEvent.START_ELEMENT => 0,
|
|
EXIEvent.END_ELEMENT => 1,
|
|
EXIEvent.CHARACTERS => 2,
|
|
EXIEvent.ATTRIBUTE => 3,
|
|
EXIEvent.END_DOCUMENT => 3,
|
|
_ => 0
|
|
};
|
|
|
|
outputStream.WriteBits(code, 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write element name to stream
|
|
/// </summary>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
/// <param name="name">Element name</param>
|
|
private void WriteElementName(BitOutputStream outputStream, string name)
|
|
{
|
|
// Simplified name encoding - in real implementation would use string tables
|
|
var nameBytes = System.Text.Encoding.UTF8.GetBytes(name);
|
|
outputStream.WriteUnsignedInteger((uint)nameBytes.Length);
|
|
outputStream.WriteBytes(nameBytes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write attribute name to stream
|
|
/// </summary>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
/// <param name="name">Attribute name</param>
|
|
private void WriteAttributeName(BitOutputStream outputStream, string name)
|
|
{
|
|
// Simplified attribute name encoding
|
|
var nameBytes = System.Text.Encoding.UTF8.GetBytes(name);
|
|
outputStream.WriteUnsignedInteger((uint)nameBytes.Length);
|
|
outputStream.WriteBytes(nameBytes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write attribute value to stream
|
|
/// </summary>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
/// <param name="value">Attribute value</param>
|
|
private void WriteAttributeValue(BitOutputStream outputStream, string value)
|
|
{
|
|
// Simplified attribute value encoding
|
|
var valueBytes = System.Text.Encoding.UTF8.GetBytes(value ?? string.Empty);
|
|
outputStream.WriteUnsignedInteger((uint)valueBytes.Length);
|
|
outputStream.WriteBytes(valueBytes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write character data to stream
|
|
/// </summary>
|
|
/// <param name="outputStream">Output bit stream</param>
|
|
/// <param name="text">Character data</param>
|
|
private void WriteCharacters(BitOutputStream outputStream, string text)
|
|
{
|
|
var encoding = _config.Strings switch
|
|
{
|
|
EXIConfig.StringRepresentation.ASCII => System.Text.Encoding.ASCII,
|
|
EXIConfig.StringRepresentation.UCS => System.Text.Encoding.UTF8,
|
|
_ => System.Text.Encoding.UTF8
|
|
};
|
|
|
|
var textBytes = encoding.GetBytes(text);
|
|
outputStream.WriteUnsignedInteger((uint)textBytes.Length);
|
|
outputStream.WriteBytes(textBytes);
|
|
}
|
|
}
|
|
} |