Wasm/NameSection.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using WasmBox.Wasm.Binary;
namespace WasmBox.Wasm {
/// <summary>
/// A type of section that defines names for debugging purposes.
/// </summary>
public sealed class NameSection : Section {
/// <summary>
/// Creates an empty name section.
/// </summary>
public NameSection() {
this.Names = new List<NameEntry>();
}
/// <summary>
/// Creates a name section from the given sequence of name entries.
/// </summary>
/// <param name="names">The name entries to initialize this section with.</param>
public NameSection(IEnumerable<NameEntry> names) {
this.Names = new List<NameEntry>(names);
}
/// <summary>
/// The custom name used for name sections.
/// </summary>
public const string CustomName = "name";
/// <inheritdoc/>
public override SectionName Name => new SectionName(CustomName);
/// <summary>
/// Gets the name entries in this section.
/// </summary>
/// <returns>The name entries.</returns>
public List<NameEntry> Names { get; private set; }
/// <inheritdoc/>
public override void WritePayloadTo(BinaryWasmWriter writer) {
foreach (var entry in Names) {
entry.WriteTo(writer);
}
}
/// <inheritdoc/>
public override void Dump(TextWriter writer) {
writer.Write(Name.ToString());
writer.Write("; number of entries: ");
writer.Write(Names.Count);
writer.WriteLine();
for (int i = 0; i < Names.Count; i++) {
writer.Write("#");
writer.Write(i);
writer.Write(" -> ");
Names[i].Dump(writer);
writer.WriteLine();
}
}
/// <summary>
/// Reads the name section with the given header.
/// </summary>
/// <param name="header">The section header.</param>
/// <param name="reader">The WebAssembly file reader.</param>
/// <returns>The parsed section.</returns>
public static NameSection ReadSectionPayload(SectionHeader header, BinaryWasmReader reader) {
var section = new NameSection();
long startPos = reader.Position;
while (reader.Position - startPos < header.PayloadLength) {
// Read entries until we've read the entire section.
section.Names.Add(NameEntry.Read(reader));
}
return section;
}
}
/// <summary>
/// An enumeration of encodings for name section entries.
/// </summary>
public enum NameEntryKind : byte {
/// <summary>
/// The name entry code for a module name entry.
/// </summary>
Module = 0,
/// <summary>
/// The name entry code for a function name entry.
/// </summary>
Function = 1,
/// <summary>
/// The name entry code for a local name entry.
/// </summary>
Local = 2
}
/// <summary>
/// A base class for entries in the name section.
/// </summary>
public abstract class NameEntry {
/// <summary>
/// Gets this name entry's kind.
/// </summary>
/// <returns>The name entry kind.</returns>
public abstract NameEntryKind Kind { get; }
/// <summary>
/// Writes this name entry's payload to the given writer.
/// </summary>
/// <param name="writer">The writer to write the payload to.</param>
public abstract void WritePayloadTo(BinaryWasmWriter writer);
/// <summary>
/// Writes a textual representation of this name entry to the given writer.
/// </summary>
/// <param name="writer">The text writer.</param>
public virtual void Dump(TextWriter writer) {
using (var memStream = new MemoryStream()) {
using (var binaryWriter = new BinaryWriter(memStream)) {
WritePayloadTo(new BinaryWasmWriter(binaryWriter));
memStream.Seek(0, SeekOrigin.Begin);
writer.WriteLine("entry kind '{0}', payload size: {1}", Kind, memStream.Length);
var instructionWriter = DumpHelpers.CreateIndentedTextWriter(writer);
DumpHelpers.DumpStream(memStream, writer);
}
}
}
/// <summary>
/// Writes this name entry's header and payload to the given writer.
/// </summary>
/// <param name="writer">The writer to write the header and payload to.</param>
public void WriteTo(BinaryWasmWriter writer) {
writer.WriteVarUInt7((byte)Kind);
writer.WriteLengthPrefixed(WritePayloadTo);
}
/// <inheritdoc/>
public override string ToString() {
var builder = new StringBuilder();
Dump(new StringWriter(builder));
return builder.ToString();
}
/// <summary>
/// Reads a name entry's header and payload from the given binary
/// WebAssembly reader.
/// </summary>
/// <param name="reader">The reader to read the name entry from.</param>
/// <returns>A name entry.</returns>
public static NameEntry Read(BinaryWasmReader reader) {
NameEntryKind kind = (NameEntryKind)reader.ReadVarUInt7();
uint length = reader.ReadVarUInt32();
switch (kind) {
case NameEntryKind.Module:
return ModuleNameEntry.ReadPayload(reader, length);
default:
return UnknownNameEntry.ReadPayload(reader, kind, length);
}
}
}
/// <summary>
/// Describes a name section entry with an unknown entry kind code.
/// </summary>
public sealed class UnknownNameEntry : NameEntry {
/// <summary>
/// Creates an unknown name entry from the given entry kind and payload.
/// </summary>
public UnknownNameEntry(NameEntryKind kind, byte[] payload) {
this.entryKind = kind;
this.Payload = payload;
}
private NameEntryKind entryKind;
/// <summary>
/// Gets the payload for this unknown name entry.
/// </summary>
/// <returns>The payload.</returns>
public byte[] Payload { get; set; }
/// <inheritdoc/>
public override NameEntryKind Kind => entryKind;
/// <inheritdoc/>
public override void WritePayloadTo(BinaryWasmWriter writer) {
writer.Writer.Write(Payload);
}
/// <summary>
/// Reads an unknown name entry's payload.
/// </summary>
/// <param name="reader">The reader to read the name entry payload from.</param>
/// <param name="kind">The kind of name entry to read.</param>
/// <param name="length">The length of the name entry's payload, in bytes.</param>
/// <returns>An unknown name entry.</returns>
public static UnknownNameEntry ReadPayload(BinaryWasmReader reader, NameEntryKind kind, uint length) {
return new UnknownNameEntry(kind, reader.ReadBytes((int)length));
}
}
/// <summary>
/// A name entry type that defines a module's name.
/// </summary>
public sealed class ModuleNameEntry : NameEntry {
/// <summary>
/// Creates a module name entry from the given name.
/// </summary>
public ModuleNameEntry(string moduleName) {
this.ModuleName = moduleName;
}
/// <inheritdoc/>
public override NameEntryKind Kind => NameEntryKind.Module;
/// <summary>
/// Gets or sets the module's name.
/// </summary>
/// <returns>The module's name.</returns>
public string ModuleName { get; set; }
/// <inheritdoc/>
public override void WritePayloadTo(BinaryWasmWriter writer) {
writer.WriteString(ModuleName);
}
/// <inheritdoc/>
public override void Dump(TextWriter writer) {
writer.Write("module name: {0}", ModuleName);
}
/// <summary>
/// Reads a module name entry's payload.
/// </summary>
/// <param name="reader">The reader to read the name entry payload from.</param>
/// <param name="length">The length of the name entry's payload, in bytes.</param>
/// <returns>A module name entry.</returns>
public static ModuleNameEntry ReadPayload(BinaryWasmReader reader, uint length) {
return new ModuleNameEntry(reader.ReadString());
}
}
}