mirror of
https://github.com/DeclanHoare/whoa.git
synced 2025-01-22 06:01:49 -05:00
first version
This commit is contained in:
parent
7d637c031c
commit
c549608895
10 changed files with 702 additions and 0 deletions
26
README.md
Normal file
26
README.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Whoa
|
||||
|
||||
## About
|
||||
Whoa is a serialisation library for C#. Its output is ultra small and
|
||||
you can add members to your type and still be able to deserialise old
|
||||
versions. Since it stores the bare minimum of type data, it is a bit
|
||||
more finicky than other serialisation solutions like BinaryFormatter,
|
||||
but produces much smaller output.
|
||||
|
||||
## Usage
|
||||
|
||||
For Whoa to produce meaningful output, your type will need to have a
|
||||
public constructor with no arguments, and every field or property that
|
||||
you would like to save needs to be public (properties must have a public
|
||||
getter AND a public setter) and have a Whoa.OrderAttribute. Also, if you
|
||||
want to preserve backwards compatibility, don't rearrange or remove
|
||||
any of the members with OrderAttributes. You can, however, add new ones
|
||||
to the end of your class without issue.
|
||||
|
||||
To serialise an object:
|
||||
`Whoa.Whoa.SerialiseObject(outstream, obj);`
|
||||
|
||||
To deserialise an object:
|
||||
`Whoa.Whoa.DeserialiseObject<T>(instream);`
|
||||
|
||||
|
6
Tests/App.config
Normal file
6
Tests/App.config
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
|
||||
</startup>
|
||||
</configuration>
|
36
Tests/Properties/AssemblyInfo.cs
Normal file
36
Tests/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Declan Hoare")]
|
||||
[assembly: AssemblyProduct("Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright 2017 Declan Hoare")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("2330458c-1fa0-4a6a-b088-5e8692602acb")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
137
Tests/Test.cs
Normal file
137
Tests/Test.cs
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Copyright 2017 Declan Hoare
|
||||
// This file is part of Whoa.
|
||||
//
|
||||
// Whoa 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.
|
||||
//
|
||||
// Whoa 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Whoa. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Whoa;
|
||||
|
||||
namespace Whoa.Tests
|
||||
{
|
||||
public static class Test
|
||||
{
|
||||
private class Record
|
||||
{
|
||||
[Order]
|
||||
public string title;
|
||||
|
||||
[Order]
|
||||
public string artist;
|
||||
|
||||
[Order]
|
||||
public int rpm;
|
||||
|
||||
[Order]
|
||||
public double price;
|
||||
|
||||
[Order]
|
||||
public bool inLibrary;
|
||||
|
||||
[Order]
|
||||
public bool otherBool;
|
||||
|
||||
[Order]
|
||||
public List<string> songs;
|
||||
|
||||
[Order]
|
||||
public Guid guidForSomeReason;
|
||||
|
||||
[Order]
|
||||
public List<bool> moreBools;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string ret = $@"{title}
|
||||
Artist: {artist}
|
||||
RPM: {rpm}
|
||||
Price: {price}
|
||||
";
|
||||
ret += inLibrary ? "In" : "Not in";
|
||||
ret += " library" + Environment.NewLine;
|
||||
ret += "Something else about it: ";
|
||||
ret += otherBool ? "Yep" : "Nope";
|
||||
ret += Environment.NewLine;
|
||||
ret += "Songs:";
|
||||
ret += Environment.NewLine;
|
||||
int track = 0;
|
||||
foreach (string song in songs)
|
||||
ret += $"{++track}. {song}" + Environment.NewLine;
|
||||
ret += $"Guid (?!): {guidForSomeReason}";
|
||||
ret += Environment.NewLine;
|
||||
ret += "Some more information:";
|
||||
ret += Environment.NewLine;
|
||||
foreach (bool info in moreBools)
|
||||
ret += (info ? "Yes" : "No") + Environment.NewLine;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
using (var str = new MemoryStream())
|
||||
{
|
||||
var rec = new Record()
|
||||
{
|
||||
title = "Cool Songs For Cool People",
|
||||
artist = "Ethan Klein",
|
||||
rpm = 78,
|
||||
price = 99.99,
|
||||
inLibrary = true,
|
||||
otherBool = true,
|
||||
songs = new string[]
|
||||
{
|
||||
"International Tiles",
|
||||
"Test Data"
|
||||
}.ToList(),
|
||||
guidForSomeReason = Guid.NewGuid(),
|
||||
moreBools = new bool[] {true, false, false, true, true, true, false, false, true, true}.ToList()
|
||||
};
|
||||
string expected = rec.ToString();
|
||||
Whoa.SerialiseObject(str, rec);
|
||||
if (args.Length > 0) // Save output for debugging.
|
||||
{
|
||||
str.Position = 0;
|
||||
using (var fobj = File.OpenWrite(args[0]))
|
||||
str.CopyTo(fobj);
|
||||
}
|
||||
str.Position = 0;
|
||||
var res = Whoa.DeserialiseObject<Record>(str);
|
||||
string actual = res.ToString();
|
||||
Console.Write("Test ");
|
||||
if (expected == actual)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Green;
|
||||
Console.WriteLine("passed");
|
||||
Console.ResetColor();
|
||||
Console.Write(actual);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine("FAILED");
|
||||
Console.ResetColor();
|
||||
Console.WriteLine("Expected:");
|
||||
Console.Write(expected);
|
||||
Console.WriteLine("");
|
||||
Console.WriteLine("Actual:");
|
||||
Console.Write(actual);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
Tests/Tests.csproj
Normal file
58
Tests/Tests.csproj
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{2330458C-1FA0-4A6A-B088-5E8692602ACB}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Tests</RootNamespace>
|
||||
<AssemblyName>Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Test.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Whoa\Whoa.csproj">
|
||||
<Project>{493a0902-9d25-4c60-a419-2c4082577c9d}</Project>
|
||||
<Name>Whoa</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
28
Whoa.sln
Normal file
28
Whoa.sln
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26430.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Whoa", "Whoa\Whoa.csproj", "{493A0902-9D25-4C60-A419-2C4082577C9D}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{2330458C-1FA0-4A6A-B088-5E8692602ACB}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{493A0902-9D25-4C60-A419-2C4082577C9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{493A0902-9D25-4C60-A419-2C4082577C9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{493A0902-9D25-4C60-A419-2C4082577C9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{493A0902-9D25-4C60-A419-2C4082577C9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2330458C-1FA0-4A6A-B088-5E8692602ACB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2330458C-1FA0-4A6A-B088-5E8692602ACB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2330458C-1FA0-4A6A-B088-5E8692602ACB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2330458C-1FA0-4A6A-B088-5E8692602ACB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
31
Whoa/OrderAttribute.cs
Normal file
31
Whoa/OrderAttribute.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2017 Declan Hoare
|
||||
// This file is part of Whoa.
|
||||
//
|
||||
// Whoa 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.
|
||||
//
|
||||
// Whoa 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Whoa. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Whoa
|
||||
{
|
||||
public sealed class OrderAttribute : Attribute
|
||||
{
|
||||
private readonly int order_;
|
||||
public OrderAttribute([CallerLineNumber]int order = 0)
|
||||
{
|
||||
order_ = order;
|
||||
}
|
||||
public int Order { get { return order_; } }
|
||||
}
|
||||
}
|
36
Whoa/Properties/AssemblyInfo.cs
Normal file
36
Whoa/Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Whoa")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Declan Hoare")]
|
||||
[assembly: AssemblyProduct("Whoa")]
|
||||
[assembly: AssemblyCopyright("Copyright 2017 Declan Hoare")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("493a0902-9d25-4c60-a419-2c4082577c9d")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
296
Whoa/Whoa.cs
Normal file
296
Whoa/Whoa.cs
Normal file
|
@ -0,0 +1,296 @@
|
|||
// Copyright 2017 Declan Hoare
|
||||
// This file is part of Whoa.
|
||||
//
|
||||
// Whoa 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.
|
||||
//
|
||||
// Whoa 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with Whoa. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Whoa
|
||||
{
|
||||
public static class Whoa
|
||||
{
|
||||
private class SpecialSerialiserAttribute: Attribute
|
||||
{
|
||||
public Type t { get; private set; }
|
||||
public SpecialSerialiserAttribute(Type in_t)
|
||||
{
|
||||
t = in_t;
|
||||
}
|
||||
}
|
||||
|
||||
private class SpecialDeserialiserAttribute: Attribute
|
||||
{
|
||||
public Type t { get; private set; }
|
||||
public SpecialDeserialiserAttribute(Type in_t)
|
||||
{
|
||||
t = in_t;
|
||||
}
|
||||
}
|
||||
|
||||
[SpecialSerialiser(typeof(Guid))]
|
||||
private static void SerialiseGuid(Stream fobj, dynamic obj)
|
||||
{
|
||||
fobj.Write(obj.ToByteArray(), 0, 16);
|
||||
}
|
||||
|
||||
[SpecialDeserialiser(typeof(Guid))]
|
||||
private static object DeserialiseGuid(Stream fobj)
|
||||
{
|
||||
var guid = new byte[16];
|
||||
fobj.Read(guid, 0, 16);
|
||||
return new Guid(guid);
|
||||
}
|
||||
|
||||
private static IOrderedEnumerable<MemberInfo> Members(Type t)
|
||||
{
|
||||
return t.GetProperties().Select(m => m as MemberInfo).Concat(t.GetFields().Select(m => m as MemberInfo)).Where(m => (m.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute) != null).OrderBy(m => (m.GetCustomAttributes(typeof(OrderAttribute), false).SingleOrDefault() as OrderAttribute).Order);
|
||||
}
|
||||
|
||||
private static List<bool> ReadBitfield(Stream fobj, int count)
|
||||
{
|
||||
sbyte bit = 7;
|
||||
int cur = 0;
|
||||
var bitfields = new byte[count / 8 + 1];
|
||||
var bools = new List<bool>(count);
|
||||
fobj.Read(bitfields, 0, bitfields.Length);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
bools.Add(((bitfields[cur] >> bit) & 1) == 1);
|
||||
bit--;
|
||||
if (bit < 0)
|
||||
{
|
||||
bit = 7;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
return bools;
|
||||
}
|
||||
|
||||
private static void WriteBitfield(Stream fobj, IEnumerable<bool> bools)
|
||||
{
|
||||
sbyte bit = 7;
|
||||
int cur = 0;
|
||||
var bitfields = new byte[bools.Count() / 8 + 1];
|
||||
foreach (bool mybool in bools)
|
||||
{
|
||||
if (mybool)
|
||||
bitfields[cur] |= (byte) (1 << bit);
|
||||
bit--;
|
||||
if (bit < 0)
|
||||
{
|
||||
bit = 7;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
fobj.Write(bitfields, 0, bitfields.Length);
|
||||
}
|
||||
|
||||
public static T DeserialiseObject<T>(Stream fobj)
|
||||
{
|
||||
return (T)DeserialiseObject(typeof(T), fobj);
|
||||
}
|
||||
|
||||
public static object DeserialiseObject(Type t, Stream fobj)
|
||||
{
|
||||
using (var read = new BinaryReader(fobj, Encoding.UTF8, true))
|
||||
{
|
||||
if (t.IsGenericType)
|
||||
{
|
||||
var gent = t.GetGenericTypeDefinition();
|
||||
|
||||
if (gent == typeof(List<>))
|
||||
{
|
||||
int numelems = read.ReadInt32();
|
||||
dynamic retl = Activator.CreateInstance(t, new object[] { numelems });
|
||||
Type elemtype = t.GetGenericArguments()[0];
|
||||
for (int i = 0; i < numelems; i++)
|
||||
retl.Add((dynamic)DeserialiseObject(elemtype, fobj));
|
||||
return retl;
|
||||
}
|
||||
|
||||
if (gent == typeof(Dictionary<,>))
|
||||
{
|
||||
int numpairs = read.ReadInt32();
|
||||
dynamic retd = Activator.CreateInstance(t, new object[] { numpairs });
|
||||
Type[] arguments = t.GetGenericArguments();
|
||||
for (int i = 0; i < numpairs; i++)
|
||||
{
|
||||
dynamic key = DeserialiseObject(arguments[0], fobj);
|
||||
dynamic val = DeserialiseObject(arguments[1], fobj);
|
||||
retd.Add(key, val);
|
||||
}
|
||||
return retd;
|
||||
}
|
||||
}
|
||||
|
||||
// A little self reflection.
|
||||
var specialmethod = typeof(Whoa).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).FirstOrDefault(m =>
|
||||
{
|
||||
var attr = m.GetCustomAttributes(typeof(SpecialDeserialiserAttribute), false).SingleOrDefault() as SpecialDeserialiserAttribute;
|
||||
if (attr == null)
|
||||
return false;
|
||||
return attr.t == t;
|
||||
});
|
||||
|
||||
if (specialmethod != null)
|
||||
return specialmethod.Invoke(null, new object[] { fobj });
|
||||
|
||||
var readermethod = typeof(BinaryReader).GetMethods().FirstOrDefault(m => m.Name.Length > 4 && m.Name.StartsWith("Read") && m.ReturnType == t);
|
||||
if (readermethod != null)
|
||||
return readermethod.Invoke(read, new object[] { });
|
||||
|
||||
object ret = t.GetConstructor(Type.EmptyTypes).Invoke(new object[] { });
|
||||
int nummembers = read.ReadInt32();
|
||||
var bools = new List<dynamic>();
|
||||
|
||||
foreach (dynamic member in Members(t).Take(nummembers))
|
||||
{
|
||||
Type memt;
|
||||
if (member.MemberType == MemberTypes.Field)
|
||||
memt = member.FieldType;
|
||||
else
|
||||
memt = member.PropertyType;
|
||||
|
||||
if (memt == typeof(bool))
|
||||
bools.Add(member);
|
||||
else if (memt == typeof(List<bool>))
|
||||
member.SetValue(ret, ReadBitfield(fobj, read.ReadInt32()));
|
||||
else if (memt == typeof(bool[]))
|
||||
member.SetValue(ret, ReadBitfield(fobj, read.ReadInt32()).ToArray());
|
||||
else
|
||||
member.SetValue(ret, DeserialiseObject(memt, fobj));
|
||||
}
|
||||
|
||||
if (bools.Count > 0)
|
||||
{
|
||||
var loaded = ReadBitfield(fobj, bools.Count);
|
||||
foreach (var item in bools.Zip(loaded, (m, b) => new { Member = m, Value = b }))
|
||||
item.Member.SetValue(ret, item.Value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SerialiseObject(Stream fobj, dynamic obj)
|
||||
{
|
||||
using (var write = new BinaryWriter(fobj, Encoding.UTF8, true))
|
||||
{
|
||||
Type t = obj.GetType();
|
||||
|
||||
if (t.IsGenericType)
|
||||
{
|
||||
var gent = t.GetGenericTypeDefinition();
|
||||
|
||||
if (gent == typeof(List<>))
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
write.Write(0);
|
||||
return;
|
||||
}
|
||||
write.Write(obj.Count);
|
||||
foreach (dynamic item in obj)
|
||||
SerialiseObject(fobj, item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gent == typeof(Dictionary<,>))
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
write.Write(0);
|
||||
return;
|
||||
}
|
||||
write.Write(obj.Count);
|
||||
foreach (dynamic pair in obj)
|
||||
{
|
||||
SerialiseObject(fobj, pair.Key);
|
||||
SerialiseObject(fobj, pair.Value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var specialmethod = typeof(Whoa).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).FirstOrDefault(m =>
|
||||
{
|
||||
var attr = m.GetCustomAttributes(typeof(SpecialSerialiserAttribute), false).SingleOrDefault() as SpecialSerialiserAttribute;
|
||||
if (attr == null)
|
||||
return false;
|
||||
return attr.t == t;
|
||||
});
|
||||
|
||||
if (specialmethod != null)
|
||||
{
|
||||
specialmethod.Invoke(null, new object[] { fobj, obj });
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
write.Write(obj); // Will fail if not an integral type
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
write.Write(0);
|
||||
return;
|
||||
}
|
||||
|
||||
var bools = new List<bool>();
|
||||
var members = Members(t);
|
||||
write.Write(members.Count());
|
||||
|
||||
foreach (dynamic member in members)
|
||||
{
|
||||
Type memt;
|
||||
if (member.MemberType == MemberTypes.Field)
|
||||
memt = member.FieldType;
|
||||
else
|
||||
memt = member.PropertyType;
|
||||
|
||||
if (memt == typeof(bool))
|
||||
bools.Add(member.GetValue(obj));
|
||||
else if (typeof(IEnumerable<bool>).IsAssignableFrom(memt))
|
||||
{
|
||||
var val = member.GetValue(obj) as IEnumerable<bool>;
|
||||
if (val == null)
|
||||
write.Write(0);
|
||||
else
|
||||
{
|
||||
write.Write(val.Count());
|
||||
WriteBitfield(fobj, val.ToList());
|
||||
}
|
||||
}
|
||||
else
|
||||
SerialiseObject(fobj, member.GetValue(obj));
|
||||
}
|
||||
|
||||
WriteBitfield(fobj, bools);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
Whoa/Whoa.csproj
Normal file
48
Whoa/Whoa.csproj
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{493A0902-9D25-4C60-A419-2C4082577C9D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Whoa</RootNamespace>
|
||||
<AssemblyName>Whoa</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="OrderAttribute.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Whoa.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
Loading…
Reference in a new issue