feat: Complete cross-platform build system and folder reorganization
- 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>
This commit is contained in:
275
DotNet/V2G/EXIEncoder.cs
Normal file
275
DotNet/V2G/EXIEncoder.cs
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user