import MochaBinary from mocha-legacy

This commit is contained in:
Michael Becker 2024-08-10 13:03:59 -04:00
parent 6ed80b56ad
commit 2ef33f8af3
44 changed files with 5287 additions and 12 deletions

View File

@ -41,6 +41,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{B024
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Plugins.Libraries.Yaml", "mocha-dotnet\src\plugins\Mocha.Plugins.Libraries.Yaml\Mocha.Plugins.Libraries.Yaml.csproj", "{96400F5A-98ED-48FF-8000-6135BDF10360}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mocha.Plugins.Libraries.MochaBinary", "mocha-dotnet\src\plugins\Mocha.Plugins.Libraries.MochaBinary\Mocha.Plugins.Libraries.MochaBinary.csproj", "{2519497F-DDDA-4918-9AD0-880CAA2E541F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -71,6 +73,10 @@ Global
{96400F5A-98ED-48FF-8000-6135BDF10360}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96400F5A-98ED-48FF-8000-6135BDF10360}.Release|Any CPU.Build.0 = Release|Any CPU
{2519497F-DDDA-4918-9AD0-880CAA2E541F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2519497F-DDDA-4918-9AD0-880CAA2E541F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2519497F-DDDA-4918-9AD0-880CAA2E541F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2519497F-DDDA-4918-9AD0-880CAA2E541F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -92,6 +98,7 @@ Global
{20B7D199-322C-4942-85FE-46B90C75E92A} = {27C300F5-5172-4225-A6F7-3503B9007DD8}
{B024FD23-7084-4DDF-A185-D58BEE7A006F} = {66EB3261-A473-41C7-8D40-E1B4DC8ED4B3}
{96400F5A-98ED-48FF-8000-6135BDF10360} = {B024FD23-7084-4DDF-A185-D58BEE7A006F}
{2519497F-DDDA-4918-9AD0-880CAA2E541F} = {B024FD23-7084-4DDF-A185-D58BEE7A006F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D28A9CF8-0235-4F8F-865F-C460BDCAE16D}

View File

@ -0,0 +1,50 @@

namespace MBS.Editor.Core;
public abstract class DataFormat
{
protected virtual void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
}
protected abstract void LoadInternal(ObjectModel? objectModel, Stream stream);
protected virtual void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
}
public void Load(ObjectModel? objectModel, Stream stream)
{
Stack<ObjectModel> stack = new Stack<ObjectModel>();
stack.Push(objectModel);
BeforeLoadInternal(stack);
objectModel = stack.Pop();
LoadInternal(objectModel, stream);
stack.Push(objectModel);
AfterLoadInternal(stack);
}
protected virtual void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
}
protected abstract void SaveInternal(ObjectModel? objectModel, Stream stream);
protected virtual void AfterSaveInternal(Stack<ObjectModel> objectModels)
{
}
public void Save(ObjectModel? objectModel, Stream stream)
{
Stack<ObjectModel> stack = new Stack<ObjectModel>();
stack.Push(objectModel);
BeforeSaveInternal(stack);
objectModel = stack.Pop();
SaveInternal(objectModel, stream);
stack.Push(objectModel);
AfterSaveInternal(stack);
}
}

View File

@ -0,0 +1,19 @@

namespace MBS.Editor.Core.DataFormats.YAML;
public class YAMLDataFormat : DataFormat
{
protected override void LoadInternal(ObjectModel? objectModel, Stream stream)
{
StreamReader sr = new StreamReader(stream);
int ic = -1;
while ((ic = sr.Read()) != -1)
{
char c = (char)ic;
if (c == '-')
{
}
}
}
}

View File

@ -0,0 +1,27 @@
namespace MBS.Editor.Core;
public class Document
{
public ObjectModel? ObjectModel { get; set; } = null;
public DataFormat? DataFormat { get; set; } = null;
public Stream Stream { get; set; }
public Document(ObjectModel objectModel, DataFormat dataFormat, Stream stream)
{
ObjectModel = objectModel;
DataFormat = dataFormat;
Stream = stream;
}
public static Document Load(ObjectModel objectModel, DataFormat dataFormat, Stream stream)
{
Document d = new Document(objectModel, dataFormat, stream);
d.Load();
return d;
}
public void Load()
{
DataFormat.Load(ObjectModel, Stream);
}
}

View File

@ -0,0 +1,7 @@
namespace MBS.Editor.Core.IO;
public enum Endianness
{
LittleEndian,
BigEndian
}

View File

@ -0,0 +1,11 @@
namespace MBS.Editor.Core.IO;
public enum NewLineSequence
{
Automatic,
SystemDefault,
CarriageReturn,
LineFeed,
CarriageReturnLineFeed,
LineFeedCarriageReturn
}

View File

@ -0,0 +1,79 @@
using System.Text;
namespace MBS.Editor.Core.IO;
public class ReaderWriterBase
{
private readonly Stream _st;
/// <summary>
/// Exposes access to the underlying stream of the <see cref="ReaderWriterBase" />.
/// </summary>
/// <value>
/// The underlying stream associated with the <see cref="ReaderWriterBase" />.
/// </value>
public Stream BaseStream { get { return _st; } }
public Encoding DefaultEncoding { get; set; } = Encoding.UTF8;
public NewLineSequence NewLineSequence { get; set; } = NewLineSequence.SystemDefault;
public Endianness Endianness { get; set; } = Endianness.LittleEndian;
public bool SwapEndianness()
{
if (Endianness == Endianness.LittleEndian)
{
Endianness = Endianness.BigEndian;
return true;
}
else if (Endianness == Endianness.BigEndian)
{
Endianness = Endianness.LittleEndian;
return true;
}
return false;
}
protected string GetNewLineSequence()
{
switch (NewLineSequence)
{
case NewLineSequence.SystemDefault: return System.Environment.NewLine;
case NewLineSequence.CarriageReturnLineFeed: return "\r\n";
case NewLineSequence.CarriageReturn: return "\r";
case NewLineSequence.LineFeed: return "\n";
}
return System.Environment.NewLine;
}
public ReaderWriterBase(Stream st)
{
_st = st;
}
/// <summary>
/// Aligns the <see cref="Writer" /> to the specified number of bytes. If the current
/// position of the <see cref="Writer" /> is not a multiple of the specified number of bytes,
/// the position will be increased by the amount of bytes necessary to bring it to the
/// aligned position.
/// </summary>
/// <param name="alignTo">The number of bytes on which to align the <see cref="Reader"/>.</param>
/// <param name="extraPadding">Any additional padding bytes that should be included after aligning to the specified boundary.</param>
public void Align(int alignTo, int extraPadding = 0)
{
if (alignTo == 0)
return;
long paddingCount = ((alignTo - (_st.Position % alignTo)) % alignTo);
paddingCount += extraPadding;
if (_st.Position == _st.Length)
{
byte[] buffer = new byte[paddingCount];
_st.Write(buffer, 0, buffer.Length);
}
else
{
_st.Position += paddingCount;
}
}
}

View File

@ -0,0 +1,29 @@
namespace MBS.Editor.Core;
public class InvalidDataFormatException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="InvalidDataFormatException" /> class.
/// </summary>
public InvalidDataFormatException() : base() { }
/// <summary>
/// Initializes a new instance of the <see cref="InvalidDataFormatException" /> class
/// with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public InvalidDataFormatException(string? message) : base(message) { }
/// <summary>
/// Initializes a new instance of the <see cref="InvalidDataFormatException" /> class
/// with a specified error message and a reference to the inner exception that is the
/// cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">
/// The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified.
/// </param>
public InvalidDataFormatException(string? message, Exception? innerException) : base(message, innerException) { }
}

View File

@ -0,0 +1,6 @@
namespace MBS.Editor.Core;
public abstract class ObjectModel
{
}

View File

@ -0,0 +1,39 @@
namespace MBS.Editor.Core;
public class ObjectModelNotSupportedException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ObjectModelNotSupportedException" /> class.
/// </summary>
public ObjectModelNotSupportedException() : base() { }
/// <summary>
/// Initializes a new instance of the <see cref="ObjectModelNotSupportedException" /> class
/// with a specified error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public ObjectModelNotSupportedException(string? message) : base(message) { }
/// <summary>
/// Initializes a new instance of the <see cref="ObjectModelNotSupportedException" /> class
/// with a specified error message and a reference to the inner exception that is the
/// cause of this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">
/// The exception that is the cause of the current exception, or a null reference
/// (Nothing in Visual Basic) if no inner exception is specified.
/// </param>
public ObjectModelNotSupportedException(string? message, Exception? innerException) : base(message, innerException) { }
public Type? ExpectedObjectModelType { get; }
public Type? ActualObjectModelType { get; }
public ObjectModelNotSupportedException(Type expectedObjectModelType, Type? actualObjectModelType) : this("The object model is not supported", expectedObjectModelType, actualObjectModelType) { }
public ObjectModelNotSupportedException(string? message, Type expectedObjectModelType, Type? actualObjectModelType) : base(message)
{
ExpectedObjectModelType = expectedObjectModelType;
ActualObjectModelType = actualObjectModelType;
}
}

View File

@ -0,0 +1,25 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public abstract class FileSource
{
public long Length { get { return GetLengthInternal(); } }
protected abstract long GetLengthInternal();
protected abstract byte[] GetDataInternal(long offset, long length);
public byte[] GetData() { return GetData(0, GetLengthInternal()); }
public byte[] GetData(long offset, long length)
{
byte[] data = GetDataInternal(offset, length);
MemoryStream msInput = new MemoryStream(data);
/*
for (int i = 0; i < Transformations.Count; i++)
{
System.IO.MemoryStream msOutput = new System.IO.MemoryStream();
Transformations[i].Function(this, msInput, msOutput);
msInput = msOutput;
}
*/
return msInput.ToArray();
}
}

View File

@ -0,0 +1,55 @@
//
// MemoryFileSource.cs - provides a FileSource for retrieving file data from a byte array
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2011-2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Data;
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
/// <summary>
/// Provides a <see cref="FileSource" /> for retrieving file data from a <see cref="MemoryAccessor" />.
/// </summary>
public class ByteArrayFileSource : FileSource
{
public byte[] Data { get; set; }
public ByteArrayFileSource(byte[] data)
{
Data = data;
}
protected override byte[] GetDataInternal(long offset, long length)
{
long realLength = Math.Min(length, Data.Length);
byte[] realData = Data;
long remaining = realData.Length - offset;
realLength = Math.Min(realLength, remaining);
byte[] data = new byte[realLength];
Array.Copy(realData, offset, data, 0, realLength);
return data;
}
protected override long GetLengthInternal()
{
return Data.Length;
}
}

View File

@ -0,0 +1,54 @@
using MBS.Core.Collections;
using MBS.Editor.Core.Compression;
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
public class CompressedEmbeddedFileSource : EmbeddedFileSource
{
public CompressionModule? CompressionModule { get; set; } = null;
public long CompressedLength { get; set; }
private long DecompressedLength { get; set; }
protected override long ActualLength => DecompressedLength;
private byte[]? _decompressedData = null;
protected override byte[] GetDataInternal(long offset, long length)
{
if (_decompressedData == null)
{
Stream.Seek(Offset + offset, SeekOrigin.Begin);
byte[] compressedData = new byte[CompressedLength];
Stream.Read(compressedData, 0, compressedData.Length);
Console.WriteLine("compressed data: " + compressedData.ToString(" ", "x"));
byte[] decompressedData = compressedData;
if (CompressionModule != null)
{
decompressedData = CompressionModule.Decompress(compressedData);
}
_decompressedData = decompressedData;
Console.WriteLine("decompressed data: " + decompressedData.ToString(" ", "x"));
}
if (offset + length > _decompressedData.Length)
{
Console.WriteLine(String.Format("embedded file offset: {0}", Offset));
Console.WriteLine(String.Format("requested offset: {0}", offset));
Console.WriteLine(String.Format("requested length: {0}", length));
Console.WriteLine(String.Format("actual stream length: {0}", _decompressedData.Length));
throw new ArgumentOutOfRangeException("offset + length", "embedded file offset + requested offset + requested length extends past the actual length of the underlying stream");
}
byte[] data = new byte[length];
Array.Copy(_decompressedData, offset, data, 0, data.Length);
return data;
}
public CompressedEmbeddedFileSource(Stream stream, long offset, long compressedLength, long decompressedLength) : base(stream, offset, decompressedLength)
{
CompressedLength = compressedLength;
DecompressedLength = decompressedLength;
}
}

View File

@ -0,0 +1,34 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
public class EmbeddedFileSource : FileSource
{
public Stream Stream { get; }
public long Offset { get; set; }
protected virtual long ActualLength { get; }
protected override long GetLengthInternal()
{
return ActualLength;
}
protected override byte[] GetDataInternal(long offset, long length)
{
if (Offset + offset + length >= Stream.Length)
{
throw new ArgumentOutOfRangeException("embedded file offset + requested offset + requested length extends past the actual length of the underlying stream");
}
Stream.Seek(Offset + offset, SeekOrigin.Begin);
byte[] data = new byte[length];
Stream.Read(data, 0, data.Length);
return data;
}
public EmbeddedFileSource(Stream stream, long offset, long length)
{
Stream = stream;
Offset = offset;
ActualLength = length;
}
}

View File

@ -0,0 +1,59 @@
//
// StreamFileSource.cs - provides a FileSource for retrieving file data from a System.IO.Stream
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2011-2024 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
/// <summary>
/// Provides a <see cref="FileSource" /> for retrieving file data from a <see cref="MemoryAccessor" />.
/// </summary>
public class StreamFileSource : FileSource
{
public Stream BaseStream { get; set; }
public StreamFileSource(Stream stream)
{
BaseStream = stream;
}
protected override byte[] GetDataInternal(long offset, long length)
{
byte[] buffer = new byte[length];
try
{
if (offset + length > BaseStream.Length)
{
throw new ArgumentOutOfRangeException("offset + length is out of range");
}
}
catch (NotSupportedException ex)
{
// continue anyway
}
BaseStream.Seek(offset, SeekOrigin.Begin);
BaseStream.Read(buffer, 0, (int)length);
return buffer;
}
protected override long GetLengthInternal()
{
return BaseStream.Length;
}
}

View File

@ -0,0 +1,29 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public class FileSystemCustomDetailCollection
{
private struct _item
{
public string id;
public string title;
}
private Dictionary<string, _item> _dict = new Dictionary<string, _item>();
public void Add(string id, string title)
{
_item item = new _item();
item.id = id;
item.title = title;
_dict[id] = item;
}
public bool Contains(string id)
{
return _dict.ContainsKey(id);
}
public string GetTitle(string id)
{
_item item = _dict[id];
return item.title;
}
}

View File

@ -0,0 +1,20 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public class FileSystemFile : FileSystemItem
{
public FileSource? Source { get; set; } = null;
public DateTime? ModificationTimestamp { get; set; } = null;
public Dictionary<string, object> CustomDetails { get; } = new Dictionary<string, object>();
public long Size
{
get
{
if (Source == null)
return 0;
return Source.Length;
}
}
}

View File

@ -0,0 +1,12 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public class FileSystemFolder : FileSystemItem, IFileSystemItemContainer
{
public FileSystemItemCollection Items { get; }
public FileSystemFolder()
{
Items = new FileSystemItemCollection(this);
}
}

View File

@ -0,0 +1,8 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public class FileSystemItem
{
public FileSystemObjectModel FileSystem { get { return Parent?.FileSystem; } }
public string? Name { get; set; } = null;
public IFileSystemItemContainer? Parent { get; internal set; }
}

View File

@ -0,0 +1,181 @@
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public class FileSystemItemCollection
: System.Collections.ObjectModel.Collection<FileSystemItem>
{
public IFileSystemItemContainer Parent { get; }
public FileSystemItemCollection(IFileSystemItemContainer parent)
{
Parent = parent;
}
public bool Contains(string filename)
{
return this[filename] != null;
}
public FileSystemItem? this[string filename]
{
get
{
foreach (FileSystemItem item in this)
{
if (item.Name == filename)
{
return item;
}
}
return null;
}
}
protected override void ClearItems()
{
for (int i = 0; i < Count; i++)
{
this[i].Parent = null;
}
base.ClearItems();
}
protected override void InsertItem(int index, FileSystemItem item)
{
base.InsertItem(index, item);
item.Parent = Parent;
}
protected override void RemoveItem(int index)
{
this[index].Parent = null;
base.RemoveItem(index);
}
public FileSystemFolder AddFolder(string name)
{
string[] path = name.Split(Parent.FileSystem.PathSeparators, StringSplitOptions.None);
FileSystemFolder parent = null;
for (int i = 0; i < path.Length; i++)
{
if (parent == null)
{
parent = this[path[i]] as FileSystemFolder;
if (parent == null)
{
FileSystemFolder f = new FileSystemFolder();
f.Name = path[i];
Add(f);
parent = f;
}
}
else
{
FileSystemFolder new_parent = parent.Items[path[i]] as FileSystemFolder;
if (new_parent == null)
{
new_parent = new FileSystemFolder();
new_parent.Name = path[i];
parent.Items.Add(new_parent);
}
parent = new_parent;
}
if (parent == null) throw new DirectoryNotFoundException();
}
return parent;
}
public FileSystemFile AddFile(string name, FileSource? source = null)
{
if (name == null) name = String.Empty;
string[] path = name.Split(Parent.FileSystem.PathSeparators, StringSplitOptions.None);
FileSystemFolder parent = null;
for (int i = 0; i < path.Length - 1; i++)
{
if (parent == null)
{
if (Contains(path[i]))
{
parent = this[path[i]] as FileSystemFolder;
}
else
{
parent = AddFolder(path[i]);
}
}
else
{
if (parent.Items.Contains(path[i]))
{
parent = parent.Items[path[i]] as FileSystemFolder;
}
else
{
parent = parent.Items.AddFolder(path[i]);
}
}
if (parent == null)
{
throw new System.IO.DirectoryNotFoundException();
}
}
FileSystemFile file = new FileSystemFile();
file.Name = path[path.Length - 1];
file.Source = source;
if (parent == null)
{
Add(file);
}
else
{
parent.Items.Add(file);
}
return file;
}
public FileSystemFile[] GetAllFiles()
{
List<FileSystemFile> list = new List<FileSystemFile>();
for (int i = 0; i < Count; i++)
{
if (this[i] is FileSystemFile Peter)
{
list.Add(Peter);
}
else if (this[i] is FileSystemFolder folder)
{
FileSystemFile[] files2 = folder.Items.GetAllFiles();
list.AddRange(files2);
}
}
return list.ToArray();
}
public FileSystemFile[] GetFiles()
{
List<FileSystemFile> list = new List<FileSystemFile>();
for (int i = 0; i < Count; i++)
{
if (this[i] is FileSystemFile Peter)
{
list.Add(Peter);
}
}
return list.ToArray();
}
public FileSystemFolder[] GetFolders()
{
List<FileSystemFolder> list = new List<FileSystemFolder>();
for (int i = 0; i < Count; i++)
{
if (this[i] is FileSystemFolder folder)
{
list.Add(folder);
}
}
return list.ToArray();
}
}

View File

@ -0,0 +1,20 @@
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public class FileSystemObjectModel : ObjectModel, IFileSystemItemContainer
{
public FileSystemObjectModel FileSystem { get { return this; } }
public FileSystemItemCollection Items { get; }
public FileSystemObjectModel()
{
Items = new FileSystemItemCollection(this);
}
public FileSystemCustomDetailCollection CustomDetails { get; } = new FileSystemCustomDetailCollection();
public string[] PathSeparators { get; set; } = { "/", "\\" }; // System.IO.Path.DirectorySeparatorChar.ToString(), System.IO.Path.AltDirectorySeparatorChar.ToString() };
}

View File

@ -0,0 +1,7 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public interface IFileSystemItemContainer
{
FileSystemObjectModel FileSystem { get; }
FileSystemItemCollection Items { get; }
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,28 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
namespace Mocha.Plugins.Libraries.MochaBinary;
public enum MochaAttributeType
{
Unknown = -1,
None = 0,
Text = 1,
Boolean = 2,
Numeric = 3,
Date = 4
}

View File

@ -0,0 +1,659 @@
using MBS.Editor.Core;
using MBS.Editor.Core.IO;
using MBS.Editor.Core.ObjectModels.FileSystem;
using Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary;
namespace Mocha.Plugins.Libraries.MochaBinary;
public class MochaBinaryDataFormat : SlickBinaryDataFormat
{
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
base.BeforeLoadInternal(objectModels);
objectModels.Push(new FileSystemObjectModel());
}
private struct LIBRARY_INFO
{
public int libraryReferenceCount;
public int instanceCount;
public int attributeValueCount;
public int relationshipCount;
}
private struct INSTANCE_INFO
{
public int instanceIndex;
public int attributeValueCount;
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
if (objectModels.Count < 2) throw new ObjectModelNotSupportedException("must have a FileSystemObjectModel and a MochaClassLibraryObjectModel in the stack");
FileSystemObjectModel fsom = (objectModels.Pop() as FileSystemObjectModel);
if (fsom == null) throw new ObjectModelNotSupportedException();
MochaClassLibraryObjectModel mcl = (objectModels.Pop() as MochaClassLibraryObjectModel);
if (mcl == null) throw new ObjectModelNotSupportedException();
List<Guid> _instanceGuids = new List<Guid>();
List<string> _stringTable = new List<string>();
LIBRARY_INFO[] library_info = null;
#region Libraries
{
FileSystemFile fLibraries = fsom.Items.FindFile("Libraries");
using (MemoryStream ms = new MemoryStream(fLibraries.Source.GetData()))
{
Reader reader = new Reader(ms);
int libraryCount = reader.ReadInt32();
library_info = new LIBRARY_INFO[libraryCount];
for (int i = 0; i < libraryCount; i++)
{
MochaLibrary library = new MochaLibrary();
library.ID = reader.ReadGuid();
library_info[i].libraryReferenceCount = reader.ReadInt32();
library_info[i].instanceCount = reader.ReadInt32();
// library_info[i].attributeValueCount = ma.Reader.ReadInt32();
library_info[i].relationshipCount = reader.ReadInt32();
mcl.Libraries.Add(library);
}
}
}
#endregion
#region Guid Table
{
File fGlobalIdentifiers = fsom.FindFile("GlobalIdentifiers");
using (MemoryAccessor ma = new MemoryAccessor(fGlobalIdentifiers.GetData()))
{
int instanceCount = ma.Reader.ReadInt32();
for (int i = 0; i < instanceCount; i++)
{
_instanceGuids.Add(ma.Reader.ReadGuid());
}
}
}
#endregion
#region String Table
{
File f = fsom.FindFile("StringTable");
using (MemoryAccessor ma = new MemoryAccessor(f.GetData()))
{
int stringTableCount = ma.Reader.ReadInt32();
for (int i = 0; i < stringTableCount; i++)
{
string value = ma.Reader.ReadNullTerminatedString();
_stringTable.Add(value);
}
}
}
#endregion
INSTANCE_INFO[] instance_info = null;
#region Instances
{
File f = fsom.FindFile("Instances");
using (MemoryAccessor ma = new MemoryAccessor(f.GetData()))
{
for (int i = 0; i < mcl.Libraries.Count; i++)
{
int instance_info_offset = 0; // fixme: this should not be needed
int libraryReferenceCount = ma.Reader.ReadInt32();
for (int j = 0; j < libraryReferenceCount; j++)
{
int libraryIndex = ma.Reader.ReadInt32();
Guid libraryID = _instanceGuids[libraryIndex];
mcl.Libraries[i].LibraryReferences.Add(libraryID);
}
int instanceCount = ma.Reader.ReadInt32();
// if (instance_info == null)
{
instance_info = new INSTANCE_INFO[instanceCount];
}
/*
else
{
instance_info_offset = instance_info.Length;
Array.Resize<INSTANCE_INFO>(ref instance_info, instance_info.Length + instanceCount);
}
*/
for (int j = 0; j < instanceCount; j++)
{
instance_info[j + instance_info_offset].instanceIndex = ma.Reader.ReadInt32();
instance_info[j + instance_info_offset].attributeValueCount = ma.Reader.ReadInt32();
MochaInstanceFlags flags = (MochaInstanceFlags)ma.Reader.ReadInt32();
int? index = null;
if ((flags & MochaInstanceFlags.HasIndex) == MochaInstanceFlags.HasIndex)
{
index = ma.Reader.ReadInt32();
}
MochaInstance inst = new MochaInstance();
inst.ID = _instanceGuids[instance_info[j + instance_info_offset].instanceIndex];
inst.Index = index;
mcl.Libraries[i].Instances.Add(inst);
}
}
}
}
#endregion
#region Attributes
{
File f = fsom.FindFile("Attributes");
using (MemoryAccessor ma = new MemoryAccessor(f.GetData()))
{
for (int i = 0; i < mcl.Libraries.Count; i++)
{
for (int j = 0; j < mcl.Libraries[i].Instances.Count; j++)
{
for (int k = 0; k < instance_info[j].attributeValueCount; k++)
{
int attributeInstanceIndex = ma.Reader.ReadInt32();
MochaAttributeValue val = new MochaAttributeValue();
val.AttributeInstanceID = _instanceGuids[attributeInstanceIndex];
val.Value = ReadMochaAttributeValue(ma.Reader, _stringTable);
mcl.Libraries[i].Instances[j].AttributeValues.Add(val);
}
}
}
}
}
#endregion
#region Relationships
{
File f = fsom.FindFile("Relationships");
using (MemoryAccessor ma = new MemoryAccessor(f.GetData()))
{
for (int i = 0; i < mcl.Libraries.Count; i++)
{
for (int j = 0; j < library_info[i].relationshipCount; j++)
{
int relationshipIndex = ma.Reader.ReadInt32();
int sourceInstanceIndex = ma.Reader.ReadInt32();
MochaRelationship rel = new MochaRelationship();
rel.RelationshipInstanceID = _instanceGuids[relationshipIndex];
rel.SourceInstanceID = _instanceGuids[sourceInstanceIndex];
int targetInstanceCount = ma.Reader.ReadInt32();
for (int k = 0; k < targetInstanceCount; k++)
{
int instanceIndex = ma.Reader.ReadInt32();
rel.DestinationInstanceIDs.Add(_instanceGuids[instanceIndex]);
}
mcl.Libraries[i].Relationships.Add(rel);
}
}
}
}
#endregion
#region Tenants
{
File f = fsom.FindFile("Tenants");
if (f != null)
{
using (MemoryAccessor ma = new MemoryAccessor(f.GetData()))
{
int tenantCount = ma.Reader.ReadInt32();
for (int i = 0; i < tenantCount; i++)
{
int instanceIndex = ma.Reader.ReadInt32();
Guid instanceGuid = _instanceGuids[instanceIndex];
int tenantNameIndex = ma.Reader.ReadInt32();
string tenantName = _stringTable[tenantNameIndex];
MochaTenant tenant = new MochaTenant();
tenant.ID = instanceGuid;
tenant.Name = tenantName;
int libraryReferenceCount = ma.Reader.ReadInt32();
for (int j = 0; j < libraryReferenceCount; j++)
{
int libraryIndex = ma.Reader.ReadInt32();
Guid libraryID = _instanceGuids[libraryIndex];
tenant.LibraryReferences.Add(libraryID);
}
int instanceCount = ma.Reader.ReadInt32();
for (int j = 0; j < instanceCount; j++)
{
int instanceIndex2 = ma.Reader.ReadInt32();
MochaInstance inst = new MochaInstance();
inst.ID = _instanceGuids[instanceIndex2];
tenant.Instances.Add(inst);
}
int relationshipCount = ma.Reader.ReadInt32();
for (int j = 0; j < relationshipCount; j++)
{
int sourceInex = ma.Reader.ReadInt32();
Guid ssource = _instanceGuids[sourceInex];
int relationshipInex = ma.Reader.ReadInt32();
Guid relati = _instanceGuids[relationshipInex];
MochaRelationship rel = new MochaRelationship();
rel.SourceInstanceID = ssource;
rel.RelationshipInstanceID = relati;
int count = ma.Reader.ReadInt32();
for (int k = 0; k < count; k++)
{
int targetIndex = ma.Reader.ReadInt32();
Guid targ = _instanceGuids[targetIndex];
rel.DestinationInstanceIDs.Add(targ);
}
tenant.Relationships.Add(rel);
}
mcl.Tenants.Add(tenant);
}
ma.Close();
f.SetData(ma.ToArray());
}
}
}
#endregion
#region Journal
{
// journal is present in MCX / MCD (application, data files)
// is an opcode based format
// eg. 0x01 = create instance, 0x02 = delete instance
// 0x04 = set attribute value, 0x05 = delete attribute value
// 0x08 = create relationship, 0x09 = remove relationship
File f = fsom.FindFile("Journal");
if (f != null)
{
using (MemoryAccessor ma = new MemoryAccessor(f.GetData()))
{
for (int i = 0; i < mcl.Tenants.Count; i++)
{
bool readingTenant = true;
while (readingTenant)
{
MochaOpcode opcode = (MochaOpcode)ma.Reader.ReadByte();
switch (opcode)
{
case MochaOpcode.BeginTenant:
{
int tenantNameIndex = ma.Reader.ReadInt32();
break;
}
case MochaOpcode.EndTenant:
{
readingTenant = false; // exit outer loop
break;
}
case MochaOpcode.CreateInstance:
{
int guidIndex = ma.Reader.ReadInt32();
MochaInstance inst = new MochaInstance();
inst.ID = _instanceGuids[guidIndex];
mcl.Tenants[i].Instances.Add(inst);
break;
}
case MochaOpcode.CreateRelationship:
case MochaOpcode.RemoveRelationship:
{
int relationshipIndex = ma.Reader.ReadInt32();
int sourceInstanceIndex = ma.Reader.ReadInt32();
MochaRelationship rel = new MochaRelationship();
rel.RelationshipInstanceID = _instanceGuids[relationshipIndex];
rel.SourceInstanceID = _instanceGuids[sourceInstanceIndex];
int targetInstanceCount = ma.Reader.ReadInt32();
for (int k = 0; k < targetInstanceCount; k++)
{
int instanceIndex = ma.Reader.ReadInt32();
rel.DestinationInstanceIDs.Add(_instanceGuids[instanceIndex]);
}
if (opcode == MochaOpcode.RemoveRelationship)
{
rel.Remove = true;
}
mcl.Tenants[i].Relationships.Add(rel);
break;
}
case MochaOpcode.SetAttributeValue:
{
int instanceIndex = ma.Reader.ReadInt32();
Guid instanceID = _instanceGuids[instanceIndex];
int attributeIndex = ma.Reader.ReadInt32();
Guid attributeInstanceID = _instanceGuids[attributeIndex];
object value = ReadMochaAttributeValue(ma.Reader, _stringTable);
MochaAttributeValue mav = new MochaAttributeValue();
mav.AttributeInstanceID = attributeInstanceID;
mav.Value = value;
mcl.Tenants[i].Instances[instanceID].AttributeValues.Add(mav);
break;
}
}
}
}
}
}
}
#endregion
}
private object ReadMochaAttributeValue(Reader reader, List<string>_stringTable)
{
MochaAttributeType attributeType = (MochaAttributeType)reader.ReadInt32();
switch (attributeType)
{
case MochaAttributeType.None:
{
return null;
}
case MochaAttributeType.Text:
{
int stringTableIndex = reader.ReadInt32();
string value = _stringTable[stringTableIndex];
return value;
}
case MochaAttributeType.Boolean:
{
bool value = reader.ReadBoolean();
return value;
}
case MochaAttributeType.Date:
{
DateTime value = reader.ReadDateTime();
return value;
}
case MochaAttributeType.Numeric:
{
decimal value = reader.ReadDecimal();
return value;
}
case MochaAttributeType.Unknown:
{
break;
}
}
throw new NotSupportedException();
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
FileNameSize = 32;
MochaClassLibraryObjectModel mcl = (objectModels.Pop() as MochaClassLibraryObjectModel);
if (mcl == null) throw new ObjectModelNotSupportedException();
FileSystemObjectModel fsom = new FileSystemObjectModel();
List<Guid> _instanceIndices = new List<Guid>();
List<string> _stringTable = new List<string>();
#region Libraries
{
File f = fsom.AddFile("Libraries");
MemoryAccessor ma = new MemoryAccessor();
ma.Writer.WriteInt32(mcl.Libraries.Count);
for (int i = 0; i < mcl.Libraries.Count; i++)
{
ma.Writer.WriteGuid(mcl.Libraries[i].ID);
ma.Writer.WriteInt32(mcl.Libraries[i].LibraryReferences.Count);
ma.Writer.WriteInt32(mcl.Libraries[i].Instances.Count);
ma.Writer.WriteInt32(mcl.Libraries[i].Relationships.Count);
}
ma.Close();
f.SetData(ma.ToArray());
}
#endregion
#region Instances
{
File f = fsom.AddFile("Instances");
MemoryAccessor ma = new MemoryAccessor();
for (int i = 0; i < mcl.Libraries.Count; i++)
{
ma.Writer.WriteInt32(mcl.Libraries[i].LibraryReferences.Count);
for (int j = 0; j < mcl.Libraries[i].LibraryReferences.Count; j++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, mcl.Libraries[i].LibraryReferences[j]));
}
ma.Writer.WriteInt32(mcl.Libraries[i].Instances.Count);
for (int j = 0; j < mcl.Libraries[i].Instances.Count; j++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, mcl.Libraries[i].Instances[j].ID));
ma.Writer.WriteInt32(mcl.Libraries[i].Instances[j].AttributeValues.Count);
MochaInstanceFlags flags = MochaInstanceFlags.None;
if (mcl.Libraries[i].Instances[j].Index != null)
{
flags |= MochaInstanceFlags.HasIndex;
}
ma.Writer.WriteInt32((int)flags);
if ((flags & MochaInstanceFlags.HasIndex) == MochaInstanceFlags.HasIndex)
{
ma.Writer.WriteInt32(mcl.Libraries[i].Instances[j].Index.Value);
}
}
}
ma.Close();
f.SetData(ma.ToArray());
}
#endregion
#region Attributes
{
File f = fsom.AddFile("Attributes");
MemoryAccessor ma = new MemoryAccessor();
for (int i = 0; i < mcl.Libraries.Count; i++)
{
/*
writer.WriteInt32(mcl.Libraries[i].Metadata.Count);
for (int j = 0; j < mcl.Libraries[i].Metadata.Count; j++)
{
writer.WriteNullTerminatedString(mcl.Libraries[i].Metadata[j].Name);
writer.WriteNullTerminatedString(mcl.Libraries[i].Metadata[j].Value);
}
*/
for (int j = 0; j < mcl.Libraries[i].Instances.Count; j++)
{
for (int k = 0; k < mcl.Libraries[i].Instances[j].AttributeValues.Count; k++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, mcl.Libraries[i].Instances[j].AttributeValues[k].AttributeInstanceID));
WriteMochaAttributeValue(ma.Writer, _stringTable, mcl.Libraries[i].Instances[j].AttributeValues[k].Value);
}
}
}
ma.Close();
f.SetData(ma.ToArray());
}
#endregion
#region Relationships
{
File f = fsom.AddFile("Relationships");
MemoryAccessor ma = new MemoryAccessor();
for (int i = 0; i < mcl.Libraries.Count; i++)
{
for (int j = 0; j < mcl.Libraries[i].Relationships.Count; j++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, mcl.Libraries[i].Relationships[j].RelationshipInstanceID));
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, mcl.Libraries[i].Relationships[j].SourceInstanceID));
ma.Writer.WriteInt32(mcl.Libraries[i].Relationships[j].DestinationInstanceIDs.Count);
for (int k = 0; k < mcl.Libraries[i].Relationships[j].DestinationInstanceIDs.Count; k++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, mcl.Libraries[i].Relationships[j].DestinationInstanceIDs[k]));
}
}
}
ma.Close();
f.SetData(ma.ToArray());
}
#endregion
#region Tenants
{
if (mcl.Tenants.Count > 0)
{
File f = fsom.AddFile("Tenants");
MemoryAccessor ma = new MemoryAccessor();
ma.Writer.WriteInt32(mcl.Tenants.Count);
foreach (MochaTenant tenant in mcl.Tenants)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.ID));
ma.Writer.WriteInt32(AddOrUpdateLookupTable<string>(_stringTable, tenant.Name));
ma.Writer.WriteInt32(tenant.LibraryReferences.Count);
for (int i = 0; i < tenant.LibraryReferences.Count; i++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.LibraryReferences[i]));
}
ma.Writer.WriteInt32(tenant.Instances.Count);
for (int i = 0; i < tenant.Instances.Count; i++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.Instances[i].ID));
}
ma.Writer.WriteInt32(tenant.Relationships.Count);
for (int i = 0; i < tenant.Relationships.Count; i++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.Relationships[i].SourceInstanceID));
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.Relationships[i].RelationshipInstanceID));
ma.Writer.WriteInt32(tenant.Relationships[i].DestinationInstanceIDs.Count);
for (int j = 0; j < tenant.Relationships[i].DestinationInstanceIDs.Count; j++)
{
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.Relationships[i].DestinationInstanceIDs[j]));
}
}
}
ma.Close();
f.SetData(ma.ToArray());
}
}
#endregion
#region Journal
{
if (mcl.Tenants.Count > 0)
{
File f = fsom.AddFile("Journal");
MemoryAccessor ma = new MemoryAccessor();
foreach (MochaTenant tenant in mcl.Tenants)
{
ma.Writer.WriteByte((byte)MochaOpcode.BeginTenant);
ma.Writer.WriteInt32(AddOrUpdateLookupTable<string>(_stringTable, tenant.Name));
for (int i = 0; i < tenant.Instances.Count; i++)
{
for (int j = 0; j < tenant.Instances[i].AttributeValues.Count; j++)
{
ma.Writer.WriteByte((byte)MochaOpcode.SetAttributeValue);
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.Instances[i].ID));
ma.Writer.WriteInt32(AddOrUpdateLookupTable<Guid>(_instanceIndices, tenant.Instances[i].AttributeValues[j].AttributeInstanceID));
WriteMochaAttributeValue(ma.Writer, _stringTable, tenant.Instances[i].AttributeValues[j].Value);
}
}
ma.Writer.WriteByte((byte)MochaOpcode.EndTenant);
}
ma.Close();
f.SetData(ma.ToArray());
}
}
#endregion
#region Guid Table
{
File f = fsom.AddFile("GlobalIdentifiers");
MemoryAccessor ma = new MemoryAccessor();
ma.Writer.WriteInt32(_instanceIndices.Count);
foreach (Guid id in _instanceIndices)
{
ma.Writer.WriteGuid(id);
}
ma.Close();
f.SetData(ma.ToArray());
}
#endregion
#region String Table
{
File f = fsom.AddFile("StringTable");
MemoryAccessor ma = new MemoryAccessor();
ma.Writer.WriteInt32(_stringTable.Count);
foreach (string id in _stringTable)
{
ma.Writer.WriteNullTerminatedString(id);
}
ma.Close();
f.SetData(ma.ToArray());
}
#endregion
objectModels.Push(fsom);
}
private void WriteMochaAttributeValue(Writer writer, List<string> _stringTable, object value)
{
if (value == null)
{
writer.WriteInt32((int)MochaAttributeType.None);
}
else if (value is string)
{
writer.WriteInt32((int)MochaAttributeType.Text);
writer.WriteInt32(AddOrUpdateLookupTable<string>(_stringTable, value as string));
}
else if (value is bool)
{
writer.WriteInt32((int)MochaAttributeType.Boolean);
writer.WriteBoolean((bool)value);
}
else if (value is DateTime)
{
writer.WriteInt32((int)MochaAttributeType.Date);
writer.WriteDateTime((DateTime)value);
}
else if (value is decimal || value is int)
{
writer.WriteInt32((int)MochaAttributeType.Numeric);
// ...... eww.
writer.WriteDecimal(Decimal.Parse(value.ToString()));
}
else
{
writer.WriteInt32((int)MochaAttributeType.Unknown);
writer.WriteObject(value);
}
}
private int AddOrUpdateLookupTable<T1>(List<T1> dict, T1 id)
{
if (!dict.Contains(id))
{
dict.Add(id);
}
return dict.IndexOf(id);
}
}

View File

@ -0,0 +1,26 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
namespace Mocha.Plugins.Libraries.MochaBinary;
[Flags()]
public enum MochaInstanceFlags
{
None = 0,
HasIndex = 1
}

View File

@ -0,0 +1,33 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
namespace Mocha.Plugins.Libraries.MochaBinary;
public enum MochaOpcode : byte
{
CreateInstance = 0x01,
DeleteInstance = 0x02,
SetAttributeValue = 0x04,
DeleteAttributeValue = 0x05,
CreateRelationship = 0x08,
RemoveRelationship = 0x09,
BeginTenant = 0x0A,
EndTenant = 0x8A
}

View File

@ -0,0 +1,35 @@
//
// IMochaStore.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2021 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public interface IMochaStore
{
List<Guid> LibraryReferences { get; }
MochaInstance.MochaInstanceCollection Instances { get; }
MochaRelationship.MochaRelationshipCollection Relationships { get; }
Guid DefaultObjectSourceID { get; }
MochaInstance FindInstance(Guid id);
}
}

View File

@ -0,0 +1,50 @@
//
// MochaAttributeValue.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaAttributeValue : ICloneable
{
public class MochaAttributeValueCollection
: System.Collections.ObjectModel.Collection<MochaAttributeValue>
{
}
public Guid AttributeInstanceID { get; set; }
public object Value { get; set; }
public object Clone()
{
MochaAttributeValue clone = new MochaAttributeValue();
clone.AttributeInstanceID = AttributeInstanceID;
if (Value is ICloneable)
{
clone.Value = (Value as ICloneable).Clone();
}
else
{
clone.Value = Value;
}
return clone;
}
}
}

View File

@ -0,0 +1,112 @@
//
// MochaClassLibrary.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using MBS.Editor.Core;
using Mocha.Core;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaClassLibraryObjectModel : ObjectModel
{
public MochaTenant.MochaTenantCollection Tenants { get; } = new MochaTenant.MochaTenantCollection();
public MochaLibrary.MochaLibraryCollection Libraries { get; } = new MochaLibrary.MochaLibraryCollection();
/*
public override void Clear()
{
Libraries.Clear();
}
public override void CopyTo(ObjectModel where)
{
MochaClassLibraryObjectModel clone = (where as MochaClassLibraryObjectModel);
if (clone == null) throw new ObjectModelNotSupportedException();
for (int i = 0; i < Libraries.Count; i++)
{
clone.Libraries.Add(Libraries[i].Clone() as MochaLibrary);
}
for (int i = 0; i < Tenants.Count; i++)
{
clone.Tenants.Add(Tenants[i].Clone() as MochaTenant);
}
}
*/
public MochaInstance FindInstance(Guid id)
{
return FindInstance(id, out IMochaStore store);
}
public MochaInstance FindInstance(Guid id, out IMochaStore store)
{
for (int i = 0; i < Libraries.Count; i++)
{
MochaInstance inst = Libraries[i].Instances[id];
if (inst != null)
{
store = Libraries[i];
return inst;
}
}
for (int i = 0; i < Tenants.Count; i++)
{
MochaInstance inst = Tenants[i].Instances[id];
if (inst != null)
{
store = Tenants[i];
return inst;
}
}
store = null;
return null;
}
public MochaRelationship FindRelationship(RelationshipKey relationshipKey)
{
return FindRelationship(relationshipKey, out IMochaStore store);
}
public MochaRelationship FindRelationship(RelationshipKey relationshipKey, out IMochaStore store)
{
for (int i = 0; i < Libraries.Count; i++)
{
MochaRelationship rel = Libraries[i].Relationships[relationshipKey];
if (rel != null)
{
store = Libraries[i];
return rel;
}
}
for (int i = 0; i < Tenants.Count; i++)
{
MochaRelationship rel = Tenants[i].Relationships[relationshipKey];
if (rel != null)
{
store = Tenants[i];
return rel;
}
}
store = null;
return null;
}
}
}

View File

@ -0,0 +1,87 @@
//
// MochaInstance.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaInstance : ICloneable
{
public class MochaInstanceCollection
: System.Collections.ObjectModel.Collection<MochaInstance>
{
public MochaInstance this[Guid id]
{
get
{
for (int i = 0; i < Count; i++)
{
if (this[i].ID == id)
return this[i];
}
return null;
}
}
public void Merge(MochaInstance item)
{
MochaInstance orig = this[item.ID];
if (orig != null)
{
orig.Merge(item);
return;
}
Add(item);
}
public bool Contains(Guid id)
{
for (int i = 0; i < Count;i ++)
{
if (this[i].ID == id)
return true;
}
return false;
}
}
private void Merge(MochaInstance item)
{
if (ID != item.ID)
throw new InvalidOperationException("cannot merge two instances with different global identifiers");
}
public Guid ID { get; set; } = Guid.Empty;
public int? Index { get; set; } = null;
public MochaAttributeValue.MochaAttributeValueCollection AttributeValues { get; } = new MochaAttributeValue.MochaAttributeValueCollection();
public object Clone()
{
MochaInstance clone = new MochaInstance();
clone.ID = ID;
clone.Index = Index;
for (int i = 0; i < AttributeValues.Count; i++)
{
clone.AttributeValues.Add(AttributeValues[i].Clone() as MochaAttributeValue);
}
return clone;
}
}
}

View File

@ -0,0 +1,117 @@
//
// MochaLibrary.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaLibrary : ICloneable, IMochaStore
{
public class MochaLibraryCollection
: System.Collections.ObjectModel.Collection<MochaLibrary>
{
public MochaLibrary this[Guid id]
{
get
{
for (int i = 0; i < Count; i++)
{
if (this[i].ID == id)
return this[i];
}
return null;
}
}
public void Merge(MochaLibrary item)
{
MochaLibrary orig = this[item.ID];
if (orig != null)
{
orig.Merge(item);
return;
}
Add(item);
}
}
private void Merge(MochaLibrary item)
{
for (int i = 0; i < item.Metadata.Count; i++)
{
if (!Metadata.Contains(item.Metadata[i].Name))
{
Metadata.Add(item.Metadata[i]);
}
}
for (int i = 0; i < item.Instances.Count; i++)
{
Instances.Merge(item.Instances[i]);
}
for (int i = 0; i < item.Relationships.Count; i++)
{
Relationships.Merge(item.Relationships[i]);
}
for (int i = 0; i < item.LibraryReferences.Count; i++)
{
LibraryReferences.Add(item.LibraryReferences[i]);
}
}
public Guid ID { get; set; }
public MochaLibraryMetadata.MochaLibraryMetadataCollection Metadata { get; } = new MochaLibraryMetadata.MochaLibraryMetadataCollection();
public MochaInstance.MochaInstanceCollection Instances { get; } = new MochaInstance.MochaInstanceCollection();
public MochaRelationship.MochaRelationshipCollection Relationships { get; } = new MochaRelationship.MochaRelationshipCollection();
public System.Collections.Generic.List<Guid> LibraryReferences { get; } = new System.Collections.Generic.List<Guid>();
public Guid DefaultObjectSourceID { get; set; }
public object Clone()
{
MochaLibrary clone = new MochaLibrary();
clone.ID = ID;
clone.DefaultObjectSourceID = DefaultObjectSourceID;
for (int i = 0; i < Metadata.Count; i++)
{
clone.Metadata.Add(Metadata[i].Clone() as MochaLibraryMetadata);
}
for (int i = 0; i < Instances.Count; i++)
{
clone.Instances.Add(Instances[i].Clone() as MochaInstance);
}
for (int i = 0; i < Relationships.Count; i++)
{
clone.Relationships.Add(Relationships[i].Clone() as MochaRelationship);
}
for (int i = 0; i < LibraryReferences.Count; i++)
{
clone.LibraryReferences.Add(LibraryReferences[i]);
}
return clone;
}
public MochaInstance FindInstance(Guid id)
{
if (Instances[id] != null)
return Instances[id];
return null;
}
}
}

View File

@ -0,0 +1,79 @@
//
// MochaLibraryMetadata.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaLibraryMetadata : ICloneable
{
public class MochaLibraryMetadataCollection
: System.Collections.ObjectModel.Collection<MochaLibraryMetadata>
{
private Dictionary<string, MochaLibraryMetadata> _itemsByName = new Dictionary<string, MochaLibraryMetadata>();
public MochaLibraryMetadata this[string name]
{
get
{
if (_itemsByName.ContainsKey(name))
return _itemsByName[name];
return null;
}
}
public bool Contains(string name)
{
return _itemsByName.ContainsKey(name);
}
protected override void ClearItems()
{
base.ClearItems();
_itemsByName.Clear();
}
protected override void InsertItem(int index, MochaLibraryMetadata item)
{
base.InsertItem(index, item);
_itemsByName[item.Name] = item;
}
protected override void RemoveItem(int index)
{
if (_itemsByName.ContainsKey(this[index].Name))
_itemsByName.Remove(this[index].Name);
base.RemoveItem(index);
}
}
public string Name { get; set; }
public string Value { get; set; }
public MochaLibraryMetadata(string name, string value)
{
Name = name;
Value = value;
}
public object Clone()
{
MochaLibraryMetadata clone = new MochaLibraryMetadata(Name?.Clone() as string, Value?.Clone() as string);
return clone;
}
}
}

View File

@ -0,0 +1,102 @@
//
// MochaRelationship.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using Mocha.Core;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaRelationship : ICloneable
{
public class MochaRelationshipCollection
: System.Collections.ObjectModel.Collection<MochaRelationship>
{
private Dictionary<RelationshipKey, MochaRelationship> _itemsByKey = new Dictionary<RelationshipKey, MochaRelationship>();
public MochaRelationship this[RelationshipKey key]
{
get
{
if (_itemsByKey.ContainsKey(key))
return _itemsByKey[key];
return null;
}
}
protected override void ClearItems()
{
base.ClearItems();
_itemsByKey.Clear();
}
protected override void InsertItem(int index, MochaRelationship item)
{
base.InsertItem(index, item);
_itemsByKey[new RelationshipKey(item.SourceInstanceID, item.RelationshipInstanceID)] = item;
}
protected override void RemoveItem(int index)
{
_itemsByKey.Remove(new RelationshipKey(this[index].SourceInstanceID, this[index].RelationshipInstanceID));
base.RemoveItem(index);
}
public void Merge(MochaRelationship item)
{
MochaRelationship orig = this[new RelationshipKey(item.SourceInstanceID, item.RelationshipInstanceID)];
if (orig != null)
{
orig.Merge(item);
return;
}
Add(item);
}
}
public Guid RelationshipInstanceID { get; set; }
public Guid SourceInstanceID { get; set; }
public List<Guid> DestinationInstanceIDs { get; set; } = new List<Guid>();
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MochaRelationship"/> should be removed from the tenant.
/// </summary>
/// <value><c>true</c> if remove; otherwise, <c>false</c>.</value>
public bool Remove { get; set; } = false;
private void Merge(MochaRelationship item)
{
if (!(SourceInstanceID == item.SourceInstanceID && RelationshipInstanceID == item.RelationshipInstanceID))
throw new InvalidOperationException("cannot merge two instances with different (source and relationship) identifiers");
foreach (Guid id in item.DestinationInstanceIDs)
DestinationInstanceIDs.Add(id);
}
public object Clone()
{
MochaRelationship clone = new MochaRelationship();
clone.RelationshipInstanceID = RelationshipInstanceID;
clone.SourceInstanceID = SourceInstanceID;
for (int i = 0; i < DestinationInstanceIDs.Count; i++)
{
clone.DestinationInstanceIDs.Add(DestinationInstanceIDs[i]);
}
return clone;
}
}
}

View File

@ -0,0 +1,137 @@
//
// MochaTenant.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2021 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace Mocha.Plugins.Libraries.MochaBinary.ObjectModels.MochaClassLibrary
{
public class MochaTenant : ICloneable, IMochaStore
{
public class MochaTenantCollection
: System.Collections.ObjectModel.Collection<MochaTenant>
{
public MochaTenant this[Guid id]
{
get
{
foreach (MochaTenant tenant in this)
{
if (tenant.ID == id)
return tenant;
}
return null;
}
}
public MochaTenant this[string name]
{
get
{
foreach (MochaTenant tenant in this)
{
if (tenant.Name == name)
return tenant;
}
return null;
}
}
public void Merge(MochaTenant tenant)
{
MochaTenant existing = this[tenant.ID];
if (existing != null)
{
if (existing.Name == null && tenant.Name != null)
{
existing.Name = tenant.Name;
}
if (existing.DefaultObjectSourceID == Guid.Empty)
existing.DefaultObjectSourceID = tenant.DefaultObjectSourceID;
foreach (Guid lref in tenant.LibraryReferences)
{
if (!existing.LibraryReferences.Contains(lref))
existing.LibraryReferences.Add(lref);
}
foreach (MochaInstance inst in tenant.Instances)
{
if (!existing.Instances.Contains(inst))
{
existing.Instances.Add(inst);
}
}
foreach (MochaRelationship rel in tenant.Relationships)
{
if (!existing.Relationships.Contains(rel))
{
existing.Relationships.Add(rel);
}
}
}
else
{
Add(tenant);
}
}
}
public Guid ID { get; set; }
public Guid DefaultObjectSourceID { get; set; }
public string Name { get; set; } = null;
public MochaLibraryMetadata.MochaLibraryMetadataCollection Metadata { get; } = new MochaLibraryMetadata.MochaLibraryMetadataCollection();
public MochaInstance.MochaInstanceCollection Instances { get; } = new MochaInstance.MochaInstanceCollection();
public MochaRelationship.MochaRelationshipCollection Relationships { get; } = new MochaRelationship.MochaRelationshipCollection();
public System.Collections.Generic.List<Guid> LibraryReferences { get; } = new System.Collections.Generic.List<Guid>();
public object Clone()
{
MochaTenant clone = new MochaTenant();
clone.ID = ID;
clone.DefaultObjectSourceID = DefaultObjectSourceID;
clone.Name = (Name.Clone() as string);
foreach (MochaLibraryMetadata item in Metadata)
{
clone.Metadata.Add(item.Clone() as MochaLibraryMetadata);
}
foreach (MochaInstance item in Instances)
{
clone.Instances.Add(item.Clone() as MochaInstance);
}
foreach (MochaRelationship item in Relationships)
{
clone.Relationships.Add(item.Clone() as MochaRelationship);
}
foreach (Guid item in LibraryReferences)
{
clone.LibraryReferences.Add((Guid)item);
}
return clone;
}
public MochaInstance FindInstance(Guid id)
{
MochaInstance inst = Instances[id];
return inst;
}
}
}

View File

@ -0,0 +1,98 @@
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
//
// This file is part of Mocha.NET.
//
// Mocha.NET is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mocha.NET is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mocha.NET. If not, see <https://www.gnu.org/licenses/>.
using MBS.Editor.Core;
using MBS.Editor.Core.IO;
using MBS.Editor.Core.ObjectModels.FileSystem;
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
public class SlickBinaryDataFormat : DataFormat
{
public SlickBinaryDataFormat()
{
}
public int FileNameSize { get; set; } = 128;
protected override void LoadInternal(ObjectModel objectModel, Stream stream)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null)
throw new ObjectModelNotSupportedException();
Reader reader = new Reader(stream);
string signature = reader.ReadFixedLengthString(8);
if (!signature.Equals("slick!\0\0"))
throw new InvalidDataFormatException("");
float version = reader.ReadSingle();
if (version != 1.0f)
throw new InvalidDataFormatException();
FileNameSize = reader.ReadInt32();
int fileCount = reader.ReadInt32();
for (int i = 0; i < fileCount; i++)
{
string fileName = reader.ReadFixedLengthString(FileNameSize); // .TrimNull();
int q = -1;
if ((q = fileName.IndexOf('\0')) != -1)
{
fileName = fileName.Substring(0, q);
}
int offset = reader.ReadInt32();
int length = reader.ReadInt32();
FileSystemFile file = fsom.Items.AddFile(fileName);
file.Source = new EmbeddedFileSource(stream, offset, length);
}
}
protected override void SaveInternal(ObjectModel objectModel, Stream stream)
{
FileSystemObjectModel fsom = (objectModel as FileSystemObjectModel);
if (fsom == null)
throw new ObjectModelNotSupportedException();
Writer writer = new Writer(stream);
writer.WriteFixedLengthString("slick!\0\0");
writer.WriteSingle(1.0f);
writer.WriteInt32(FileNameSize);
FileSystemFile[] files = fsom.Items.GetAllFiles();
writer.WriteInt32(files.Length);
int foffset = 20 + ((FileNameSize + 8) * files.Length);
for (int i = 0; i < files.Length; i++)
{
writer.WriteFixedLengthString(files[i].Name, FileNameSize);
writer.WriteInt32(foffset);
int datalen = files[i].Source.GetData().Length;
writer.WriteInt32(datalen);
foffset += datalen;
}
for (int i = 0; i < files.Length; i++)
{
writer.WriteBytes(files[i].Source.GetData());
}
}
}

View File

@ -0,0 +1,12 @@

namespace MBS.Editor.Core;
public abstract class DataFormat
{
protected abstract void LoadInternal(ObjectModel? objectModel, Stream stream);
public void Load(ObjectModel? objectModel, Stream stream)
{
LoadInternal(objectModel, stream);
}
}

View File

@ -0,0 +1,19 @@

namespace MBS.Editor.Core.DataFormats.YAML;
public class YAMLDataFormat : DataFormat
{
protected override void LoadInternal(ObjectModel? objectModel, Stream stream)
{
StreamReader sr = new StreamReader(stream);
int ic = -1;
while ((ic = sr.Read()) != -1)
{
char c = (char)ic;
if (c == '-')
{
}
}
}
}

View File

@ -0,0 +1,27 @@
namespace MBS.Editor.Core;
public class Document
{
public ObjectModel? ObjectModel { get; set; } = null;
public DataFormat? DataFormat { get; set; } = null;
public Stream Stream { get; set; }
public Document(ObjectModel objectModel, DataFormat dataFormat, Stream stream)
{
ObjectModel = objectModel;
DataFormat = dataFormat;
Stream = stream;
}
public static Document Load(ObjectModel objectModel, DataFormat dataFormat, Stream stream)
{
Document d = new Document(objectModel, dataFormat, stream);
d.Load();
return d;
}
public void Load()
{
DataFormat.Load(ObjectModel, Stream);
}
}

View File

@ -0,0 +1,6 @@
namespace MBS.Editor.Core;
public abstract class ObjectModel
{
}

View File

@ -19,9 +19,8 @@ public class YamlLibraryPlugin : LibraryPlugin
FileStream fs = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.Read);
StreamReader sr = new StreamReader(fs);
var yaml = new YamlStream();
yaml.Load(sr);
// var yaml = new YAMLDataFormat();
// yaml.Load(sr);
}
}
}

View File

@ -1,9 +0,0 @@
namespace Mocha.Plugins.Libraries.Yaml;
public class YamlParser
{
public Dictionary<string, object> Parse(Stream stream)
{
StreamReader sr = new StreamReader(stream);
}
}