Ported .Net Core commits:
hondacrx: - Initial commit: Switch to .Net Core 2.0 - Fix build and removed not needed files Fabi: - Updated solution platforms. - Changed folder structure. - Change library target framework to netstandard2.0. - Updated solution platforms again... - Removed windows specific kernel32 function usage (Ctrl-C handler).
This commit is contained in:
@@ -1,171 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{668E1664-FB63-47DA-9EA1-93B59851BF1E}</ProjectGuid>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>BNetServer</RootNamespace>
|
|
||||||
<AssemblyName>BNetServer</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
|
||||||
<PublishUrl>publish\</PublishUrl>
|
|
||||||
<Install>true</Install>
|
|
||||||
<InstallFrom>Disk</InstallFrom>
|
|
||||||
<UpdateEnabled>false</UpdateEnabled>
|
|
||||||
<UpdateMode>Foreground</UpdateMode>
|
|
||||||
<UpdateInterval>7</UpdateInterval>
|
|
||||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
|
||||||
<UpdatePeriodically>false</UpdatePeriodically>
|
|
||||||
<UpdateRequired>false</UpdateRequired>
|
|
||||||
<MapFileExtensions>true</MapFileExtensions>
|
|
||||||
<ApplicationRevision>0</ApplicationRevision>
|
|
||||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
|
||||||
<UseApplicationTrust>false</UseApplicationTrust>
|
|
||||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<StartupObject>BNetServer.Server</StartupObject>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ApplicationIcon>Red.ico</ApplicationIcon>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\x64\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
|
||||||
<CodeAnalysisIgnoreGeneratedCode>false</CodeAnalysisIgnoreGeneratedCode>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
|
||||||
<OutputPath>..\Build\x64\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
|
||||||
<OutputPath>..\Build\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Prefer32Bit>true</Prefer32Bit>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup />
|
|
||||||
<PropertyGroup />
|
|
||||||
<PropertyGroup>
|
|
||||||
<SignManifests>false</SignManifests>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ManifestCertificateThumbprint>7EA13AA3A2003652283599344471651FF1C1100A</ManifestCertificateThumbprint>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<ManifestKeyFile>BNetServer_TemporaryKey.pfx</ManifestKeyFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<SignAssembly>false</SignAssembly>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\Libs\Google.Protobuf.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Numerics" />
|
|
||||||
<Reference Include="System.Runtime.Serialization" />
|
|
||||||
<Reference Include="System.Runtime.Serialization.Formatters.Soap" />
|
|
||||||
<Reference Include="System.Web" />
|
|
||||||
<Reference Include="System.Web.Extensions" />
|
|
||||||
<Reference Include="System.Web.Services" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Managers\SessionManager.cs" />
|
|
||||||
<Compile Include="Networking\RestSession.cs" />
|
|
||||||
<Compile Include="Managers\Global.cs" />
|
|
||||||
<Compile Include="Networking\Session.cs" />
|
|
||||||
<Compile Include="Server.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<Compile Include="Services\AccountService.cs" />
|
|
||||||
<Compile Include="Services\AuthenticationService.cs" />
|
|
||||||
<Compile Include="Services\ChallengeService.cs" />
|
|
||||||
<Compile Include="Services\ChannelService.cs" />
|
|
||||||
<Compile Include="Services\ConnectionService.cs" />
|
|
||||||
<Compile Include="Services\FriendService.cs" />
|
|
||||||
<Compile Include="Services\GameUtilitiesService.cs" />
|
|
||||||
<Compile Include="Services\PresenceService.cs" />
|
|
||||||
<Compile Include="Services\ReportService.cs" />
|
|
||||||
<Compile Include="Services\ResourcesService.cs" />
|
|
||||||
<Compile Include="Services\ServiceDispatcher.cs" />
|
|
||||||
<Compile Include="Services\UserManagerService.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="Red.ico" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="BNetServer.conf.dist">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="BNetServer.pfx">
|
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Framework\Framework.csproj">
|
|
||||||
<Project>{82d442a9-18c0-4c59-8ec6-0dfe3e34d334}</Project>
|
|
||||||
<Name>Framework</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
|
||||||
<Visible>False</Visible>
|
|
||||||
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
|
|
||||||
<Install>true</Install>
|
|
||||||
</BootstrapperPackage>
|
|
||||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
|
||||||
<Visible>False</Visible>
|
|
||||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
|
||||||
<Install>false</Install>
|
|
||||||
</BootstrapperPackage>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup />
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<PreBuildEvent>
|
|
||||||
</PreBuildEvent>
|
|
||||||
</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>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("BNetServer")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("BNetServer")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("ffe6ae44-fd7a-431f-b65d-fe8ac7bfc86a")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
+101
-97
@@ -1,115 +1,119 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26430.12
|
VisualStudioVersion = 15.0.26730.10
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorldServer", "WorldServer\WorldServer.csproj", "{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BNetServer", "Source\BNetServer\BNetServer.csproj", "{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736} = {9E28B9C1-E473-4DAE-813F-3243CE318736}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BNetServer", "BNetServer\BNetServer.csproj", "{668E1664-FB63-47DA-9EA1-93B59851BF1E}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorldServer", "Source\WorldServer\WorldServer.csproj", "{E5DF8709-16D8-4357-976A-DF54AD3DDD66}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game\Game.csproj", "{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Scripts", "Source\Scripts\Scripts.csproj", "{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Scripts", "Scripts\Scripts.csproj", "{9E28B9C1-E473-4DAE-813F-3243CE318736}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Source\Game\Game.csproj", "{1899C17C-1FA4-4807-B90E-0336C5748C1A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Framework", "Framework\Framework.csproj", "{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Framework", "Source\Framework\Framework.csproj", "{2F7515AD-18E3-4ACA-A14B-1929F76299E7}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Servers", "Servers", "{480EFA6E-4FEC-483A-8432-09964C3486E0}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{0C88588D-45B8-4AA9-8EEA-DB1A1BD19D19}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf", "Deps\Source\Google.Protobuf\Google.Protobuf.csproj", "{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|linux-x64 = Debug|linux-x64
|
||||||
Debug|x86 = Debug|x86
|
Debug|mac-x64 = Debug|mac-x64
|
||||||
DebugMono|x64 = DebugMono|x64
|
Debug|win-x64 = Debug|win-x64
|
||||||
DebugMono|x86 = DebugMono|x86
|
Release|linux-x64 = Release|linux-x64
|
||||||
Release|x64 = Release|x64
|
Release|mac-x64 = Release|mac-x64
|
||||||
Release|x86 = Release|x86
|
Release|win-x64 = Release|win-x64
|
||||||
ReleaseMono|x64 = ReleaseMono|x64
|
|
||||||
ReleaseMono|x86 = ReleaseMono|x86
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x64.ActiveCfg = Debug|x64
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|linux-x64.ActiveCfg = Debug|linux-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x64.Build.0 = Debug|x64
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|linux-x64.Build.0 = Debug|linux-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x86.ActiveCfg = Debug|x86
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|mac-x64.ActiveCfg = Debug|mac-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x86.Build.0 = Debug|x86
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|mac-x64.Build.0 = Debug|mac-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x64.ActiveCfg = Debug|x64
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|win-x64.ActiveCfg = Debug|win-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x64.Build.0 = Debug|x64
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|win-x64.Build.0 = Debug|win-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x86.ActiveCfg = Debug|x86
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|linux-x64.ActiveCfg = Release|linux-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x86.Build.0 = Debug|x86
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|linux-x64.Build.0 = Release|linux-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x64.ActiveCfg = Release|x64
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|mac-x64.ActiveCfg = Release|mac-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x64.Build.0 = Release|x64
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|mac-x64.Build.0 = Release|mac-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x86.ActiveCfg = Release|x86
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|win-x64.ActiveCfg = Release|win-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x86.Build.0 = Release|x86
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|win-x64.Build.0 = Release|win-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x64.ActiveCfg = Release|x64
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|linux-x64.ActiveCfg = Debug|linux-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x64.Build.0 = Release|x64
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|linux-x64.Build.0 = Debug|linux-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x86.ActiveCfg = Release|x86
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|mac-x64.ActiveCfg = Debug|mac-x64
|
||||||
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x86.Build.0 = Release|x86
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|mac-x64.Build.0 = Debug|mac-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x64.ActiveCfg = Debug|x64
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|win-x64.ActiveCfg = Debug|win-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x64.Build.0 = Debug|x64
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|win-x64.Build.0 = Debug|win-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x86.ActiveCfg = Debug|x86
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|linux-x64.ActiveCfg = Release|linux-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x86.Build.0 = Debug|x86
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|linux-x64.Build.0 = Release|linux-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x64.ActiveCfg = Debug|x64
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|mac-x64.ActiveCfg = Release|mac-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x64.Build.0 = Debug|x64
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|mac-x64.Build.0 = Release|mac-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x86.ActiveCfg = Debug|x86
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|win-x64.ActiveCfg = Release|win-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x86.Build.0 = Debug|x86
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|win-x64.Build.0 = Release|win-x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x64.ActiveCfg = Release|x64
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|linux-x64.ActiveCfg = Debug|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x64.Build.0 = Release|x64
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|linux-x64.Build.0 = Debug|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x86.ActiveCfg = Release|x86
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|mac-x64.ActiveCfg = Debug|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x86.Build.0 = Release|x86
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|mac-x64.Build.0 = Debug|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x64.ActiveCfg = Release|x64
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|win-x64.ActiveCfg = Debug|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x64.Build.0 = Release|x64
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|win-x64.Build.0 = Debug|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x86.ActiveCfg = Release|x86
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|linux-x64.ActiveCfg = Release|x64
|
||||||
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x86.Build.0 = Release|x86
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|linux-x64.Build.0 = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x64.ActiveCfg = Debug|x64
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|mac-x64.ActiveCfg = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x64.Build.0 = Debug|x64
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|mac-x64.Build.0 = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x86.ActiveCfg = Debug|x86
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|win-x64.ActiveCfg = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x86.Build.0 = Debug|x86
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|win-x64.Build.0 = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x64.ActiveCfg = Debug|x64
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|linux-x64.ActiveCfg = Debug|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x64.Build.0 = Debug|x64
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|linux-x64.Build.0 = Debug|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x86.ActiveCfg = Debug|x86
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|mac-x64.ActiveCfg = Debug|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x86.Build.0 = Debug|x86
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|mac-x64.Build.0 = Debug|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x64.ActiveCfg = Release|x64
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|win-x64.ActiveCfg = Debug|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x64.Build.0 = Release|x64
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|win-x64.Build.0 = Debug|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x86.ActiveCfg = Release|x86
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|linux-x64.ActiveCfg = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x86.Build.0 = Release|x86
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|linux-x64.Build.0 = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x64.ActiveCfg = Release|x64
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|mac-x64.ActiveCfg = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x64.Build.0 = Release|x64
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|mac-x64.Build.0 = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x86.ActiveCfg = Release|x86
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|win-x64.ActiveCfg = Release|x64
|
||||||
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x86.Build.0 = Release|x86
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|win-x64.Build.0 = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x64.ActiveCfg = Debug|x64
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|linux-x64.ActiveCfg = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x64.Build.0 = Debug|x64
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|linux-x64.Build.0 = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x86.ActiveCfg = Debug|x86
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|mac-x64.ActiveCfg = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x86.Build.0 = Debug|x86
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|mac-x64.Build.0 = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x64.ActiveCfg = Debug|x64
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|win-x64.ActiveCfg = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x64.Build.0 = Debug|x64
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|win-x64.Build.0 = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x86.ActiveCfg = Debug|x86
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|linux-x64.ActiveCfg = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x86.Build.0 = Debug|x86
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|linux-x64.Build.0 = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x64.ActiveCfg = Release|x64
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|mac-x64.ActiveCfg = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x64.Build.0 = Release|x64
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|mac-x64.Build.0 = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x86.ActiveCfg = Release|x86
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|win-x64.ActiveCfg = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x86.Build.0 = Release|x86
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|win-x64.Build.0 = Release|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x64.ActiveCfg = Release|x64
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|linux-x64.ActiveCfg = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x64.Build.0 = Release|x64
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|linux-x64.Build.0 = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x86.ActiveCfg = Release|x86
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|mac-x64.ActiveCfg = Debug|x64
|
||||||
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x86.Build.0 = Release|x86
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|mac-x64.Build.0 = Debug|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x64.ActiveCfg = Debug|x64
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|win-x64.ActiveCfg = Debug|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x64.Build.0 = Debug|x64
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|win-x64.Build.0 = Debug|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x86.ActiveCfg = Debug|x86
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|linux-x64.ActiveCfg = Release|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x86.Build.0 = Debug|x86
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|linux-x64.Build.0 = Release|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x64.ActiveCfg = Debug|x64
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|mac-x64.ActiveCfg = Release|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x64.Build.0 = Debug|x64
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|mac-x64.Build.0 = Release|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x86.ActiveCfg = Debug|x86
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|win-x64.ActiveCfg = Release|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x86.Build.0 = Debug|x86
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|win-x64.Build.0 = Release|x64
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Release|x64.Build.0 = Release|x64
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Release|x86.ActiveCfg = Release|x86
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Release|x86.Build.0 = Release|x86
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.ReleaseMono|x64.ActiveCfg = Release|x64
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.ReleaseMono|x64.Build.0 = Release|x64
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.ReleaseMono|x86.ActiveCfg = Release|x86
|
|
||||||
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.ReleaseMono|x86.Build.0 = Release|x86
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218} = {480EFA6E-4FEC-483A-8432-09964C3486E0}
|
||||||
|
{E5DF8709-16D8-4357-976A-DF54AD3DDD66} = {480EFA6E-4FEC-483A-8432-09964C3486E0}
|
||||||
|
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6} = {0C88588D-45B8-4AA9-8EEA-DB1A1BD19D19}
|
||||||
|
{1899C17C-1FA4-4807-B90E-0336C5748C1A} = {0C88588D-45B8-4AA9-8EEA-DB1A1BD19D19}
|
||||||
|
{2F7515AD-18E3-4ACA-A14B-1929F76299E7} = {0C88588D-45B8-4AA9-8EEA-DB1A1BD19D19}
|
||||||
|
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D} = {0C88588D-45B8-4AA9-8EEA-DB1A1BD19D19}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {836F0B44-1360-4E79-8ED9-F3D23C2ACEF5}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a utility routine to copy small arrays much more quickly than Buffer.BlockCopy
|
||||||
|
/// </summary>
|
||||||
|
internal static class ByteArray
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The threshold above which you should use Buffer.BlockCopy rather than ByteArray.Copy
|
||||||
|
/// </summary>
|
||||||
|
private const int CopyThreshold = 12;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines which copy routine to use based on the number of bytes to be copied.
|
||||||
|
/// </summary>
|
||||||
|
internal static void Copy(byte[] src, int srcOffset, byte[] dst, int dstOffset, int count)
|
||||||
|
{
|
||||||
|
if (count > CopyThreshold)
|
||||||
|
{
|
||||||
|
Buffer.BlockCopy(src, srcOffset, dst, dstOffset, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int stop = srcOffset + count;
|
||||||
|
for (int i = srcOffset; i < stop; i++)
|
||||||
|
{
|
||||||
|
dst[dstOffset++] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reverses the order of bytes in the array
|
||||||
|
/// </summary>
|
||||||
|
internal static void Reverse(byte[] bytes)
|
||||||
|
{
|
||||||
|
for (int first = 0, last = bytes.Length - 1; first < last; first++, last--)
|
||||||
|
{
|
||||||
|
byte temp = bytes[first];
|
||||||
|
bytes[first] = bytes[last];
|
||||||
|
bytes[last] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,401 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
#if !NET35
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
#endif
|
||||||
|
#if NET35
|
||||||
|
using Google.Protobuf.Compatibility;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Immutable array of bytes.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ByteString : IEnumerable<byte>, IEquatable<ByteString>
|
||||||
|
{
|
||||||
|
private static readonly ByteString empty = new ByteString(new byte[0]);
|
||||||
|
|
||||||
|
private readonly byte[] bytes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unsafe operations that can cause IO Failure and/or other catestrophic side-effects.
|
||||||
|
/// </summary>
|
||||||
|
internal static class Unsafe
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new ByteString from the given byte array. The array is
|
||||||
|
/// *not* copied, and must not be modified after this constructor is called.
|
||||||
|
/// </summary>
|
||||||
|
internal static ByteString FromBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return new ByteString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides direct, unrestricted access to the bytes contained in this instance.
|
||||||
|
/// You must not modify or resize the byte array returned by this method.
|
||||||
|
/// </summary>
|
||||||
|
internal static byte[] GetBuffer(ByteString bytes)
|
||||||
|
{
|
||||||
|
return bytes.bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal use only. Ensure that the provided array is not mutated and belongs to this instance.
|
||||||
|
/// </summary>
|
||||||
|
internal static ByteString AttachBytes(byte[] bytes)
|
||||||
|
{
|
||||||
|
return new ByteString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new ByteString from the given byte array. The array is
|
||||||
|
/// *not* copied, and must not be modified after this constructor is called.
|
||||||
|
/// </summary>
|
||||||
|
private ByteString(byte[] bytes)
|
||||||
|
{
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an empty ByteString.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteString Empty
|
||||||
|
{
|
||||||
|
get { return empty; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the length of this ByteString in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public int Length
|
||||||
|
{
|
||||||
|
get { return bytes.Length; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns <c>true</c> if this byte string is empty, <c>false</c> otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEmpty
|
||||||
|
{
|
||||||
|
get { return Length == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this <see cref="ByteString"/> into a byte array.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The data is copied - changes to the returned array will not be reflected in this <c>ByteString</c>.</remarks>
|
||||||
|
/// <returns>A byte array with the same data as this <c>ByteString</c>.</returns>
|
||||||
|
public byte[] ToByteArray()
|
||||||
|
{
|
||||||
|
return (byte[]) bytes.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this <see cref="ByteString"/> into a standard base64 representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A base64 representation of this <c>ByteString</c>.</returns>
|
||||||
|
public string ToBase64()
|
||||||
|
{
|
||||||
|
return Convert.ToBase64String(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a <see cref="ByteString" /> from the Base64 Encoded String.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteString FromBase64(string bytes)
|
||||||
|
{
|
||||||
|
// By handling the empty string explicitly, we not only optimize but we fix a
|
||||||
|
// problem on CF 2.0. See issue 61 for details.
|
||||||
|
return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a <see cref="ByteString"/> from data in the given stream, synchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position
|
||||||
|
/// at the start of the call.</remarks>
|
||||||
|
/// <param name="stream">The stream to copy into a ByteString.</param>
|
||||||
|
/// <returns>A ByteString with content read from the given stream.</returns>
|
||||||
|
public static ByteString FromStream(Stream stream)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(stream, nameof(stream));
|
||||||
|
int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0;
|
||||||
|
var memoryStream = new MemoryStream(capacity);
|
||||||
|
stream.CopyTo(memoryStream);
|
||||||
|
#if NETSTANDARD1_0
|
||||||
|
byte[] bytes = memoryStream.ToArray();
|
||||||
|
#else
|
||||||
|
// Avoid an extra copy if we can.
|
||||||
|
byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray();
|
||||||
|
#endif
|
||||||
|
return AttachBytes(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !NET35
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a <see cref="ByteString"/> from data in the given stream, asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>If successful, <paramref name="stream"/> will be read completely, from the position
|
||||||
|
/// at the start of the call.</remarks>
|
||||||
|
/// <param name="stream">The stream to copy into a ByteString.</param>
|
||||||
|
/// <param name="cancellationToken">The cancellation token to use when reading from the stream, if any.</param>
|
||||||
|
/// <returns>A ByteString with content read from the given stream.</returns>
|
||||||
|
public async static Task<ByteString> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(stream, nameof(stream));
|
||||||
|
int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0;
|
||||||
|
var memoryStream = new MemoryStream(capacity);
|
||||||
|
// We have to specify the buffer size here, as there's no overload accepting the cancellation token
|
||||||
|
// alone. But it's documented to use 81920 by default if not specified.
|
||||||
|
await stream.CopyToAsync(memoryStream, 81920, cancellationToken);
|
||||||
|
#if NETSTANDARD1_0
|
||||||
|
byte[] bytes = memoryStream.ToArray();
|
||||||
|
#else
|
||||||
|
// Avoid an extra copy if we can.
|
||||||
|
byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray();
|
||||||
|
#endif
|
||||||
|
return AttachBytes(bytes);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a <see cref="ByteString" /> from the given array. The contents
|
||||||
|
/// are copied, so further modifications to the array will not
|
||||||
|
/// be reflected in the returned ByteString.
|
||||||
|
/// This method can also be invoked in <c>ByteString.CopyFrom(0xaa, 0xbb, ...)</c> form
|
||||||
|
/// which is primarily useful for testing.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteString CopyFrom(params byte[] bytes)
|
||||||
|
{
|
||||||
|
return new ByteString((byte[]) bytes.Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a <see cref="ByteString" /> from a portion of a byte array.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteString CopyFrom(byte[] bytes, int offset, int count)
|
||||||
|
{
|
||||||
|
byte[] portion = new byte[count];
|
||||||
|
ByteArray.Copy(bytes, offset, portion, 0, count);
|
||||||
|
return new ByteString(portion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ByteString" /> by encoding the specified text with
|
||||||
|
/// the given encoding.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteString CopyFrom(string text, Encoding encoding)
|
||||||
|
{
|
||||||
|
return new ByteString(encoding.GetBytes(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="ByteString" /> by encoding the specified text in UTF-8.
|
||||||
|
/// </summary>
|
||||||
|
public static ByteString CopyFromUtf8(string text)
|
||||||
|
{
|
||||||
|
return CopyFrom(text, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retuns the byte at the given index.
|
||||||
|
/// </summary>
|
||||||
|
public byte this[int index]
|
||||||
|
{
|
||||||
|
get { return bytes[index]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this <see cref="ByteString"/> into a string by applying the given encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method should only be used to convert binary data which was the result of encoding
|
||||||
|
/// text with the given encoding.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="encoding">The encoding to use to decode the binary data into text.</param>
|
||||||
|
/// <returns>The result of decoding the binary data with the given decoding.</returns>
|
||||||
|
public string ToString(Encoding encoding)
|
||||||
|
{
|
||||||
|
return encoding.GetString(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this <see cref="ByteString"/> into a string by applying the UTF-8 encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method should only be used to convert binary data which was the result of encoding
|
||||||
|
/// text with UTF-8.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>The result of decoding the binary data with the given decoding.</returns>
|
||||||
|
public string ToStringUtf8()
|
||||||
|
{
|
||||||
|
return ToString(Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an iterator over the bytes in this <see cref="ByteString"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An iterator over the bytes in this object.</returns>
|
||||||
|
public IEnumerator<byte> GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable<byte>) bytes).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an iterator over the bytes in this <see cref="ByteString"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An iterator over the bytes in this object.</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a CodedInputStream from this ByteString's data.
|
||||||
|
/// </summary>
|
||||||
|
public CodedInputStream CreateCodedInput()
|
||||||
|
{
|
||||||
|
// We trust CodedInputStream not to reveal the provided byte array or modify it
|
||||||
|
return new CodedInputStream(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two byte strings for equality.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The first byte string to compare.</param>
|
||||||
|
/// <param name="rhs">The second byte string to compare.</param>
|
||||||
|
/// <returns><c>true</c> if the byte strings are equal; false otherwise.</returns>
|
||||||
|
public static bool operator ==(ByteString lhs, ByteString rhs)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(lhs, rhs))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (lhs.bytes.Length != rhs.bytes.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < lhs.Length; i++)
|
||||||
|
{
|
||||||
|
if (rhs.bytes[i] != lhs.bytes[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares two byte strings for inequality.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The first byte string to compare.</param>
|
||||||
|
/// <param name="rhs">The second byte string to compare.</param>
|
||||||
|
/// <returns><c>false</c> if the byte strings are equal; true otherwise.</returns>
|
||||||
|
public static bool operator !=(ByteString lhs, ByteString rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this byte string with another object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to compare this with.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="obj"/> refers to an equal <see cref="ByteString"/>; <c>false</c> otherwise.</returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return this == (obj as ByteString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for this object. Two equal byte strings
|
||||||
|
/// will return the same hash code.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A hash code for this object.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int ret = 23;
|
||||||
|
foreach (byte b in bytes)
|
||||||
|
{
|
||||||
|
ret = (ret * 31) + b;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this byte string with another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="ByteString"/> to compare this with.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="other"/> refers to an equal byte string; <c>false</c> otherwise.</returns>
|
||||||
|
public bool Equals(ByteString other)
|
||||||
|
{
|
||||||
|
return this == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used internally by CodedOutputStream to avoid creating a copy for the write
|
||||||
|
/// </summary>
|
||||||
|
internal void WriteRawBytesTo(CodedOutputStream outputStream)
|
||||||
|
{
|
||||||
|
outputStream.WriteRawBytes(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the entire byte array to the destination array provided at the offset specified.
|
||||||
|
/// </summary>
|
||||||
|
public void CopyTo(byte[] array, int position)
|
||||||
|
{
|
||||||
|
ByteArray.Copy(bytes, 0, array, position, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the entire byte array to the provided stream
|
||||||
|
/// </summary>
|
||||||
|
public void WriteTo(Stream outputStream)
|
||||||
|
{
|
||||||
|
outputStream.Write(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,304 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
// This part of CodedOutputStream provides all the static entry points that are used
|
||||||
|
// by generated code and internally to compute the size of messages prior to being
|
||||||
|
// written to an instance of CodedOutputStream.
|
||||||
|
public sealed partial class CodedOutputStream
|
||||||
|
{
|
||||||
|
private const int LittleEndian64Size = 8;
|
||||||
|
private const int LittleEndian32Size = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// double field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeDoubleSize(double value)
|
||||||
|
{
|
||||||
|
return LittleEndian64Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// float field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeFloatSize(float value)
|
||||||
|
{
|
||||||
|
return LittleEndian32Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// uint64 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeUInt64Size(ulong value)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint64Size(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// int64 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeInt64Size(long value)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint64Size((ulong) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// int32 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeInt32Size(int value)
|
||||||
|
{
|
||||||
|
if (value >= 0)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint32Size((uint) value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Must sign-extend.
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// fixed64 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeFixed64Size(ulong value)
|
||||||
|
{
|
||||||
|
return LittleEndian64Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// fixed32 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeFixed32Size(uint value)
|
||||||
|
{
|
||||||
|
return LittleEndian32Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// bool field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeBoolSize(bool value)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// string field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeStringSize(String value)
|
||||||
|
{
|
||||||
|
int byteArraySize = Utf8Encoding.GetByteCount(value);
|
||||||
|
return ComputeLengthSize(byteArraySize) + byteArraySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// group field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeGroupSize(IMessage value)
|
||||||
|
{
|
||||||
|
return value.CalculateSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// embedded message field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeMessageSize(IMessage value)
|
||||||
|
{
|
||||||
|
int size = value.CalculateSize();
|
||||||
|
return ComputeLengthSize(size) + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// bytes field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeBytesSize(ByteString value)
|
||||||
|
{
|
||||||
|
return ComputeLengthSize(value.Length) + value.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// uint32 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeUInt32Size(uint value)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint32Size(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a
|
||||||
|
/// enum field, including the tag. The caller is responsible for
|
||||||
|
/// converting the enum value to its numeric value.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeEnumSize(int value)
|
||||||
|
{
|
||||||
|
// Currently just a pass-through, but it's nice to separate it logically.
|
||||||
|
return ComputeInt32Size(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// sfixed32 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeSFixed32Size(int value)
|
||||||
|
{
|
||||||
|
return LittleEndian32Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// sfixed64 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeSFixed64Size(long value)
|
||||||
|
{
|
||||||
|
return LittleEndian64Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// sint32 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeSInt32Size(int value)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint32Size(EncodeZigZag32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode an
|
||||||
|
/// sint64 field, including the tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeSInt64Size(long value)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint64Size(EncodeZigZag64(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a length,
|
||||||
|
/// as written by <see cref="WriteLength"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeLengthSize(int length)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint32Size((uint) length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a varint.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeRawVarint32Size(uint value)
|
||||||
|
{
|
||||||
|
if ((value & (0xffffffff << 7)) == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffff << 14)) == 0)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffff << 21)) == 0)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffff << 28)) == 0)
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a varint.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeRawVarint64Size(ulong value)
|
||||||
|
{
|
||||||
|
if ((value & (0xffffffffffffffffL << 7)) == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 14)) == 0)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 21)) == 0)
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 28)) == 0)
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 35)) == 0)
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 42)) == 0)
|
||||||
|
{
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 49)) == 0)
|
||||||
|
{
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 56)) == 0)
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
if ((value & (0xffffffffffffffffL << 63)) == 0)
|
||||||
|
{
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the number of bytes that would be needed to encode a tag.
|
||||||
|
/// </summary>
|
||||||
|
public static int ComputeTagSize(int fieldNumber)
|
||||||
|
{
|
||||||
|
return ComputeRawVarint32Size(WireFormat.MakeTag(fieldNumber, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,760 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Encodes and writes protocol message fields.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This class is generally used by generated code to write appropriate
|
||||||
|
/// primitives to the stream. It effectively encapsulates the lowest
|
||||||
|
/// levels of protocol buffer format. Unlike some other implementations,
|
||||||
|
/// this does not include combined "write tag and value" methods. Generated
|
||||||
|
/// code knows the exact byte representations of the tags they're going to write,
|
||||||
|
/// so there's no need to re-encode them each time. Manually-written code calling
|
||||||
|
/// this class should just call one of the <c>WriteTag</c> overloads before each value.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Repeated fields and map fields are not handled by this class; use <c>RepeatedField<T></c>
|
||||||
|
/// and <c>MapField<TKey, TValue></c> to serialize such fields.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public sealed partial class CodedOutputStream : IDisposable
|
||||||
|
{
|
||||||
|
// "Local" copy of Encoding.UTF8, for efficiency. (Yes, it makes a difference.)
|
||||||
|
internal static readonly Encoding Utf8Encoding = Encoding.UTF8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffer size used by CreateInstance(Stream).
|
||||||
|
/// </summary>
|
||||||
|
public static readonly int DefaultBufferSize = 4096;
|
||||||
|
|
||||||
|
private readonly bool leaveOpen;
|
||||||
|
private readonly byte[] buffer;
|
||||||
|
private readonly int limit;
|
||||||
|
private int position;
|
||||||
|
private readonly Stream output;
|
||||||
|
|
||||||
|
#region Construction
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new CodedOutputStream that writes directly to the given
|
||||||
|
/// byte array. If more bytes are written than fit in the array,
|
||||||
|
/// OutOfSpaceException will be thrown.
|
||||||
|
/// </summary>
|
||||||
|
public CodedOutputStream(byte[] flatArray) : this(flatArray, 0, flatArray.Length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new CodedOutputStream that writes directly to the given
|
||||||
|
/// byte array slice. If more bytes are written than fit in the array,
|
||||||
|
/// OutOfSpaceException will be thrown.
|
||||||
|
/// </summary>
|
||||||
|
private CodedOutputStream(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
this.output = null;
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.position = offset;
|
||||||
|
this.limit = offset + length;
|
||||||
|
leaveOpen = true; // Simple way of avoiding trying to dispose of a null reference
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodedOutputStream(Stream output, byte[] buffer, bool leaveOpen)
|
||||||
|
{
|
||||||
|
this.output = ProtoPreconditions.CheckNotNull(output, nameof(output));
|
||||||
|
this.buffer = buffer;
|
||||||
|
this.position = 0;
|
||||||
|
this.limit = buffer.Length;
|
||||||
|
this.leaveOpen = leaveOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="CodedOutputStream" /> which write to the given stream, and disposes of that
|
||||||
|
/// stream when the returned <c>CodedOutputStream</c> is disposed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
|
||||||
|
public CodedOutputStream(Stream output) : this(output, DefaultBufferSize, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new CodedOutputStream which write to the given stream and uses
|
||||||
|
/// the specified buffer size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">The stream to write to. It will be disposed when the returned <c>CodedOutputStream is disposed.</c></param>
|
||||||
|
/// <param name="bufferSize">The size of buffer to use internally.</param>
|
||||||
|
public CodedOutputStream(Stream output, int bufferSize) : this(output, new byte[bufferSize], false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new CodedOutputStream which write to the given stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">The stream to write to.</param>
|
||||||
|
/// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
|
||||||
|
/// if <c>false</c>, the provided stream is disposed as well.</param>
|
||||||
|
public CodedOutputStream(Stream output, bool leaveOpen) : this(output, DefaultBufferSize, leaveOpen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new CodedOutputStream which write to the given stream and uses
|
||||||
|
/// the specified buffer size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">The stream to write to.</param>
|
||||||
|
/// <param name="bufferSize">The size of buffer to use internally.</param>
|
||||||
|
/// <param name="leaveOpen">If <c>true</c>, <paramref name="output"/> is left open when the returned <c>CodedOutputStream</c> is disposed;
|
||||||
|
/// if <c>false</c>, the provided stream is disposed as well.</param>
|
||||||
|
public CodedOutputStream(Stream output, int bufferSize, bool leaveOpen) : this(output, new byte[bufferSize], leaveOpen)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the current position in the stream, or the position in the output buffer
|
||||||
|
/// </summary>
|
||||||
|
public long Position
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (output != null)
|
||||||
|
{
|
||||||
|
return output.Position + position;
|
||||||
|
}
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Writing of values (not including tags)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a double field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteDouble(double value)
|
||||||
|
{
|
||||||
|
WriteRawLittleEndian64((ulong)BitConverter.DoubleToInt64Bits(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a float field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteFloat(float value)
|
||||||
|
{
|
||||||
|
byte[] rawBytes = BitConverter.GetBytes(value);
|
||||||
|
if (!BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
ByteArray.Reverse(rawBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit - position >= 4)
|
||||||
|
{
|
||||||
|
buffer[position++] = rawBytes[0];
|
||||||
|
buffer[position++] = rawBytes[1];
|
||||||
|
buffer[position++] = rawBytes[2];
|
||||||
|
buffer[position++] = rawBytes[3];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteRawBytes(rawBytes, 0, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a uint64 field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteUInt64(ulong value)
|
||||||
|
{
|
||||||
|
WriteRawVarint64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an int64 field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteInt64(long value)
|
||||||
|
{
|
||||||
|
WriteRawVarint64((ulong) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an int32 field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteInt32(int value)
|
||||||
|
{
|
||||||
|
if (value >= 0)
|
||||||
|
{
|
||||||
|
WriteRawVarint32((uint) value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Must sign-extend.
|
||||||
|
WriteRawVarint64((ulong) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a fixed64 field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteFixed64(ulong value)
|
||||||
|
{
|
||||||
|
WriteRawLittleEndian64(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a fixed32 field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteFixed32(uint value)
|
||||||
|
{
|
||||||
|
WriteRawLittleEndian32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a bool field value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteBool(bool value)
|
||||||
|
{
|
||||||
|
WriteRawByte(value ? (byte) 1 : (byte) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a string field value, without a tag, to the stream.
|
||||||
|
/// The data is length-prefixed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteString(string value)
|
||||||
|
{
|
||||||
|
// Optimise the case where we have enough space to write
|
||||||
|
// the string directly to the buffer, which should be common.
|
||||||
|
int length = Utf8Encoding.GetByteCount(value);
|
||||||
|
WriteLength(length);
|
||||||
|
if (limit - position >= length)
|
||||||
|
{
|
||||||
|
if (length == value.Length) // Must be all ASCII...
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
buffer[position + i] = (byte)value[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Utf8Encoding.GetBytes(value, 0, value.Length, buffer, position);
|
||||||
|
}
|
||||||
|
position += length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] bytes = Utf8Encoding.GetBytes(value);
|
||||||
|
WriteRawBytes(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a message, without a tag, to the stream.
|
||||||
|
/// The data is length-prefixed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteMessage(IMessage value)
|
||||||
|
{
|
||||||
|
WriteLength(value.CalculateSize());
|
||||||
|
value.WriteTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write a byte string, without a tag, to the stream.
|
||||||
|
/// The data is length-prefixed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteBytes(ByteString value)
|
||||||
|
{
|
||||||
|
WriteLength(value.Length);
|
||||||
|
value.WriteRawBytesTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a uint32 value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteUInt32(uint value)
|
||||||
|
{
|
||||||
|
WriteRawVarint32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an enum value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteEnum(int value)
|
||||||
|
{
|
||||||
|
WriteInt32(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an sfixed32 value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write.</param>
|
||||||
|
public void WriteSFixed32(int value)
|
||||||
|
{
|
||||||
|
WriteRawLittleEndian32((uint) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an sfixed64 value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteSFixed64(long value)
|
||||||
|
{
|
||||||
|
WriteRawLittleEndian64((ulong) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an sint32 value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteSInt32(int value)
|
||||||
|
{
|
||||||
|
WriteRawVarint32(EncodeZigZag32(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an sint64 value, without a tag, to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write</param>
|
||||||
|
public void WriteSInt64(long value)
|
||||||
|
{
|
||||||
|
WriteRawVarint64(EncodeZigZag64(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a length (in bytes) for length-delimited data.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method simply writes a rawint, but exists for clarity in calling code.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="length">Length value, in bytes.</param>
|
||||||
|
public void WriteLength(int length)
|
||||||
|
{
|
||||||
|
WriteRawVarint32((uint) length);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Raw tag writing
|
||||||
|
/// <summary>
|
||||||
|
/// Encodes and writes a tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fieldNumber">The number of the field to write the tag for</param>
|
||||||
|
/// <param name="type">The wire format type of the tag to write</param>
|
||||||
|
public void WriteTag(int fieldNumber, WireFormat.WireType type)
|
||||||
|
{
|
||||||
|
WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes an already-encoded tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The encoded tag</param>
|
||||||
|
public void WriteTag(uint tag)
|
||||||
|
{
|
||||||
|
WriteRawVarint32(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given single-byte tag directly to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="b1">The encoded tag</param>
|
||||||
|
public void WriteRawTag(byte b1)
|
||||||
|
{
|
||||||
|
WriteRawByte(b1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given two-byte tag directly to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="b1">The first byte of the encoded tag</param>
|
||||||
|
/// <param name="b2">The second byte of the encoded tag</param>
|
||||||
|
public void WriteRawTag(byte b1, byte b2)
|
||||||
|
{
|
||||||
|
WriteRawByte(b1);
|
||||||
|
WriteRawByte(b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given three-byte tag directly to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="b1">The first byte of the encoded tag</param>
|
||||||
|
/// <param name="b2">The second byte of the encoded tag</param>
|
||||||
|
/// <param name="b3">The third byte of the encoded tag</param>
|
||||||
|
public void WriteRawTag(byte b1, byte b2, byte b3)
|
||||||
|
{
|
||||||
|
WriteRawByte(b1);
|
||||||
|
WriteRawByte(b2);
|
||||||
|
WriteRawByte(b3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given four-byte tag directly to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="b1">The first byte of the encoded tag</param>
|
||||||
|
/// <param name="b2">The second byte of the encoded tag</param>
|
||||||
|
/// <param name="b3">The third byte of the encoded tag</param>
|
||||||
|
/// <param name="b4">The fourth byte of the encoded tag</param>
|
||||||
|
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4)
|
||||||
|
{
|
||||||
|
WriteRawByte(b1);
|
||||||
|
WriteRawByte(b2);
|
||||||
|
WriteRawByte(b3);
|
||||||
|
WriteRawByte(b4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given five-byte tag directly to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="b1">The first byte of the encoded tag</param>
|
||||||
|
/// <param name="b2">The second byte of the encoded tag</param>
|
||||||
|
/// <param name="b3">The third byte of the encoded tag</param>
|
||||||
|
/// <param name="b4">The fourth byte of the encoded tag</param>
|
||||||
|
/// <param name="b5">The fifth byte of the encoded tag</param>
|
||||||
|
public void WriteRawTag(byte b1, byte b2, byte b3, byte b4, byte b5)
|
||||||
|
{
|
||||||
|
WriteRawByte(b1);
|
||||||
|
WriteRawByte(b2);
|
||||||
|
WriteRawByte(b3);
|
||||||
|
WriteRawByte(b4);
|
||||||
|
WriteRawByte(b5);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Underlying writing primitives
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a 32 bit value as a varint. The fast route is taken when
|
||||||
|
/// there's enough buffer space left to whizz through without checking
|
||||||
|
/// for each byte; otherwise, we resort to calling WriteRawByte each time.
|
||||||
|
/// </summary>
|
||||||
|
internal void WriteRawVarint32(uint value)
|
||||||
|
{
|
||||||
|
// Optimize for the common case of a single byte value
|
||||||
|
if (value < 128 && position < limit)
|
||||||
|
{
|
||||||
|
buffer[position++] = (byte)value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (value > 127 && position < limit)
|
||||||
|
{
|
||||||
|
buffer[position++] = (byte) ((value & 0x7F) | 0x80);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
while (value > 127)
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) ((value & 0x7F) | 0x80));
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
if (position < limit)
|
||||||
|
{
|
||||||
|
buffer[position++] = (byte) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteRawVarint64(ulong value)
|
||||||
|
{
|
||||||
|
while (value > 127 && position < limit)
|
||||||
|
{
|
||||||
|
buffer[position++] = (byte) ((value & 0x7F) | 0x80);
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
while (value > 127)
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) ((value & 0x7F) | 0x80));
|
||||||
|
value >>= 7;
|
||||||
|
}
|
||||||
|
if (position < limit)
|
||||||
|
{
|
||||||
|
buffer[position++] = (byte) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteRawLittleEndian32(uint value)
|
||||||
|
{
|
||||||
|
if (position + 4 > limit)
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) value);
|
||||||
|
WriteRawByte((byte) (value >> 8));
|
||||||
|
WriteRawByte((byte) (value >> 16));
|
||||||
|
WriteRawByte((byte) (value >> 24));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer[position++] = ((byte) value);
|
||||||
|
buffer[position++] = ((byte) (value >> 8));
|
||||||
|
buffer[position++] = ((byte) (value >> 16));
|
||||||
|
buffer[position++] = ((byte) (value >> 24));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteRawLittleEndian64(ulong value)
|
||||||
|
{
|
||||||
|
if (position + 8 > limit)
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) value);
|
||||||
|
WriteRawByte((byte) (value >> 8));
|
||||||
|
WriteRawByte((byte) (value >> 16));
|
||||||
|
WriteRawByte((byte) (value >> 24));
|
||||||
|
WriteRawByte((byte) (value >> 32));
|
||||||
|
WriteRawByte((byte) (value >> 40));
|
||||||
|
WriteRawByte((byte) (value >> 48));
|
||||||
|
WriteRawByte((byte) (value >> 56));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer[position++] = ((byte) value);
|
||||||
|
buffer[position++] = ((byte) (value >> 8));
|
||||||
|
buffer[position++] = ((byte) (value >> 16));
|
||||||
|
buffer[position++] = ((byte) (value >> 24));
|
||||||
|
buffer[position++] = ((byte) (value >> 32));
|
||||||
|
buffer[position++] = ((byte) (value >> 40));
|
||||||
|
buffer[position++] = ((byte) (value >> 48));
|
||||||
|
buffer[position++] = ((byte) (value >> 56));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteRawByte(byte value)
|
||||||
|
{
|
||||||
|
if (position == limit)
|
||||||
|
{
|
||||||
|
RefreshBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[position++] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteRawByte(uint value)
|
||||||
|
{
|
||||||
|
WriteRawByte((byte) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes out an array of bytes.
|
||||||
|
/// </summary>
|
||||||
|
internal void WriteRawBytes(byte[] value)
|
||||||
|
{
|
||||||
|
WriteRawBytes(value, 0, value.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes out part of an array of bytes.
|
||||||
|
/// </summary>
|
||||||
|
internal void WriteRawBytes(byte[] value, int offset, int length)
|
||||||
|
{
|
||||||
|
if (limit - position >= length)
|
||||||
|
{
|
||||||
|
ByteArray.Copy(value, offset, buffer, position, length);
|
||||||
|
// We have room in the current buffer.
|
||||||
|
position += length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write extends past current buffer. Fill the rest of this buffer and
|
||||||
|
// flush.
|
||||||
|
int bytesWritten = limit - position;
|
||||||
|
ByteArray.Copy(value, offset, buffer, position, bytesWritten);
|
||||||
|
offset += bytesWritten;
|
||||||
|
length -= bytesWritten;
|
||||||
|
position = limit;
|
||||||
|
RefreshBuffer();
|
||||||
|
|
||||||
|
// Now deal with the rest.
|
||||||
|
// Since we have an output stream, this is our buffer
|
||||||
|
// and buffer offset == 0
|
||||||
|
if (length <= limit)
|
||||||
|
{
|
||||||
|
// Fits in new buffer.
|
||||||
|
ByteArray.Copy(value, offset, buffer, 0, length);
|
||||||
|
position = length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write is very big. Let's do it all at once.
|
||||||
|
output.Write(value, offset, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encode a 32-bit value with ZigZag encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// ZigZag encodes signed integers into values that can be efficiently
|
||||||
|
/// encoded with varint. (Otherwise, negative values must be
|
||||||
|
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||||
|
/// 10 bytes on the wire.)
|
||||||
|
/// </remarks>
|
||||||
|
internal static uint EncodeZigZag32(int n)
|
||||||
|
{
|
||||||
|
// Note: the right-shift must be arithmetic
|
||||||
|
return (uint) ((n << 1) ^ (n >> 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encode a 64-bit value with ZigZag encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// ZigZag encodes signed integers into values that can be efficiently
|
||||||
|
/// encoded with varint. (Otherwise, negative values must be
|
||||||
|
/// sign-extended to 64 bits to be varint encoded, thus always taking
|
||||||
|
/// 10 bytes on the wire.)
|
||||||
|
/// </remarks>
|
||||||
|
internal static ulong EncodeZigZag64(long n)
|
||||||
|
{
|
||||||
|
return (ulong) ((n << 1) ^ (n >> 63));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshBuffer()
|
||||||
|
{
|
||||||
|
if (output == null)
|
||||||
|
{
|
||||||
|
// We're writing to a single buffer.
|
||||||
|
throw new OutOfSpaceException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we have an output stream, this is our buffer
|
||||||
|
// and buffer offset == 0
|
||||||
|
output.Write(buffer, 0, position);
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that a CodedOutputStream wrapping a flat byte array
|
||||||
|
/// ran out of space.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class OutOfSpaceException : IOException
|
||||||
|
{
|
||||||
|
internal OutOfSpaceException()
|
||||||
|
: base("CodedOutputStream was writing to a flat byte array and ran out of space.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes any buffered data and optionally closes the underlying stream, if any.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// By default, any underlying stream is closed by this method. To configure this behaviour,
|
||||||
|
/// use a constructor overload with a <c>leaveOpen</c> parameter. If this instance does not
|
||||||
|
/// have an underlying stream, this method does nothing.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For the sake of efficiency, calling this method does not prevent future write calls - but
|
||||||
|
/// if a later write ends up writing to a stream which has been disposed, that is likely to
|
||||||
|
/// fail. It is recommend that you not call any other methods after this.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
if (!leaveOpen)
|
||||||
|
{
|
||||||
|
output.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes any buffered data to the underlying stream (if there is one).
|
||||||
|
/// </summary>
|
||||||
|
public void Flush()
|
||||||
|
{
|
||||||
|
if (output != null)
|
||||||
|
{
|
||||||
|
RefreshBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies that SpaceLeft returns zero. It's common to create a byte array
|
||||||
|
/// that is exactly big enough to hold a message, then write to it with
|
||||||
|
/// a CodedOutputStream. Calling CheckNoSpaceLeft after writing verifies that
|
||||||
|
/// the message was actually as big as expected, which can help bugs.
|
||||||
|
/// </summary>
|
||||||
|
public void CheckNoSpaceLeft()
|
||||||
|
{
|
||||||
|
if (SpaceLeft != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Did not write as much data as expected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If writing to a flat array, returns the space left in the array. Otherwise,
|
||||||
|
/// throws an InvalidOperationException.
|
||||||
|
/// </summary>
|
||||||
|
public int SpaceLeft
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (output == null)
|
||||||
|
{
|
||||||
|
return limit - position;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"SpaceLeft can only be called on CodedOutputStreams that are " +
|
||||||
|
"writing to a flat array.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,770 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using Google.Protobuf.Reflection;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Collections
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Representation of a map field in a Protocol Buffer message.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
|
||||||
|
/// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Null values are not permitted in the map, either for wrapper types or regular messages.
|
||||||
|
/// If a map is deserialized from a data stream and the value is missing from an entry, a default value
|
||||||
|
/// is created instead. For primitive types, that is the regular default value (0, the empty string and so
|
||||||
|
/// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
|
||||||
|
/// encoded value for the field.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This implementation does not generally prohibit the use of key/value types which are not
|
||||||
|
/// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
|
||||||
|
/// that all operations will work in such cases.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The order in which entries are returned when iterating over this object is undefined, and may change
|
||||||
|
/// in future versions.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
|
||||||
|
#if !NET35
|
||||||
|
, IReadOnlyDictionary<TKey, TValue>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
|
||||||
|
private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
|
||||||
|
new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
|
||||||
|
private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a deep clone of this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A deep clone of this object.
|
||||||
|
/// </returns>
|
||||||
|
public MapField<TKey, TValue> Clone()
|
||||||
|
{
|
||||||
|
var clone = new MapField<TKey, TValue>();
|
||||||
|
// Keys are never cloneable. Values might be.
|
||||||
|
if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
|
||||||
|
{
|
||||||
|
foreach (var pair in list)
|
||||||
|
{
|
||||||
|
clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Nothing is cloneable, so we don't need to worry.
|
||||||
|
clone.Add(this);
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified key/value pair to the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="key">The key to add</param>
|
||||||
|
/// <param name="value">The value to add.</param>
|
||||||
|
/// <exception cref="System.ArgumentException">The given key already exists in map.</exception>
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
// Validation of arguments happens in ContainsKey and the indexer
|
||||||
|
if (ContainsKey(key))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Key already exists in map", nameof(key));
|
||||||
|
}
|
||||||
|
this[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified key is present in the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key to check.</param>
|
||||||
|
/// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
|
||||||
|
public bool ContainsKey(TKey key)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
|
||||||
|
return map.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainsValue(TValue value)
|
||||||
|
{
|
||||||
|
var comparer = EqualityComparer<TValue>.Default;
|
||||||
|
return list.Any(pair => comparer.Equals(pair.Value, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the entry identified by the given key from the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key indicating the entry to remove from the map.</param>
|
||||||
|
/// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
|
||||||
|
public bool Remove(TKey key)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
|
||||||
|
LinkedListNode<KeyValuePair<TKey, TValue>> node;
|
||||||
|
if (map.TryGetValue(key, out node))
|
||||||
|
{
|
||||||
|
map.Remove(key);
|
||||||
|
node.List.Remove(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value associated with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key whose value to get.</param>
|
||||||
|
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found;
|
||||||
|
/// otherwise, the default value for the type of the <paramref name="value"/> parameter.
|
||||||
|
/// This parameter is passed uninitialized.</param>
|
||||||
|
/// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
|
||||||
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
|
{
|
||||||
|
LinkedListNode<KeyValuePair<TKey, TValue>> node;
|
||||||
|
if (map.TryGetValue(key, out node))
|
||||||
|
{
|
||||||
|
value = node.Value.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = default(TValue);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value associated with the specified key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">The key of the value to get or set.</param>
|
||||||
|
/// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
|
||||||
|
/// <returns>The value associated with the specified key. If the specified key is not found,
|
||||||
|
/// a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
|
||||||
|
TValue value;
|
||||||
|
if (TryGetValue(key, out value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
|
||||||
|
// value == null check here is redundant, but avoids boxing.
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
|
||||||
|
}
|
||||||
|
LinkedListNode<KeyValuePair<TKey, TValue>> node;
|
||||||
|
var pair = new KeyValuePair<TKey, TValue>(key, value);
|
||||||
|
if (map.TryGetValue(key, out node))
|
||||||
|
{
|
||||||
|
node.Value = pair;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = list.AddLast(pair);
|
||||||
|
map[key] = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a collection containing the keys in the map.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a collection containing the values in the map.
|
||||||
|
/// </summary>
|
||||||
|
public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified entries to the map. The keys and values are not automatically cloned.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="entries">The entries to add to the map.</param>
|
||||||
|
public void Add(IDictionary<TKey, TValue> entries)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(entries, nameof(entries));
|
||||||
|
foreach (var pair in entries)
|
||||||
|
{
|
||||||
|
Add(pair.Key, pair.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates through the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// An enumerator that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return list.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates through a collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified item to the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to add to the map.</param>
|
||||||
|
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
Add(item.Key, item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all items from the map.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
list.Clear();
|
||||||
|
map.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether map contains an entry equivalent to the given key/value pair.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The key/value pair to find.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
TValue value;
|
||||||
|
return TryGetValue(item.Key, out value)
|
||||||
|
&& EqualityComparer<TValue>.Default.Equals(item.Value, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the key/value pairs in this map to an array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">The array to copy the entries into.</param>
|
||||||
|
/// <param name="arrayIndex">The index of the array at which to start copying values.</param>
|
||||||
|
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
list.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the specified key/value pair from the map.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Both the key and the value must be found for the entry to be removed.</remarks>
|
||||||
|
/// <param name="item">The key/value pair to remove.</param>
|
||||||
|
/// <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>
|
||||||
|
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
if (item.Key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Key is null", nameof(item));
|
||||||
|
}
|
||||||
|
LinkedListNode<KeyValuePair<TKey, TValue>> node;
|
||||||
|
if (map.TryGetValue(item.Key, out node) &&
|
||||||
|
EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))
|
||||||
|
{
|
||||||
|
map.Remove(item.Key);
|
||||||
|
node.List.Remove(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of elements contained in the map.
|
||||||
|
/// </summary>
|
||||||
|
public int Count { get { return list.Count; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the map is read-only.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly { get { return false; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool Equals(object other)
|
||||||
|
{
|
||||||
|
return Equals(other as MapField<TKey, TValue>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||||
|
/// </returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
var valueComparer = EqualityComparer<TValue>.Default;
|
||||||
|
int hash = 0;
|
||||||
|
foreach (var pair in list)
|
||||||
|
{
|
||||||
|
hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value);
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this map with another for equality.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The order of the key/value pairs in the maps is not deemed significant in this comparison.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="other">The map to compare this with.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
|
||||||
|
public bool Equals(MapField<TKey, TValue> other)
|
||||||
|
{
|
||||||
|
if (other == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (other == this)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (other.Count != this.Count)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var valueComparer = EqualityComparer<TValue>.Default;
|
||||||
|
foreach (var pair in this)
|
||||||
|
{
|
||||||
|
TValue value;
|
||||||
|
if (!other.TryGetValue(pair.Key, out value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!valueComparer.Equals(value, pair.Value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds entries to the map from the given stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// It is assumed that the stream is initially positioned after the tag specified by the codec.
|
||||||
|
/// This method will continue reading entries from the stream until the end is reached, or
|
||||||
|
/// a different tag is encountered.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="input">Stream to read from</param>
|
||||||
|
/// <param name="codec">Codec describing how the key/value pairs are encoded</param>
|
||||||
|
public void AddEntriesFrom(CodedInputStream input, Codec codec)
|
||||||
|
{
|
||||||
|
var adapter = new Codec.MessageAdapter(codec);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
adapter.Reset();
|
||||||
|
input.ReadMessage(adapter);
|
||||||
|
this[adapter.Key] = adapter.Value;
|
||||||
|
} while (input.MaybeConsumeTag(codec.MapTag));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the contents of this map to the given coded output stream, using the specified codec
|
||||||
|
/// to encode each entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">The output stream to write to.</param>
|
||||||
|
/// <param name="codec">The codec to use for each entry.</param>
|
||||||
|
public void WriteTo(CodedOutputStream output, Codec codec)
|
||||||
|
{
|
||||||
|
var message = new Codec.MessageAdapter(codec);
|
||||||
|
foreach (var entry in list)
|
||||||
|
{
|
||||||
|
message.Key = entry.Key;
|
||||||
|
message.Value = entry.Value;
|
||||||
|
output.WriteTag(codec.MapTag);
|
||||||
|
output.WriteMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the size of this map based on the given entry codec.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codec">The codec to use to encode each entry.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int CalculateSize(Codec codec)
|
||||||
|
{
|
||||||
|
if (Count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
var message = new Codec.MessageAdapter(codec);
|
||||||
|
int size = 0;
|
||||||
|
foreach (var entry in list)
|
||||||
|
{
|
||||||
|
message.Key = entry.Key;
|
||||||
|
message.Value = entry.Value;
|
||||||
|
size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
|
||||||
|
size += CodedOutputStream.ComputeMessageSize(message);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this repeated field, in the same
|
||||||
|
/// way as it would be represented by the default JSON formatter.
|
||||||
|
/// </summary>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var writer = new StringWriter();
|
||||||
|
JsonFormatter.Default.WriteDictionary(writer, this);
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDictionary explicit interface implementation
|
||||||
|
void IDictionary.Add(object key, object value)
|
||||||
|
{
|
||||||
|
Add((TKey)key, (TValue)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IDictionary.Contains(object key)
|
||||||
|
{
|
||||||
|
if (!(key is TKey))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ContainsKey((TKey)key);
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionaryEnumerator IDictionary.GetEnumerator()
|
||||||
|
{
|
||||||
|
return new DictionaryEnumerator(GetEnumerator());
|
||||||
|
}
|
||||||
|
|
||||||
|
void IDictionary.Remove(object key)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(key, nameof(key));
|
||||||
|
if (!(key is TKey))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Remove((TKey)key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection.CopyTo(Array array, int index)
|
||||||
|
{
|
||||||
|
// This is ugly and slow as heck, but with any luck it will never be used anyway.
|
||||||
|
ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
|
||||||
|
temp.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IDictionary.IsFixedSize { get { return false; } }
|
||||||
|
|
||||||
|
ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
|
||||||
|
|
||||||
|
ICollection IDictionary.Values { get { return (ICollection)Values; } }
|
||||||
|
|
||||||
|
bool ICollection.IsSynchronized { get { return false; } }
|
||||||
|
|
||||||
|
object ICollection.SyncRoot { get { return this; } }
|
||||||
|
|
||||||
|
object IDictionary.this[object key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(key, nameof(key));
|
||||||
|
if (!(key is TKey))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
TValue value;
|
||||||
|
TryGetValue((TKey)key, out value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this[(TKey)key] = (TValue)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IReadOnlyDictionary explicit interface implementation
|
||||||
|
#if !NET35
|
||||||
|
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
|
||||||
|
|
||||||
|
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
|
||||||
|
#endif
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private class DictionaryEnumerator : IDictionaryEnumerator
|
||||||
|
{
|
||||||
|
private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
|
||||||
|
|
||||||
|
internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
|
||||||
|
{
|
||||||
|
this.enumerator = enumerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
return enumerator.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
enumerator.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Current { get { return Entry; } }
|
||||||
|
public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
|
||||||
|
public object Key { get { return enumerator.Current.Key; } }
|
||||||
|
public object Value { get { return enumerator.Current.Value; } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A codec for a specific map field. This contains all the information required to encode and
|
||||||
|
/// decode the nested messages.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class Codec
|
||||||
|
{
|
||||||
|
private readonly FieldCodec<TKey> keyCodec;
|
||||||
|
private readonly FieldCodec<TValue> valueCodec;
|
||||||
|
private readonly uint mapTag;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new entry codec based on a separate key codec and value codec,
|
||||||
|
/// and the tag to use for each map entry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keyCodec">The key codec.</param>
|
||||||
|
/// <param name="valueCodec">The value codec.</param>
|
||||||
|
/// <param name="mapTag">The map tag to use to introduce each map entry.</param>
|
||||||
|
public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)
|
||||||
|
{
|
||||||
|
this.keyCodec = keyCodec;
|
||||||
|
this.valueCodec = valueCodec;
|
||||||
|
this.mapTag = mapTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tag used in the enclosing message to indicate map entries.
|
||||||
|
/// </summary>
|
||||||
|
internal uint MapTag { get { return mapTag; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A mutable message class, used for parsing and serializing. This
|
||||||
|
/// delegates the work to a codec, but implements the <see cref="IMessage"/> interface
|
||||||
|
/// for interop with <see cref="CodedInputStream"/> and <see cref="CodedOutputStream"/>.
|
||||||
|
/// This is nested inside Codec as it's tightly coupled to the associated codec,
|
||||||
|
/// and it's simpler if it has direct access to all its fields.
|
||||||
|
/// </summary>
|
||||||
|
internal class MessageAdapter : IMessage
|
||||||
|
{
|
||||||
|
private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
|
||||||
|
|
||||||
|
private readonly Codec codec;
|
||||||
|
internal TKey Key { get; set; }
|
||||||
|
internal TValue Value { get; set; }
|
||||||
|
|
||||||
|
internal MessageAdapter(Codec codec)
|
||||||
|
{
|
||||||
|
this.codec = codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Reset()
|
||||||
|
{
|
||||||
|
Key = codec.keyCodec.DefaultValue;
|
||||||
|
Value = codec.valueCodec.DefaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void MergeFrom(CodedInputStream input)
|
||||||
|
{
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0)
|
||||||
|
{
|
||||||
|
if (tag == codec.keyCodec.Tag)
|
||||||
|
{
|
||||||
|
Key = codec.keyCodec.Read(input);
|
||||||
|
}
|
||||||
|
else if (tag == codec.valueCodec.Tag)
|
||||||
|
{
|
||||||
|
Value = codec.valueCodec.Read(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input.SkipLastField();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Corner case: a map entry with a key but no value, where the value type is a message.
|
||||||
|
// Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
|
||||||
|
if (Value == null)
|
||||||
|
{
|
||||||
|
Value = codec.valueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTo(CodedOutputStream output)
|
||||||
|
{
|
||||||
|
codec.keyCodec.WriteTagAndValue(output, Key);
|
||||||
|
codec.valueCodec.WriteTagAndValue(output, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CalculateSize()
|
||||||
|
{
|
||||||
|
return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageDescriptor IMessage.Descriptor { get { return null; } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MapView<T> : ICollection<T>, ICollection
|
||||||
|
{
|
||||||
|
private readonly MapField<TKey, TValue> parent;
|
||||||
|
private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
|
||||||
|
private readonly Func<T, bool> containsCheck;
|
||||||
|
|
||||||
|
internal MapView(
|
||||||
|
MapField<TKey, TValue> parent,
|
||||||
|
Func<KeyValuePair<TKey, TValue>, T> projection,
|
||||||
|
Func<T, bool> containsCheck)
|
||||||
|
{
|
||||||
|
this.parent = parent;
|
||||||
|
this.projection = projection;
|
||||||
|
this.containsCheck = containsCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count { get { return parent.Count; } }
|
||||||
|
|
||||||
|
public bool IsReadOnly { get { return true; } }
|
||||||
|
|
||||||
|
public bool IsSynchronized { get { return false; } }
|
||||||
|
|
||||||
|
public object SyncRoot { get { return parent; } }
|
||||||
|
|
||||||
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(T item)
|
||||||
|
{
|
||||||
|
return containsCheck(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
if (arrayIndex < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||||
|
}
|
||||||
|
if (arrayIndex + Count > array.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Not enough space in the array", nameof(array));
|
||||||
|
}
|
||||||
|
foreach (var item in this)
|
||||||
|
{
|
||||||
|
array[arrayIndex++] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return parent.list.Select(projection).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(T item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(Array array, int index)
|
||||||
|
{
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
if (index + Count > array.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Not enough space in the array", nameof(array));
|
||||||
|
}
|
||||||
|
foreach (var item in this)
|
||||||
|
{
|
||||||
|
array.SetValue(item, index++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Collections
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Read-only wrapper around another dictionary.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
|
||||||
|
{
|
||||||
|
private readonly IDictionary<TKey, TValue> wrapped;
|
||||||
|
|
||||||
|
public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped)
|
||||||
|
{
|
||||||
|
this.wrapped = wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ContainsKey(TKey key)
|
||||||
|
{
|
||||||
|
return wrapped.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<TKey> Keys
|
||||||
|
{
|
||||||
|
get { return wrapped.Keys; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(TKey key)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetValue(TKey key, out TValue value)
|
||||||
|
{
|
||||||
|
return wrapped.TryGetValue(key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICollection<TValue> Values
|
||||||
|
{
|
||||||
|
get { return wrapped.Values; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TValue this[TKey key]
|
||||||
|
{
|
||||||
|
get { return wrapped[key]; }
|
||||||
|
set { throw new InvalidOperationException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
return wrapped.Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
wrapped.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get { return wrapped.Count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||||
|
{
|
||||||
|
return wrapped.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable) wrapped).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return wrapped.Equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return wrapped.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return wrapped.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,594 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Collections
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The contents of a repeated field: essentially, a collection with some extra
|
||||||
|
/// restrictions (no null values) and capabilities (deep cloning).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This implementation does not generally prohibit the use of types which are not
|
||||||
|
/// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The element type of the repeated field.</typeparam>
|
||||||
|
public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>
|
||||||
|
#if !NET35
|
||||||
|
, IReadOnlyList<T>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
private static readonly T[] EmptyArray = new T[0];
|
||||||
|
private const int MinArraySize = 8;
|
||||||
|
|
||||||
|
private T[] array = EmptyArray;
|
||||||
|
private int count = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a deep clone of this repeated field.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the field type is
|
||||||
|
/// a message type, each element is also cloned; otherwise, it is
|
||||||
|
/// assumed that the field type is primitive (including string and
|
||||||
|
/// bytes, both of which are immutable) and so a simple copy is
|
||||||
|
/// equivalent to a deep clone.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>A deep clone of this repeated field.</returns>
|
||||||
|
public RepeatedField<T> Clone()
|
||||||
|
{
|
||||||
|
RepeatedField<T> clone = new RepeatedField<T>();
|
||||||
|
if (array != EmptyArray)
|
||||||
|
{
|
||||||
|
clone.array = (T[])array.Clone();
|
||||||
|
IDeepCloneable<T>[] cloneableArray = clone.array as IDeepCloneable<T>[];
|
||||||
|
if (cloneableArray != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
clone.array[i] = cloneableArray[i].Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clone.count = count;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the entries from the given input stream, decoding them with the specified codec.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input stream to read from.</param>
|
||||||
|
/// <param name="codec">The codec to use in order to read each entry.</param>
|
||||||
|
public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
// TODO: Inline some of the Add code, so we can avoid checking the size on every
|
||||||
|
// iteration.
|
||||||
|
uint tag = input.LastTag;
|
||||||
|
var reader = codec.ValueReader;
|
||||||
|
// Non-nullable value types can be packed or not.
|
||||||
|
if (FieldCodec<T>.IsPackedRepeatedField(tag))
|
||||||
|
{
|
||||||
|
int length = input.ReadLength();
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
int oldLimit = input.PushLimit(length);
|
||||||
|
while (!input.ReachedLimit)
|
||||||
|
{
|
||||||
|
Add(reader(input));
|
||||||
|
}
|
||||||
|
input.PopLimit(oldLimit);
|
||||||
|
}
|
||||||
|
// Empty packed field. Odd, but valid - just ignore.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not packed... (possibly not packable)
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Add(reader(input));
|
||||||
|
} while (input.MaybeConsumeTag(tag));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the size of this collection based on the given codec.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="codec">The codec to use when encoding each field.</param>
|
||||||
|
/// <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
|
||||||
|
/// using the same codec.</returns>
|
||||||
|
public int CalculateSize(FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint tag = codec.Tag;
|
||||||
|
if (codec.PackedRepeatedField)
|
||||||
|
{
|
||||||
|
int dataSize = CalculatePackedDataSize(codec);
|
||||||
|
return CodedOutputStream.ComputeRawVarint32Size(tag) +
|
||||||
|
CodedOutputStream.ComputeLengthSize(dataSize) +
|
||||||
|
dataSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var sizeCalculator = codec.ValueSizeCalculator;
|
||||||
|
int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
size += sizeCalculator(array[i]);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CalculatePackedDataSize(FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
int fixedSize = codec.FixedSize;
|
||||||
|
if (fixedSize == 0)
|
||||||
|
{
|
||||||
|
var calculator = codec.ValueSizeCalculator;
|
||||||
|
int tmp = 0;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tmp += calculator(array[i]);
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return fixedSize * Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
|
||||||
|
/// encoding each value using the specified codec.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">The output stream to write to.</param>
|
||||||
|
/// <param name="codec">The codec to use when encoding each value.</param>
|
||||||
|
public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var writer = codec.ValueWriter;
|
||||||
|
var tag = codec.Tag;
|
||||||
|
if (codec.PackedRepeatedField)
|
||||||
|
{
|
||||||
|
// Packed primitive type
|
||||||
|
uint size = (uint)CalculatePackedDataSize(codec);
|
||||||
|
output.WriteTag(tag);
|
||||||
|
output.WriteRawVarint32(size);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
writer(output, array[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Not packed: a simple tag/value pair for each value.
|
||||||
|
// Can't use codec.WriteTagAndValue, as that omits default values.
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
output.WriteTag(tag);
|
||||||
|
writer(output, array[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureSize(int size)
|
||||||
|
{
|
||||||
|
if (array.Length < size)
|
||||||
|
{
|
||||||
|
size = Math.Max(size, MinArraySize);
|
||||||
|
int newSize = Math.Max(array.Length * 2, size);
|
||||||
|
var tmp = new T[newSize];
|
||||||
|
Array.Copy(array, 0, tmp, 0, array.Length);
|
||||||
|
array = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified item to the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to add.</param>
|
||||||
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
|
||||||
|
EnsureSize(count + 1);
|
||||||
|
array[count++] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes all items from the collection.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
array = EmptyArray;
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether this collection contains the given item.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to find.</param>
|
||||||
|
/// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
|
||||||
|
public bool Contains(T item)
|
||||||
|
{
|
||||||
|
return IndexOf(item) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies this collection to the given array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">The array to copy to.</param>
|
||||||
|
/// <param name="arrayIndex">The first index of the array to copy to.</param>
|
||||||
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
Array.Copy(this.array, 0, array, arrayIndex, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the specified item from the collection
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to remove.</param>
|
||||||
|
/// <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
|
||||||
|
public bool Remove(T item)
|
||||||
|
{
|
||||||
|
int index = IndexOf(item);
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Array.Copy(array, index + 1, array, index, count - index - 1);
|
||||||
|
count--;
|
||||||
|
array[count] = default(T);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of elements contained in the collection.
|
||||||
|
/// </summary>
|
||||||
|
public int Count => count;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the collection is read-only.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds all of the specified values into this collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The values to add to this collection.</param>
|
||||||
|
public void AddRange(IEnumerable<T> values)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(values, nameof(values));
|
||||||
|
|
||||||
|
// Optimization 1: If the collection we're adding is already a RepeatedField<T>,
|
||||||
|
// we know the values are valid.
|
||||||
|
var otherRepeatedField = values as RepeatedField<T>;
|
||||||
|
if (otherRepeatedField != null)
|
||||||
|
{
|
||||||
|
EnsureSize(count + otherRepeatedField.count);
|
||||||
|
Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count);
|
||||||
|
count += otherRepeatedField.count;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimization 2: The collection is an ICollection, so we can expand
|
||||||
|
// just once and ask the collection to copy itself into the array.
|
||||||
|
var collection = values as ICollection;
|
||||||
|
if (collection != null)
|
||||||
|
{
|
||||||
|
var extraCount = collection.Count;
|
||||||
|
// For reference types and nullable value types, we need to check that there are no nulls
|
||||||
|
// present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
|
||||||
|
// We expect the JITter to optimize this test to true/false, so it's effectively conditional
|
||||||
|
// specialization.
|
||||||
|
if (default(T) == null)
|
||||||
|
{
|
||||||
|
// TODO: Measure whether iterating once to check and then letting the collection copy
|
||||||
|
// itself is faster or slower than iterating and adding as we go. For large
|
||||||
|
// collections this will not be great in terms of cache usage... but the optimized
|
||||||
|
// copy may be significantly faster than doing it one at a time.
|
||||||
|
foreach (var item in collection)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Sequence contained null element", nameof(values));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EnsureSize(count + extraCount);
|
||||||
|
collection.CopyTo(array, count);
|
||||||
|
count += extraCount;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We *could* check for ICollection<T> as well, but very very few collections implement
|
||||||
|
// ICollection<T> but not ICollection. (HashSet<T> does, for one...)
|
||||||
|
|
||||||
|
// Fall back to a slower path of adding items one at a time.
|
||||||
|
foreach (T item in values)
|
||||||
|
{
|
||||||
|
Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds all of the specified values into this collection. This method is present to
|
||||||
|
/// allow repeated fields to be constructed from queries within collection initializers.
|
||||||
|
/// Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
|
||||||
|
/// method instead for clarity.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="values">The values to add to this collection.</param>
|
||||||
|
public void Add(IEnumerable<T> values)
|
||||||
|
{
|
||||||
|
AddRange(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates through the collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// An enumerator that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
yield return array[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
|
||||||
|
/// </returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return Equals(obj as RepeatedField<T>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an enumerator that iterates through a collection.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
|
||||||
|
/// </returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a hash code for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||||
|
/// </returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hash = 0;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
hash = hash * 31 + array[i].GetHashCode();
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this repeated field with another for equality.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="other">The repeated field to compare this with.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
|
||||||
|
public bool Equals(RepeatedField<T> other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(other, null))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (other.Count != this.Count)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (!comparer.Equals(array[i], other.array[i]))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the index of the given item within the collection, or -1 if the item is not
|
||||||
|
/// present.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to find in the collection.</param>
|
||||||
|
/// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
|
||||||
|
public int IndexOf(T item)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
|
||||||
|
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (comparer.Equals(array[i], item))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inserts the given item at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index at which to insert the item.</param>
|
||||||
|
/// <param name="item">The item to insert.</param>
|
||||||
|
public void Insert(int index, T item)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
|
||||||
|
if (index < 0 || index > count)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
EnsureSize(count + 1);
|
||||||
|
Array.Copy(array, index, array, index + 1, count - index);
|
||||||
|
array[index] = item;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the item at the given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The zero-based index of the item to remove.</param>
|
||||||
|
public void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= count)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
Array.Copy(array, index + 1, array, index, count - index - 1);
|
||||||
|
count--;
|
||||||
|
array[count] = default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this repeated field, in the same
|
||||||
|
/// way as it would be represented by the default JSON formatter.
|
||||||
|
/// </summary>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
var writer = new StringWriter();
|
||||||
|
JsonFormatter.Default.WriteList(writer, this);
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the item at the specified index.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The element at the specified index.
|
||||||
|
/// </value>
|
||||||
|
/// <param name="index">The zero-based index of the element to get or set.</param>
|
||||||
|
/// <returns>The item at the specified index.</returns>
|
||||||
|
public T this[int index]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= count)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
return array[index];
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= count)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
|
||||||
|
array[index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Explicit interface implementation for IList and ICollection.
|
||||||
|
bool IList.IsFixedSize => false;
|
||||||
|
|
||||||
|
void ICollection.CopyTo(Array array, int index)
|
||||||
|
{
|
||||||
|
Array.Copy(this.array, 0, array, index, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICollection.IsSynchronized => false;
|
||||||
|
|
||||||
|
object ICollection.SyncRoot => this;
|
||||||
|
|
||||||
|
object IList.this[int index]
|
||||||
|
{
|
||||||
|
get { return this[index]; }
|
||||||
|
set { this[index] = (T)value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.Add(object value)
|
||||||
|
{
|
||||||
|
Add((T) value);
|
||||||
|
return count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IList.Contains(object value)
|
||||||
|
{
|
||||||
|
return (value is T && Contains((T)value));
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.IndexOf(object value)
|
||||||
|
{
|
||||||
|
if (!(value is T))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return IndexOf((T)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Insert(int index, object value)
|
||||||
|
{
|
||||||
|
Insert(index, (T) value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IList.Remove(object value)
|
||||||
|
{
|
||||||
|
if (!(value is T))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Remove((T)value);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Compatibility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="PropertyInfo"/>, effectively providing
|
||||||
|
/// the familiar members from previous desktop framework versions while
|
||||||
|
/// targeting the newer releases, .NET Core etc.
|
||||||
|
/// </summary>
|
||||||
|
internal static class PropertyInfoExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the public getter of a property, or null if there is no such getter
|
||||||
|
/// (either because it's read-only, or the getter isn't public).
|
||||||
|
/// </summary>
|
||||||
|
internal static MethodInfo GetGetMethod(this PropertyInfo target)
|
||||||
|
{
|
||||||
|
#if NET35
|
||||||
|
var method = target.GetGetMethod();
|
||||||
|
#else
|
||||||
|
var method = target.GetMethod;
|
||||||
|
#endif
|
||||||
|
return method != null && method.IsPublic ? method : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the public setter of a property, or null if there is no such setter
|
||||||
|
/// (either because it's write-only, or the setter isn't public).
|
||||||
|
/// </summary>
|
||||||
|
internal static MethodInfo GetSetMethod(this PropertyInfo target)
|
||||||
|
{
|
||||||
|
#if NET35
|
||||||
|
var method = target.GetSetMethod();
|
||||||
|
#else
|
||||||
|
var method = target.SetMethod;
|
||||||
|
#endif
|
||||||
|
return method != null && method.IsPublic ? method : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#if NET35
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Compatibility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="Stream"/> in order to provide
|
||||||
|
/// backwards compatibility with .NET 3.5
|
||||||
|
/// </summary>
|
||||||
|
public static class StreamExtensions
|
||||||
|
{
|
||||||
|
// 81920 seems to be the default buffer size used in .NET 4.5.1
|
||||||
|
private const int BUFFER_SIZE = 81920;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write the contents of the current stream to the destination stream
|
||||||
|
/// </summary>
|
||||||
|
public static void CopyTo(this Stream source, Stream destination)
|
||||||
|
{
|
||||||
|
if (destination == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
int numBytesRead;
|
||||||
|
while ((numBytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
|
||||||
|
destination.Write(buffer, 0, numBytesRead);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
#if !NET35
|
||||||
|
namespace Google.Protobuf.Compatibility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods on Type that just proxy to TypeInfo.
|
||||||
|
/// These are used to support the new type system from .NET 4.5, without
|
||||||
|
/// having calls to GetTypeInfo all over the place. While the methods here are meant to be
|
||||||
|
/// broadly compatible with the desktop framework, there are some subtle differences in behaviour - but
|
||||||
|
/// they're not expected to affect our use cases. While the class is internal, that should be fine: we can
|
||||||
|
/// evaluate each new use appropriately.
|
||||||
|
/// </summary>
|
||||||
|
internal static class TypeExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// See https://msdn.microsoft.com/en-us/library/system.type.isassignablefrom
|
||||||
|
/// </summary>
|
||||||
|
internal static bool IsAssignableFrom(this Type target, Type c)
|
||||||
|
{
|
||||||
|
return target.GetTypeInfo().IsAssignableFrom(c.GetTypeInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a representation of the public property associated with the given name in the given type,
|
||||||
|
/// including inherited properties or null if there is no such public property.
|
||||||
|
/// Here, "public property" means a property where either the getter, or the setter, or both, is public.
|
||||||
|
/// </summary>
|
||||||
|
internal static PropertyInfo GetProperty(this Type target, string name)
|
||||||
|
{
|
||||||
|
// GetDeclaredProperty only returns properties declared in the given type, so we need to recurse.
|
||||||
|
while (target != null)
|
||||||
|
{
|
||||||
|
var typeInfo = target.GetTypeInfo();
|
||||||
|
var ret = typeInfo.GetDeclaredProperty(name);
|
||||||
|
if (ret != null && ((ret.CanRead && ret.GetMethod.IsPublic) || (ret.CanWrite && ret.SetMethod.IsPublic)))
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
target = typeInfo.BaseType;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a representation of the public method associated with the given name in the given type,
|
||||||
|
/// including inherited methods.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This has a few differences compared with Type.GetMethod in the desktop framework. It will throw
|
||||||
|
/// if there is an ambiguous match even between a private method and a public one, but it *won't* throw
|
||||||
|
/// if there are two overloads at different levels in the type hierarchy (e.g. class Base declares public void Foo(int) and
|
||||||
|
/// class Child : Base declares public void Foo(long)).
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="AmbiguousMatchException">One type in the hierarchy declared more than one method with the same name</exception>
|
||||||
|
internal static MethodInfo GetMethod(this Type target, string name)
|
||||||
|
{
|
||||||
|
// GetDeclaredMethod only returns methods declared in the given type, so we need to recurse.
|
||||||
|
while (target != null)
|
||||||
|
{
|
||||||
|
var typeInfo = target.GetTypeInfo();
|
||||||
|
var ret = typeInfo.GetDeclaredMethod(name);
|
||||||
|
if (ret != null && ret.IsPublic)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
target = typeInfo.BaseType;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,473 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Factory methods for <see cref="FieldCodec{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class FieldCodec
|
||||||
|
{
|
||||||
|
// TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a string field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<string> ForString(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a bytes field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<ByteString> ForBytes(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a bool field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<bool> ForBool(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an int32 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<int> ForInt32(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an sint32 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<int> ForSInt32(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a fixed32 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<uint> ForFixed32(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), 4, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an sfixed32 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<int> ForSFixed32(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), 4, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a uint32 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<uint> ForUInt32(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an int64 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<long> ForInt64(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an sint64 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<long> ForSInt64(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a fixed64 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<ulong> ForFixed64(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an sfixed64 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<long> ForSFixed64(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a uint64 field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<ulong> ForUInt64(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a float field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<float> ForFloat(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a double field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<double> ForDouble(uint tag)
|
||||||
|
{
|
||||||
|
return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums are tricky. We can probably use expression trees to build these delegates automatically,
|
||||||
|
// but it's easy to generate the code for it.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for an enum field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
|
||||||
|
/// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
|
||||||
|
{
|
||||||
|
return new FieldCodec<T>(input => fromInt32(
|
||||||
|
input.ReadEnum()),
|
||||||
|
(output, value) => output.WriteEnum(toInt32(value)),
|
||||||
|
value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a codec suitable for a message field with the given tag.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tag">The tag.</param>
|
||||||
|
/// <param name="parser">A parser to use for the message type.</param>
|
||||||
|
/// <returns>A codec for the given tag.</returns>
|
||||||
|
public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : IMessage<T>
|
||||||
|
{
|
||||||
|
return new FieldCodec<T>(input => { T message = parser.CreateTemplate(); input.ReadMessage(message); return message; },
|
||||||
|
(output, value) => output.WriteMessage(value), message => CodedOutputStream.ComputeMessageSize(message), tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a codec for a wrapper type of a class - which must be string or ByteString.
|
||||||
|
/// </summary>
|
||||||
|
public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class
|
||||||
|
{
|
||||||
|
var nestedCodec = WrapperCodecs.GetCodec<T>();
|
||||||
|
return new FieldCodec<T>(
|
||||||
|
input => WrapperCodecs.Read<T>(input, nestedCodec),
|
||||||
|
(output, value) => WrapperCodecs.Write<T>(output, value, nestedCodec),
|
||||||
|
value => WrapperCodecs.CalculateSize<T>(value, nestedCodec),
|
||||||
|
tag,
|
||||||
|
null); // Default value for the wrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64,
|
||||||
|
/// Bool, Single or Double.
|
||||||
|
/// </summary>
|
||||||
|
public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : struct
|
||||||
|
{
|
||||||
|
var nestedCodec = WrapperCodecs.GetCodec<T>();
|
||||||
|
return new FieldCodec<T?>(
|
||||||
|
input => WrapperCodecs.Read<T>(input, nestedCodec),
|
||||||
|
(output, value) => WrapperCodecs.Write<T>(output, value.Value, nestedCodec),
|
||||||
|
value => value == null ? 0 : WrapperCodecs.CalculateSize<T>(value.Value, nestedCodec),
|
||||||
|
tag,
|
||||||
|
null); // Default value for the wrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Helper code to create codecs for wrapper types.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it
|
||||||
|
/// slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place,
|
||||||
|
/// we can refactor later if we come up with something cleaner.
|
||||||
|
/// </remarks>
|
||||||
|
private static class WrapperCodecs
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object>
|
||||||
|
{
|
||||||
|
{ typeof(bool), ForBool(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||||
|
{ typeof(int), ForInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||||
|
{ typeof(long), ForInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||||
|
{ typeof(uint), ForUInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||||
|
{ typeof(ulong), ForUInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||||
|
{ typeof(float), ForFloat(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
|
||||||
|
{ typeof(double), ForDouble(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
|
||||||
|
{ typeof(string), ForString(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
|
||||||
|
{ typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a field codec which effectively wraps a value of type T in a message.
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
internal static FieldCodec<T> GetCodec<T>()
|
||||||
|
{
|
||||||
|
object value;
|
||||||
|
if (!Codecs.TryGetValue(typeof(T), out value))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T));
|
||||||
|
}
|
||||||
|
return (FieldCodec<T>) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static T Read<T>(CodedInputStream input, FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
int length = input.ReadLength();
|
||||||
|
int oldLimit = input.PushLimit(length);
|
||||||
|
|
||||||
|
uint tag;
|
||||||
|
T value = codec.DefaultValue;
|
||||||
|
while ((tag = input.ReadTag()) != 0)
|
||||||
|
{
|
||||||
|
if (tag == codec.Tag)
|
||||||
|
{
|
||||||
|
value = codec.Read(input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input.SkipLastField();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
input.CheckReadEndOfStreamTag();
|
||||||
|
input.PopLimit(oldLimit);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Write<T>(CodedOutputStream output, T value, FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
output.WriteLength(codec.CalculateSizeWithTag(value));
|
||||||
|
codec.WriteTagAndValue(output, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int CalculateSize<T>(T value, FieldCodec<T> codec)
|
||||||
|
{
|
||||||
|
int fieldLength = codec.CalculateSizeWithTag(value);
|
||||||
|
return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>
|
||||||
|
/// An encode/decode pair for a single field. This effectively encapsulates
|
||||||
|
/// all the information needed to read or write the field value from/to a coded
|
||||||
|
/// stream.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This class is public and has to be as it is used by generated code, but its public
|
||||||
|
/// API is very limited - just what the generated code needs to call directly.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This never writes default values to the stream, and does not address "packedness"
|
||||||
|
/// in repeated fields itself, other than to know whether or not the field *should* be packed.
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class FieldCodec<T>
|
||||||
|
{
|
||||||
|
private static readonly T DefaultDefault;
|
||||||
|
// Only non-nullable value types support packing. This is the simplest way of detecting that.
|
||||||
|
private static readonly bool TypeSupportsPacking = default(T) != null;
|
||||||
|
|
||||||
|
static FieldCodec()
|
||||||
|
{
|
||||||
|
if (typeof(T) == typeof(string))
|
||||||
|
{
|
||||||
|
DefaultDefault = (T)(object)"";
|
||||||
|
}
|
||||||
|
else if (typeof(T) == typeof(ByteString))
|
||||||
|
{
|
||||||
|
DefaultDefault = (T)(object)ByteString.Empty;
|
||||||
|
}
|
||||||
|
// Otherwise it's the default value of the CLR type
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsPackedRepeatedField(uint tag) =>
|
||||||
|
TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited;
|
||||||
|
|
||||||
|
internal bool PackedRepeatedField { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a delegate to write a value (unconditionally) to a coded output stream.
|
||||||
|
/// </summary>
|
||||||
|
internal Action<CodedOutputStream, T> ValueWriter { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the size calculator for just a value.
|
||||||
|
/// </summary>
|
||||||
|
internal Func<T, int> ValueSizeCalculator { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a delegate to read a value from a coded input stream. It is assumed that
|
||||||
|
/// the stream is already positioned on the appropriate tag.
|
||||||
|
/// </summary>
|
||||||
|
internal Func<CodedInputStream, T> ValueReader { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the fixed size for an entry, or 0 if sizes vary.
|
||||||
|
/// </summary>
|
||||||
|
internal int FixedSize { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the tag of the codec.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The tag of the codec.
|
||||||
|
/// </value>
|
||||||
|
internal uint Tag { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default value for this codec. Usually the same for every instance of the same type, but
|
||||||
|
/// for string/ByteString wrapper fields the codec's default value is null, whereas for
|
||||||
|
/// other string/ByteString fields it's "" or ByteString.Empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The default value of the codec's type.
|
||||||
|
/// </value>
|
||||||
|
internal T DefaultValue { get; }
|
||||||
|
|
||||||
|
private readonly int tagSize;
|
||||||
|
|
||||||
|
internal FieldCodec(
|
||||||
|
Func<CodedInputStream, T> reader,
|
||||||
|
Action<CodedOutputStream, T> writer,
|
||||||
|
int fixedSize,
|
||||||
|
uint tag) : this(reader, writer, _ => fixedSize, tag)
|
||||||
|
{
|
||||||
|
FixedSize = fixedSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FieldCodec(
|
||||||
|
Func<CodedInputStream, T> reader,
|
||||||
|
Action<CodedOutputStream, T> writer,
|
||||||
|
Func<T, int> sizeCalculator,
|
||||||
|
uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FieldCodec(
|
||||||
|
Func<CodedInputStream, T> reader,
|
||||||
|
Action<CodedOutputStream, T> writer,
|
||||||
|
Func<T, int> sizeCalculator,
|
||||||
|
uint tag,
|
||||||
|
T defaultValue)
|
||||||
|
{
|
||||||
|
ValueReader = reader;
|
||||||
|
ValueWriter = writer;
|
||||||
|
ValueSizeCalculator = sizeCalculator;
|
||||||
|
FixedSize = 0;
|
||||||
|
Tag = tag;
|
||||||
|
DefaultValue = defaultValue;
|
||||||
|
tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
|
||||||
|
// Detect packed-ness once, so we can check for it within RepeatedField<T>.
|
||||||
|
PackedRepeatedField = IsPackedRepeatedField(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write a tag and the given value, *if* the value is not the default.
|
||||||
|
/// </summary>
|
||||||
|
public void WriteTagAndValue(CodedOutputStream output, T value)
|
||||||
|
{
|
||||||
|
if (!IsDefault(value))
|
||||||
|
{
|
||||||
|
output.WriteTag(Tag);
|
||||||
|
ValueWriter(output, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a value of the codec type from the given <see cref="CodedInputStream"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The input stream to read from.</param>
|
||||||
|
/// <returns>The value read from the stream.</returns>
|
||||||
|
public T Read(CodedInputStream input) => ValueReader(input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the size required to write the given value, with a tag,
|
||||||
|
/// if the value is not the default.
|
||||||
|
/// </summary>
|
||||||
|
public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize;
|
||||||
|
|
||||||
|
private bool IsDefault(T value) => EqualityComparer<T>.Default.Equals(value, DefaultValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class containing helpful workarounds for various platform compatibility
|
||||||
|
/// </summary>
|
||||||
|
internal static class FrameworkPortability
|
||||||
|
{
|
||||||
|
// The value of RegexOptions.Compiled is 8. We can test for the presence at
|
||||||
|
// execution time using Enum.IsDefined, so a single build will do the right thing
|
||||||
|
// on each platform. (RegexOptions.Compiled isn't supported by PCLs.)
|
||||||
|
internal static readonly RegexOptions CompiledRegexWhereAvailable =
|
||||||
|
Enum.IsDefined(typeof(RegexOptions), 8) ? (RegexOptions)8 : RegexOptions.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Description>C# runtime library for Protocol Buffers - Google's data interchange format.</Description>
|
||||||
|
<Copyright>Copyright 2015, Google Inc.</Copyright>
|
||||||
|
<AssemblyTitle>Google Protocol Buffers</AssemblyTitle>
|
||||||
|
<VersionPrefix>3.4.1</VersionPrefix>
|
||||||
|
<Authors>Google Inc.</Authors>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<PackageTags>Protocol;Buffers;Binary;Serialization;Format;Google;proto;proto3</PackageTags>
|
||||||
|
<PackageReleaseNotes>C# proto3 support</PackageReleaseNotes>
|
||||||
|
<PackageProjectUrl>https://github.com/google/protobuf</PackageProjectUrl>
|
||||||
|
<PackageLicenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</PackageLicenseUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<RepositoryUrl>https://github.com/google/protobuf.git</RepositoryUrl>
|
||||||
|
<IncludeSymbols>true</IncludeSymbols>
|
||||||
|
<IncludeSource>true</IncludeSource>
|
||||||
|
<Platforms>x64</Platforms>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A message type that has a custom string format for diagnostic purposes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Calling <see cref="object.ToString"/> on a generated message type normally
|
||||||
|
/// returns the JSON representation. If a message type implements this interface,
|
||||||
|
/// then the <see cref="ToDiagnosticString"/> method will be called instead of the regular
|
||||||
|
/// JSON formatting code, but only when <c>ToString()</c> is called either on the message itself
|
||||||
|
/// or on another message which contains it. This does not affect the normal JSON formatting of
|
||||||
|
/// the message.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For example, if you create a proto message representing a GUID, the internal
|
||||||
|
/// representation may be a <c>bytes</c> field or four <c>fixed32</c> fields. However, when debugging
|
||||||
|
/// it may be more convenient to see a result in the same format as <see cref="System.Guid"/> provides.
|
||||||
|
/// </para>
|
||||||
|
/// <para>This interface extends <see cref="IMessage"/> to avoid it accidentally being implemented
|
||||||
|
/// on types other than messages, where it would not be used by anything in the framework.</para>
|
||||||
|
/// </remarks>
|
||||||
|
public interface ICustomDiagnosticMessage : IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this object, for diagnostic purposes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method is called when a message is formatted as part of a <see cref="object.ToString"/>
|
||||||
|
/// call. It does not affect the JSON representation used by <see cref="JsonFormatter"/> other than
|
||||||
|
/// in calls to <see cref="JsonFormatter.ToDiagnosticString(IMessage)"/>. While it is recommended
|
||||||
|
/// that the result is valid JSON, this is never assumed by the Protobuf library.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>A string representation of this object, for diagnostic purposes.</returns>
|
||||||
|
string ToDiagnosticString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generic interface for a deeply cloneable type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// All generated messages implement this interface, but so do some non-message types.
|
||||||
|
/// Additionally, due to the type constraint on <c>T</c> in <see cref="IMessage{T}"/>,
|
||||||
|
/// it is simpler to keep this as a separate interface.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The type itself, returned by the <see cref="Clone"/> method.</typeparam>
|
||||||
|
public interface IDeepCloneable<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a deep clone of this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A deep clone of this object.</returns>
|
||||||
|
T Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Google.Protobuf.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for a Protocol Buffers message, supporting
|
||||||
|
/// basic operations required for serialization.
|
||||||
|
/// </summary>
|
||||||
|
public interface IMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Merges the data from the specified coded input stream with the current message.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>See the user guide for precise merge semantics.</remarks>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
void MergeFrom(CodedInputStream input);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the data to the given coded output stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="output">Coded output stream to write the data to. Must not be null.</param>
|
||||||
|
void WriteTo(CodedOutputStream output);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the size of this message in Protocol Buffer wire format, in bytes.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The number of bytes required to write this message
|
||||||
|
/// to a coded output stream.</returns>
|
||||||
|
int CalculateSize();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Descriptor for this message. All instances are expected to return the same descriptor,
|
||||||
|
/// and for generated types this will be an explicitly-implemented member, returning the
|
||||||
|
/// same value as the static property declared on the type.
|
||||||
|
/// </summary>
|
||||||
|
MessageDescriptor Descriptor { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generic interface for a Protocol Buffers message,
|
||||||
|
/// where the type parameter is expected to be the same type as
|
||||||
|
/// the implementation class.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The message type.</typeparam>
|
||||||
|
public interface IMessage<T> : IMessage, IEquatable<T>, IDeepCloneable<T> where T : IMessage<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Merges the given message into this one.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>See the user guide for precise merge semantics.</remarks>
|
||||||
|
/// <param name="message">The message to merge with this one. Must not be null.</param>
|
||||||
|
void MergeFrom(T message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Thrown when an attempt is made to parse invalid JSON, e.g. using
|
||||||
|
/// a non-string property key, or including a redundant comma. Parsing a protocol buffer
|
||||||
|
/// message represented in JSON using <see cref="JsonParser"/> can throw both this
|
||||||
|
/// exception and <see cref="InvalidProtocolBufferException"/> depending on the situation. This
|
||||||
|
/// exception is only thrown for "pure JSON" errors, whereas <c>InvalidProtocolBufferException</c>
|
||||||
|
/// is thrown when the JSON may be valid in and of itself, but cannot be parsed as a protocol buffer
|
||||||
|
/// message.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class InvalidJsonException : IOException
|
||||||
|
{
|
||||||
|
internal InvalidJsonException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Thrown when a protocol message being parsed is invalid in some way,
|
||||||
|
/// e.g. it contains a malformed varint or a negative byte length.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class InvalidProtocolBufferException : IOException
|
||||||
|
{
|
||||||
|
internal InvalidProtocolBufferException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal InvalidProtocolBufferException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException MoreDataAvailable()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Completed reading a message while more data was available in the stream.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException TruncatedMessage()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"While parsing a protocol message, the input ended unexpectedly " +
|
||||||
|
"in the middle of a field. This could mean either that the " +
|
||||||
|
"input has been truncated or that an embedded message " +
|
||||||
|
"misreported its own length.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException NegativeSize()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"CodedInputStream encountered an embedded string or message " +
|
||||||
|
"which claimed to have negative size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException MalformedVarint()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"CodedInputStream encountered a malformed varint.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an exception for an error condition of an invalid tag being encountered.
|
||||||
|
/// </summary>
|
||||||
|
internal static InvalidProtocolBufferException InvalidTag()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Protocol message contained an invalid tag (zero).");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException InvalidBase64(Exception innerException)
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException("Invalid base64 data", innerException);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException InvalidEndTag()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Protocol message end-group tag did not match expected tag.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException RecursionLimitExceeded()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Protocol message had too many levels of nesting. May be malicious. " +
|
||||||
|
"Use CodedInputStream.SetRecursionLimit() to increase the depth limit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException JsonRecursionLimitExceeded()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Protocol message had too many levels of nesting. May be malicious. " +
|
||||||
|
"Use JsonParser.Settings to increase the depth limit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException SizeLimitExceeded()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Protocol message was too large. May be malicious. " +
|
||||||
|
"Use CodedInputStream.SetSizeLimit() to increase the size limit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static InvalidProtocolBufferException InvalidMessageStreamTag()
|
||||||
|
{
|
||||||
|
return new InvalidProtocolBufferException(
|
||||||
|
"Stream of protocol messages had invalid tag. Expected tag is length-delimited field 1.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,902 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using Google.Protobuf.Reflection;
|
||||||
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reflection-based converter from messages to JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Instances of this class are thread-safe, with no mutable state.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// This is a simple start to get JSON formatting working. As it's reflection-based,
|
||||||
|
/// it's not as quick as baking calls into generated messages - but is a simpler implementation.
|
||||||
|
/// (This code is generally not heavily optimized.)
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class JsonFormatter
|
||||||
|
{
|
||||||
|
internal const string AnyTypeUrlField = "@type";
|
||||||
|
internal const string AnyDiagnosticValueField = "@value";
|
||||||
|
internal const string AnyWellKnownTypeValueField = "value";
|
||||||
|
private const string TypeUrlPrefix = "type.googleapis.com";
|
||||||
|
private const string NameValueSeparator = ": ";
|
||||||
|
private const string PropertySeparator = ", ";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a formatter using the default settings.
|
||||||
|
/// </summary>
|
||||||
|
public static JsonFormatter Default { get; } = new JsonFormatter(Settings.Default);
|
||||||
|
|
||||||
|
// A JSON formatter which *only* exists
|
||||||
|
private static readonly JsonFormatter diagnosticFormatter = new JsonFormatter(Settings.Default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The JSON representation of the first 160 characters of Unicode.
|
||||||
|
/// Empty strings are replaced by the static constructor.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string[] CommonRepresentations = {
|
||||||
|
// C0 (ASCII and derivatives) control characters
|
||||||
|
"\\u0000", "\\u0001", "\\u0002", "\\u0003", // 0x00
|
||||||
|
"\\u0004", "\\u0005", "\\u0006", "\\u0007",
|
||||||
|
"\\b", "\\t", "\\n", "\\u000b",
|
||||||
|
"\\f", "\\r", "\\u000e", "\\u000f",
|
||||||
|
"\\u0010", "\\u0011", "\\u0012", "\\u0013", // 0x10
|
||||||
|
"\\u0014", "\\u0015", "\\u0016", "\\u0017",
|
||||||
|
"\\u0018", "\\u0019", "\\u001a", "\\u001b",
|
||||||
|
"\\u001c", "\\u001d", "\\u001e", "\\u001f",
|
||||||
|
// Escaping of " and \ are required by www.json.org string definition.
|
||||||
|
// Escaping of < and > are required for HTML security.
|
||||||
|
"", "", "\\\"", "", "", "", "", "", // 0x20
|
||||||
|
"", "", "", "", "", "", "", "",
|
||||||
|
"", "", "", "", "", "", "", "", // 0x30
|
||||||
|
"", "", "", "", "\\u003c", "", "\\u003e", "",
|
||||||
|
"", "", "", "", "", "", "", "", // 0x40
|
||||||
|
"", "", "", "", "", "", "", "",
|
||||||
|
"", "", "", "", "", "", "", "", // 0x50
|
||||||
|
"", "", "", "", "\\\\", "", "", "",
|
||||||
|
"", "", "", "", "", "", "", "", // 0x60
|
||||||
|
"", "", "", "", "", "", "", "",
|
||||||
|
"", "", "", "", "", "", "", "", // 0x70
|
||||||
|
"", "", "", "", "", "", "", "\\u007f",
|
||||||
|
// C1 (ISO 8859 and Unicode) extended control characters
|
||||||
|
"\\u0080", "\\u0081", "\\u0082", "\\u0083", // 0x80
|
||||||
|
"\\u0084", "\\u0085", "\\u0086", "\\u0087",
|
||||||
|
"\\u0088", "\\u0089", "\\u008a", "\\u008b",
|
||||||
|
"\\u008c", "\\u008d", "\\u008e", "\\u008f",
|
||||||
|
"\\u0090", "\\u0091", "\\u0092", "\\u0093", // 0x90
|
||||||
|
"\\u0094", "\\u0095", "\\u0096", "\\u0097",
|
||||||
|
"\\u0098", "\\u0099", "\\u009a", "\\u009b",
|
||||||
|
"\\u009c", "\\u009d", "\\u009e", "\\u009f"
|
||||||
|
};
|
||||||
|
|
||||||
|
static JsonFormatter()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < CommonRepresentations.Length; i++)
|
||||||
|
{
|
||||||
|
if (CommonRepresentations[i] == "")
|
||||||
|
{
|
||||||
|
CommonRepresentations[i] = ((char) i).ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Settings settings;
|
||||||
|
|
||||||
|
private bool DiagnosticOnly => ReferenceEquals(this, diagnosticFormatter);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new formatted with the given settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings.</param>
|
||||||
|
public JsonFormatter(Settings settings)
|
||||||
|
{
|
||||||
|
this.settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formats the specified message as JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to format.</param>
|
||||||
|
/// <returns>The formatted message.</returns>
|
||||||
|
public string Format(IMessage message)
|
||||||
|
{
|
||||||
|
var writer = new StringWriter();
|
||||||
|
Format(message, writer);
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Formats the specified message as JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to format.</param>
|
||||||
|
/// <param name="writer">The TextWriter to write the formatted message to.</param>
|
||||||
|
/// <returns>The formatted message.</returns>
|
||||||
|
public void Format(IMessage message, TextWriter writer)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, nameof(message));
|
||||||
|
ProtoPreconditions.CheckNotNull(writer, nameof(writer));
|
||||||
|
|
||||||
|
if (message.Descriptor.IsWellKnownType)
|
||||||
|
{
|
||||||
|
WriteWellKnownTypeValue(writer, message.Descriptor, message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteMessage(writer, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a message to JSON for diagnostic purposes with no extra context.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This differs from calling <see cref="Format(IMessage)"/> on the default JSON
|
||||||
|
/// formatter in its handling of <see cref="Any"/>. As no type registry is available
|
||||||
|
/// in <see cref="object.ToString"/> calls, the normal way of resolving the type of
|
||||||
|
/// an <c>Any</c> message cannot be applied. Instead, a JSON property named <c>@value</c>
|
||||||
|
/// is included with the base64 data from the <see cref="Any.Value"/> property of the message.
|
||||||
|
/// </para>
|
||||||
|
/// <para>The value returned by this method is only designed to be used for diagnostic
|
||||||
|
/// purposes. It may not be parsable by <see cref="JsonParser"/>, and may not be parsable
|
||||||
|
/// by other Protocol Buffer implementations.</para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="message">The message to format for diagnostic purposes.</param>
|
||||||
|
/// <returns>The diagnostic-only JSON representation of the message</returns>
|
||||||
|
public static string ToDiagnosticString(IMessage message)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, nameof(message));
|
||||||
|
return diagnosticFormatter.Format(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteMessage(TextWriter writer, IMessage message)
|
||||||
|
{
|
||||||
|
if (message == null)
|
||||||
|
{
|
||||||
|
WriteNull(writer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DiagnosticOnly)
|
||||||
|
{
|
||||||
|
ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage;
|
||||||
|
if (customDiagnosticMessage != null)
|
||||||
|
{
|
||||||
|
writer.Write(customDiagnosticMessage.ToDiagnosticString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.Write("{ ");
|
||||||
|
bool writtenFields = WriteMessageFields(writer, message, false);
|
||||||
|
writer.Write(writtenFields ? " }" : "}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten)
|
||||||
|
{
|
||||||
|
var fields = message.Descriptor.Fields;
|
||||||
|
bool first = !assumeFirstFieldWritten;
|
||||||
|
// First non-oneof fields
|
||||||
|
foreach (var field in fields.InFieldNumberOrder())
|
||||||
|
{
|
||||||
|
var accessor = field.Accessor;
|
||||||
|
if (field.ContainingOneof != null && field.ContainingOneof.Accessor.GetCaseFieldDescriptor(message) != field)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Omit default values unless we're asked to format them, or they're oneofs (where the default
|
||||||
|
// value is still formatted regardless, because that's how we preserve the oneof case).
|
||||||
|
object value = accessor.GetValue(message);
|
||||||
|
if (field.ContainingOneof == null && !settings.FormatDefaultValues && IsDefaultValue(accessor, value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, all tests complete: let's write the field value...
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
writer.Write(PropertySeparator);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteString(writer, accessor.Descriptor.JsonName);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
WriteValue(writer, value);
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
return !first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converted from java/core/src/main/java/com/google/protobuf/Descriptors.java
|
||||||
|
internal static string ToJsonName(string name)
|
||||||
|
{
|
||||||
|
StringBuilder result = new StringBuilder(name.Length);
|
||||||
|
bool isNextUpperCase = false;
|
||||||
|
foreach (char ch in name)
|
||||||
|
{
|
||||||
|
if (ch == '_')
|
||||||
|
{
|
||||||
|
isNextUpperCase = true;
|
||||||
|
}
|
||||||
|
else if (isNextUpperCase)
|
||||||
|
{
|
||||||
|
result.Append(char.ToUpperInvariant(ch));
|
||||||
|
isNextUpperCase = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.Append(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteNull(TextWriter writer)
|
||||||
|
{
|
||||||
|
writer.Write("null");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsDefaultValue(IFieldAccessor accessor, object value)
|
||||||
|
{
|
||||||
|
if (accessor.Descriptor.IsMap)
|
||||||
|
{
|
||||||
|
IDictionary dictionary = (IDictionary) value;
|
||||||
|
return dictionary.Count == 0;
|
||||||
|
}
|
||||||
|
if (accessor.Descriptor.IsRepeated)
|
||||||
|
{
|
||||||
|
IList list = (IList) value;
|
||||||
|
return list.Count == 0;
|
||||||
|
}
|
||||||
|
switch (accessor.Descriptor.FieldType)
|
||||||
|
{
|
||||||
|
case FieldType.Bool:
|
||||||
|
return (bool) value == false;
|
||||||
|
case FieldType.Bytes:
|
||||||
|
return (ByteString) value == ByteString.Empty;
|
||||||
|
case FieldType.String:
|
||||||
|
return (string) value == "";
|
||||||
|
case FieldType.Double:
|
||||||
|
return (double) value == 0.0;
|
||||||
|
case FieldType.SInt32:
|
||||||
|
case FieldType.Int32:
|
||||||
|
case FieldType.SFixed32:
|
||||||
|
case FieldType.Enum:
|
||||||
|
return (int) value == 0;
|
||||||
|
case FieldType.Fixed32:
|
||||||
|
case FieldType.UInt32:
|
||||||
|
return (uint) value == 0;
|
||||||
|
case FieldType.Fixed64:
|
||||||
|
case FieldType.UInt64:
|
||||||
|
return (ulong) value == 0;
|
||||||
|
case FieldType.SFixed64:
|
||||||
|
case FieldType.Int64:
|
||||||
|
case FieldType.SInt64:
|
||||||
|
return (long) value == 0;
|
||||||
|
case FieldType.Float:
|
||||||
|
return (float) value == 0f;
|
||||||
|
case FieldType.Message:
|
||||||
|
case FieldType.Group: // Never expect to get this, but...
|
||||||
|
return value == null;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Invalid field type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a single value to the given writer as JSON. Only types understood by
|
||||||
|
/// Protocol Buffers can be written in this way. This method is only exposed for
|
||||||
|
/// advanced use cases; most users should be using <see cref="Format(IMessage)"/>
|
||||||
|
/// or <see cref="Format(IMessage, TextWriter)"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="writer">The writer to write the value to. Must not be null.</param>
|
||||||
|
/// <param name="value">The value to write. May be null.</param>
|
||||||
|
public void WriteValue(TextWriter writer, object value)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull(writer);
|
||||||
|
}
|
||||||
|
else if (value is bool)
|
||||||
|
{
|
||||||
|
writer.Write((bool)value ? "true" : "false");
|
||||||
|
}
|
||||||
|
else if (value is ByteString)
|
||||||
|
{
|
||||||
|
// Nothing in Base64 needs escaping
|
||||||
|
writer.Write('"');
|
||||||
|
writer.Write(((ByteString)value).ToBase64());
|
||||||
|
writer.Write('"');
|
||||||
|
}
|
||||||
|
else if (value is string)
|
||||||
|
{
|
||||||
|
WriteString(writer, (string)value);
|
||||||
|
}
|
||||||
|
else if (value is IDictionary)
|
||||||
|
{
|
||||||
|
WriteDictionary(writer, (IDictionary)value);
|
||||||
|
}
|
||||||
|
else if (value is IList)
|
||||||
|
{
|
||||||
|
WriteList(writer, (IList)value);
|
||||||
|
}
|
||||||
|
else if (value is int || value is uint)
|
||||||
|
{
|
||||||
|
IFormattable formattable = (IFormattable) value;
|
||||||
|
writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
else if (value is long || value is ulong)
|
||||||
|
{
|
||||||
|
writer.Write('"');
|
||||||
|
IFormattable formattable = (IFormattable) value;
|
||||||
|
writer.Write(formattable.ToString("d", CultureInfo.InvariantCulture));
|
||||||
|
writer.Write('"');
|
||||||
|
}
|
||||||
|
else if (value is System.Enum)
|
||||||
|
{
|
||||||
|
if (settings.FormatEnumsAsIntegers)
|
||||||
|
{
|
||||||
|
WriteValue(writer, (int)value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string name = OriginalEnumValueHelper.GetOriginalName(value);
|
||||||
|
if (name != null)
|
||||||
|
{
|
||||||
|
WriteString(writer, name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteValue(writer, (int)value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value is float || value is double)
|
||||||
|
{
|
||||||
|
string text = ((IFormattable) value).ToString("r", CultureInfo.InvariantCulture);
|
||||||
|
if (text == "NaN" || text == "Infinity" || text == "-Infinity")
|
||||||
|
{
|
||||||
|
writer.Write('"');
|
||||||
|
writer.Write(text);
|
||||||
|
writer.Write('"');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.Write(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value is IMessage)
|
||||||
|
{
|
||||||
|
Format((IMessage)value, writer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Unable to format value of type " + value.GetType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Central interception point for well-known type formatting. Any well-known types which
|
||||||
|
/// don't need special handling can fall back to WriteMessage. We avoid assuming that the
|
||||||
|
/// values are using the embedded well-known types, in order to allow for dynamic messages
|
||||||
|
/// in the future.
|
||||||
|
/// </summary>
|
||||||
|
private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value)
|
||||||
|
{
|
||||||
|
// Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
|
||||||
|
// this would do the right thing.
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
WriteNull(writer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// For wrapper types, the value will either be the (possibly boxed) "native" value,
|
||||||
|
// or the message itself if we're formatting it at the top level (e.g. just calling ToString on the object itself).
|
||||||
|
// If it's the message form, we can extract the value first, which *will* be the (possibly boxed) native value,
|
||||||
|
// and then proceed, writing it as if we were definitely in a field. (We never need to wrap it in an extra string...
|
||||||
|
// WriteValue will do the right thing.)
|
||||||
|
if (descriptor.IsWrapperType)
|
||||||
|
{
|
||||||
|
if (value is IMessage)
|
||||||
|
{
|
||||||
|
var message = (IMessage) value;
|
||||||
|
value = message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.GetValue(message);
|
||||||
|
}
|
||||||
|
WriteValue(writer, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == Timestamp.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
WriteTimestamp(writer, (IMessage)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == Duration.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
WriteDuration(writer, (IMessage)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == FieldMask.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
WriteFieldMask(writer, (IMessage)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == Struct.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
WriteStruct(writer, (IMessage)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == ListValue.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
|
||||||
|
WriteList(writer, (IList)fieldAccessor.GetValue((IMessage)value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == Value.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
WriteStructFieldValue(writer, (IMessage)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descriptor.FullName == Any.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
WriteAny(writer, (IMessage)value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WriteMessage(writer, (IMessage)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteTimestamp(TextWriter writer, IMessage value)
|
||||||
|
{
|
||||||
|
// TODO: In the common case where this *is* using the built-in Timestamp type, we could
|
||||||
|
// avoid all the reflection at this point, by casting to Timestamp. In the interests of
|
||||||
|
// avoiding subtle bugs, don't do that until we've implemented DynamicMessage so that we can prove
|
||||||
|
// it still works in that case.
|
||||||
|
int nanos = (int) value.Descriptor.Fields[Timestamp.NanosFieldNumber].Accessor.GetValue(value);
|
||||||
|
long seconds = (long) value.Descriptor.Fields[Timestamp.SecondsFieldNumber].Accessor.GetValue(value);
|
||||||
|
writer.Write(Timestamp.ToJson(seconds, nanos, DiagnosticOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteDuration(TextWriter writer, IMessage value)
|
||||||
|
{
|
||||||
|
// TODO: Same as for WriteTimestamp
|
||||||
|
int nanos = (int) value.Descriptor.Fields[Duration.NanosFieldNumber].Accessor.GetValue(value);
|
||||||
|
long seconds = (long) value.Descriptor.Fields[Duration.SecondsFieldNumber].Accessor.GetValue(value);
|
||||||
|
writer.Write(Duration.ToJson(seconds, nanos, DiagnosticOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteFieldMask(TextWriter writer, IMessage value)
|
||||||
|
{
|
||||||
|
var paths = (IList<string>) value.Descriptor.Fields[FieldMask.PathsFieldNumber].Accessor.GetValue(value);
|
||||||
|
writer.Write(FieldMask.ToJson(paths, DiagnosticOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteAny(TextWriter writer, IMessage value)
|
||||||
|
{
|
||||||
|
if (DiagnosticOnly)
|
||||||
|
{
|
||||||
|
WriteDiagnosticOnlyAny(writer, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
|
||||||
|
ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
|
||||||
|
string typeName = Any.GetTypeName(typeUrl);
|
||||||
|
MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName);
|
||||||
|
if (descriptor == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
|
||||||
|
}
|
||||||
|
IMessage message = descriptor.Parser.ParseFrom(data);
|
||||||
|
writer.Write("{ ");
|
||||||
|
WriteString(writer, AnyTypeUrlField);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
WriteString(writer, typeUrl);
|
||||||
|
|
||||||
|
if (descriptor.IsWellKnownType)
|
||||||
|
{
|
||||||
|
writer.Write(PropertySeparator);
|
||||||
|
WriteString(writer, AnyWellKnownTypeValueField);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
WriteWellKnownTypeValue(writer, descriptor, message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteMessageFields(writer, message, true);
|
||||||
|
}
|
||||||
|
writer.Write(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteDiagnosticOnlyAny(TextWriter writer, IMessage value)
|
||||||
|
{
|
||||||
|
string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value);
|
||||||
|
ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value);
|
||||||
|
writer.Write("{ ");
|
||||||
|
WriteString(writer, AnyTypeUrlField);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
WriteString(writer, typeUrl);
|
||||||
|
writer.Write(PropertySeparator);
|
||||||
|
WriteString(writer, AnyDiagnosticValueField);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
writer.Write('"');
|
||||||
|
writer.Write(data.ToBase64());
|
||||||
|
writer.Write('"');
|
||||||
|
writer.Write(" }");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteStruct(TextWriter writer, IMessage message)
|
||||||
|
{
|
||||||
|
writer.Write("{ ");
|
||||||
|
IDictionary fields = (IDictionary) message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message);
|
||||||
|
bool first = true;
|
||||||
|
foreach (DictionaryEntry entry in fields)
|
||||||
|
{
|
||||||
|
string key = (string) entry.Key;
|
||||||
|
IMessage value = (IMessage) entry.Value;
|
||||||
|
if (string.IsNullOrEmpty(key) || value == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
writer.Write(PropertySeparator);
|
||||||
|
}
|
||||||
|
WriteString(writer, key);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
WriteStructFieldValue(writer, value);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
writer.Write(first ? "}" : " }");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteStructFieldValue(TextWriter writer, IMessage message)
|
||||||
|
{
|
||||||
|
var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
|
||||||
|
if (specifiedField == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Value message must contain a value for the oneof.");
|
||||||
|
}
|
||||||
|
|
||||||
|
object value = specifiedField.Accessor.GetValue(message);
|
||||||
|
|
||||||
|
switch (specifiedField.FieldNumber)
|
||||||
|
{
|
||||||
|
case Value.BoolValueFieldNumber:
|
||||||
|
case Value.StringValueFieldNumber:
|
||||||
|
case Value.NumberValueFieldNumber:
|
||||||
|
WriteValue(writer, value);
|
||||||
|
return;
|
||||||
|
case Value.StructValueFieldNumber:
|
||||||
|
case Value.ListValueFieldNumber:
|
||||||
|
// Structs and ListValues are nested messages, and already well-known types.
|
||||||
|
var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message);
|
||||||
|
WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage);
|
||||||
|
return;
|
||||||
|
case Value.NullValueFieldNumber:
|
||||||
|
WriteNull(writer);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected case in struct field: " + specifiedField.FieldNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteList(TextWriter writer, IList list)
|
||||||
|
{
|
||||||
|
writer.Write("[ ");
|
||||||
|
bool first = true;
|
||||||
|
foreach (var value in list)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
writer.Write(PropertySeparator);
|
||||||
|
}
|
||||||
|
WriteValue(writer, value);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
writer.Write(first ? "]" : " ]");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void WriteDictionary(TextWriter writer, IDictionary dictionary)
|
||||||
|
{
|
||||||
|
writer.Write("{ ");
|
||||||
|
bool first = true;
|
||||||
|
// This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
|
||||||
|
foreach (DictionaryEntry pair in dictionary)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
{
|
||||||
|
writer.Write(PropertySeparator);
|
||||||
|
}
|
||||||
|
string keyText;
|
||||||
|
if (pair.Key is string)
|
||||||
|
{
|
||||||
|
keyText = (string) pair.Key;
|
||||||
|
}
|
||||||
|
else if (pair.Key is bool)
|
||||||
|
{
|
||||||
|
keyText = (bool) pair.Key ? "true" : "false";
|
||||||
|
}
|
||||||
|
else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong)
|
||||||
|
{
|
||||||
|
keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pair.Key == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Dictionary has entry with null key");
|
||||||
|
}
|
||||||
|
throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
|
||||||
|
}
|
||||||
|
WriteString(writer, keyText);
|
||||||
|
writer.Write(NameValueSeparator);
|
||||||
|
WriteValue(writer, pair.Value);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
writer.Write(first ? "}" : " }");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a string (including leading and trailing double quotes) to a builder, escaping as required.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Other than surrogate pair handling, this code is mostly taken from src/google/protobuf/util/internal/json_escaping.cc.
|
||||||
|
/// </remarks>
|
||||||
|
internal static void WriteString(TextWriter writer, string text)
|
||||||
|
{
|
||||||
|
writer.Write('"');
|
||||||
|
for (int i = 0; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
char c = text[i];
|
||||||
|
if (c < 0xa0)
|
||||||
|
{
|
||||||
|
writer.Write(CommonRepresentations[c]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (char.IsHighSurrogate(c))
|
||||||
|
{
|
||||||
|
// Encountered first part of a surrogate pair.
|
||||||
|
// Check that we have the whole pair, and encode both parts as hex.
|
||||||
|
i++;
|
||||||
|
if (i == text.Length || !char.IsLowSurrogate(text[i]))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("String contains low surrogate not followed by high surrogate");
|
||||||
|
}
|
||||||
|
HexEncodeUtf16CodeUnit(writer, c);
|
||||||
|
HexEncodeUtf16CodeUnit(writer, text[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (char.IsLowSurrogate(c))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("String contains high surrogate not preceded by low surrogate");
|
||||||
|
}
|
||||||
|
switch ((uint) c)
|
||||||
|
{
|
||||||
|
// These are not required by json spec
|
||||||
|
// but used to prevent security bugs in javascript.
|
||||||
|
case 0xfeff: // Zero width no-break space
|
||||||
|
case 0xfff9: // Interlinear annotation anchor
|
||||||
|
case 0xfffa: // Interlinear annotation separator
|
||||||
|
case 0xfffb: // Interlinear annotation terminator
|
||||||
|
|
||||||
|
case 0x00ad: // Soft-hyphen
|
||||||
|
case 0x06dd: // Arabic end of ayah
|
||||||
|
case 0x070f: // Syriac abbreviation mark
|
||||||
|
case 0x17b4: // Khmer vowel inherent Aq
|
||||||
|
case 0x17b5: // Khmer vowel inherent Aa
|
||||||
|
HexEncodeUtf16CodeUnit(writer, c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if ((c >= 0x0600 && c <= 0x0603) || // Arabic signs
|
||||||
|
(c >= 0x200b && c <= 0x200f) || // Zero width etc.
|
||||||
|
(c >= 0x2028 && c <= 0x202e) || // Separators etc.
|
||||||
|
(c >= 0x2060 && c <= 0x2064) || // Invisible etc.
|
||||||
|
(c >= 0x206a && c <= 0x206f))
|
||||||
|
{
|
||||||
|
HexEncodeUtf16CodeUnit(writer, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No handling of surrogates here - that's done earlier
|
||||||
|
writer.Write(c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.Write('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string Hex = "0123456789abcdef";
|
||||||
|
private static void HexEncodeUtf16CodeUnit(TextWriter writer, char c)
|
||||||
|
{
|
||||||
|
writer.Write("\\u");
|
||||||
|
writer.Write(Hex[(c >> 12) & 0xf]);
|
||||||
|
writer.Write(Hex[(c >> 8) & 0xf]);
|
||||||
|
writer.Write(Hex[(c >> 4) & 0xf]);
|
||||||
|
writer.Write(Hex[(c >> 0) & 0xf]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Settings controlling JSON formatting.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default settings, as used by <see cref="JsonFormatter.Default"/>
|
||||||
|
/// </summary>
|
||||||
|
public static Settings Default { get; }
|
||||||
|
|
||||||
|
// Workaround for the Mono compiler complaining about XML comments not being on
|
||||||
|
// valid language elements.
|
||||||
|
static Settings()
|
||||||
|
{
|
||||||
|
Default = new Settings(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether fields whose values are the default for the field type (e.g. 0 for integers)
|
||||||
|
/// should be formatted (true) or omitted (false).
|
||||||
|
/// </summary>
|
||||||
|
public bool FormatDefaultValues { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type registry used to format <see cref="Any"/> messages.
|
||||||
|
/// </summary>
|
||||||
|
public TypeRegistry TypeRegistry { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to format enums as ints. Defaults to false.
|
||||||
|
/// </summary>
|
||||||
|
public bool FormatEnumsAsIntegers { get; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values
|
||||||
|
/// and an empty type registry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
|
||||||
|
public Settings(bool formatDefaultValues) : this(formatDefaultValues, TypeRegistry.Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values
|
||||||
|
/// and type registry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
|
||||||
|
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
|
||||||
|
public Settings(bool formatDefaultValues, TypeRegistry typeRegistry) : this(formatDefaultValues, typeRegistry, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="Settings"/> object with the specified parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
|
||||||
|
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages. TypeRegistry.Empty will be used if it is null.</param>
|
||||||
|
/// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param>
|
||||||
|
private Settings(bool formatDefaultValues,
|
||||||
|
TypeRegistry typeRegistry,
|
||||||
|
bool formatEnumsAsIntegers)
|
||||||
|
{
|
||||||
|
FormatDefaultValues = formatDefaultValues;
|
||||||
|
TypeRegistry = typeRegistry ?? TypeRegistry.Empty;
|
||||||
|
FormatEnumsAsIntegers = formatEnumsAsIntegers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values and the current settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
|
||||||
|
public Settings WithFormatDefaultValues(bool formatDefaultValues) => new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="Settings"/> object with the specified type registry and the current settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
|
||||||
|
public Settings WithTypeRegistry(TypeRegistry typeRegistry) => new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="Settings"/> object with the specified enums formatting option and the current settings.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param>
|
||||||
|
public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effectively a cache of mapping from enum values to the original name as specified in the proto file,
|
||||||
|
// fetched by reflection.
|
||||||
|
// The need for this is unfortunate, as is its unbounded size, but realistically it shouldn't cause issues.
|
||||||
|
private static class OriginalEnumValueHelper
|
||||||
|
{
|
||||||
|
// TODO: In the future we might want to use ConcurrentDictionary, at the point where all
|
||||||
|
// the platforms we target have it.
|
||||||
|
private static readonly Dictionary<System.Type, Dictionary<object, string>> dictionaries
|
||||||
|
= new Dictionary<System.Type, Dictionary<object, string>>();
|
||||||
|
|
||||||
|
internal static string GetOriginalName(object value)
|
||||||
|
{
|
||||||
|
var enumType = value.GetType();
|
||||||
|
Dictionary<object, string> nameMapping;
|
||||||
|
lock (dictionaries)
|
||||||
|
{
|
||||||
|
if (!dictionaries.TryGetValue(enumType, out nameMapping))
|
||||||
|
{
|
||||||
|
nameMapping = GetNameMapping(enumType);
|
||||||
|
dictionaries[enumType] = nameMapping;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string originalName;
|
||||||
|
// If this returns false, originalName will be null, which is what we want.
|
||||||
|
nameMapping.TryGetValue(value, out originalName);
|
||||||
|
return originalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NET35
|
||||||
|
// TODO: Consider adding functionality to TypeExtensions to avoid this difference.
|
||||||
|
private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
|
||||||
|
enumType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
|
||||||
|
.Where(f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
|
||||||
|
.FirstOrDefault() as OriginalNameAttribute)
|
||||||
|
?.PreferredAlias ?? true)
|
||||||
|
.ToDictionary(f => f.GetValue(null),
|
||||||
|
f => (f.GetCustomAttributes(typeof(OriginalNameAttribute), false)
|
||||||
|
.FirstOrDefault() as OriginalNameAttribute)
|
||||||
|
// If the attribute hasn't been applied, fall back to the name of the field.
|
||||||
|
?.Name ?? f.Name);
|
||||||
|
#else
|
||||||
|
private static Dictionary<object, string> GetNameMapping(System.Type enumType) =>
|
||||||
|
enumType.GetTypeInfo().DeclaredFields
|
||||||
|
.Where(f => f.IsStatic)
|
||||||
|
.Where(f => f.GetCustomAttributes<OriginalNameAttribute>()
|
||||||
|
.FirstOrDefault()?.PreferredAlias ?? true)
|
||||||
|
.ToDictionary(f => f.GetValue(null),
|
||||||
|
f => f.GetCustomAttributes<OriginalNameAttribute>()
|
||||||
|
.FirstOrDefault()
|
||||||
|
// If the attribute hasn't been applied, fall back to the name of the field.
|
||||||
|
?.Name ?? f.Name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
internal sealed class JsonToken : IEquatable<JsonToken>
|
||||||
|
{
|
||||||
|
// Tokens with no value can be reused.
|
||||||
|
private static readonly JsonToken _true = new JsonToken(TokenType.True);
|
||||||
|
private static readonly JsonToken _false = new JsonToken(TokenType.False);
|
||||||
|
private static readonly JsonToken _null = new JsonToken(TokenType.Null);
|
||||||
|
private static readonly JsonToken startObject = new JsonToken(TokenType.StartObject);
|
||||||
|
private static readonly JsonToken endObject = new JsonToken(TokenType.EndObject);
|
||||||
|
private static readonly JsonToken startArray = new JsonToken(TokenType.StartArray);
|
||||||
|
private static readonly JsonToken endArray = new JsonToken(TokenType.EndArray);
|
||||||
|
private static readonly JsonToken endDocument = new JsonToken(TokenType.EndDocument);
|
||||||
|
|
||||||
|
internal static JsonToken Null { get { return _null; } }
|
||||||
|
internal static JsonToken False { get { return _false; } }
|
||||||
|
internal static JsonToken True { get { return _true; } }
|
||||||
|
internal static JsonToken StartObject{ get { return startObject; } }
|
||||||
|
internal static JsonToken EndObject { get { return endObject; } }
|
||||||
|
internal static JsonToken StartArray { get { return startArray; } }
|
||||||
|
internal static JsonToken EndArray { get { return endArray; } }
|
||||||
|
internal static JsonToken EndDocument { get { return endDocument; } }
|
||||||
|
|
||||||
|
internal static JsonToken Name(string name)
|
||||||
|
{
|
||||||
|
return new JsonToken(TokenType.Name, stringValue: name);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static JsonToken Value(string value)
|
||||||
|
{
|
||||||
|
return new JsonToken(TokenType.StringValue, stringValue: value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static JsonToken Value(double value)
|
||||||
|
{
|
||||||
|
return new JsonToken(TokenType.Number, numberValue: value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum TokenType
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
StringValue,
|
||||||
|
Number,
|
||||||
|
Name,
|
||||||
|
StartObject,
|
||||||
|
EndObject,
|
||||||
|
StartArray,
|
||||||
|
EndArray,
|
||||||
|
EndDocument
|
||||||
|
}
|
||||||
|
|
||||||
|
// A value is a string, number, array, object, null, true or false
|
||||||
|
// Arrays and objects have start/end
|
||||||
|
// A document consists of a value
|
||||||
|
// Objects are name/value sequences.
|
||||||
|
|
||||||
|
private readonly TokenType type;
|
||||||
|
private readonly string stringValue;
|
||||||
|
private readonly double numberValue;
|
||||||
|
|
||||||
|
internal TokenType Type { get { return type; } }
|
||||||
|
internal string StringValue { get { return stringValue; } }
|
||||||
|
internal double NumberValue { get { return numberValue; } }
|
||||||
|
|
||||||
|
private JsonToken(TokenType type, string stringValue = null, double numberValue = 0)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.stringValue = stringValue;
|
||||||
|
this.numberValue = numberValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return Equals(obj as JsonToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int hash = 17;
|
||||||
|
hash = hash * 31 + (int) type;
|
||||||
|
hash = hash * 31 + stringValue == null ? 0 : stringValue.GetHashCode();
|
||||||
|
hash = hash * 31 + numberValue.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TokenType.Null:
|
||||||
|
return "null";
|
||||||
|
case TokenType.True:
|
||||||
|
return "true";
|
||||||
|
case TokenType.False:
|
||||||
|
return "false";
|
||||||
|
case TokenType.Name:
|
||||||
|
return "name (" + stringValue + ")";
|
||||||
|
case TokenType.StringValue:
|
||||||
|
return "value (" + stringValue + ")";
|
||||||
|
case TokenType.Number:
|
||||||
|
return "number (" + numberValue + ")";
|
||||||
|
case TokenType.StartObject:
|
||||||
|
return "start-object";
|
||||||
|
case TokenType.EndObject:
|
||||||
|
return "end-object";
|
||||||
|
case TokenType.StartArray:
|
||||||
|
return "start-array";
|
||||||
|
case TokenType.EndArray:
|
||||||
|
return "end-array";
|
||||||
|
case TokenType.EndDocument:
|
||||||
|
return "end-document";
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Token is of unknown type " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(JsonToken other)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(other, null))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Note use of other.numberValue.Equals rather than ==, so that NaN compares appropriately.
|
||||||
|
return other.type == type && other.stringValue == stringValue && other.numberValue.Equals(numberValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,738 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Simple but strict JSON tokenizer, rigidly following RFC 7159.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This tokenizer is stateful, and only returns "useful" tokens - names, values etc.
|
||||||
|
/// It does not create tokens for the separator between names and values, or for the comma
|
||||||
|
/// between values. It validates the token stream as it goes - so callers can assume that the
|
||||||
|
/// tokens it produces are appropriate. For example, it would never produce "start object, end array."
|
||||||
|
/// </para>
|
||||||
|
/// <para>Implementation details: the base class handles single token push-back and </para>
|
||||||
|
/// <para>Not thread-safe.</para>
|
||||||
|
/// </remarks>
|
||||||
|
internal abstract class JsonTokenizer
|
||||||
|
{
|
||||||
|
private JsonToken bufferedToken;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a tokenizer that reads from the given text reader.
|
||||||
|
/// </summary>
|
||||||
|
internal static JsonTokenizer FromTextReader(TextReader reader)
|
||||||
|
{
|
||||||
|
return new JsonTextTokenizer(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a tokenizer that first replays the given list of tokens, then continues reading
|
||||||
|
/// from another tokenizer. Note that if the returned tokenizer is "pushed back", that does not push back
|
||||||
|
/// on the continuation tokenizer, or vice versa. Care should be taken when using this method - it was
|
||||||
|
/// created for the sake of Any parsing.
|
||||||
|
/// </summary>
|
||||||
|
internal static JsonTokenizer FromReplayedTokens(IList<JsonToken> tokens, JsonTokenizer continuation)
|
||||||
|
{
|
||||||
|
return new JsonReplayTokenizer(tokens, continuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the depth of the stack, purely in objects (not collections).
|
||||||
|
/// Informally, this is the number of remaining unclosed '{' characters we have.
|
||||||
|
/// </summary>
|
||||||
|
internal int ObjectDepth { get; private set; }
|
||||||
|
|
||||||
|
// TODO: Why do we allow a different token to be pushed back? It might be better to always remember the previous
|
||||||
|
// token returned, and allow a parameterless Rewind() method (which could only be called once, just like the current PushBack).
|
||||||
|
internal void PushBack(JsonToken token)
|
||||||
|
{
|
||||||
|
if (bufferedToken != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Can't push back twice");
|
||||||
|
}
|
||||||
|
bufferedToken = token;
|
||||||
|
if (token.Type == JsonToken.TokenType.StartObject)
|
||||||
|
{
|
||||||
|
ObjectDepth--;
|
||||||
|
}
|
||||||
|
else if (token.Type == JsonToken.TokenType.EndObject)
|
||||||
|
{
|
||||||
|
ObjectDepth++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the next JSON token in the stream. An EndDocument token is returned to indicate the end of the stream,
|
||||||
|
/// after which point <c>Next()</c> should not be called again.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This implementation provides single-token buffering, and calls <see cref="NextImpl"/> if there is no buffered token.</remarks>
|
||||||
|
/// <returns>The next token in the stream. This is never null.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
|
||||||
|
/// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
|
||||||
|
internal JsonToken Next()
|
||||||
|
{
|
||||||
|
JsonToken tokenToReturn;
|
||||||
|
if (bufferedToken != null)
|
||||||
|
{
|
||||||
|
tokenToReturn = bufferedToken;
|
||||||
|
bufferedToken = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tokenToReturn = NextImpl();
|
||||||
|
}
|
||||||
|
if (tokenToReturn.Type == JsonToken.TokenType.StartObject)
|
||||||
|
{
|
||||||
|
ObjectDepth++;
|
||||||
|
}
|
||||||
|
else if (tokenToReturn.Type == JsonToken.TokenType.EndObject)
|
||||||
|
{
|
||||||
|
ObjectDepth--;
|
||||||
|
}
|
||||||
|
return tokenToReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the next JSON token in the stream, when requested by the base class. (The <see cref="Next"/> method delegates
|
||||||
|
/// to this if it doesn't have a buffered token.)
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
|
||||||
|
/// <exception cref="InvalidJsonException">The input text does not comply with RFC 7159</exception>
|
||||||
|
protected abstract JsonToken NextImpl();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tokenizer which first exhausts a list of tokens, then consults another tokenizer.
|
||||||
|
/// </summary>
|
||||||
|
private class JsonReplayTokenizer : JsonTokenizer
|
||||||
|
{
|
||||||
|
private readonly IList<JsonToken> tokens;
|
||||||
|
private readonly JsonTokenizer nextTokenizer;
|
||||||
|
private int nextTokenIndex;
|
||||||
|
|
||||||
|
internal JsonReplayTokenizer(IList<JsonToken> tokens, JsonTokenizer nextTokenizer)
|
||||||
|
{
|
||||||
|
this.tokens = tokens;
|
||||||
|
this.nextTokenizer = nextTokenizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Object depth not maintained...
|
||||||
|
protected override JsonToken NextImpl()
|
||||||
|
{
|
||||||
|
if (nextTokenIndex >= tokens.Count)
|
||||||
|
{
|
||||||
|
return nextTokenizer.Next();
|
||||||
|
}
|
||||||
|
return tokens[nextTokenIndex++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tokenizer which does all the *real* work of parsing JSON.
|
||||||
|
/// </summary>
|
||||||
|
private sealed class JsonTextTokenizer : JsonTokenizer
|
||||||
|
{
|
||||||
|
// The set of states in which a value is valid next token.
|
||||||
|
private static readonly State ValueStates = State.ArrayStart | State.ArrayAfterComma | State.ObjectAfterColon | State.StartOfDocument;
|
||||||
|
|
||||||
|
private readonly Stack<ContainerType> containerStack = new Stack<ContainerType>();
|
||||||
|
private readonly PushBackReader reader;
|
||||||
|
private State state;
|
||||||
|
|
||||||
|
internal JsonTextTokenizer(TextReader reader)
|
||||||
|
{
|
||||||
|
this.reader = new PushBackReader(reader);
|
||||||
|
state = State.StartOfDocument;
|
||||||
|
containerStack.Push(ContainerType.Document);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// This method essentially just loops through characters skipping whitespace, validating and
|
||||||
|
/// changing state (e.g. from ObjectBeforeColon to ObjectAfterColon)
|
||||||
|
/// until it reaches something which will be a genuine token (e.g. a start object, or a value) at which point
|
||||||
|
/// it returns the token. Although the method is large, it would be relatively hard to break down further... most
|
||||||
|
/// of it is the large switch statement, which sometimes returns and sometimes doesn't.
|
||||||
|
/// </remarks>
|
||||||
|
protected override JsonToken NextImpl()
|
||||||
|
{
|
||||||
|
if (state == State.ReaderExhausted)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Next() called after end of document");
|
||||||
|
}
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var next = reader.Read();
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
ValidateState(State.ExpectedEndOfDocument, "Unexpected end of document in state: ");
|
||||||
|
state = State.ReaderExhausted;
|
||||||
|
return JsonToken.EndDocument;
|
||||||
|
}
|
||||||
|
switch (next.Value)
|
||||||
|
{
|
||||||
|
// Skip whitespace between tokens
|
||||||
|
case ' ':
|
||||||
|
case '\t':
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
ValidateState(State.ObjectBeforeColon, "Invalid state to read a colon: ");
|
||||||
|
state = State.ObjectAfterColon;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
ValidateState(State.ObjectAfterProperty | State.ArrayAfterValue, "Invalid state to read a colon: ");
|
||||||
|
state = state == State.ObjectAfterProperty ? State.ObjectAfterComma : State.ArrayAfterComma;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
string stringValue = ReadString();
|
||||||
|
if ((state & (State.ObjectStart | State.ObjectAfterComma)) != 0)
|
||||||
|
{
|
||||||
|
state = State.ObjectBeforeColon;
|
||||||
|
return JsonToken.Name(stringValue);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
|
||||||
|
return JsonToken.Value(stringValue);
|
||||||
|
}
|
||||||
|
case '{':
|
||||||
|
ValidateState(ValueStates, "Invalid state to read an open brace: ");
|
||||||
|
state = State.ObjectStart;
|
||||||
|
containerStack.Push(ContainerType.Object);
|
||||||
|
return JsonToken.StartObject;
|
||||||
|
case '}':
|
||||||
|
ValidateState(State.ObjectAfterProperty | State.ObjectStart, "Invalid state to read a close brace: ");
|
||||||
|
PopContainer();
|
||||||
|
return JsonToken.EndObject;
|
||||||
|
case '[':
|
||||||
|
ValidateState(ValueStates, "Invalid state to read an open square bracket: ");
|
||||||
|
state = State.ArrayStart;
|
||||||
|
containerStack.Push(ContainerType.Array);
|
||||||
|
return JsonToken.StartArray;
|
||||||
|
case ']':
|
||||||
|
ValidateState(State.ArrayAfterValue | State.ArrayStart, "Invalid state to read a close square bracket: ");
|
||||||
|
PopContainer();
|
||||||
|
return JsonToken.EndArray;
|
||||||
|
case 'n': // Start of null
|
||||||
|
ConsumeLiteral("null");
|
||||||
|
ValidateAndModifyStateForValue("Invalid state to read a null literal: ");
|
||||||
|
return JsonToken.Null;
|
||||||
|
case 't': // Start of true
|
||||||
|
ConsumeLiteral("true");
|
||||||
|
ValidateAndModifyStateForValue("Invalid state to read a true literal: ");
|
||||||
|
return JsonToken.True;
|
||||||
|
case 'f': // Start of false
|
||||||
|
ConsumeLiteral("false");
|
||||||
|
ValidateAndModifyStateForValue("Invalid state to read a false literal: ");
|
||||||
|
return JsonToken.False;
|
||||||
|
case '-': // Start of a number
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
double number = ReadNumber(next.Value);
|
||||||
|
ValidateAndModifyStateForValue("Invalid state to read a number token: ");
|
||||||
|
return JsonToken.Value(number);
|
||||||
|
default:
|
||||||
|
throw new InvalidJsonException("Invalid first character of token: " + next.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ValidateState(State validStates, string errorPrefix)
|
||||||
|
{
|
||||||
|
if ((validStates & state) == 0)
|
||||||
|
{
|
||||||
|
throw reader.CreateException(errorPrefix + state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a string token. It is assumed that the opening " has already been read.
|
||||||
|
/// </summary>
|
||||||
|
private string ReadString()
|
||||||
|
{
|
||||||
|
var value = new StringBuilder();
|
||||||
|
bool haveHighSurrogate = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char c = reader.ReadOrFail("Unexpected end of text while reading string");
|
||||||
|
if (c < ' ')
|
||||||
|
{
|
||||||
|
throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in string literal: U+{0:x4}", (int) c));
|
||||||
|
}
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
if (haveHighSurrogate)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid use of surrogate pair code units");
|
||||||
|
}
|
||||||
|
return value.ToString();
|
||||||
|
}
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
c = ReadEscapedCharacter();
|
||||||
|
}
|
||||||
|
// TODO: Consider only allowing surrogate pairs that are either both escaped,
|
||||||
|
// or both not escaped. It would be a very odd text stream that contained a "lone" high surrogate
|
||||||
|
// followed by an escaped low surrogate or vice versa... and that couldn't even be represented in UTF-8.
|
||||||
|
if (haveHighSurrogate != char.IsLowSurrogate(c))
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid use of surrogate pair code units");
|
||||||
|
}
|
||||||
|
haveHighSurrogate = char.IsHighSurrogate(c);
|
||||||
|
value.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an escaped character. It is assumed that the leading backslash has already been read.
|
||||||
|
/// </summary>
|
||||||
|
private char ReadEscapedCharacter()
|
||||||
|
{
|
||||||
|
char c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence");
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'n':
|
||||||
|
return '\n';
|
||||||
|
case '\\':
|
||||||
|
return '\\';
|
||||||
|
case 'b':
|
||||||
|
return '\b';
|
||||||
|
case 'f':
|
||||||
|
return '\f';
|
||||||
|
case 'r':
|
||||||
|
return '\r';
|
||||||
|
case 't':
|
||||||
|
return '\t';
|
||||||
|
case '"':
|
||||||
|
return '"';
|
||||||
|
case '/':
|
||||||
|
return '/';
|
||||||
|
case 'u':
|
||||||
|
return ReadUnicodeEscape();
|
||||||
|
default:
|
||||||
|
throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an escaped Unicode 4-nybble hex sequence. It is assumed that the leading \u has already been read.
|
||||||
|
/// </summary>
|
||||||
|
private char ReadUnicodeEscape()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
char c = reader.ReadOrFail("Unexpected end of text while reading Unicode escape sequence");
|
||||||
|
int nybble;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
nybble = c - '0';
|
||||||
|
}
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
{
|
||||||
|
nybble = c - 'a' + 10;
|
||||||
|
}
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
{
|
||||||
|
nybble = c - 'A' + 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
|
||||||
|
}
|
||||||
|
result = (result << 4) + nybble;
|
||||||
|
}
|
||||||
|
return (char) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Consumes a text-only literal, throwing an exception if the read text doesn't match it.
|
||||||
|
/// It is assumed that the first letter of the literal has already been read.
|
||||||
|
/// </summary>
|
||||||
|
private void ConsumeLiteral(string text)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
char? next = reader.Read();
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Unexpected end of text while reading literal token " + text);
|
||||||
|
}
|
||||||
|
if (next.Value != text[i])
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Unexpected character while reading literal token " + text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double ReadNumber(char initialCharacter)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if (initialCharacter == '-')
|
||||||
|
{
|
||||||
|
builder.Append("-");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reader.PushBack(initialCharacter);
|
||||||
|
}
|
||||||
|
// Each method returns the character it read that doesn't belong in that part,
|
||||||
|
// so we know what to do next, including pushing the character back at the end.
|
||||||
|
// null is returned for "end of text".
|
||||||
|
char? next = ReadInt(builder);
|
||||||
|
if (next == '.')
|
||||||
|
{
|
||||||
|
next = ReadFrac(builder);
|
||||||
|
}
|
||||||
|
if (next == 'e' || next == 'E')
|
||||||
|
{
|
||||||
|
next = ReadExp(builder);
|
||||||
|
}
|
||||||
|
// If we read a character which wasn't part of the number, push it back so we can read it again
|
||||||
|
// to parse the next token.
|
||||||
|
if (next != null)
|
||||||
|
{
|
||||||
|
reader.PushBack(next.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: What exception should we throw if the value can't be represented as a double?
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return double.Parse(builder.ToString(),
|
||||||
|
NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
|
||||||
|
CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
catch (OverflowException)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Numeric value out of range: " + builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private char? ReadInt(StringBuilder builder)
|
||||||
|
{
|
||||||
|
char first = reader.ReadOrFail("Invalid numeric literal");
|
||||||
|
if (first < '0' || first > '9')
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid numeric literal");
|
||||||
|
}
|
||||||
|
builder.Append(first);
|
||||||
|
int digitCount;
|
||||||
|
char? next = ConsumeDigits(builder, out digitCount);
|
||||||
|
if (first == '0' && digitCount != 0)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.");
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char? ReadFrac(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append('.'); // Already consumed this
|
||||||
|
int digitCount;
|
||||||
|
char? next = ConsumeDigits(builder, out digitCount);
|
||||||
|
if (digitCount == 0)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits");
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char? ReadExp(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Append('E'); // Already consumed this (or 'e')
|
||||||
|
char? next = reader.Read();
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid numeric literal: exponent with no trailing digits");
|
||||||
|
}
|
||||||
|
if (next == '-' || next == '+')
|
||||||
|
{
|
||||||
|
builder.Append(next.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reader.PushBack(next.Value);
|
||||||
|
}
|
||||||
|
int digitCount;
|
||||||
|
next = ConsumeDigits(builder, out digitCount);
|
||||||
|
if (digitCount == 0)
|
||||||
|
{
|
||||||
|
throw reader.CreateException("Invalid numeric literal: exponent without value");
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
private char? ConsumeDigits(StringBuilder builder, out int count)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
char? next = reader.Read();
|
||||||
|
if (next == null || next.Value < '0' || next.Value > '9')
|
||||||
|
{
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
builder.Append(next.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates that we're in a valid state to read a value (using the given error prefix if necessary)
|
||||||
|
/// and changes the state to the appropriate one, e.g. ObjectAfterColon to ObjectAfterProperty.
|
||||||
|
/// </summary>
|
||||||
|
private void ValidateAndModifyStateForValue(string errorPrefix)
|
||||||
|
{
|
||||||
|
ValidateState(ValueStates, errorPrefix);
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case State.StartOfDocument:
|
||||||
|
state = State.ExpectedEndOfDocument;
|
||||||
|
return;
|
||||||
|
case State.ObjectAfterColon:
|
||||||
|
state = State.ObjectAfterProperty;
|
||||||
|
return;
|
||||||
|
case State.ArrayStart:
|
||||||
|
case State.ArrayAfterComma:
|
||||||
|
state = State.ArrayAfterValue;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("ValidateAndModifyStateForValue does not handle all value states (and should)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pops the top-most container, and sets the state to the appropriate one for the end of a value
|
||||||
|
/// in the parent container.
|
||||||
|
/// </summary>
|
||||||
|
private void PopContainer()
|
||||||
|
{
|
||||||
|
containerStack.Pop();
|
||||||
|
var parent = containerStack.Peek();
|
||||||
|
switch (parent)
|
||||||
|
{
|
||||||
|
case ContainerType.Object:
|
||||||
|
state = State.ObjectAfterProperty;
|
||||||
|
break;
|
||||||
|
case ContainerType.Array:
|
||||||
|
state = State.ArrayAfterValue;
|
||||||
|
break;
|
||||||
|
case ContainerType.Document:
|
||||||
|
state = State.ExpectedEndOfDocument;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException("Unexpected container type: " + parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ContainerType
|
||||||
|
{
|
||||||
|
Document, Object, Array
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Possible states of the tokenizer.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>This is a flags enum purely so we can simply and efficiently represent a set of valid states
|
||||||
|
/// for checking.</para>
|
||||||
|
/// <para>
|
||||||
|
/// Each is documented with an example,
|
||||||
|
/// where ^ represents the current position within the text stream. The examples all use string values,
|
||||||
|
/// but could be any value, including nested objects/arrays.
|
||||||
|
/// The complete state of the tokenizer also includes a stack to indicate the contexts (arrays/objects).
|
||||||
|
/// Any additional notional state of "AfterValue" indicates that a value has been completed, at which
|
||||||
|
/// point there's an immediate transition to ExpectedEndOfDocument, ObjectAfterProperty or ArrayAfterValue.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// These states were derived manually by reading RFC 7159 carefully.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[Flags]
|
||||||
|
private enum State
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ^ { "foo": "bar" }
|
||||||
|
/// Before the value in a document. Next states: ObjectStart, ArrayStart, "AfterValue"
|
||||||
|
/// </summary>
|
||||||
|
StartOfDocument = 1 << 0,
|
||||||
|
/// <summary>
|
||||||
|
/// { "foo": "bar" } ^
|
||||||
|
/// After the value in a document. Next states: ReaderExhausted
|
||||||
|
/// </summary>
|
||||||
|
ExpectedEndOfDocument = 1 << 1,
|
||||||
|
/// <summary>
|
||||||
|
/// { "foo": "bar" } ^ (and already read to the end of the reader)
|
||||||
|
/// Terminal state.
|
||||||
|
/// </summary>
|
||||||
|
ReaderExhausted = 1 << 2,
|
||||||
|
/// <summary>
|
||||||
|
/// { ^ "foo": "bar" }
|
||||||
|
/// Before the *first* property in an object.
|
||||||
|
/// Next states:
|
||||||
|
/// "AfterValue" (empty object)
|
||||||
|
/// ObjectBeforeColon (read a name)
|
||||||
|
/// </summary>
|
||||||
|
ObjectStart = 1 << 3,
|
||||||
|
/// <summary>
|
||||||
|
/// { "foo" ^ : "bar", "x": "y" }
|
||||||
|
/// Next state: ObjectAfterColon
|
||||||
|
/// </summary>
|
||||||
|
ObjectBeforeColon = 1 << 4,
|
||||||
|
/// <summary>
|
||||||
|
/// { "foo" : ^ "bar", "x": "y" }
|
||||||
|
/// Before any property other than the first in an object.
|
||||||
|
/// (Equivalently: after any property in an object)
|
||||||
|
/// Next states:
|
||||||
|
/// "AfterValue" (value is simple)
|
||||||
|
/// ObjectStart (value is object)
|
||||||
|
/// ArrayStart (value is array)
|
||||||
|
/// </summary>
|
||||||
|
ObjectAfterColon = 1 << 5,
|
||||||
|
/// <summary>
|
||||||
|
/// { "foo" : "bar" ^ , "x" : "y" }
|
||||||
|
/// At the end of a property, so expecting either a comma or end-of-object
|
||||||
|
/// Next states: ObjectAfterComma or "AfterValue"
|
||||||
|
/// </summary>
|
||||||
|
ObjectAfterProperty = 1 << 6,
|
||||||
|
/// <summary>
|
||||||
|
/// { "foo":"bar", ^ "x":"y" }
|
||||||
|
/// Read the comma after the previous property, so expecting another property.
|
||||||
|
/// This is like ObjectStart, but closing brace isn't valid here
|
||||||
|
/// Next state: ObjectBeforeColon.
|
||||||
|
/// </summary>
|
||||||
|
ObjectAfterComma = 1 << 7,
|
||||||
|
/// <summary>
|
||||||
|
/// [ ^ "foo", "bar" ]
|
||||||
|
/// Before the *first* value in an array.
|
||||||
|
/// Next states:
|
||||||
|
/// "AfterValue" (read a value)
|
||||||
|
/// "AfterValue" (end of array; will pop stack)
|
||||||
|
/// </summary>
|
||||||
|
ArrayStart = 1 << 8,
|
||||||
|
/// <summary>
|
||||||
|
/// [ "foo" ^ , "bar" ]
|
||||||
|
/// After any value in an array, so expecting either a comma or end-of-array
|
||||||
|
/// Next states: ArrayAfterComma or "AfterValue"
|
||||||
|
/// </summary>
|
||||||
|
ArrayAfterValue = 1 << 9,
|
||||||
|
/// <summary>
|
||||||
|
/// [ "foo", ^ "bar" ]
|
||||||
|
/// After a comma in an array, so there *must* be another value (simple or complex).
|
||||||
|
/// Next states: "AfterValue" (simple value), StartObject, StartArray
|
||||||
|
/// </summary>
|
||||||
|
ArrayAfterComma = 1 << 10
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wrapper around a text reader allowing small amounts of buffering and location handling.
|
||||||
|
/// </summary>
|
||||||
|
private class PushBackReader
|
||||||
|
{
|
||||||
|
// TODO: Add locations for errors etc.
|
||||||
|
|
||||||
|
private readonly TextReader reader;
|
||||||
|
|
||||||
|
internal PushBackReader(TextReader reader)
|
||||||
|
{
|
||||||
|
// TODO: Wrap the reader in a BufferedReader?
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffered next character, if we have one.
|
||||||
|
/// </summary>
|
||||||
|
private char? nextChar;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the next character in the stream, or null if we have reached the end.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
internal char? Read()
|
||||||
|
{
|
||||||
|
if (nextChar != null)
|
||||||
|
{
|
||||||
|
char? tmp = nextChar;
|
||||||
|
nextChar = null;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
int next = reader.Read();
|
||||||
|
return next == -1 ? null : (char?) next;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal char ReadOrFail(string messageOnFailure)
|
||||||
|
{
|
||||||
|
char? next = Read();
|
||||||
|
if (next == null)
|
||||||
|
{
|
||||||
|
throw CreateException(messageOnFailure);
|
||||||
|
}
|
||||||
|
return next.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PushBack(char c)
|
||||||
|
{
|
||||||
|
if (nextChar != null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Cannot push back when already buffering a character");
|
||||||
|
}
|
||||||
|
nextChar = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new exception appropriate for the current state of the reader.
|
||||||
|
/// </summary>
|
||||||
|
internal InvalidJsonException CreateException(string message)
|
||||||
|
{
|
||||||
|
// TODO: Keep track of and use the location.
|
||||||
|
return new InvalidJsonException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stream implementation which proxies another stream, only allowing a certain amount
|
||||||
|
/// of data to be read. Note that this is only used to read delimited streams, so it
|
||||||
|
/// doesn't attempt to implement everything.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class LimitedInputStream : Stream
|
||||||
|
{
|
||||||
|
private readonly Stream proxied;
|
||||||
|
private int bytesLeft;
|
||||||
|
|
||||||
|
internal LimitedInputStream(Stream proxied, int size)
|
||||||
|
{
|
||||||
|
this.proxied = proxied;
|
||||||
|
bytesLeft = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
set { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (bytesLeft > 0)
|
||||||
|
{
|
||||||
|
int bytesRead = proxied.Read(buffer, offset, Math.Min(bytesLeft, count));
|
||||||
|
bytesLeft -= bytesRead;
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods on <see cref="IMessage"/> and <see cref="IMessage{T}"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class MessageExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Merges data from the given byte array into an existing message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to merge the data into.</param>
|
||||||
|
/// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
|
||||||
|
public static void MergeFrom(this IMessage message, byte[] data)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
ProtoPreconditions.CheckNotNull(data, "data");
|
||||||
|
CodedInputStream input = new CodedInputStream(data);
|
||||||
|
message.MergeFrom(input);
|
||||||
|
input.CheckReadEndOfStreamTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Merges data from the given byte string into an existing message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to merge the data into.</param>
|
||||||
|
/// <param name="data">The data to merge, which must be protobuf-encoded binary data.</param>
|
||||||
|
public static void MergeFrom(this IMessage message, ByteString data)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
ProtoPreconditions.CheckNotNull(data, "data");
|
||||||
|
CodedInputStream input = data.CreateCodedInput();
|
||||||
|
message.MergeFrom(input);
|
||||||
|
input.CheckReadEndOfStreamTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Merges data from the given stream into an existing message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to merge the data into.</param>
|
||||||
|
/// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
|
||||||
|
public static void MergeFrom(this IMessage message, Stream input)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
ProtoPreconditions.CheckNotNull(input, "input");
|
||||||
|
CodedInputStream codedInput = new CodedInputStream(input);
|
||||||
|
message.MergeFrom(codedInput);
|
||||||
|
codedInput.CheckReadEndOfStreamTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Merges length-delimited data from the given stream into an existing message.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The stream is expected to contain a length and then the data. Only the amount of data
|
||||||
|
/// specified by the length will be consumed.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="message">The message to merge the data into.</param>
|
||||||
|
/// <param name="input">Stream containing the data to merge, which must be protobuf-encoded binary data.</param>
|
||||||
|
public static void MergeDelimitedFrom(this IMessage message, Stream input)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
ProtoPreconditions.CheckNotNull(input, "input");
|
||||||
|
int size = (int) CodedInputStream.ReadRawVarint32(input);
|
||||||
|
Stream limitedStream = new LimitedInputStream(input, size);
|
||||||
|
message.MergeFrom(limitedStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given message into a byte array in protobuf encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to convert.</param>
|
||||||
|
/// <returns>The message data as a byte array.</returns>
|
||||||
|
public static byte[] ToByteArray(this IMessage message)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
byte[] result = new byte[message.CalculateSize()];
|
||||||
|
CodedOutputStream output = new CodedOutputStream(result);
|
||||||
|
message.WriteTo(output);
|
||||||
|
output.CheckNoSpaceLeft();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the given message data to the given stream in protobuf encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to write to the stream.</param>
|
||||||
|
/// <param name="output">The stream to write to.</param>
|
||||||
|
public static void WriteTo(this IMessage message, Stream output)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
ProtoPreconditions.CheckNotNull(output, "output");
|
||||||
|
CodedOutputStream codedOutput = new CodedOutputStream(output);
|
||||||
|
message.WriteTo(codedOutput);
|
||||||
|
codedOutput.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the length and then data of the given message to a stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to write.</param>
|
||||||
|
/// <param name="output">The output stream to write to.</param>
|
||||||
|
public static void WriteDelimitedTo(this IMessage message, Stream output)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
ProtoPreconditions.CheckNotNull(output, "output");
|
||||||
|
CodedOutputStream codedOutput = new CodedOutputStream(output);
|
||||||
|
codedOutput.WriteRawVarint32((uint)message.CalculateSize());
|
||||||
|
message.WriteTo(codedOutput);
|
||||||
|
codedOutput.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given message into a byte string in protobuf encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to convert.</param>
|
||||||
|
/// <returns>The message data as a byte string.</returns>
|
||||||
|
public static ByteString ToByteString(this IMessage message)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, "message");
|
||||||
|
return ByteString.AttachBytes(message.ToByteArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A general message parser, typically used by reflection-based code as all the methods
|
||||||
|
/// return simple <see cref="IMessage"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class MessageParser
|
||||||
|
{
|
||||||
|
private Func<IMessage> factory;
|
||||||
|
|
||||||
|
internal MessageParser(Func<IMessage> factory)
|
||||||
|
{
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a template instance ready for population.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An empty message.</returns>
|
||||||
|
internal IMessage CreateTemplate()
|
||||||
|
{
|
||||||
|
return factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from a byte array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The byte array containing the message. Must not be null.</param>
|
||||||
|
/// <returns>The newly parsed message.</returns>
|
||||||
|
public IMessage ParseFrom(byte[] data)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(data, "data");
|
||||||
|
IMessage message = factory();
|
||||||
|
message.MergeFrom(data);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given byte string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The data to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public IMessage ParseFrom(ByteString data)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(data, "data");
|
||||||
|
IMessage message = factory();
|
||||||
|
message.MergeFrom(data);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The stream to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public IMessage ParseFrom(Stream input)
|
||||||
|
{
|
||||||
|
IMessage message = factory();
|
||||||
|
message.MergeFrom(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a length-delimited message from the given stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The stream is expected to contain a length and then the data. Only the amount of data
|
||||||
|
/// specified by the length will be consumed.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="input">The stream to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public IMessage ParseDelimitedFrom(Stream input)
|
||||||
|
{
|
||||||
|
IMessage message = factory();
|
||||||
|
message.MergeDelimitedFrom(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given coded input stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The stream to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public IMessage ParseFrom(CodedInputStream input)
|
||||||
|
{
|
||||||
|
IMessage message = factory();
|
||||||
|
message.MergeFrom(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">The JSON to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
/// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
|
||||||
|
/// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
|
||||||
|
public IMessage ParseJson(string json)
|
||||||
|
{
|
||||||
|
IMessage message = factory();
|
||||||
|
JsonParser.Default.Merge(message, json);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A parser for a specific message type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <p>
|
||||||
|
/// This delegates most behavior to the
|
||||||
|
/// <see cref="IMessage.MergeFrom"/> implementation within the original type, but
|
||||||
|
/// provides convenient overloads to parse from a variety of sources.
|
||||||
|
/// </p>
|
||||||
|
/// <p>
|
||||||
|
/// Most applications will never need to create their own instances of this type;
|
||||||
|
/// instead, use the static <c>Parser</c> property of a generated message type to obtain a
|
||||||
|
/// parser for that type.
|
||||||
|
/// </p>
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The type of message to be parsed.</typeparam>
|
||||||
|
public sealed class MessageParser<T> : MessageParser where T : IMessage<T>
|
||||||
|
{
|
||||||
|
// Implementation note: all the methods here *could* just delegate up to the base class and cast the result.
|
||||||
|
// The current implementation avoids a virtual method call and a cast, which *may* be significant in some cases.
|
||||||
|
// Benchmarking work is required to measure the significance - but it's only a few lines of code in any case.
|
||||||
|
// The API wouldn't change anyway - just the implementation - so this work can be deferred.
|
||||||
|
private readonly Func<T> factory;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new parser.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The factory method is effectively an optimization over using a generic constraint
|
||||||
|
/// to require a parameterless constructor: delegates are significantly faster to execute.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="factory">Function to invoke when a new, empty message is required.</param>
|
||||||
|
public MessageParser(Func<T> factory) : base(() => factory())
|
||||||
|
{
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a template instance ready for population.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An empty message.</returns>
|
||||||
|
internal new T CreateTemplate()
|
||||||
|
{
|
||||||
|
return factory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from a byte array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The byte array containing the message. Must not be null.</param>
|
||||||
|
/// <returns>The newly parsed message.</returns>
|
||||||
|
public new T ParseFrom(byte[] data)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(data, "data");
|
||||||
|
T message = factory();
|
||||||
|
message.MergeFrom(data);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given byte string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The data to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public new T ParseFrom(ByteString data)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(data, "data");
|
||||||
|
T message = factory();
|
||||||
|
message.MergeFrom(data);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The stream to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public new T ParseFrom(Stream input)
|
||||||
|
{
|
||||||
|
T message = factory();
|
||||||
|
message.MergeFrom(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a length-delimited message from the given stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The stream is expected to contain a length and then the data. Only the amount of data
|
||||||
|
/// specified by the length will be consumed.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="input">The stream to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public new T ParseDelimitedFrom(Stream input)
|
||||||
|
{
|
||||||
|
T message = factory();
|
||||||
|
message.MergeDelimitedFrom(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given coded input stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The stream to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
public new T ParseFrom(CodedInputStream input)
|
||||||
|
{
|
||||||
|
T message = factory();
|
||||||
|
message.MergeFrom(input);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a message from the given JSON.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">The JSON to parse.</param>
|
||||||
|
/// <returns>The parsed message.</returns>
|
||||||
|
/// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
|
||||||
|
/// <exception cref="InvalidProtocolBufferException">The JSON does not represent a Protocol Buffers message correctly</exception>
|
||||||
|
public new T ParseJson(string json)
|
||||||
|
{
|
||||||
|
T message = factory();
|
||||||
|
JsonParser.Default.Merge(message, json);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Security;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
|
||||||
|
#if !NCRUNCH
|
||||||
|
[assembly: AllowPartiallyTrustedCallers]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("Google.Protobuf.Test, PublicKey=" +
|
||||||
|
"002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" +
|
||||||
|
"7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" +
|
||||||
|
"981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" +
|
||||||
|
"b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" +
|
||||||
|
"c5ae9cb6")]
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper methods for throwing exceptions when preconditions are not met.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class is used internally and by generated code; it is not particularly
|
||||||
|
/// expected to be used from application code, although nothing prevents it
|
||||||
|
/// from being used that way.
|
||||||
|
/// </remarks>
|
||||||
|
public static class ProtoPreconditions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an ArgumentNullException if the given value is null, otherwise
|
||||||
|
/// return the value to the caller.
|
||||||
|
/// </summary>
|
||||||
|
public static T CheckNotNull<T>(T value, string name) where T : class
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(name);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Throws an ArgumentNullException if the given value is null, otherwise
|
||||||
|
/// return the value to the caller.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is equivalent to <see cref="CheckNotNull{T}(T, string)"/> but without the type parameter
|
||||||
|
/// constraint. In most cases, the constraint is useful to prevent you from calling CheckNotNull
|
||||||
|
/// with a value type - but it gets in the way if either you want to use it with a nullable
|
||||||
|
/// value type, or you want to use it with an unconstrained type parameter.
|
||||||
|
/// </remarks>
|
||||||
|
internal static T CheckNotNullUnconstrained<T>(T value, string name)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(name);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Container for a set of custom options specified within a message, field etc.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This type is publicly immutable, but internally mutable. It is only populated
|
||||||
|
/// by the descriptor parsing code - by the time any user code is able to see an instance,
|
||||||
|
/// it will be fully initialized.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// If an option is requested using the incorrect method, an answer may still be returned: all
|
||||||
|
/// of the numeric types are represented internally using 64-bit integers, for example. It is up to
|
||||||
|
/// the caller to ensure that they make the appropriate method call for the option they're interested in.
|
||||||
|
/// Note that enum options are simply stored as integers, so the value should be fetched using
|
||||||
|
/// <see cref="TryGetInt32(int, out int)"/> and then cast appropriately.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Repeated options are currently not supported. Asking for a single value of an option
|
||||||
|
/// which was actually repeated will return the last value, except for message types where
|
||||||
|
/// all the set values are merged together.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class CustomOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Singleton for all descriptors with an empty set of options.
|
||||||
|
/// </summary>
|
||||||
|
internal static readonly CustomOptions Empty = new CustomOptions();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A sequence of values per field. This needs to be per field rather than per tag to allow correct deserialization
|
||||||
|
/// of repeated fields which could be "int, ByteString, int" - unlikely as that is. The fact that values are boxed
|
||||||
|
/// is unfortunate; we might be able to use a struct instead, and we could combine uint and ulong values.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Dictionary<int, List<FieldValue>> valuesByField = new Dictionary<int, List<FieldValue>>();
|
||||||
|
|
||||||
|
private CustomOptions() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a Boolean value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetBool(int field, out bool value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = tmp == 1UL;
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a signed 32-bit integer value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetInt32(int field, out int value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = (int) tmp.GetValueOrDefault();
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a signed 64-bit integer value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetInt64(int field, out long value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = (long) tmp.GetValueOrDefault();
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves an unsigned 32-bit integer value for the specified option field,
|
||||||
|
/// assuming a fixed-length representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetFixed32(int field, out uint value) => TryGetUInt32(field, out value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves an unsigned 64-bit integer value for the specified option field,
|
||||||
|
/// assuming a fixed-length representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetFixed64(int field, out ulong value) => TryGetUInt64(field, out value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a signed 32-bit integer value for the specified option field,
|
||||||
|
/// assuming a fixed-length representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetSFixed32(int field, out int value) => TryGetInt32(field, out value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a signed 64-bit integer value for the specified option field,
|
||||||
|
/// assuming a fixed-length representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetSFixed64(int field, out long value) => TryGetInt64(field, out value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a signed 32-bit integer value for the specified option field,
|
||||||
|
/// assuming a zigzag encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetSInt32(int field, out int value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = CodedInputStream.DecodeZigZag32((uint) tmp.GetValueOrDefault());
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a signed 64-bit integer value for the specified option field,
|
||||||
|
/// assuming a zigzag encoding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetSInt64(int field, out long value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = CodedInputStream.DecodeZigZag64(tmp.GetValueOrDefault());
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves an unsigned 32-bit integer value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetUInt32(int field, out uint value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = (uint) tmp.GetValueOrDefault();
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves an unsigned 64-bit integer value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetUInt64(int field, out ulong value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = tmp.GetValueOrDefault();
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a 32-bit floating point value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetFloat(int field, out float value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
int int32 = (int) tmp.GetValueOrDefault();
|
||||||
|
byte[] bytes = BitConverter.GetBytes(int32);
|
||||||
|
value = BitConverter.ToSingle(bytes, 0);
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a 64-bit floating point value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetDouble(int field, out double value)
|
||||||
|
{
|
||||||
|
ulong? tmp = GetLastNumericValue(field);
|
||||||
|
value = BitConverter.Int64BitsToDouble((long) tmp.GetValueOrDefault());
|
||||||
|
return tmp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a string value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetString(int field, out string value)
|
||||||
|
{
|
||||||
|
ByteString bytes = GetLastByteStringValue(field);
|
||||||
|
value = bytes?.ToStringUtf8();
|
||||||
|
return bytes != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a bytes value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetBytes(int field, out ByteString value)
|
||||||
|
{
|
||||||
|
ByteString bytes = GetLastByteStringValue(field);
|
||||||
|
value = bytes;
|
||||||
|
return bytes != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves a message value for the specified option field.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="field">The field to fetch the value for.</param>
|
||||||
|
/// <param name="value">The output variable to populate.</param>
|
||||||
|
/// <returns><c>true</c> if a suitable value for the field was found; <c>false</c> otherwise.</returns>
|
||||||
|
public bool TryGetMessage<T>(int field, out T value) where T : class, IMessage, new()
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
List<FieldValue> values;
|
||||||
|
if (!valuesByField.TryGetValue(field, out values))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (FieldValue fieldValue in values)
|
||||||
|
{
|
||||||
|
if (fieldValue.ByteString != null)
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
value = new T();
|
||||||
|
}
|
||||||
|
value.MergeFrom(fieldValue.ByteString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong? GetLastNumericValue(int field)
|
||||||
|
{
|
||||||
|
List<FieldValue> values;
|
||||||
|
if (!valuesByField.TryGetValue(field, out values))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = values.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
// A non-bytestring value is a numeric value
|
||||||
|
if (values[i].ByteString == null)
|
||||||
|
{
|
||||||
|
return values[i].Number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteString GetLastByteStringValue(int field)
|
||||||
|
{
|
||||||
|
List<FieldValue> values;
|
||||||
|
if (!valuesByField.TryGetValue(field, out values))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (int i = values.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (values[i].ByteString != null)
|
||||||
|
{
|
||||||
|
return values[i].ByteString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads an unknown field, either parsing it and storing it or skipping it.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the current set of options is empty and we manage to read a field, a new set of options
|
||||||
|
/// will be created and returned. Otherwise, the return value is <c>this</c>. This allows
|
||||||
|
/// us to start with a singleton empty set of options and just create new ones where necessary.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="input">Input stream to read from. </param>
|
||||||
|
/// <returns>The resulting set of custom options, either <c>this</c> or a new set.</returns>
|
||||||
|
internal CustomOptions ReadOrSkipUnknownField(CodedInputStream input)
|
||||||
|
{
|
||||||
|
var tag = input.LastTag;
|
||||||
|
var field = WireFormat.GetTagFieldNumber(tag);
|
||||||
|
switch (WireFormat.GetTagWireType(tag))
|
||||||
|
{
|
||||||
|
case WireFormat.WireType.LengthDelimited:
|
||||||
|
return AddValue(field, new FieldValue(input.ReadBytes()));
|
||||||
|
case WireFormat.WireType.Fixed32:
|
||||||
|
return AddValue(field, new FieldValue(input.ReadFixed32()));
|
||||||
|
case WireFormat.WireType.Fixed64:
|
||||||
|
return AddValue(field, new FieldValue(input.ReadFixed64()));
|
||||||
|
case WireFormat.WireType.Varint:
|
||||||
|
return AddValue(field, new FieldValue(input.ReadRawVarint64()));
|
||||||
|
// For StartGroup, EndGroup or any wire format we don't understand,
|
||||||
|
// just use the normal behavior (call SkipLastField).
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CustomOptions AddValue(int field, FieldValue value)
|
||||||
|
{
|
||||||
|
var ret = valuesByField.Count == 0 ? new CustomOptions() : this;
|
||||||
|
List<FieldValue> valuesForField;
|
||||||
|
if (!ret.valuesByField.TryGetValue(field, out valuesForField))
|
||||||
|
{
|
||||||
|
// Expect almost all
|
||||||
|
valuesForField = new List<FieldValue>(1);
|
||||||
|
ret.valuesByField[field] = valuesForField;
|
||||||
|
}
|
||||||
|
valuesForField.Add(value);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All field values can be stored as a byte string or a 64-bit integer.
|
||||||
|
/// This struct avoids unnecessary boxing.
|
||||||
|
/// </summary>
|
||||||
|
private struct FieldValue
|
||||||
|
{
|
||||||
|
internal ulong Number { get; }
|
||||||
|
internal ByteString ByteString { get; }
|
||||||
|
|
||||||
|
internal FieldValue(ulong number)
|
||||||
|
{
|
||||||
|
Number = number;
|
||||||
|
ByteString = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal FieldValue(ByteString byteString)
|
||||||
|
{
|
||||||
|
Number = 0;
|
||||||
|
ByteString = byteString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for nearly all descriptors, providing common functionality.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DescriptorBase : IDescriptor
|
||||||
|
{
|
||||||
|
private readonly FileDescriptor file;
|
||||||
|
private readonly string fullName;
|
||||||
|
private readonly int index;
|
||||||
|
|
||||||
|
internal DescriptorBase(FileDescriptor file, string fullName, int index)
|
||||||
|
{
|
||||||
|
this.file = file;
|
||||||
|
this.fullName = fullName;
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The index of this descriptor within its parent descriptor.
|
||||||
|
/// </value>
|
||||||
|
/// <remarks>
|
||||||
|
/// This returns the index of this descriptor within its parent, for
|
||||||
|
/// this descriptor's type. (There can be duplicate values for different
|
||||||
|
/// types, e.g. one enum type with index 0 and one message type with index 0.)
|
||||||
|
/// </remarks>
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
get { return index; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the name of the entity (field, message etc) being described.
|
||||||
|
/// </summary>
|
||||||
|
public abstract string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The fully qualified name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public string FullName
|
||||||
|
{
|
||||||
|
get { return fullName; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The file this descriptor was declared in.
|
||||||
|
/// </value>
|
||||||
|
public FileDescriptor File
|
||||||
|
{
|
||||||
|
get { return file; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,368 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains lookup tables containing all the descriptors defined in a particular file.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class DescriptorPool
|
||||||
|
{
|
||||||
|
private readonly IDictionary<string, IDescriptor> descriptorsByName =
|
||||||
|
new Dictionary<string, IDescriptor>();
|
||||||
|
|
||||||
|
private readonly IDictionary<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
|
||||||
|
new Dictionary<DescriptorIntPair, FieldDescriptor>();
|
||||||
|
|
||||||
|
private readonly IDictionary<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber =
|
||||||
|
new Dictionary<DescriptorIntPair, EnumValueDescriptor>();
|
||||||
|
|
||||||
|
private readonly HashSet<FileDescriptor> dependencies;
|
||||||
|
|
||||||
|
internal DescriptorPool(FileDescriptor[] dependencyFiles)
|
||||||
|
{
|
||||||
|
dependencies = new HashSet<FileDescriptor>();
|
||||||
|
for (int i = 0; i < dependencyFiles.Length; i++)
|
||||||
|
{
|
||||||
|
dependencies.Add(dependencyFiles[i]);
|
||||||
|
ImportPublicDependencies(dependencyFiles[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FileDescriptor dependency in dependencyFiles)
|
||||||
|
{
|
||||||
|
AddPackage(dependency.Package, dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ImportPublicDependencies(FileDescriptor file)
|
||||||
|
{
|
||||||
|
foreach (FileDescriptor dependency in file.PublicDependencies)
|
||||||
|
{
|
||||||
|
if (dependencies.Add(dependency))
|
||||||
|
{
|
||||||
|
ImportPublicDependencies(dependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a symbol of the given name within the pool.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of symbol to look for</typeparam>
|
||||||
|
/// <param name="fullName">Fully-qualified name to look up</param>
|
||||||
|
/// <returns>The symbol with the given name and type,
|
||||||
|
/// or null if the symbol doesn't exist or has the wrong type</returns>
|
||||||
|
internal T FindSymbol<T>(string fullName) where T : class
|
||||||
|
{
|
||||||
|
IDescriptor result;
|
||||||
|
descriptorsByName.TryGetValue(fullName, out result);
|
||||||
|
T descriptor = result as T;
|
||||||
|
if (descriptor != null)
|
||||||
|
{
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dependencies contains direct dependencies and any *public* dependencies
|
||||||
|
// of those dependencies (transitively)... so we don't need to recurse here.
|
||||||
|
foreach (FileDescriptor dependency in dependencies)
|
||||||
|
{
|
||||||
|
dependency.DescriptorPool.descriptorsByName.TryGetValue(fullName, out result);
|
||||||
|
descriptor = result as T;
|
||||||
|
if (descriptor != null)
|
||||||
|
{
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a package to the symbol tables. If a package by the same name
|
||||||
|
/// already exists, that is fine, but if some other kind of symbol
|
||||||
|
/// exists under the same name, an exception is thrown. If the package
|
||||||
|
/// has multiple components, this also adds the parent package(s).
|
||||||
|
/// </summary>
|
||||||
|
internal void AddPackage(string fullName, FileDescriptor file)
|
||||||
|
{
|
||||||
|
int dotpos = fullName.LastIndexOf('.');
|
||||||
|
String name;
|
||||||
|
if (dotpos != -1)
|
||||||
|
{
|
||||||
|
AddPackage(fullName.Substring(0, dotpos), file);
|
||||||
|
name = fullName.Substring(dotpos + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
IDescriptor old;
|
||||||
|
if (descriptorsByName.TryGetValue(fullName, out old))
|
||||||
|
{
|
||||||
|
if (!(old is PackageDescriptor))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(file,
|
||||||
|
"\"" + name +
|
||||||
|
"\" is already defined (as something other than a " +
|
||||||
|
"package) in file \"" + old.File.Name + "\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptorsByName[fullName] = new PackageDescriptor(name, fullName, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a symbol to the symbol table.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="DescriptorValidationException">The symbol already existed
|
||||||
|
/// in the symbol table.</exception>
|
||||||
|
internal void AddSymbol(IDescriptor descriptor)
|
||||||
|
{
|
||||||
|
ValidateSymbolName(descriptor);
|
||||||
|
String fullName = descriptor.FullName;
|
||||||
|
|
||||||
|
IDescriptor old;
|
||||||
|
if (descriptorsByName.TryGetValue(fullName, out old))
|
||||||
|
{
|
||||||
|
int dotPos = fullName.LastIndexOf('.');
|
||||||
|
string message;
|
||||||
|
if (descriptor.File == old.File)
|
||||||
|
{
|
||||||
|
if (dotPos == -1)
|
||||||
|
{
|
||||||
|
message = "\"" + fullName + "\" is already defined.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "\"" + fullName.Substring(dotPos + 1) + "\" is already defined in \"" +
|
||||||
|
fullName.Substring(0, dotPos) + "\".";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "\"" + fullName + "\" is already defined in file \"" + old.File.Name + "\".";
|
||||||
|
}
|
||||||
|
throw new DescriptorValidationException(descriptor, message);
|
||||||
|
}
|
||||||
|
descriptorsByName[fullName] = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Regex ValidationRegex = new Regex("^[_A-Za-z][_A-Za-z0-9]*$",
|
||||||
|
FrameworkPortability.CompiledRegexWhereAvailable);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies that the descriptor's name is valid (i.e. it contains
|
||||||
|
/// only letters, digits and underscores, and does not start with a digit).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptor"></param>
|
||||||
|
private static void ValidateSymbolName(IDescriptor descriptor)
|
||||||
|
{
|
||||||
|
if (descriptor.Name == "")
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(descriptor, "Missing name.");
|
||||||
|
}
|
||||||
|
if (!ValidationRegex.IsMatch(descriptor.Name))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(descriptor,
|
||||||
|
"\"" + descriptor.Name + "\" is not a valid identifier.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the field with the given number in the given descriptor,
|
||||||
|
/// or null if it can't be found.
|
||||||
|
/// </summary>
|
||||||
|
internal FieldDescriptor FindFieldByNumber(MessageDescriptor messageDescriptor, int number)
|
||||||
|
{
|
||||||
|
FieldDescriptor ret;
|
||||||
|
fieldsByNumber.TryGetValue(new DescriptorIntPair(messageDescriptor, number), out ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal EnumValueDescriptor FindEnumValueByNumber(EnumDescriptor enumDescriptor, int number)
|
||||||
|
{
|
||||||
|
EnumValueDescriptor ret;
|
||||||
|
enumValuesByNumber.TryGetValue(new DescriptorIntPair(enumDescriptor, number), out ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a field to the fieldsByNumber table.
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="DescriptorValidationException">A field with the same
|
||||||
|
/// containing type and number already exists.</exception>
|
||||||
|
internal void AddFieldByNumber(FieldDescriptor field)
|
||||||
|
{
|
||||||
|
DescriptorIntPair key = new DescriptorIntPair(field.ContainingType, field.FieldNumber);
|
||||||
|
FieldDescriptor old;
|
||||||
|
if (fieldsByNumber.TryGetValue(key, out old))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(field, "Field number " + field.FieldNumber +
|
||||||
|
"has already been used in \"" +
|
||||||
|
field.ContainingType.FullName +
|
||||||
|
"\" by field \"" + old.Name + "\".");
|
||||||
|
}
|
||||||
|
fieldsByNumber[key] = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an enum value to the enumValuesByNumber table. If an enum value
|
||||||
|
/// with the same type and number already exists, this method does nothing.
|
||||||
|
/// (This is allowed; the first value defined with the number takes precedence.)
|
||||||
|
/// </summary>
|
||||||
|
internal void AddEnumValueByNumber(EnumValueDescriptor enumValue)
|
||||||
|
{
|
||||||
|
DescriptorIntPair key = new DescriptorIntPair(enumValue.EnumDescriptor, enumValue.Number);
|
||||||
|
if (!enumValuesByNumber.ContainsKey(key))
|
||||||
|
{
|
||||||
|
enumValuesByNumber[key] = enumValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a descriptor by name, relative to some other descriptor.
|
||||||
|
/// The name may be fully-qualified (with a leading '.'), partially-qualified,
|
||||||
|
/// or unqualified. C++-like name lookup semantics are used to search for the
|
||||||
|
/// matching descriptor.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This isn't heavily optimized, but it's only used during cross linking anyway.
|
||||||
|
/// If it starts being used more widely, we should look at performance more carefully.
|
||||||
|
/// </remarks>
|
||||||
|
internal IDescriptor LookupSymbol(string name, IDescriptor relativeTo)
|
||||||
|
{
|
||||||
|
IDescriptor result;
|
||||||
|
if (name.StartsWith("."))
|
||||||
|
{
|
||||||
|
// Fully-qualified name.
|
||||||
|
result = FindSymbol<IDescriptor>(name.Substring(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If "name" is a compound identifier, we want to search for the
|
||||||
|
// first component of it, then search within it for the rest.
|
||||||
|
int firstPartLength = name.IndexOf('.');
|
||||||
|
string firstPart = firstPartLength == -1 ? name : name.Substring(0, firstPartLength);
|
||||||
|
|
||||||
|
// We will search each parent scope of "relativeTo" looking for the
|
||||||
|
// symbol.
|
||||||
|
StringBuilder scopeToTry = new StringBuilder(relativeTo.FullName);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// Chop off the last component of the scope.
|
||||||
|
|
||||||
|
int dotpos = scopeToTry.ToString().LastIndexOf(".");
|
||||||
|
if (dotpos == -1)
|
||||||
|
{
|
||||||
|
result = FindSymbol<IDescriptor>(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scopeToTry.Length = dotpos + 1;
|
||||||
|
|
||||||
|
// Append firstPart and try to find.
|
||||||
|
scopeToTry.Append(firstPart);
|
||||||
|
result = FindSymbol<IDescriptor>(scopeToTry.ToString());
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
if (firstPartLength != -1)
|
||||||
|
{
|
||||||
|
// We only found the first part of the symbol. Now look for
|
||||||
|
// the whole thing. If this fails, we *don't* want to keep
|
||||||
|
// searching parent scopes.
|
||||||
|
scopeToTry.Length = dotpos + 1;
|
||||||
|
scopeToTry.Append(name);
|
||||||
|
result = FindSymbol<IDescriptor>(scopeToTry.ToString());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found. Remove the name so we can try again.
|
||||||
|
scopeToTry.Length = dotpos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(relativeTo, "\"" + name + "\" is not defined.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Struct used to hold the keys for the fieldByNumber table.
|
||||||
|
/// </summary>
|
||||||
|
private struct DescriptorIntPair : IEquatable<DescriptorIntPair>
|
||||||
|
{
|
||||||
|
private readonly int number;
|
||||||
|
private readonly IDescriptor descriptor;
|
||||||
|
|
||||||
|
internal DescriptorIntPair(IDescriptor descriptor, int number)
|
||||||
|
{
|
||||||
|
this.number = number;
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(DescriptorIntPair other)
|
||||||
|
{
|
||||||
|
return descriptor == other.descriptor
|
||||||
|
&& number == other.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is DescriptorIntPair)
|
||||||
|
{
|
||||||
|
return Equals((DescriptorIntPair) obj);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return descriptor.GetHashCode()*((1 << 16) - 1) + number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Internal class containing utility methods when working with descriptors.
|
||||||
|
/// </summary>
|
||||||
|
internal static class DescriptorUtil
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Equivalent to Func[TInput, int, TOutput] but usable in .NET 2.0. Only used to convert
|
||||||
|
/// arrays.
|
||||||
|
/// </summary>
|
||||||
|
internal delegate TOutput IndexedConverter<TInput, TOutput>(TInput element, int index);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given array into a read-only list, applying the specified conversion to
|
||||||
|
/// each input element.
|
||||||
|
/// </summary>
|
||||||
|
internal static IList<TOutput> ConvertAndMakeReadOnly<TInput, TOutput>
|
||||||
|
(IList<TInput> input, IndexedConverter<TInput, TOutput> converter)
|
||||||
|
{
|
||||||
|
TOutput[] array = new TOutput[input.Count];
|
||||||
|
for (int i = 0; i < array.Length; i++)
|
||||||
|
{
|
||||||
|
array[i] = converter(input[i], i);
|
||||||
|
}
|
||||||
|
return new ReadOnlyCollection<TOutput>(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Thrown when building descriptors fails because the source DescriptorProtos
|
||||||
|
/// are not valid.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DescriptorValidationException : Exception
|
||||||
|
{
|
||||||
|
private readonly String name;
|
||||||
|
private readonly string description;
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The full name of the descriptor where the error occurred.
|
||||||
|
/// </value>
|
||||||
|
public String ProblemSymbolName
|
||||||
|
{
|
||||||
|
get { return name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// A human-readable description of the error. (The Message property
|
||||||
|
/// is made up of the descriptor's name and this description.)
|
||||||
|
/// </value>
|
||||||
|
public string Description
|
||||||
|
{
|
||||||
|
get { return description; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DescriptorValidationException(IDescriptor problemDescriptor, string description) :
|
||||||
|
base(problemDescriptor.FullName + ": " + description)
|
||||||
|
{
|
||||||
|
// Note that problemDescriptor may be partially uninitialized, so we
|
||||||
|
// don't want to expose it directly to the user. So, we only provide
|
||||||
|
// the name and the original proto.
|
||||||
|
name = problemDescriptor.FullName;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DescriptorValidationException(IDescriptor problemDescriptor, string description, Exception cause) :
|
||||||
|
base(problemDescriptor.FullName + ": " + description, cause)
|
||||||
|
{
|
||||||
|
name = problemDescriptor.FullName;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Descriptor for an enum type in a .proto file.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EnumDescriptor : DescriptorBase
|
||||||
|
{
|
||||||
|
private readonly EnumDescriptorProto proto;
|
||||||
|
private readonly MessageDescriptor containingType;
|
||||||
|
private readonly IList<EnumValueDescriptor> values;
|
||||||
|
private readonly Type clrType;
|
||||||
|
|
||||||
|
internal EnumDescriptor(EnumDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, Type clrType)
|
||||||
|
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
||||||
|
{
|
||||||
|
this.proto = proto;
|
||||||
|
this.clrType = clrType;
|
||||||
|
containingType = parent;
|
||||||
|
|
||||||
|
if (proto.Value.Count == 0)
|
||||||
|
{
|
||||||
|
// We cannot allow enums with no values because this would mean there
|
||||||
|
// would be no valid default value for fields of this type.
|
||||||
|
throw new DescriptorValidationException(this, "Enums must contain at least one value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
values = DescriptorUtil.ConvertAndMakeReadOnly(proto.Value,
|
||||||
|
(value, i) => new EnumValueDescriptor(value, file, this, i));
|
||||||
|
|
||||||
|
File.DescriptorPool.AddSymbol(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal EnumDescriptorProto Proto { get { return proto; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The brief name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name { get { return proto.Name; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CLR type for this enum. For generated code, this will be a CLR enum type.
|
||||||
|
/// </summary>
|
||||||
|
public Type ClrType { get { return clrType; } }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// If this is a nested type, get the outer descriptor, otherwise null.
|
||||||
|
/// </value>
|
||||||
|
public MessageDescriptor ContainingType
|
||||||
|
{
|
||||||
|
get { return containingType; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// An unmodifiable list of defined value descriptors for this enum.
|
||||||
|
/// </value>
|
||||||
|
public IList<EnumValueDescriptor> Values
|
||||||
|
{
|
||||||
|
get { return values; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds an enum value by number. If multiple enum values have the
|
||||||
|
/// same number, this returns the first defined value with that number.
|
||||||
|
/// If there is no value for the given number, this returns <c>null</c>.
|
||||||
|
/// </summary>
|
||||||
|
public EnumValueDescriptor FindValueByNumber(int number)
|
||||||
|
{
|
||||||
|
return File.DescriptorPool.FindEnumValueByNumber(this, number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds an enum value by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The unqualified name of the value (e.g. "FOO").</param>
|
||||||
|
/// <returns>The value's descriptor, or null if not found.</returns>
|
||||||
|
public EnumValueDescriptor FindValueByName(string name)
|
||||||
|
{
|
||||||
|
return File.DescriptorPool.FindSymbol<EnumValueDescriptor>(FullName + "." + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this enum.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Descriptor for a single enum value within an enum in a .proto file.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class EnumValueDescriptor : DescriptorBase
|
||||||
|
{
|
||||||
|
private readonly EnumDescriptor enumDescriptor;
|
||||||
|
private readonly EnumValueDescriptorProto proto;
|
||||||
|
|
||||||
|
internal EnumValueDescriptor(EnumValueDescriptorProto proto, FileDescriptor file,
|
||||||
|
EnumDescriptor parent, int index)
|
||||||
|
: base(file, parent.FullName + "." + proto.Name, index)
|
||||||
|
{
|
||||||
|
this.proto = proto;
|
||||||
|
enumDescriptor = parent;
|
||||||
|
file.DescriptorPool.AddSymbol(this);
|
||||||
|
file.DescriptorPool.AddEnumValueByNumber(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal EnumValueDescriptorProto Proto { get { return proto; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the name of the enum value described by this object.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name { get { return proto.Name; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the number associated with this enum value.
|
||||||
|
/// </summary>
|
||||||
|
public int Number { get { return Proto.Number; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the enum descriptor that this value is part of.
|
||||||
|
/// </summary>
|
||||||
|
public EnumDescriptor EnumDescriptor { get { return enumDescriptor; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this enum value.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for field accessors.
|
||||||
|
/// </summary>
|
||||||
|
internal abstract class FieldAccessorBase : IFieldAccessor
|
||||||
|
{
|
||||||
|
private readonly Func<IMessage, object> getValueDelegate;
|
||||||
|
private readonly FieldDescriptor descriptor;
|
||||||
|
|
||||||
|
internal FieldAccessorBase(PropertyInfo property, FieldDescriptor descriptor)
|
||||||
|
{
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
getValueDelegate = ReflectionUtil.CreateFuncIMessageObject(property.GetGetMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldDescriptor Descriptor { get { return descriptor; } }
|
||||||
|
|
||||||
|
public object GetValue(IMessage message)
|
||||||
|
{
|
||||||
|
return getValueDelegate(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void Clear(IMessage message);
|
||||||
|
public abstract void SetValue(IMessage message, object value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Descriptor for a field or extension within a message in a .proto file.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
|
||||||
|
{
|
||||||
|
private EnumDescriptor enumType;
|
||||||
|
private MessageDescriptor messageType;
|
||||||
|
private FieldType fieldType;
|
||||||
|
private readonly string propertyName; // Annoyingly, needed in Crosslink.
|
||||||
|
private IFieldAccessor accessor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the field's containing message type.
|
||||||
|
/// </summary>
|
||||||
|
public MessageDescriptor ContainingType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
|
||||||
|
/// </summary>
|
||||||
|
public OneofDescriptor ContainingOneof { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The effective JSON name for this field. This is usually the lower-camel-cased form of the field name,
|
||||||
|
/// but can be overridden using the <c>json_name</c> option in the .proto file.
|
||||||
|
/// </summary>
|
||||||
|
public string JsonName { get; }
|
||||||
|
|
||||||
|
internal FieldDescriptorProto Proto { get; }
|
||||||
|
|
||||||
|
internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file,
|
||||||
|
MessageDescriptor parent, int index, string propertyName)
|
||||||
|
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
||||||
|
{
|
||||||
|
Proto = proto;
|
||||||
|
if (proto.Type != 0)
|
||||||
|
{
|
||||||
|
fieldType = GetFieldTypeFromProtoType(proto.Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FieldNumber <= 0)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "Field numbers must be positive integers.");
|
||||||
|
}
|
||||||
|
ContainingType = parent;
|
||||||
|
// OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction.
|
||||||
|
if (proto.OneofIndex != -1)
|
||||||
|
{
|
||||||
|
if (proto.OneofIndex < 0 || proto.OneofIndex >= parent.Proto.OneofDecl.Count)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this,
|
||||||
|
$"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}");
|
||||||
|
}
|
||||||
|
ContainingOneof = parent.Oneofs[proto.OneofIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
file.DescriptorPool.AddSymbol(this);
|
||||||
|
// We can't create the accessor until we've cross-linked, unfortunately, as we
|
||||||
|
// may not know whether the type of the field is a map or not. Remember the property name
|
||||||
|
// for later.
|
||||||
|
// We could trust the generated code and check whether the type of the property is
|
||||||
|
// a MapField, but that feels a tad nasty.
|
||||||
|
this.propertyName = propertyName;
|
||||||
|
JsonName = Proto.JsonName == "" ? JsonFormatter.ToJsonName(Proto.Name) : Proto.JsonName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The brief name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name => Proto.Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the accessor for this field.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// While a <see cref="FieldDescriptor"/> describes the field, it does not provide
|
||||||
|
/// any way of obtaining or changing the value of the field within a specific message;
|
||||||
|
/// that is the responsibility of the accessor.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The value returned by this property will be non-null for all regular fields. However,
|
||||||
|
/// if a message containing a map field is introspected, the list of nested messages will include
|
||||||
|
/// an auto-generated nested key/value pair message for the field. This is not represented in any
|
||||||
|
/// generated type, and the value of the map field itself is represented by a dictionary in the
|
||||||
|
/// reflection API. There are never instances of those "hidden" messages, so no accessor is provided
|
||||||
|
/// and this property will return null.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public IFieldAccessor Accessor => accessor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps a field type as included in the .proto file to a FieldType.
|
||||||
|
/// </summary>
|
||||||
|
private static FieldType GetFieldTypeFromProtoType(FieldDescriptorProto.Types.Type type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case FieldDescriptorProto.Types.Type.Double:
|
||||||
|
return FieldType.Double;
|
||||||
|
case FieldDescriptorProto.Types.Type.Float:
|
||||||
|
return FieldType.Float;
|
||||||
|
case FieldDescriptorProto.Types.Type.Int64:
|
||||||
|
return FieldType.Int64;
|
||||||
|
case FieldDescriptorProto.Types.Type.Uint64:
|
||||||
|
return FieldType.UInt64;
|
||||||
|
case FieldDescriptorProto.Types.Type.Int32:
|
||||||
|
return FieldType.Int32;
|
||||||
|
case FieldDescriptorProto.Types.Type.Fixed64:
|
||||||
|
return FieldType.Fixed64;
|
||||||
|
case FieldDescriptorProto.Types.Type.Fixed32:
|
||||||
|
return FieldType.Fixed32;
|
||||||
|
case FieldDescriptorProto.Types.Type.Bool:
|
||||||
|
return FieldType.Bool;
|
||||||
|
case FieldDescriptorProto.Types.Type.String:
|
||||||
|
return FieldType.String;
|
||||||
|
case FieldDescriptorProto.Types.Type.Group:
|
||||||
|
return FieldType.Group;
|
||||||
|
case FieldDescriptorProto.Types.Type.Message:
|
||||||
|
return FieldType.Message;
|
||||||
|
case FieldDescriptorProto.Types.Type.Bytes:
|
||||||
|
return FieldType.Bytes;
|
||||||
|
case FieldDescriptorProto.Types.Type.Uint32:
|
||||||
|
return FieldType.UInt32;
|
||||||
|
case FieldDescriptorProto.Types.Type.Enum:
|
||||||
|
return FieldType.Enum;
|
||||||
|
case FieldDescriptorProto.Types.Type.Sfixed32:
|
||||||
|
return FieldType.SFixed32;
|
||||||
|
case FieldDescriptorProto.Types.Type.Sfixed64:
|
||||||
|
return FieldType.SFixed64;
|
||||||
|
case FieldDescriptorProto.Types.Type.Sint32:
|
||||||
|
return FieldType.SInt32;
|
||||||
|
case FieldDescriptorProto.Types.Type.Sint64:
|
||||||
|
return FieldType.SInt64;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException("Invalid type specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsMap => fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPacked =>
|
||||||
|
// Note the || rather than && here - we're effectively defaulting to packed, because that *is*
|
||||||
|
// the default in proto3, which is all we support. We may give the wrong result for the protos
|
||||||
|
// within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked
|
||||||
|
// within the runtime.
|
||||||
|
Proto.Options == null || Proto.Options.Packed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the type of the field.
|
||||||
|
/// </summary>
|
||||||
|
public FieldType FieldType => fieldType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the field number declared in the proto file.
|
||||||
|
/// </summary>
|
||||||
|
public int FieldNumber => Proto.Number;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compares this descriptor with another one, ordering in "canonical" order
|
||||||
|
/// which simply means ascending order by field number. <paramref name="other"/>
|
||||||
|
/// must be a field of the same type, i.e. the <see cref="ContainingType"/> of
|
||||||
|
/// both fields must be the same.
|
||||||
|
/// </summary>
|
||||||
|
public int CompareTo(FieldDescriptor other)
|
||||||
|
{
|
||||||
|
if (other.ContainingType != ContainingType)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " +
|
||||||
|
"for fields of the same message type.");
|
||||||
|
}
|
||||||
|
return FieldNumber - other.FieldNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For enum fields, returns the field's type.
|
||||||
|
/// </summary>
|
||||||
|
public EnumDescriptor EnumType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (fieldType != FieldType.Enum)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("EnumType is only valid for enum fields.");
|
||||||
|
}
|
||||||
|
return enumType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For embedded message and group fields, returns the field's type.
|
||||||
|
/// </summary>
|
||||||
|
public MessageDescriptor MessageType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (fieldType != FieldType.Message)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("MessageType is only valid for message fields.");
|
||||||
|
}
|
||||||
|
return messageType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this field.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Look up and cross-link all field types etc.
|
||||||
|
/// </summary>
|
||||||
|
internal void CrossLink()
|
||||||
|
{
|
||||||
|
if (Proto.TypeName != "")
|
||||||
|
{
|
||||||
|
IDescriptor typeDescriptor =
|
||||||
|
File.DescriptorPool.LookupSymbol(Proto.TypeName, this);
|
||||||
|
|
||||||
|
if (Proto.Type != 0)
|
||||||
|
{
|
||||||
|
// Choose field type based on symbol.
|
||||||
|
if (typeDescriptor is MessageDescriptor)
|
||||||
|
{
|
||||||
|
fieldType = FieldType.Message;
|
||||||
|
}
|
||||||
|
else if (typeDescriptor is EnumDescriptor)
|
||||||
|
{
|
||||||
|
fieldType = FieldType.Enum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldType == FieldType.Message)
|
||||||
|
{
|
||||||
|
if (!(typeDescriptor is MessageDescriptor))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not a message type.");
|
||||||
|
}
|
||||||
|
messageType = (MessageDescriptor) typeDescriptor;
|
||||||
|
|
||||||
|
if (Proto.DefaultValue != "")
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "Messages can't have default values.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fieldType == FieldType.Enum)
|
||||||
|
{
|
||||||
|
if (!(typeDescriptor is EnumDescriptor))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, $"\"{Proto.TypeName}\" is not an enum type.");
|
||||||
|
}
|
||||||
|
enumType = (EnumDescriptor) typeDescriptor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "Field with primitive type has type_name.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fieldType == FieldType.Message || fieldType == FieldType.Enum)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "Field with message or enum type missing type_name.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: no attempt to perform any default value parsing
|
||||||
|
|
||||||
|
File.DescriptorPool.AddFieldByNumber(this);
|
||||||
|
|
||||||
|
if (ContainingType != null && ContainingType.Proto.Options != null && ContainingType.Proto.Options.MessageSetWireFormat)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "MessageSet format is not supported.");
|
||||||
|
}
|
||||||
|
accessor = CreateAccessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IFieldAccessor CreateAccessor()
|
||||||
|
{
|
||||||
|
// If we're given no property name, that's because we really don't want an accessor.
|
||||||
|
// (At the moment, that means it's a map entry message...)
|
||||||
|
if (propertyName == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var property = ContainingType.ClrType.GetProperty(propertyName);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, $"Property {propertyName} not found in {ContainingType.ClrType}");
|
||||||
|
}
|
||||||
|
return IsMap ? new MapFieldAccessor(property, this)
|
||||||
|
: IsRepeated ? new RepeatedFieldAccessor(property, this)
|
||||||
|
: (IFieldAccessor) new SingleFieldAccessor(property, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration of all the possible field types.
|
||||||
|
/// </summary>
|
||||||
|
public enum FieldType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>double</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Double,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>float</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Float,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>int64</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Int64,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>uint64</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
UInt64,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>int32</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Int32,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>fixed64</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Fixed64,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>fixed32</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Fixed32,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>bool</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Bool,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>string</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
String,
|
||||||
|
/// <summary>
|
||||||
|
/// The field type used for groups (not supported in this implementation).
|
||||||
|
/// </summary>
|
||||||
|
Group,
|
||||||
|
/// <summary>
|
||||||
|
/// The field type used for message fields.
|
||||||
|
/// </summary>
|
||||||
|
Message,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>bytes</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
Bytes,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>uint32</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
UInt32,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>sfixed32</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
SFixed32,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>sfixed64</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
SFixed64,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>sint32</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
SInt32,
|
||||||
|
/// <summary>
|
||||||
|
/// The <c>sint64</c> field type.
|
||||||
|
/// </summary>
|
||||||
|
SInt64,
|
||||||
|
/// <summary>
|
||||||
|
/// The field type used for enum fields.
|
||||||
|
/// </summary>
|
||||||
|
Enum
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,338 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a .proto file, including everything defined within.
|
||||||
|
/// IDescriptor is implemented such that the File property returns this descriptor,
|
||||||
|
/// and the FullName is the same as the Name.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FileDescriptor : IDescriptor
|
||||||
|
{
|
||||||
|
private FileDescriptor(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
|
||||||
|
{
|
||||||
|
SerializedData = descriptorData;
|
||||||
|
DescriptorPool = pool;
|
||||||
|
Proto = proto;
|
||||||
|
Dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
|
||||||
|
|
||||||
|
PublicDependencies = DeterminePublicDependencies(this, proto, dependencies, allowUnknownDependencies);
|
||||||
|
|
||||||
|
pool.AddPackage(Package, this);
|
||||||
|
|
||||||
|
MessageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageType,
|
||||||
|
(message, index) =>
|
||||||
|
new MessageDescriptor(message, this, null, index, generatedCodeInfo.NestedTypes[index]));
|
||||||
|
|
||||||
|
EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumType,
|
||||||
|
(enumType, index) =>
|
||||||
|
new EnumDescriptor(enumType, this, null, index, generatedCodeInfo.NestedEnums[index]));
|
||||||
|
|
||||||
|
Services = DescriptorUtil.ConvertAndMakeReadOnly(proto.Service,
|
||||||
|
(service, index) =>
|
||||||
|
new ServiceDescriptor(service, this, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Computes the full name of a descriptor within this file, with an optional parent message.
|
||||||
|
/// </summary>
|
||||||
|
internal string ComputeFullName(MessageDescriptor parent, string name)
|
||||||
|
{
|
||||||
|
if (parent != null)
|
||||||
|
{
|
||||||
|
return parent.FullName + "." + name;
|
||||||
|
}
|
||||||
|
if (Package.Length > 0)
|
||||||
|
{
|
||||||
|
return Package + "." + name;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extracts public dependencies from direct dependencies. This is a static method despite its
|
||||||
|
/// first parameter, as the value we're in the middle of constructing is only used for exceptions.
|
||||||
|
/// </summary>
|
||||||
|
private static IList<FileDescriptor> DeterminePublicDependencies(FileDescriptor @this, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies)
|
||||||
|
{
|
||||||
|
var nameToFileMap = new Dictionary<string, FileDescriptor>();
|
||||||
|
foreach (var file in dependencies)
|
||||||
|
{
|
||||||
|
nameToFileMap[file.Name] = file;
|
||||||
|
}
|
||||||
|
var publicDependencies = new List<FileDescriptor>();
|
||||||
|
for (int i = 0; i < proto.PublicDependency.Count; i++)
|
||||||
|
{
|
||||||
|
int index = proto.PublicDependency[i];
|
||||||
|
if (index < 0 || index >= proto.Dependency.Count)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(@this, "Invalid public dependency index.");
|
||||||
|
}
|
||||||
|
string name = proto.Dependency[index];
|
||||||
|
FileDescriptor file = nameToFileMap[name];
|
||||||
|
if (file == null)
|
||||||
|
{
|
||||||
|
if (!allowUnknownDependencies)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(@this, "Invalid public dependency: " + name);
|
||||||
|
}
|
||||||
|
// Ignore unknown dependencies.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
publicDependencies.Add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new ReadOnlyCollection<FileDescriptor>(publicDependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The descriptor in its protocol message representation.
|
||||||
|
/// </value>
|
||||||
|
internal FileDescriptorProto Proto { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The file name.
|
||||||
|
/// </value>
|
||||||
|
public string Name => Proto.Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The package as declared in the .proto file. This may or may not
|
||||||
|
/// be equivalent to the .NET namespace of the generated classes.
|
||||||
|
/// </summary>
|
||||||
|
public string Package => Proto.Package;
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Unmodifiable list of top-level message types declared in this file.
|
||||||
|
/// </value>
|
||||||
|
public IList<MessageDescriptor> MessageTypes { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Unmodifiable list of top-level enum types declared in this file.
|
||||||
|
/// </value>
|
||||||
|
public IList<EnumDescriptor> EnumTypes { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Unmodifiable list of top-level services declared in this file.
|
||||||
|
/// </value>
|
||||||
|
public IList<ServiceDescriptor> Services { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Unmodifiable list of this file's dependencies (imports).
|
||||||
|
/// </value>
|
||||||
|
public IList<FileDescriptor> Dependencies { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Unmodifiable list of this file's public dependencies (public imports).
|
||||||
|
/// </value>
|
||||||
|
public IList<FileDescriptor> PublicDependencies { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The original serialized binary form of this descriptor.
|
||||||
|
/// </value>
|
||||||
|
public ByteString SerializedData { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Implementation of IDescriptor.FullName - just returns the same as Name.
|
||||||
|
/// </value>
|
||||||
|
string IDescriptor.FullName => Name;
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Implementation of IDescriptor.File - just returns this descriptor.
|
||||||
|
/// </value>
|
||||||
|
FileDescriptor IDescriptor.File => this;
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Pool containing symbol descriptors.
|
||||||
|
/// </value>
|
||||||
|
internal DescriptorPool DescriptorPool { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The unqualified type name to look for.</param>
|
||||||
|
/// <typeparam name="T">The type of descriptor to look for</typeparam>
|
||||||
|
/// <returns>The type's descriptor, or null if not found.</returns>
|
||||||
|
public T FindTypeByName<T>(String name)
|
||||||
|
where T : class, IDescriptor
|
||||||
|
{
|
||||||
|
// Don't allow looking up nested types. This will make optimization
|
||||||
|
// easier later.
|
||||||
|
if (name.IndexOf('.') != -1)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (Package.Length > 0)
|
||||||
|
{
|
||||||
|
name = Package + "." + name;
|
||||||
|
}
|
||||||
|
T result = DescriptorPool.FindSymbol<T>(name);
|
||||||
|
if (result != null && result.File == this)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds a FileDescriptor from its protocol buffer representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="descriptorData">The original serialized descriptor data.
|
||||||
|
/// We have only limited proto2 support, so serializing FileDescriptorProto
|
||||||
|
/// would not necessarily give us this.</param>
|
||||||
|
/// <param name="proto">The protocol message form of the FileDescriptor.</param>
|
||||||
|
/// <param name="dependencies">FileDescriptors corresponding to all of the
|
||||||
|
/// file's dependencies, in the exact order listed in the .proto file. May be null,
|
||||||
|
/// in which case it is treated as an empty array.</param>
|
||||||
|
/// <param name="allowUnknownDependencies">Whether unknown dependencies are ignored (true) or cause an exception to be thrown (false).</param>
|
||||||
|
/// <param name="generatedCodeInfo">Details about generated code, for the purposes of reflection.</param>
|
||||||
|
/// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
|
||||||
|
/// a valid descriptor. This can occur for a number of reasons, such as a field
|
||||||
|
/// having an undefined type or because two messages were defined with the same name.</exception>
|
||||||
|
private static FileDescriptor BuildFrom(ByteString descriptorData, FileDescriptorProto proto, FileDescriptor[] dependencies, bool allowUnknownDependencies, GeneratedClrTypeInfo generatedCodeInfo)
|
||||||
|
{
|
||||||
|
// Building descriptors involves two steps: translating and linking.
|
||||||
|
// In the translation step (implemented by FileDescriptor's
|
||||||
|
// constructor), we build an object tree mirroring the
|
||||||
|
// FileDescriptorProto's tree and put all of the descriptors into the
|
||||||
|
// DescriptorPool's lookup tables. In the linking step, we look up all
|
||||||
|
// type references in the DescriptorPool, so that, for example, a
|
||||||
|
// FieldDescriptor for an embedded message contains a pointer directly
|
||||||
|
// to the Descriptor for that message's type. We also detect undefined
|
||||||
|
// types in the linking step.
|
||||||
|
if (dependencies == null)
|
||||||
|
{
|
||||||
|
dependencies = new FileDescriptor[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
DescriptorPool pool = new DescriptorPool(dependencies);
|
||||||
|
FileDescriptor result = new FileDescriptor(descriptorData, proto, dependencies, pool, allowUnknownDependencies, generatedCodeInfo);
|
||||||
|
|
||||||
|
// Validate that the dependencies we've been passed (as FileDescriptors) are actually the ones we
|
||||||
|
// need.
|
||||||
|
if (dependencies.Length != proto.Dependency.Count)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(
|
||||||
|
result,
|
||||||
|
"Dependencies passed to FileDescriptor.BuildFrom() don't match " +
|
||||||
|
"those listed in the FileDescriptorProto.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.CrossLink();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CrossLink()
|
||||||
|
{
|
||||||
|
foreach (MessageDescriptor message in MessageTypes)
|
||||||
|
{
|
||||||
|
message.CrossLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ServiceDescriptor service in Services)
|
||||||
|
{
|
||||||
|
service.CrossLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a descriptor for generated code.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method is only designed to be used by the results of generating code with protoc,
|
||||||
|
/// which creates the appropriate dependencies etc. It has to be public because the generated
|
||||||
|
/// code is "external", but should not be called directly by end users.
|
||||||
|
/// </remarks>
|
||||||
|
public static FileDescriptor FromGeneratedCode(
|
||||||
|
byte[] descriptorData,
|
||||||
|
FileDescriptor[] dependencies,
|
||||||
|
GeneratedClrTypeInfo generatedCodeInfo)
|
||||||
|
{
|
||||||
|
FileDescriptorProto proto;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proto = FileDescriptorProto.Parser.ParseFrom(descriptorData);
|
||||||
|
}
|
||||||
|
catch (InvalidProtocolBufferException e)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Failed to parse protocol buffer descriptor for generated code.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// When building descriptors for generated code, we allow unknown
|
||||||
|
// dependencies by default.
|
||||||
|
return BuildFrom(ByteString.CopyFrom(descriptorData), proto, dependencies, true, generatedCodeInfo);
|
||||||
|
}
|
||||||
|
catch (DescriptorValidationException e)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid embedded descriptor for \"{proto.Name}\".", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="System.String" /> that represents this instance.
|
||||||
|
/// </returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"FileDescriptor for {Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the file descriptor for descriptor.proto.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is used for protos which take a direct dependency on <c>descriptor.proto</c>, typically for
|
||||||
|
/// annotations. While <c>descriptor.proto</c> is a proto2 file, it is built into the Google.Protobuf
|
||||||
|
/// runtime for reflection purposes. The messages are internal to the runtime as they would require
|
||||||
|
/// proto2 semantics for full support, but the file descriptor is available via this property. The
|
||||||
|
/// C# codegen in protoc automatically uses this property when it detects a dependency on <c>descriptor.proto</c>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <value>
|
||||||
|
/// The file descriptor for <c>descriptor.proto</c>.
|
||||||
|
/// </value>
|
||||||
|
public static FileDescriptor DescriptorProtoFileDescriptor { get { return DescriptorReflection.Descriptor; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this file.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extra information provided by generated code when initializing a message or file descriptor.
|
||||||
|
/// These are constructed as required, and are not long-lived. Hand-written code should
|
||||||
|
/// never need to use this type.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class GeneratedClrTypeInfo
|
||||||
|
{
|
||||||
|
private static readonly string[] EmptyNames = new string[0];
|
||||||
|
private static readonly GeneratedClrTypeInfo[] EmptyCodeInfo = new GeneratedClrTypeInfo[0];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Irrelevant for file descriptors; the CLR type for the message for message descriptors.
|
||||||
|
/// </summary>
|
||||||
|
public Type ClrType { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Irrelevant for file descriptors; the parser for message descriptors.
|
||||||
|
/// </summary>
|
||||||
|
public MessageParser Parser { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Irrelevant for file descriptors; the CLR property names (in message descriptor field order)
|
||||||
|
/// for fields in the message for message descriptors.
|
||||||
|
/// </summary>
|
||||||
|
public string[] PropertyNames { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Irrelevant for file descriptors; the CLR property "base" names (in message descriptor oneof order)
|
||||||
|
/// for oneofs in the message for message descriptors. It is expected that for a oneof name of "Foo",
|
||||||
|
/// there will be a "FooCase" property and a "ClearFoo" method.
|
||||||
|
/// </summary>
|
||||||
|
public string[] OneofNames { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reflection information for types within this file/message descriptor. Elements may be null
|
||||||
|
/// if there is no corresponding generated type, e.g. for map entry types.
|
||||||
|
/// </summary>
|
||||||
|
public GeneratedClrTypeInfo[] NestedTypes { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CLR types for enums within this file/message descriptor.
|
||||||
|
/// </summary>
|
||||||
|
public Type[] NestedEnums { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a GeneratedClrTypeInfo for a message descriptor, with nested types, nested enums, the CLR type, property names and oneof names.
|
||||||
|
/// Each array parameter may be null, to indicate a lack of values.
|
||||||
|
/// The parameter order is designed to make it feasible to format the generated code readably.
|
||||||
|
/// </summary>
|
||||||
|
public GeneratedClrTypeInfo(Type clrType, MessageParser parser, string[] propertyNames, string[] oneofNames, Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
|
||||||
|
{
|
||||||
|
NestedTypes = nestedTypes ?? EmptyCodeInfo;
|
||||||
|
NestedEnums = nestedEnums ?? ReflectionUtil.EmptyTypes;
|
||||||
|
ClrType = clrType;
|
||||||
|
Parser = parser;
|
||||||
|
PropertyNames = propertyNames ?? EmptyNames;
|
||||||
|
OneofNames = oneofNames ?? EmptyNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a GeneratedClrTypeInfo for a file descriptor, with only types and enums.
|
||||||
|
/// </summary>
|
||||||
|
public GeneratedClrTypeInfo(Type[] nestedEnums, GeneratedClrTypeInfo[] nestedTypes)
|
||||||
|
: this(null, null, null, null, nestedEnums, nestedTypes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface implemented by all descriptor types.
|
||||||
|
/// </summary>
|
||||||
|
public interface IDescriptor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the name of the entity (message, field etc) being described.
|
||||||
|
/// </summary>
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the fully-qualified name of the entity being described.
|
||||||
|
/// </summary>
|
||||||
|
string FullName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the descriptor for the .proto file that this entity is part of.
|
||||||
|
/// </summary>
|
||||||
|
FileDescriptor File { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows fields to be reflectively accessed.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFieldAccessor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the descriptor associated with this field.
|
||||||
|
/// </summary>
|
||||||
|
FieldDescriptor Descriptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the field in the specified message. (For repeated fields,
|
||||||
|
/// this clears the list.)
|
||||||
|
/// </summary>
|
||||||
|
void Clear(IMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches the field value. For repeated values, this will be an
|
||||||
|
/// <see cref="IList"/> implementation. For map values, this will be an
|
||||||
|
/// <see cref="IDictionary"/> implementation.
|
||||||
|
/// </summary>
|
||||||
|
object GetValue(IMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mutator for single "simple" fields only.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Repeated fields are mutated by fetching the value and manipulating it as a list.
|
||||||
|
/// Map fields are mutated by fetching the value and manipulating it as a dictionary.
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="InvalidOperationException">The field is not a "simple" field.</exception>
|
||||||
|
void SetValue(IMessage message, object value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Accessor for map fields.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class MapFieldAccessor : FieldAccessorBase
|
||||||
|
{
|
||||||
|
internal MapFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear(IMessage message)
|
||||||
|
{
|
||||||
|
IDictionary list = (IDictionary) GetValue(message);
|
||||||
|
list.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(IMessage message, object value)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("SetValue is not implemented for map fields");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,326 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
#if NET35
|
||||||
|
// Needed for ReadOnlyDictionary, which does not exist in .NET 3.5
|
||||||
|
using Google.Protobuf.Collections;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a message type.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MessageDescriptor : DescriptorBase
|
||||||
|
{
|
||||||
|
private static readonly HashSet<string> WellKnownTypeNames = new HashSet<string>
|
||||||
|
{
|
||||||
|
"google/protobuf/any.proto",
|
||||||
|
"google/protobuf/api.proto",
|
||||||
|
"google/protobuf/duration.proto",
|
||||||
|
"google/protobuf/empty.proto",
|
||||||
|
"google/protobuf/wrappers.proto",
|
||||||
|
"google/protobuf/timestamp.proto",
|
||||||
|
"google/protobuf/field_mask.proto",
|
||||||
|
"google/protobuf/source_context.proto",
|
||||||
|
"google/protobuf/struct.proto",
|
||||||
|
"google/protobuf/type.proto",
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly IList<FieldDescriptor> fieldsInDeclarationOrder;
|
||||||
|
private readonly IList<FieldDescriptor> fieldsInNumberOrder;
|
||||||
|
private readonly IDictionary<string, FieldDescriptor> jsonFieldMap;
|
||||||
|
|
||||||
|
internal MessageDescriptor(DescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int typeIndex, GeneratedClrTypeInfo generatedCodeInfo)
|
||||||
|
: base(file, file.ComputeFullName(parent, proto.Name), typeIndex)
|
||||||
|
{
|
||||||
|
Proto = proto;
|
||||||
|
Parser = generatedCodeInfo?.Parser;
|
||||||
|
ClrType = generatedCodeInfo?.ClrType;
|
||||||
|
ContainingType = parent;
|
||||||
|
|
||||||
|
// Note use of generatedCodeInfo. rather than generatedCodeInfo?. here... we don't expect
|
||||||
|
// to see any nested oneofs, types or enums in "not actually generated" code... we do
|
||||||
|
// expect fields though (for map entry messages).
|
||||||
|
Oneofs = DescriptorUtil.ConvertAndMakeReadOnly(
|
||||||
|
proto.OneofDecl,
|
||||||
|
(oneof, index) =>
|
||||||
|
new OneofDescriptor(oneof, file, this, index, generatedCodeInfo.OneofNames[index]));
|
||||||
|
|
||||||
|
NestedTypes = DescriptorUtil.ConvertAndMakeReadOnly(
|
||||||
|
proto.NestedType,
|
||||||
|
(type, index) =>
|
||||||
|
new MessageDescriptor(type, file, this, index, generatedCodeInfo.NestedTypes[index]));
|
||||||
|
|
||||||
|
EnumTypes = DescriptorUtil.ConvertAndMakeReadOnly(
|
||||||
|
proto.EnumType,
|
||||||
|
(type, index) =>
|
||||||
|
new EnumDescriptor(type, file, this, index, generatedCodeInfo.NestedEnums[index]));
|
||||||
|
|
||||||
|
fieldsInDeclarationOrder = DescriptorUtil.ConvertAndMakeReadOnly(
|
||||||
|
proto.Field,
|
||||||
|
(field, index) =>
|
||||||
|
new FieldDescriptor(field, file, this, index, generatedCodeInfo?.PropertyNames[index]));
|
||||||
|
fieldsInNumberOrder = new ReadOnlyCollection<FieldDescriptor>(fieldsInDeclarationOrder.OrderBy(field => field.FieldNumber).ToArray());
|
||||||
|
// TODO: Use field => field.Proto.JsonName when we're confident it's appropriate. (And then use it in the formatter, too.)
|
||||||
|
jsonFieldMap = CreateJsonFieldMap(fieldsInNumberOrder);
|
||||||
|
file.DescriptorPool.AddSymbol(this);
|
||||||
|
Fields = new FieldCollection(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ReadOnlyDictionary<string, FieldDescriptor> CreateJsonFieldMap(IList<FieldDescriptor> fields)
|
||||||
|
{
|
||||||
|
var map = new Dictionary<string, FieldDescriptor>();
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
map[field.Name] = field;
|
||||||
|
map[field.JsonName] = field;
|
||||||
|
}
|
||||||
|
return new ReadOnlyDictionary<string, FieldDescriptor>(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The brief name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name => Proto.Name;
|
||||||
|
|
||||||
|
internal DescriptorProto Proto { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CLR type used to represent message instances from this descriptor.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The value returned by this property will be non-null for all regular fields. However,
|
||||||
|
/// if a message containing a map field is introspected, the list of nested messages will include
|
||||||
|
/// an auto-generated nested key/value pair message for the field. This is not represented in any
|
||||||
|
/// generated type, so this property will return null in such cases.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the type returned here
|
||||||
|
/// will be the generated message type, not the native type used by reflection for fields of those types. Code
|
||||||
|
/// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
|
||||||
|
/// a wrapper type, and handle the result appropriately.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public Type ClrType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A parser for this message type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// As <see cref="MessageDescriptor"/> is not generic, this cannot be statically
|
||||||
|
/// typed to the relevant type, but it should produce objects of a type compatible with <see cref="ClrType"/>.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// The value returned by this property will be non-null for all regular fields. However,
|
||||||
|
/// if a message containing a map field is introspected, the list of nested messages will include
|
||||||
|
/// an auto-generated nested key/value pair message for the field. No message parser object is created for
|
||||||
|
/// such messages, so this property will return null in such cases.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// For wrapper types (<see cref="Google.Protobuf.WellKnownTypes.StringValue"/> and the like), the parser returned here
|
||||||
|
/// will be the generated message type, not the native type used by reflection for fields of those types. Code
|
||||||
|
/// using reflection should call <see cref="IsWrapperType"/> to determine whether a message descriptor represents
|
||||||
|
/// a wrapper type, and handle the result appropriately.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public MessageParser Parser { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether this message is one of the "well known types" which may have runtime/protoc support.
|
||||||
|
/// </summary>
|
||||||
|
internal bool IsWellKnownType => File.Package == "google.protobuf" && WellKnownTypeNames.Contains(File.Name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether this message is one of the "wrapper types" used for fields which represent primitive values
|
||||||
|
/// with the addition of presence.
|
||||||
|
/// </summary>
|
||||||
|
internal bool IsWrapperType => File.Package == "google.protobuf" && File.Name == "google/protobuf/wrappers.proto";
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// If this is a nested type, get the outer descriptor, otherwise null.
|
||||||
|
/// </value>
|
||||||
|
public MessageDescriptor ContainingType { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// A collection of fields, which can be retrieved by name or field number.
|
||||||
|
/// </value>
|
||||||
|
public FieldCollection Fields { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// An unmodifiable list of this message type's nested types.
|
||||||
|
/// </value>
|
||||||
|
public IList<MessageDescriptor> NestedTypes { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// An unmodifiable list of this message type's enum types.
|
||||||
|
/// </value>
|
||||||
|
public IList<EnumDescriptor> EnumTypes { get; }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// An unmodifiable list of the "oneof" field collections in this message type.
|
||||||
|
/// </value>
|
||||||
|
public IList<OneofDescriptor> Oneofs { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a field by field name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The unqualified name of the field (e.g. "foo").</param>
|
||||||
|
/// <returns>The field's descriptor, or null if not found.</returns>
|
||||||
|
public FieldDescriptor FindFieldByName(String name) => File.DescriptorPool.FindSymbol<FieldDescriptor>(FullName + "." + name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a field by field number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="number">The field number within this message type.</param>
|
||||||
|
/// <returns>The field's descriptor, or null if not found.</returns>
|
||||||
|
public FieldDescriptor FindFieldByNumber(int number) => File.DescriptorPool.FindFieldByNumber(this, number);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a nested descriptor by name. The is valid for fields, nested
|
||||||
|
/// message types, oneofs and enums.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The unqualified name of the descriptor, e.g. "Foo"</param>
|
||||||
|
/// <returns>The descriptor, or null if not found.</returns>
|
||||||
|
public T FindDescriptor<T>(string name) where T : class, IDescriptor =>
|
||||||
|
File.DescriptorPool.FindSymbol<T>(FullName + "." + name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this message.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up and cross-links all fields and nested types.
|
||||||
|
/// </summary>
|
||||||
|
internal void CrossLink()
|
||||||
|
{
|
||||||
|
foreach (MessageDescriptor message in NestedTypes)
|
||||||
|
{
|
||||||
|
message.CrossLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FieldDescriptor field in fieldsInDeclarationOrder)
|
||||||
|
{
|
||||||
|
field.CrossLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (OneofDescriptor oneof in Oneofs)
|
||||||
|
{
|
||||||
|
oneof.CrossLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A collection to simplify retrieving the field accessor for a particular field.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FieldCollection
|
||||||
|
{
|
||||||
|
private readonly MessageDescriptor messageDescriptor;
|
||||||
|
|
||||||
|
internal FieldCollection(MessageDescriptor messageDescriptor)
|
||||||
|
{
|
||||||
|
this.messageDescriptor = messageDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Returns the fields in the message as an immutable list, in the order in which they
|
||||||
|
/// are declared in the source .proto file.
|
||||||
|
/// </value>
|
||||||
|
public IList<FieldDescriptor> InDeclarationOrder() => messageDescriptor.fieldsInDeclarationOrder;
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Returns the fields in the message as an immutable list, in ascending field number
|
||||||
|
/// order. Field numbers need not be contiguous, so there is no direct mapping from the
|
||||||
|
/// index in the list to the field number; to retrieve a field by field number, it is better
|
||||||
|
/// to use the <see cref="FieldCollection"/> indexer.
|
||||||
|
/// </value>
|
||||||
|
public IList<FieldDescriptor> InFieldNumberOrder() => messageDescriptor.fieldsInNumberOrder;
|
||||||
|
|
||||||
|
// TODO: consider making this public in the future. (Being conservative for now...)
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Returns a read-only dictionary mapping the field names in this message as they're available
|
||||||
|
/// in the JSON representation to the field descriptors. For example, a field <c>foo_bar</c>
|
||||||
|
/// in the message would result two entries, one with a key <c>fooBar</c> and one with a key
|
||||||
|
/// <c>foo_bar</c>, both referring to the same field.
|
||||||
|
/// </value>
|
||||||
|
internal IDictionary<string, FieldDescriptor> ByJsonName() => messageDescriptor.jsonFieldMap;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the descriptor for the field with the given number.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="number">Number of the field to retrieve the descriptor for</param>
|
||||||
|
/// <returns>The accessor for the given field</returns>
|
||||||
|
/// <exception cref="KeyNotFoundException">The message descriptor does not contain a field
|
||||||
|
/// with the given number</exception>
|
||||||
|
public FieldDescriptor this[int number]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var fieldDescriptor = messageDescriptor.FindFieldByNumber(number);
|
||||||
|
if (fieldDescriptor == null)
|
||||||
|
{
|
||||||
|
throw new KeyNotFoundException("No such field number");
|
||||||
|
}
|
||||||
|
return fieldDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the descriptor for the field with the given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of the field to retrieve the descriptor for</param>
|
||||||
|
/// <returns>The descriptor for the given field</returns>
|
||||||
|
/// <exception cref="KeyNotFoundException">The message descriptor does not contain a field
|
||||||
|
/// with the given name</exception>
|
||||||
|
public FieldDescriptor this[string name]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var fieldDescriptor = messageDescriptor.FindFieldByName(name);
|
||||||
|
if (fieldDescriptor == null)
|
||||||
|
{
|
||||||
|
throw new KeyNotFoundException("No such field name");
|
||||||
|
}
|
||||||
|
return fieldDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a single method in a service.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MethodDescriptor : DescriptorBase
|
||||||
|
{
|
||||||
|
private readonly MethodDescriptorProto proto;
|
||||||
|
private readonly ServiceDescriptor service;
|
||||||
|
private MessageDescriptor inputType;
|
||||||
|
private MessageDescriptor outputType;
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The service this method belongs to.
|
||||||
|
/// </value>
|
||||||
|
public ServiceDescriptor Service { get { return service; } }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The method's input type.
|
||||||
|
/// </value>
|
||||||
|
public MessageDescriptor InputType { get { return inputType; } }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// The method's input type.
|
||||||
|
/// </value>
|
||||||
|
public MessageDescriptor OutputType { get { return outputType; } }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Indicates if client streams multiple requests.
|
||||||
|
/// </value>
|
||||||
|
public bool IsClientStreaming { get { return proto.ClientStreaming; } }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// Indicates if server streams multiple responses.
|
||||||
|
/// </value>
|
||||||
|
public bool IsServerStreaming { get { return proto.ServerStreaming; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this method.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
|
||||||
|
internal MethodDescriptor(MethodDescriptorProto proto, FileDescriptor file,
|
||||||
|
ServiceDescriptor parent, int index)
|
||||||
|
: base(file, parent.FullName + "." + proto.Name, index)
|
||||||
|
{
|
||||||
|
this.proto = proto;
|
||||||
|
service = parent;
|
||||||
|
file.DescriptorPool.AddSymbol(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal MethodDescriptorProto Proto { get { return proto; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The brief name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name { get { return proto.Name; } }
|
||||||
|
|
||||||
|
internal void CrossLink()
|
||||||
|
{
|
||||||
|
IDescriptor lookup = File.DescriptorPool.LookupSymbol(Proto.InputType, this);
|
||||||
|
if (!(lookup is MessageDescriptor))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "\"" + Proto.InputType + "\" is not a message type.");
|
||||||
|
}
|
||||||
|
inputType = (MessageDescriptor) lookup;
|
||||||
|
|
||||||
|
lookup = File.DescriptorPool.LookupSymbol(Proto.OutputType, this);
|
||||||
|
if (!(lookup is MessageDescriptor))
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, "\"" + Proto.OutputType + "\" is not a message type.");
|
||||||
|
}
|
||||||
|
outputType = (MessageDescriptor) lookup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Reflection access for a oneof, allowing clear and "get case" actions.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class OneofAccessor
|
||||||
|
{
|
||||||
|
private readonly Func<IMessage, int> caseDelegate;
|
||||||
|
private readonly Action<IMessage> clearDelegate;
|
||||||
|
private OneofDescriptor descriptor;
|
||||||
|
|
||||||
|
internal OneofAccessor(PropertyInfo caseProperty, MethodInfo clearMethod, OneofDescriptor descriptor)
|
||||||
|
{
|
||||||
|
if (!caseProperty.CanRead)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Cannot read from property");
|
||||||
|
}
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
caseDelegate = ReflectionUtil.CreateFuncIMessageT<int>(caseProperty.GetGetMethod());
|
||||||
|
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
clearDelegate = ReflectionUtil.CreateActionIMessage(clearMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the descriptor for this oneof.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The descriptor of the oneof.
|
||||||
|
/// </value>
|
||||||
|
public OneofDescriptor Descriptor { get { return descriptor; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clears the oneof in the specified message.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear(IMessage message)
|
||||||
|
{
|
||||||
|
clearDelegate(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates which field in the oneof is set for specified message
|
||||||
|
/// </summary>
|
||||||
|
public FieldDescriptor GetCaseFieldDescriptor(IMessage message)
|
||||||
|
{
|
||||||
|
int fieldNumber = caseDelegate(message);
|
||||||
|
if (fieldNumber > 0)
|
||||||
|
{
|
||||||
|
return descriptor.ContainingType.FindFieldByNumber(fieldNumber);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a "oneof" field collection in a message type: a set of
|
||||||
|
/// fields of which at most one can be set in any particular message.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class OneofDescriptor : DescriptorBase
|
||||||
|
{
|
||||||
|
private readonly OneofDescriptorProto proto;
|
||||||
|
private MessageDescriptor containingType;
|
||||||
|
private IList<FieldDescriptor> fields;
|
||||||
|
private readonly OneofAccessor accessor;
|
||||||
|
|
||||||
|
internal OneofDescriptor(OneofDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, string clrName)
|
||||||
|
: base(file, file.ComputeFullName(parent, proto.Name), index)
|
||||||
|
{
|
||||||
|
this.proto = proto;
|
||||||
|
containingType = parent;
|
||||||
|
|
||||||
|
file.DescriptorPool.AddSymbol(this);
|
||||||
|
accessor = CreateAccessor(clrName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The brief name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name { get { return proto.Name; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the message type containing this oneof.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The message type containing this oneof.
|
||||||
|
/// </value>
|
||||||
|
public MessageDescriptor ContainingType
|
||||||
|
{
|
||||||
|
get { return containingType; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the fields within this oneof, in declaration order.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The fields within this oneof, in declaration order.
|
||||||
|
/// </value>
|
||||||
|
public IList<FieldDescriptor> Fields { get { return fields; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an accessor for reflective access to the values associated with the oneof
|
||||||
|
/// in a particular message.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The accessor used for reflective access.
|
||||||
|
/// </value>
|
||||||
|
public OneofAccessor Accessor { get { return accessor; } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this oneof.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
|
||||||
|
internal void CrossLink()
|
||||||
|
{
|
||||||
|
List<FieldDescriptor> fieldCollection = new List<FieldDescriptor>();
|
||||||
|
foreach (var field in ContainingType.Fields.InDeclarationOrder())
|
||||||
|
{
|
||||||
|
if (field.ContainingOneof == this)
|
||||||
|
{
|
||||||
|
fieldCollection.Add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fields = new ReadOnlyCollection<FieldDescriptor>(fieldCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OneofAccessor CreateAccessor(string clrName)
|
||||||
|
{
|
||||||
|
var caseProperty = containingType.ClrType.GetProperty(clrName + "Case");
|
||||||
|
if (caseProperty == null)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, $"Property {clrName}Case not found in {containingType.ClrType}");
|
||||||
|
}
|
||||||
|
var clearMethod = containingType.ClrType.GetMethod("Clear" + clrName);
|
||||||
|
if (clearMethod == null)
|
||||||
|
{
|
||||||
|
throw new DescriptorValidationException(this, $"Method Clear{clrName} not found in {containingType.ClrType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OneofAccessor(caseProperty, clearMethod, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the original name (in the .proto file) of a named element,
|
||||||
|
/// such as an enum value.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
public class OriginalNameAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the element in the .proto file.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the name is preferred in the .proto file.
|
||||||
|
/// </summary>
|
||||||
|
public bool PreferredAlias { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new attribute instance for the given name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the element in the .proto file.</param>
|
||||||
|
public OriginalNameAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = ProtoPreconditions.CheckNotNull(name, nameof(name));
|
||||||
|
PreferredAlias = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a package in the symbol table. We use PackageDescriptors
|
||||||
|
/// just as placeholders so that someone cannot define, say, a message type
|
||||||
|
/// that has the same name as an existing package.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class PackageDescriptor : IDescriptor
|
||||||
|
{
|
||||||
|
private readonly string name;
|
||||||
|
private readonly string fullName;
|
||||||
|
private readonly FileDescriptor file;
|
||||||
|
|
||||||
|
internal PackageDescriptor(string name, string fullName, FileDescriptor file)
|
||||||
|
{
|
||||||
|
this.file = file;
|
||||||
|
this.fullName = fullName;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FullName
|
||||||
|
{
|
||||||
|
get { return fullName; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileDescriptor File
|
||||||
|
{
|
||||||
|
get { return file; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
// This file just contains partial classes for any autogenerated classes that need additional support.
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
internal partial class FieldDescriptorProto
|
||||||
|
{
|
||||||
|
// We can't tell the difference between "explicitly set to 0" and "not set"
|
||||||
|
// in proto3, but we need to tell the difference for OneofIndex. descriptor.proto
|
||||||
|
// is really a proto2 file, but the runtime doesn't know about proto2 semantics...
|
||||||
|
// We fake it by defaulting to -1.
|
||||||
|
partial void OnConstruction()
|
||||||
|
{
|
||||||
|
OneofIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal partial class FieldOptions
|
||||||
|
{
|
||||||
|
// We can't tell the difference between "explicitly set to false" and "not set"
|
||||||
|
// in proto3, but we need to tell the difference for FieldDescriptor.IsPacked.
|
||||||
|
// This won't work if we ever need to support proto2, but at that point we'll be
|
||||||
|
// able to remove this hack and use field presence instead.
|
||||||
|
partial void OnConstruction()
|
||||||
|
{
|
||||||
|
Packed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The methods in this class are somewhat evil, and should not be tampered with lightly.
|
||||||
|
/// Basically they allow the creation of relatively weakly typed delegates from MethodInfos
|
||||||
|
/// which are more strongly typed. They do this by creating an appropriate strongly typed
|
||||||
|
/// delegate from the MethodInfo, and then calling that within an anonymous method.
|
||||||
|
/// Mind-bending stuff (at least to your humble narrator) but the resulting delegates are
|
||||||
|
/// very fast compared with calling Invoke later on.
|
||||||
|
/// </summary>
|
||||||
|
internal static class ReflectionUtil
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Empty Type[] used when calling GetProperty to force property instead of indexer fetching.
|
||||||
|
/// </summary>
|
||||||
|
internal static readonly Type[] EmptyTypes = new Type[0];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a delegate which will cast the argument to the appropriate method target type,
|
||||||
|
/// call the method on it, then convert the result to object.
|
||||||
|
/// </summary>
|
||||||
|
internal static Func<IMessage, object> CreateFuncIMessageObject(MethodInfo method)
|
||||||
|
{
|
||||||
|
ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
|
||||||
|
Expression downcast = Expression.Convert(parameter, method.DeclaringType);
|
||||||
|
Expression call = Expression.Call(downcast, method);
|
||||||
|
Expression upcast = Expression.Convert(call, typeof(object));
|
||||||
|
return Expression.Lambda<Func<IMessage, object>>(upcast, parameter).Compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a delegate which will cast the argument to the appropriate method target type,
|
||||||
|
/// call the method on it, then convert the result to the specified type.
|
||||||
|
/// </summary>
|
||||||
|
internal static Func<IMessage, T> CreateFuncIMessageT<T>(MethodInfo method)
|
||||||
|
{
|
||||||
|
ParameterExpression parameter = Expression.Parameter(typeof(IMessage), "p");
|
||||||
|
Expression downcast = Expression.Convert(parameter, method.DeclaringType);
|
||||||
|
Expression call = Expression.Call(downcast, method);
|
||||||
|
Expression upcast = Expression.Convert(call, typeof(T));
|
||||||
|
return Expression.Lambda<Func<IMessage, T>>(upcast, parameter).Compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a delegate which will execute the given method after casting the first argument to
|
||||||
|
/// the target type of the method, and the second argument to the first parameter type of the method.
|
||||||
|
/// </summary>
|
||||||
|
internal static Action<IMessage, object> CreateActionIMessageObject(MethodInfo method)
|
||||||
|
{
|
||||||
|
ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
|
||||||
|
ParameterExpression argParameter = Expression.Parameter(typeof(object), "arg");
|
||||||
|
Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
|
||||||
|
Expression castArgument = Expression.Convert(argParameter, method.GetParameters()[0].ParameterType);
|
||||||
|
Expression call = Expression.Call(castTarget, method, castArgument);
|
||||||
|
return Expression.Lambda<Action<IMessage, object>>(call, targetParameter, argParameter).Compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a delegate which will execute the given method after casting the first argument to
|
||||||
|
/// the target type of the method.
|
||||||
|
/// </summary>
|
||||||
|
internal static Action<IMessage> CreateActionIMessage(MethodInfo method)
|
||||||
|
{
|
||||||
|
ParameterExpression targetParameter = Expression.Parameter(typeof(IMessage), "target");
|
||||||
|
Expression castTarget = Expression.Convert(targetParameter, method.DeclaringType);
|
||||||
|
Expression call = Expression.Call(castTarget, method);
|
||||||
|
return Expression.Lambda<Action<IMessage>>(call, targetParameter).Compile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Accessor for repeated fields.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class RepeatedFieldAccessor : FieldAccessorBase
|
||||||
|
{
|
||||||
|
internal RepeatedFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear(IMessage message)
|
||||||
|
{
|
||||||
|
IList list = (IList) GetValue(message);
|
||||||
|
list.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(IMessage message, object value)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("SetValue is not implemented for repeated fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a service type.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ServiceDescriptor : DescriptorBase
|
||||||
|
{
|
||||||
|
private readonly ServiceDescriptorProto proto;
|
||||||
|
private readonly IList<MethodDescriptor> methods;
|
||||||
|
|
||||||
|
internal ServiceDescriptor(ServiceDescriptorProto proto, FileDescriptor file, int index)
|
||||||
|
: base(file, file.ComputeFullName(null, proto.Name), index)
|
||||||
|
{
|
||||||
|
this.proto = proto;
|
||||||
|
methods = DescriptorUtil.ConvertAndMakeReadOnly(proto.Method,
|
||||||
|
(method, i) => new MethodDescriptor(method, file, this, i));
|
||||||
|
|
||||||
|
file.DescriptorPool.AddSymbol(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The brief name of the descriptor's target.
|
||||||
|
/// </summary>
|
||||||
|
public override string Name { get { return proto.Name; } }
|
||||||
|
|
||||||
|
internal ServiceDescriptorProto Proto { get { return proto; } }
|
||||||
|
|
||||||
|
/// <value>
|
||||||
|
/// An unmodifiable list of methods in this service.
|
||||||
|
/// </value>
|
||||||
|
public IList<MethodDescriptor> Methods
|
||||||
|
{
|
||||||
|
get { return methods; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds a method by name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The unqualified name of the method (e.g. "Foo").</param>
|
||||||
|
/// <returns>The method's decsriptor, or null if not found.</returns>
|
||||||
|
public MethodDescriptor FindMethodByName(String name)
|
||||||
|
{
|
||||||
|
return File.DescriptorPool.FindSymbol<MethodDescriptor>(FullName + "." + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The (possibly empty) set of custom options for this service.
|
||||||
|
/// </summary>
|
||||||
|
public CustomOptions CustomOptions => Proto.Options?.CustomOptions ?? CustomOptions.Empty;
|
||||||
|
|
||||||
|
internal void CrossLink()
|
||||||
|
{
|
||||||
|
foreach (MethodDescriptor method in methods)
|
||||||
|
{
|
||||||
|
method.CrossLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Accessor for single fields.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class SingleFieldAccessor : FieldAccessorBase
|
||||||
|
{
|
||||||
|
// All the work here is actually done in the constructor - it creates the appropriate delegates.
|
||||||
|
// There are various cases to consider, based on the property type (message, string/bytes, or "genuine" primitive)
|
||||||
|
// and proto2 vs proto3 for non-message types, as proto3 doesn't support "full" presence detection or default
|
||||||
|
// values.
|
||||||
|
|
||||||
|
private readonly Action<IMessage, object> setValueDelegate;
|
||||||
|
private readonly Action<IMessage> clearDelegate;
|
||||||
|
|
||||||
|
internal SingleFieldAccessor(PropertyInfo property, FieldDescriptor descriptor) : base(property, descriptor)
|
||||||
|
{
|
||||||
|
if (!property.CanWrite)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Not all required properties/methods available");
|
||||||
|
}
|
||||||
|
setValueDelegate = ReflectionUtil.CreateActionIMessageObject(property.GetSetMethod());
|
||||||
|
|
||||||
|
var clrType = property.PropertyType;
|
||||||
|
|
||||||
|
// TODO: Validate that this is a reasonable single field? (Should be a value type, a message type, or string/ByteString.)
|
||||||
|
object defaultValue =
|
||||||
|
descriptor.FieldType == FieldType.Message ? null
|
||||||
|
: clrType == typeof(string) ? ""
|
||||||
|
: clrType == typeof(ByteString) ? ByteString.Empty
|
||||||
|
: Activator.CreateInstance(clrType);
|
||||||
|
clearDelegate = message => SetValue(message, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Clear(IMessage message)
|
||||||
|
{
|
||||||
|
clearDelegate(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetValue(IMessage message, object value)
|
||||||
|
{
|
||||||
|
setValueDelegate(message, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.Reflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An immutable registry of types which can be looked up by their full name.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TypeRegistry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An empty type registry, containing no types.
|
||||||
|
/// </summary>
|
||||||
|
public static TypeRegistry Empty { get; } = new TypeRegistry(new Dictionary<string, MessageDescriptor>());
|
||||||
|
|
||||||
|
private readonly Dictionary<string, MessageDescriptor> fullNameToMessageMap;
|
||||||
|
|
||||||
|
private TypeRegistry(Dictionary<string, MessageDescriptor> fullNameToMessageMap)
|
||||||
|
{
|
||||||
|
this.fullNameToMessageMap = fullNameToMessageMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to find a message descriptor by its full name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fullName">The full name of the message, which is the dot-separated
|
||||||
|
/// combination of package, containing messages and message name</param>
|
||||||
|
/// <returns>The message descriptor corresponding to <paramref name="fullName"/> or null
|
||||||
|
/// if there is no such message descriptor.</returns>
|
||||||
|
public MessageDescriptor Find(string fullName)
|
||||||
|
{
|
||||||
|
MessageDescriptor ret;
|
||||||
|
// Ignore the return value as ret will end up with the right value either way.
|
||||||
|
fullNameToMessageMap.TryGetValue(fullName, out ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a type registry from the specified set of file descriptors.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is a convenience overload for <see cref="FromFiles(IEnumerable{FileDescriptor})"/>
|
||||||
|
/// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
|
||||||
|
/// <returns>A type registry for the given files.</returns>
|
||||||
|
public static TypeRegistry FromFiles(params FileDescriptor[] fileDescriptors)
|
||||||
|
{
|
||||||
|
return FromFiles((IEnumerable<FileDescriptor>) fileDescriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a type registry from the specified set of file descriptors.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// All message types within all the specified files are added to the registry, and
|
||||||
|
/// the dependencies of the specified files are also added, recursively.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="fileDescriptors">The set of files to include in the registry. Must not contain null values.</param>
|
||||||
|
/// <returns>A type registry for the given files.</returns>
|
||||||
|
public static TypeRegistry FromFiles(IEnumerable<FileDescriptor> fileDescriptors)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(fileDescriptors, nameof(fileDescriptors));
|
||||||
|
var builder = new Builder();
|
||||||
|
foreach (var file in fileDescriptors)
|
||||||
|
{
|
||||||
|
builder.AddFile(file);
|
||||||
|
}
|
||||||
|
return builder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is a convenience overload for <see cref="FromMessages(IEnumerable{MessageDescriptor})"/>
|
||||||
|
/// to allow calls such as <c>TypeRegistry.FromFiles(descriptor1, descriptor2)</c>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
|
||||||
|
/// Must not contain null values.</param>
|
||||||
|
/// <returns>A type registry for the given files.</returns>
|
||||||
|
public static TypeRegistry FromMessages(params MessageDescriptor[] messageDescriptors)
|
||||||
|
{
|
||||||
|
return FromMessages((IEnumerable<MessageDescriptor>) messageDescriptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a type registry from the file descriptor parents of the specified set of message descriptors.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The specified message descriptors are only used to identify their file descriptors; the returned registry
|
||||||
|
/// contains all the types within the file descriptors which contain the specified message descriptors (and
|
||||||
|
/// the dependencies of those files), not just the specified messages.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="messageDescriptors">The set of message descriptors to use to identify file descriptors to include in the registry.
|
||||||
|
/// Must not contain null values.</param>
|
||||||
|
/// <returns>A type registry for the given files.</returns>
|
||||||
|
public static TypeRegistry FromMessages(IEnumerable<MessageDescriptor> messageDescriptors)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(messageDescriptors, nameof(messageDescriptors));
|
||||||
|
return FromFiles(messageDescriptors.Select(md => md.File));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builder class which isn't exposed, but acts as a convenient alternative to passing round two dictionaries in recursive calls.
|
||||||
|
/// </summary>
|
||||||
|
private class Builder
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, MessageDescriptor> types;
|
||||||
|
private readonly HashSet<string> fileDescriptorNames;
|
||||||
|
|
||||||
|
internal Builder()
|
||||||
|
{
|
||||||
|
types = new Dictionary<string, MessageDescriptor>();
|
||||||
|
fileDescriptorNames = new HashSet<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddFile(FileDescriptor fileDescriptor)
|
||||||
|
{
|
||||||
|
if (!fileDescriptorNames.Add(fileDescriptor.Name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var dependency in fileDescriptor.Dependencies)
|
||||||
|
{
|
||||||
|
AddFile(dependency);
|
||||||
|
}
|
||||||
|
foreach (var message in fileDescriptor.MessageTypes)
|
||||||
|
{
|
||||||
|
AddMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddMessage(MessageDescriptor messageDescriptor)
|
||||||
|
{
|
||||||
|
foreach (var nestedType in messageDescriptor.NestedTypes)
|
||||||
|
{
|
||||||
|
AddMessage(nestedType);
|
||||||
|
}
|
||||||
|
// This will overwrite any previous entry. Given that each file should
|
||||||
|
// only be added once, this could be a problem such as package A.B with type C,
|
||||||
|
// and package A with type B.C... it's unclear what we should do in that case.
|
||||||
|
types[messageDescriptor.FullName] = messageDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal TypeRegistry Build()
|
||||||
|
{
|
||||||
|
return new TypeRegistry(types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/any.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/any.proto</summary>
|
||||||
|
public static partial class AnyReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/any.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static AnyReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi",
|
||||||
|
"JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQm8KE2Nv",
|
||||||
|
"bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29s",
|
||||||
|
"YW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmiAgNHUEKqAh5Hb29nbGUuUHJvdG9i",
|
||||||
|
"dWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw=="));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Any), global::Google.Protobuf.WellKnownTypes.Any.Parser, new[]{ "TypeUrl", "Value" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||||
|
/// URL that describes the type of the serialized message.
|
||||||
|
///
|
||||||
|
/// Protobuf library provides support to pack/unpack Any values in the form
|
||||||
|
/// of utility functions or additional generated methods of the Any type.
|
||||||
|
///
|
||||||
|
/// Example 1: Pack and unpack a message in C++.
|
||||||
|
///
|
||||||
|
/// Foo foo = ...;
|
||||||
|
/// Any any;
|
||||||
|
/// any.PackFrom(foo);
|
||||||
|
/// ...
|
||||||
|
/// if (any.UnpackTo(&foo)) {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Example 2: Pack and unpack a message in Java.
|
||||||
|
///
|
||||||
|
/// Foo foo = ...;
|
||||||
|
/// Any any = Any.pack(foo);
|
||||||
|
/// ...
|
||||||
|
/// if (any.is(Foo.class)) {
|
||||||
|
/// foo = any.unpack(Foo.class);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Example 3: Pack and unpack a message in Python.
|
||||||
|
///
|
||||||
|
/// foo = Foo(...)
|
||||||
|
/// any = Any()
|
||||||
|
/// any.Pack(foo)
|
||||||
|
/// ...
|
||||||
|
/// if any.Is(Foo.DESCRIPTOR):
|
||||||
|
/// any.Unpack(foo)
|
||||||
|
/// ...
|
||||||
|
///
|
||||||
|
/// Example 4: Pack and unpack a message in Go
|
||||||
|
///
|
||||||
|
/// foo := &pb.Foo{...}
|
||||||
|
/// any, err := ptypes.MarshalAny(foo)
|
||||||
|
/// ...
|
||||||
|
/// foo := &pb.Foo{}
|
||||||
|
/// if err := ptypes.UnmarshalAny(any, foo); err != nil {
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// The pack methods provided by protobuf library will by default use
|
||||||
|
/// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||||
|
/// methods only use the fully qualified type name after the last '/'
|
||||||
|
/// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||||
|
/// name "y.z".
|
||||||
|
///
|
||||||
|
/// JSON
|
||||||
|
/// ====
|
||||||
|
/// The JSON representation of an `Any` value uses the regular
|
||||||
|
/// representation of the deserialized, embedded message, with an
|
||||||
|
/// additional field `@type` which contains the type URL. Example:
|
||||||
|
///
|
||||||
|
/// package google.profile;
|
||||||
|
/// message Person {
|
||||||
|
/// string first_name = 1;
|
||||||
|
/// string last_name = 2;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// "@type": "type.googleapis.com/google.profile.Person",
|
||||||
|
/// "firstName": <string>,
|
||||||
|
/// "lastName": <string>
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// If the embedded message type is well-known and has a custom JSON
|
||||||
|
/// representation, that representation will be embedded adding a field
|
||||||
|
/// `value` which holds the custom JSON in addition to the `@type`
|
||||||
|
/// field. Example (for message [google.protobuf.Duration][]):
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||||
|
/// "value": "1.212s"
|
||||||
|
/// }
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Any : pb::IMessage<Any> {
|
||||||
|
private static readonly pb::MessageParser<Any> _parser = new pb::MessageParser<Any>(() => new Any());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Any> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Any() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Any(Any other) : this() {
|
||||||
|
typeUrl_ = other.typeUrl_;
|
||||||
|
value_ = other.value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Any Clone() {
|
||||||
|
return new Any(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "type_url" field.</summary>
|
||||||
|
public const int TypeUrlFieldNumber = 1;
|
||||||
|
private string typeUrl_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// A URL/resource name whose content describes the type of the
|
||||||
|
/// serialized protocol buffer message.
|
||||||
|
///
|
||||||
|
/// For URLs which use the scheme `http`, `https`, or no scheme, the
|
||||||
|
/// following restrictions and interpretations apply:
|
||||||
|
///
|
||||||
|
/// * If no scheme is provided, `https` is assumed.
|
||||||
|
/// * The last segment of the URL's path must represent the fully
|
||||||
|
/// qualified name of the type (as in `path/google.protobuf.Duration`).
|
||||||
|
/// The name should be in a canonical form (e.g., leading "." is
|
||||||
|
/// not accepted).
|
||||||
|
/// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||||
|
/// value in binary format, or produce an error.
|
||||||
|
/// * Applications are allowed to cache lookup results based on the
|
||||||
|
/// URL, or have them precompiled into a binary to avoid any
|
||||||
|
/// lookup. Therefore, binary compatibility needs to be preserved
|
||||||
|
/// on changes to types. (Use versioned type names to manage
|
||||||
|
/// breaking changes.)
|
||||||
|
///
|
||||||
|
/// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||||
|
/// used with implementation specific semantics.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string TypeUrl {
|
||||||
|
get { return typeUrl_; }
|
||||||
|
set {
|
||||||
|
typeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "value" field.</summary>
|
||||||
|
public const int ValueFieldNumber = 2;
|
||||||
|
private pb::ByteString value_ = pb::ByteString.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// Must be a valid serialized protocol buffer of the above specified type.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pb::ByteString Value {
|
||||||
|
get { return value_; }
|
||||||
|
set {
|
||||||
|
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Any);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Any other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (TypeUrl != other.TypeUrl) return false;
|
||||||
|
if (Value != other.Value) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode();
|
||||||
|
if (Value.Length != 0) hash ^= Value.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (TypeUrl.Length != 0) {
|
||||||
|
output.WriteRawTag(10);
|
||||||
|
output.WriteString(TypeUrl);
|
||||||
|
}
|
||||||
|
if (Value.Length != 0) {
|
||||||
|
output.WriteRawTag(18);
|
||||||
|
output.WriteBytes(Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (TypeUrl.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(TypeUrl);
|
||||||
|
}
|
||||||
|
if (Value.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeBytesSize(Value);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Any other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.TypeUrl.Length != 0) {
|
||||||
|
TypeUrl = other.TypeUrl;
|
||||||
|
}
|
||||||
|
if (other.Value.Length != 0) {
|
||||||
|
Value = other.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
TypeUrl = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 18: {
|
||||||
|
Value = input.ReadBytes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using Google.Protobuf.Reflection;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
public partial class Any
|
||||||
|
{
|
||||||
|
private const string DefaultPrefix = "type.googleapis.com";
|
||||||
|
|
||||||
|
// This could be moved to MessageDescriptor if we wanted to, but keeping it here means
|
||||||
|
// all the Any-specific code is in the same place.
|
||||||
|
private static string GetTypeUrl(MessageDescriptor descriptor, string prefix) =>
|
||||||
|
prefix.EndsWith("/") ? prefix + descriptor.FullName : prefix + "/" + descriptor.FullName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves the type name for a type URL, matching the <see cref="DescriptorBase.FullName"/>
|
||||||
|
/// of the packed message type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// This is always just the last part of the URL, after the final slash. No validation of
|
||||||
|
/// anything before the trailing slash is performed. If the type URL does not include a slash,
|
||||||
|
/// an empty string is returned rather than an exception being thrown; this won't match any types,
|
||||||
|
/// and the calling code is probably in a better position to give a meaningful error.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// There is no handling of fragments or queries at the moment.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="typeUrl">The URL to extract the type name from</param>
|
||||||
|
/// <returns>The type name</returns>
|
||||||
|
public static string GetTypeName(string typeUrl)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(typeUrl, nameof(typeUrl));
|
||||||
|
int lastSlash = typeUrl.LastIndexOf('/');
|
||||||
|
return lastSlash == -1 ? "" : typeUrl.Substring(lastSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unpacks the content of this Any message into the target message type,
|
||||||
|
/// which must match the type URL within this Any message.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of message to unpack the content into.</typeparam>
|
||||||
|
/// <returns>The unpacked message.</returns>
|
||||||
|
/// <exception cref="InvalidProtocolBufferException">The target message type doesn't match the type URL in this message</exception>
|
||||||
|
public T Unpack<T>() where T : IMessage, new()
|
||||||
|
{
|
||||||
|
// Note: this doesn't perform as well is it might. We could take a MessageParser<T> in an alternative overload,
|
||||||
|
// which would be expected to perform slightly better... although the difference is likely to be negligible.
|
||||||
|
T target = new T();
|
||||||
|
if (GetTypeName(TypeUrl) != target.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
throw new InvalidProtocolBufferException(
|
||||||
|
$"Full type name for {target.Descriptor.Name} is {target.Descriptor.FullName}; Any message's type url is {TypeUrl}");
|
||||||
|
}
|
||||||
|
target.MergeFrom(Value);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to unpack the content of this Any message into the target message type,
|
||||||
|
/// if it matches the type URL within this Any message.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of message to attempt to unpack the content into.</typeparam>
|
||||||
|
/// <returns><c>true</c> if the message was successfully unpacked; <c>false</c> if the type name didn't match</returns>
|
||||||
|
public bool TryUnpack<T>(out T result) where T : IMessage, new()
|
||||||
|
{
|
||||||
|
// Note: deliberately avoid writing anything to result until the end, in case it's being
|
||||||
|
// monitored by other threads. (That would be a bug in the calling code, but let's not make it worse.)
|
||||||
|
T target = new T();
|
||||||
|
if (GetTypeName(TypeUrl) != target.Descriptor.FullName)
|
||||||
|
{
|
||||||
|
result = default(T); // Can't use null as there's no class constraint, but this always *will* be null in real usage.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
target.MergeFrom(Value);
|
||||||
|
result = target;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Packs the specified message into an Any message using a type URL prefix of "type.googleapis.com".
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to pack.</param>
|
||||||
|
/// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
|
||||||
|
public static Any Pack(IMessage message) => Pack(message, DefaultPrefix);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Packs the specified message into an Any message using the specified type URL prefix.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message to pack.</param>
|
||||||
|
/// <param name="typeUrlPrefix">The prefix for the type URL.</param>
|
||||||
|
/// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
|
||||||
|
public static Any Pack(IMessage message, string typeUrlPrefix)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(message, nameof(message));
|
||||||
|
ProtoPreconditions.CheckNotNull(typeUrlPrefix, nameof(typeUrlPrefix));
|
||||||
|
return new Any
|
||||||
|
{
|
||||||
|
TypeUrl = GetTypeUrl(message.Descriptor, typeUrlPrefix),
|
||||||
|
Value = message.ToByteString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,910 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/api.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbc = global::Google.Protobuf.Collections;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/api.proto</summary>
|
||||||
|
public static partial class ApiReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/api.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static ApiReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"Chlnb29nbGUvcHJvdG9idWYvYXBpLnByb3RvEg9nb29nbGUucHJvdG9idWYa",
|
||||||
|
"JGdvb2dsZS9wcm90b2J1Zi9zb3VyY2VfY29udGV4dC5wcm90bxoaZ29vZ2xl",
|
||||||
|
"L3Byb3RvYnVmL3R5cGUucHJvdG8igQIKA0FwaRIMCgRuYW1lGAEgASgJEigK",
|
||||||
|
"B21ldGhvZHMYAiADKAsyFy5nb29nbGUucHJvdG9idWYuTWV0aG9kEigKB29w",
|
||||||
|
"dGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9uEg8KB3ZlcnNp",
|
||||||
|
"b24YBCABKAkSNgoOc291cmNlX2NvbnRleHQYBSABKAsyHi5nb29nbGUucHJv",
|
||||||
|
"dG9idWYuU291cmNlQ29udGV4dBImCgZtaXhpbnMYBiADKAsyFi5nb29nbGUu",
|
||||||
|
"cHJvdG9idWYuTWl4aW4SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3Rv",
|
||||||
|
"YnVmLlN5bnRheCLVAQoGTWV0aG9kEgwKBG5hbWUYASABKAkSGAoQcmVxdWVz",
|
||||||
|
"dF90eXBlX3VybBgCIAEoCRIZChFyZXF1ZXN0X3N0cmVhbWluZxgDIAEoCBIZ",
|
||||||
|
"ChFyZXNwb25zZV90eXBlX3VybBgEIAEoCRIaChJyZXNwb25zZV9zdHJlYW1p",
|
||||||
|
"bmcYBSABKAgSKAoHb3B0aW9ucxgGIAMoCzIXLmdvb2dsZS5wcm90b2J1Zi5P",
|
||||||
|
"cHRpb24SJwoGc3ludGF4GAcgASgOMhcuZ29vZ2xlLnByb3RvYnVmLlN5bnRh",
|
||||||
|
"eCIjCgVNaXhpbhIMCgRuYW1lGAEgASgJEgwKBHJvb3QYAiABKAlCdQoTY29t",
|
||||||
|
"Lmdvb2dsZS5wcm90b2J1ZkIIQXBpUHJvdG9QAVorZ29vZ2xlLmdvbGFuZy5v",
|
||||||
|
"cmcvZ2VucHJvdG8vcHJvdG9idWYvYXBpO2FwaaICA0dQQqoCHkdvb2dsZS5Q",
|
||||||
|
"cm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.TypeReflection.Descriptor, },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Api), global::Google.Protobuf.WellKnownTypes.Api.Parser, new[]{ "Name", "Methods", "Options", "Version", "SourceContext", "Mixins", "Syntax" }, null, null, null),
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Method), global::Google.Protobuf.WellKnownTypes.Method.Parser, new[]{ "Name", "RequestTypeUrl", "RequestStreaming", "ResponseTypeUrl", "ResponseStreaming", "Options", "Syntax" }, null, null, null),
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Mixin), global::Google.Protobuf.WellKnownTypes.Mixin.Parser, new[]{ "Name", "Root" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// Api is a light-weight descriptor for an API Interface.
|
||||||
|
///
|
||||||
|
/// Interfaces are also described as "protocol buffer services" in some contexts,
|
||||||
|
/// such as by the "service" keyword in a .proto file, but they are different
|
||||||
|
/// from API Services, which represent a concrete implementation of an interface
|
||||||
|
/// as opposed to simply a description of methods and bindings. They are also
|
||||||
|
/// sometimes simply referred to as "APIs" in other contexts, such as the name of
|
||||||
|
/// this message itself. See https://cloud.google.com/apis/design/glossary for
|
||||||
|
/// detailed terminology.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Api : pb::IMessage<Api> {
|
||||||
|
private static readonly pb::MessageParser<Api> _parser = new pb::MessageParser<Api>(() => new Api());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Api> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Api() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Api(Api other) : this() {
|
||||||
|
name_ = other.name_;
|
||||||
|
methods_ = other.methods_.Clone();
|
||||||
|
options_ = other.options_.Clone();
|
||||||
|
version_ = other.version_;
|
||||||
|
SourceContext = other.sourceContext_ != null ? other.SourceContext.Clone() : null;
|
||||||
|
mixins_ = other.mixins_.Clone();
|
||||||
|
syntax_ = other.syntax_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Api Clone() {
|
||||||
|
return new Api(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "name" field.</summary>
|
||||||
|
public const int NameFieldNumber = 1;
|
||||||
|
private string name_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// The fully qualified name of this interface, including package name
|
||||||
|
/// followed by the interface's simple name.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string Name {
|
||||||
|
get { return name_; }
|
||||||
|
set {
|
||||||
|
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "methods" field.</summary>
|
||||||
|
public const int MethodsFieldNumber = 2;
|
||||||
|
private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Method> _repeated_methods_codec
|
||||||
|
= pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Method.Parser);
|
||||||
|
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> methods_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method>();
|
||||||
|
/// <summary>
|
||||||
|
/// The methods of this interface, in unspecified order.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Method> Methods {
|
||||||
|
get { return methods_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "options" field.</summary>
|
||||||
|
public const int OptionsFieldNumber = 3;
|
||||||
|
private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
|
||||||
|
= pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
|
||||||
|
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
|
||||||
|
/// <summary>
|
||||||
|
/// Any metadata attached to the interface.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
|
||||||
|
get { return options_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "version" field.</summary>
|
||||||
|
public const int VersionFieldNumber = 4;
|
||||||
|
private string version_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// A version string for this interface. If specified, must have the form
|
||||||
|
/// `major-version.minor-version`, as in `1.10`. If the minor version is
|
||||||
|
/// omitted, it defaults to zero. If the entire version field is empty, the
|
||||||
|
/// major version is derived from the package name, as outlined below. If the
|
||||||
|
/// field is not empty, the version in the package name will be verified to be
|
||||||
|
/// consistent with what is provided here.
|
||||||
|
///
|
||||||
|
/// The versioning schema uses [semantic
|
||||||
|
/// versioning](http://semver.org) where the major version number
|
||||||
|
/// indicates a breaking change and the minor version an additive,
|
||||||
|
/// non-breaking change. Both version numbers are signals to users
|
||||||
|
/// what to expect from different versions, and should be carefully
|
||||||
|
/// chosen based on the product plan.
|
||||||
|
///
|
||||||
|
/// The major version is also reflected in the package name of the
|
||||||
|
/// interface, which must end in `v<major-version>`, as in
|
||||||
|
/// `google.feature.v1`. For major versions 0 and 1, the suffix can
|
||||||
|
/// be omitted. Zero major versions must only be used for
|
||||||
|
/// experimental, non-GA interfaces.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string Version {
|
||||||
|
get { return version_; }
|
||||||
|
set {
|
||||||
|
version_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "source_context" field.</summary>
|
||||||
|
public const int SourceContextFieldNumber = 5;
|
||||||
|
private global::Google.Protobuf.WellKnownTypes.SourceContext sourceContext_;
|
||||||
|
/// <summary>
|
||||||
|
/// Source context for the protocol buffer service represented by this
|
||||||
|
/// message.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public global::Google.Protobuf.WellKnownTypes.SourceContext SourceContext {
|
||||||
|
get { return sourceContext_; }
|
||||||
|
set {
|
||||||
|
sourceContext_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "mixins" field.</summary>
|
||||||
|
public const int MixinsFieldNumber = 6;
|
||||||
|
private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Mixin> _repeated_mixins_codec
|
||||||
|
= pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Mixin.Parser);
|
||||||
|
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> mixins_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin>();
|
||||||
|
/// <summary>
|
||||||
|
/// Included interfaces. See [Mixin][].
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Mixin> Mixins {
|
||||||
|
get { return mixins_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "syntax" field.</summary>
|
||||||
|
public const int SyntaxFieldNumber = 7;
|
||||||
|
private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// The source syntax of the service.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
|
||||||
|
get { return syntax_; }
|
||||||
|
set {
|
||||||
|
syntax_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Api);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Api other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Name != other.Name) return false;
|
||||||
|
if(!methods_.Equals(other.methods_)) return false;
|
||||||
|
if(!options_.Equals(other.options_)) return false;
|
||||||
|
if (Version != other.Version) return false;
|
||||||
|
if (!object.Equals(SourceContext, other.SourceContext)) return false;
|
||||||
|
if(!mixins_.Equals(other.mixins_)) return false;
|
||||||
|
if (Syntax != other.Syntax) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (Name.Length != 0) hash ^= Name.GetHashCode();
|
||||||
|
hash ^= methods_.GetHashCode();
|
||||||
|
hash ^= options_.GetHashCode();
|
||||||
|
if (Version.Length != 0) hash ^= Version.GetHashCode();
|
||||||
|
if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
|
||||||
|
hash ^= mixins_.GetHashCode();
|
||||||
|
if (Syntax != 0) hash ^= Syntax.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (Name.Length != 0) {
|
||||||
|
output.WriteRawTag(10);
|
||||||
|
output.WriteString(Name);
|
||||||
|
}
|
||||||
|
methods_.WriteTo(output, _repeated_methods_codec);
|
||||||
|
options_.WriteTo(output, _repeated_options_codec);
|
||||||
|
if (Version.Length != 0) {
|
||||||
|
output.WriteRawTag(34);
|
||||||
|
output.WriteString(Version);
|
||||||
|
}
|
||||||
|
if (sourceContext_ != null) {
|
||||||
|
output.WriteRawTag(42);
|
||||||
|
output.WriteMessage(SourceContext);
|
||||||
|
}
|
||||||
|
mixins_.WriteTo(output, _repeated_mixins_codec);
|
||||||
|
if (Syntax != 0) {
|
||||||
|
output.WriteRawTag(56);
|
||||||
|
output.WriteEnum((int) Syntax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (Name.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
|
||||||
|
}
|
||||||
|
size += methods_.CalculateSize(_repeated_methods_codec);
|
||||||
|
size += options_.CalculateSize(_repeated_options_codec);
|
||||||
|
if (Version.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(Version);
|
||||||
|
}
|
||||||
|
if (sourceContext_ != null) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext);
|
||||||
|
}
|
||||||
|
size += mixins_.CalculateSize(_repeated_mixins_codec);
|
||||||
|
if (Syntax != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Api other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.Name.Length != 0) {
|
||||||
|
Name = other.Name;
|
||||||
|
}
|
||||||
|
methods_.Add(other.methods_);
|
||||||
|
options_.Add(other.options_);
|
||||||
|
if (other.Version.Length != 0) {
|
||||||
|
Version = other.Version;
|
||||||
|
}
|
||||||
|
if (other.sourceContext_ != null) {
|
||||||
|
if (sourceContext_ == null) {
|
||||||
|
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
|
||||||
|
}
|
||||||
|
SourceContext.MergeFrom(other.SourceContext);
|
||||||
|
}
|
||||||
|
mixins_.Add(other.mixins_);
|
||||||
|
if (other.Syntax != 0) {
|
||||||
|
Syntax = other.Syntax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
Name = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 18: {
|
||||||
|
methods_.AddEntriesFrom(input, _repeated_methods_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 26: {
|
||||||
|
options_.AddEntriesFrom(input, _repeated_options_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 34: {
|
||||||
|
Version = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 42: {
|
||||||
|
if (sourceContext_ == null) {
|
||||||
|
sourceContext_ = new global::Google.Protobuf.WellKnownTypes.SourceContext();
|
||||||
|
}
|
||||||
|
input.ReadMessage(sourceContext_);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 50: {
|
||||||
|
mixins_.AddEntriesFrom(input, _repeated_mixins_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 56: {
|
||||||
|
syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Method represents a method of an API interface.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Method : pb::IMessage<Method> {
|
||||||
|
private static readonly pb::MessageParser<Method> _parser = new pb::MessageParser<Method>(() => new Method());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Method> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[1]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Method() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Method(Method other) : this() {
|
||||||
|
name_ = other.name_;
|
||||||
|
requestTypeUrl_ = other.requestTypeUrl_;
|
||||||
|
requestStreaming_ = other.requestStreaming_;
|
||||||
|
responseTypeUrl_ = other.responseTypeUrl_;
|
||||||
|
responseStreaming_ = other.responseStreaming_;
|
||||||
|
options_ = other.options_.Clone();
|
||||||
|
syntax_ = other.syntax_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Method Clone() {
|
||||||
|
return new Method(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "name" field.</summary>
|
||||||
|
public const int NameFieldNumber = 1;
|
||||||
|
private string name_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// The simple name of this method.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string Name {
|
||||||
|
get { return name_; }
|
||||||
|
set {
|
||||||
|
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "request_type_url" field.</summary>
|
||||||
|
public const int RequestTypeUrlFieldNumber = 2;
|
||||||
|
private string requestTypeUrl_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// A URL of the input message type.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string RequestTypeUrl {
|
||||||
|
get { return requestTypeUrl_; }
|
||||||
|
set {
|
||||||
|
requestTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "request_streaming" field.</summary>
|
||||||
|
public const int RequestStreamingFieldNumber = 3;
|
||||||
|
private bool requestStreaming_;
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the request is streamed.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool RequestStreaming {
|
||||||
|
get { return requestStreaming_; }
|
||||||
|
set {
|
||||||
|
requestStreaming_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "response_type_url" field.</summary>
|
||||||
|
public const int ResponseTypeUrlFieldNumber = 4;
|
||||||
|
private string responseTypeUrl_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// The URL of the output message type.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string ResponseTypeUrl {
|
||||||
|
get { return responseTypeUrl_; }
|
||||||
|
set {
|
||||||
|
responseTypeUrl_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "response_streaming" field.</summary>
|
||||||
|
public const int ResponseStreamingFieldNumber = 5;
|
||||||
|
private bool responseStreaming_;
|
||||||
|
/// <summary>
|
||||||
|
/// If true, the response is streamed.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool ResponseStreaming {
|
||||||
|
get { return responseStreaming_; }
|
||||||
|
set {
|
||||||
|
responseStreaming_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "options" field.</summary>
|
||||||
|
public const int OptionsFieldNumber = 6;
|
||||||
|
private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Option> _repeated_options_codec
|
||||||
|
= pb::FieldCodec.ForMessage(50, global::Google.Protobuf.WellKnownTypes.Option.Parser);
|
||||||
|
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
|
||||||
|
/// <summary>
|
||||||
|
/// Any metadata attached to the method.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
|
||||||
|
get { return options_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "syntax" field.</summary>
|
||||||
|
public const int SyntaxFieldNumber = 7;
|
||||||
|
private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0;
|
||||||
|
/// <summary>
|
||||||
|
/// The source syntax of this method.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public global::Google.Protobuf.WellKnownTypes.Syntax Syntax {
|
||||||
|
get { return syntax_; }
|
||||||
|
set {
|
||||||
|
syntax_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Method);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Method other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Name != other.Name) return false;
|
||||||
|
if (RequestTypeUrl != other.RequestTypeUrl) return false;
|
||||||
|
if (RequestStreaming != other.RequestStreaming) return false;
|
||||||
|
if (ResponseTypeUrl != other.ResponseTypeUrl) return false;
|
||||||
|
if (ResponseStreaming != other.ResponseStreaming) return false;
|
||||||
|
if(!options_.Equals(other.options_)) return false;
|
||||||
|
if (Syntax != other.Syntax) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (Name.Length != 0) hash ^= Name.GetHashCode();
|
||||||
|
if (RequestTypeUrl.Length != 0) hash ^= RequestTypeUrl.GetHashCode();
|
||||||
|
if (RequestStreaming != false) hash ^= RequestStreaming.GetHashCode();
|
||||||
|
if (ResponseTypeUrl.Length != 0) hash ^= ResponseTypeUrl.GetHashCode();
|
||||||
|
if (ResponseStreaming != false) hash ^= ResponseStreaming.GetHashCode();
|
||||||
|
hash ^= options_.GetHashCode();
|
||||||
|
if (Syntax != 0) hash ^= Syntax.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (Name.Length != 0) {
|
||||||
|
output.WriteRawTag(10);
|
||||||
|
output.WriteString(Name);
|
||||||
|
}
|
||||||
|
if (RequestTypeUrl.Length != 0) {
|
||||||
|
output.WriteRawTag(18);
|
||||||
|
output.WriteString(RequestTypeUrl);
|
||||||
|
}
|
||||||
|
if (RequestStreaming != false) {
|
||||||
|
output.WriteRawTag(24);
|
||||||
|
output.WriteBool(RequestStreaming);
|
||||||
|
}
|
||||||
|
if (ResponseTypeUrl.Length != 0) {
|
||||||
|
output.WriteRawTag(34);
|
||||||
|
output.WriteString(ResponseTypeUrl);
|
||||||
|
}
|
||||||
|
if (ResponseStreaming != false) {
|
||||||
|
output.WriteRawTag(40);
|
||||||
|
output.WriteBool(ResponseStreaming);
|
||||||
|
}
|
||||||
|
options_.WriteTo(output, _repeated_options_codec);
|
||||||
|
if (Syntax != 0) {
|
||||||
|
output.WriteRawTag(56);
|
||||||
|
output.WriteEnum((int) Syntax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (Name.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
|
||||||
|
}
|
||||||
|
if (RequestTypeUrl.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(RequestTypeUrl);
|
||||||
|
}
|
||||||
|
if (RequestStreaming != false) {
|
||||||
|
size += 1 + 1;
|
||||||
|
}
|
||||||
|
if (ResponseTypeUrl.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(ResponseTypeUrl);
|
||||||
|
}
|
||||||
|
if (ResponseStreaming != false) {
|
||||||
|
size += 1 + 1;
|
||||||
|
}
|
||||||
|
size += options_.CalculateSize(_repeated_options_codec);
|
||||||
|
if (Syntax != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Method other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.Name.Length != 0) {
|
||||||
|
Name = other.Name;
|
||||||
|
}
|
||||||
|
if (other.RequestTypeUrl.Length != 0) {
|
||||||
|
RequestTypeUrl = other.RequestTypeUrl;
|
||||||
|
}
|
||||||
|
if (other.RequestStreaming != false) {
|
||||||
|
RequestStreaming = other.RequestStreaming;
|
||||||
|
}
|
||||||
|
if (other.ResponseTypeUrl.Length != 0) {
|
||||||
|
ResponseTypeUrl = other.ResponseTypeUrl;
|
||||||
|
}
|
||||||
|
if (other.ResponseStreaming != false) {
|
||||||
|
ResponseStreaming = other.ResponseStreaming;
|
||||||
|
}
|
||||||
|
options_.Add(other.options_);
|
||||||
|
if (other.Syntax != 0) {
|
||||||
|
Syntax = other.Syntax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
Name = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 18: {
|
||||||
|
RequestTypeUrl = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 24: {
|
||||||
|
RequestStreaming = input.ReadBool();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 34: {
|
||||||
|
ResponseTypeUrl = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 40: {
|
||||||
|
ResponseStreaming = input.ReadBool();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 50: {
|
||||||
|
options_.AddEntriesFrom(input, _repeated_options_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 56: {
|
||||||
|
syntax_ = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Declares an API Interface to be included in this interface. The including
|
||||||
|
/// interface must redeclare all the methods from the included interface, but
|
||||||
|
/// documentation and options are inherited as follows:
|
||||||
|
///
|
||||||
|
/// - If after comment and whitespace stripping, the documentation
|
||||||
|
/// string of the redeclared method is empty, it will be inherited
|
||||||
|
/// from the original method.
|
||||||
|
///
|
||||||
|
/// - Each annotation belonging to the service config (http,
|
||||||
|
/// visibility) which is not set in the redeclared method will be
|
||||||
|
/// inherited.
|
||||||
|
///
|
||||||
|
/// - If an http annotation is inherited, the path pattern will be
|
||||||
|
/// modified as follows. Any version prefix will be replaced by the
|
||||||
|
/// version of the including interface plus the [root][] path if
|
||||||
|
/// specified.
|
||||||
|
///
|
||||||
|
/// Example of a simple mixin:
|
||||||
|
///
|
||||||
|
/// package google.acl.v1;
|
||||||
|
/// service AccessControl {
|
||||||
|
/// // Get the underlying ACL object.
|
||||||
|
/// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||||
|
/// option (google.api.http).get = "/v1/{resource=**}:getAcl";
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// package google.storage.v2;
|
||||||
|
/// service Storage {
|
||||||
|
/// rpc GetAcl(GetAclRequest) returns (Acl);
|
||||||
|
///
|
||||||
|
/// // Get a data record.
|
||||||
|
/// rpc GetData(GetDataRequest) returns (Data) {
|
||||||
|
/// option (google.api.http).get = "/v2/{resource=**}";
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Example of a mixin configuration:
|
||||||
|
///
|
||||||
|
/// apis:
|
||||||
|
/// - name: google.storage.v2.Storage
|
||||||
|
/// mixins:
|
||||||
|
/// - name: google.acl.v1.AccessControl
|
||||||
|
///
|
||||||
|
/// The mixin construct implies that all methods in `AccessControl` are
|
||||||
|
/// also declared with same name and request/response types in
|
||||||
|
/// `Storage`. A documentation generator or annotation processor will
|
||||||
|
/// see the effective `Storage.GetAcl` method after inherting
|
||||||
|
/// documentation and annotations as follows:
|
||||||
|
///
|
||||||
|
/// service Storage {
|
||||||
|
/// // Get the underlying ACL object.
|
||||||
|
/// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||||
|
/// option (google.api.http).get = "/v2/{resource=**}:getAcl";
|
||||||
|
/// }
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Note how the version in the path pattern changed from `v1` to `v2`.
|
||||||
|
///
|
||||||
|
/// If the `root` field in the mixin is specified, it should be a
|
||||||
|
/// relative path under which inherited HTTP paths are placed. Example:
|
||||||
|
///
|
||||||
|
/// apis:
|
||||||
|
/// - name: google.storage.v2.Storage
|
||||||
|
/// mixins:
|
||||||
|
/// - name: google.acl.v1.AccessControl
|
||||||
|
/// root: acls
|
||||||
|
///
|
||||||
|
/// This implies the following inherited HTTP annotation:
|
||||||
|
///
|
||||||
|
/// service Storage {
|
||||||
|
/// // Get the underlying ACL object.
|
||||||
|
/// rpc GetAcl(GetAclRequest) returns (Acl) {
|
||||||
|
/// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl";
|
||||||
|
/// }
|
||||||
|
/// ...
|
||||||
|
/// }
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Mixin : pb::IMessage<Mixin> {
|
||||||
|
private static readonly pb::MessageParser<Mixin> _parser = new pb::MessageParser<Mixin>(() => new Mixin());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Mixin> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.ApiReflection.Descriptor.MessageTypes[2]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Mixin() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Mixin(Mixin other) : this() {
|
||||||
|
name_ = other.name_;
|
||||||
|
root_ = other.root_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Mixin Clone() {
|
||||||
|
return new Mixin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "name" field.</summary>
|
||||||
|
public const int NameFieldNumber = 1;
|
||||||
|
private string name_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// The fully qualified name of the interface which is included.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string Name {
|
||||||
|
get { return name_; }
|
||||||
|
set {
|
||||||
|
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "root" field.</summary>
|
||||||
|
public const int RootFieldNumber = 2;
|
||||||
|
private string root_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// If non-empty specifies a path under which inherited HTTP paths
|
||||||
|
/// are rooted.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string Root {
|
||||||
|
get { return root_; }
|
||||||
|
set {
|
||||||
|
root_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Mixin);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Mixin other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Name != other.Name) return false;
|
||||||
|
if (Root != other.Root) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (Name.Length != 0) hash ^= Name.GetHashCode();
|
||||||
|
if (Root.Length != 0) hash ^= Root.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (Name.Length != 0) {
|
||||||
|
output.WriteRawTag(10);
|
||||||
|
output.WriteString(Name);
|
||||||
|
}
|
||||||
|
if (Root.Length != 0) {
|
||||||
|
output.WriteRawTag(18);
|
||||||
|
output.WriteString(Root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (Name.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
|
||||||
|
}
|
||||||
|
if (Root.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(Root);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Mixin other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.Name.Length != 0) {
|
||||||
|
Name = other.Name;
|
||||||
|
}
|
||||||
|
if (other.Root.Length != 0) {
|
||||||
|
Root = other.Root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
Name = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 18: {
|
||||||
|
Root = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/duration.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/duration.proto</summary>
|
||||||
|
public static partial class DurationReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/duration.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static DurationReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90",
|
||||||
|
"b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg",
|
||||||
|
"ASgFQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoq",
|
||||||
|
"Z2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9u+AEB",
|
||||||
|
"ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90",
|
||||||
|
"bzM="));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Duration), global::Google.Protobuf.WellKnownTypes.Duration.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// A Duration represents a signed, fixed-length span of time represented
|
||||||
|
/// as a count of seconds and fractions of seconds at nanosecond
|
||||||
|
/// resolution. It is independent of any calendar and concepts like "day"
|
||||||
|
/// or "month". It is related to Timestamp in that the difference between
|
||||||
|
/// two Timestamp values is a Duration and it can be added or subtracted
|
||||||
|
/// from a Timestamp. Range is approximately +-10,000 years.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||||
|
///
|
||||||
|
/// Timestamp start = ...;
|
||||||
|
/// Timestamp end = ...;
|
||||||
|
/// Duration duration = ...;
|
||||||
|
///
|
||||||
|
/// duration.seconds = end.seconds - start.seconds;
|
||||||
|
/// duration.nanos = end.nanos - start.nanos;
|
||||||
|
///
|
||||||
|
/// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||||
|
/// duration.seconds += 1;
|
||||||
|
/// duration.nanos -= 1000000000;
|
||||||
|
/// } else if (durations.seconds > 0 && duration.nanos < 0) {
|
||||||
|
/// duration.seconds -= 1;
|
||||||
|
/// duration.nanos += 1000000000;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||||
|
///
|
||||||
|
/// Timestamp start = ...;
|
||||||
|
/// Duration duration = ...;
|
||||||
|
/// Timestamp end = ...;
|
||||||
|
///
|
||||||
|
/// end.seconds = start.seconds + duration.seconds;
|
||||||
|
/// end.nanos = start.nanos + duration.nanos;
|
||||||
|
///
|
||||||
|
/// if (end.nanos < 0) {
|
||||||
|
/// end.seconds -= 1;
|
||||||
|
/// end.nanos += 1000000000;
|
||||||
|
/// } else if (end.nanos >= 1000000000) {
|
||||||
|
/// end.seconds += 1;
|
||||||
|
/// end.nanos -= 1000000000;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||||
|
///
|
||||||
|
/// td = datetime.timedelta(days=3, minutes=10)
|
||||||
|
/// duration = Duration()
|
||||||
|
/// duration.FromTimedelta(td)
|
||||||
|
///
|
||||||
|
/// # JSON Mapping
|
||||||
|
///
|
||||||
|
/// In JSON format, the Duration type is encoded as a string rather than an
|
||||||
|
/// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||||
|
/// is preceded by the number of seconds, with nanoseconds expressed as
|
||||||
|
/// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||||
|
/// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||||
|
/// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||||
|
/// microsecond should be expressed in JSON format as "3.000001s".
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Duration : pb::IMessage<Duration> {
|
||||||
|
private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Duration> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.DurationReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Duration() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Duration(Duration other) : this() {
|
||||||
|
seconds_ = other.seconds_;
|
||||||
|
nanos_ = other.nanos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Duration Clone() {
|
||||||
|
return new Duration(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "seconds" field.</summary>
|
||||||
|
public const int SecondsFieldNumber = 1;
|
||||||
|
private long seconds_;
|
||||||
|
/// <summary>
|
||||||
|
/// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||||
|
/// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||||
|
/// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public long Seconds {
|
||||||
|
get { return seconds_; }
|
||||||
|
set {
|
||||||
|
seconds_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "nanos" field.</summary>
|
||||||
|
public const int NanosFieldNumber = 2;
|
||||||
|
private int nanos_;
|
||||||
|
/// <summary>
|
||||||
|
/// Signed fractions of a second at nanosecond resolution of the span
|
||||||
|
/// of time. Durations less than one second are represented with a 0
|
||||||
|
/// `seconds` field and a positive or negative `nanos` field. For durations
|
||||||
|
/// of one second or more, a non-zero value for the `nanos` field must be
|
||||||
|
/// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||||
|
/// to +999,999,999 inclusive.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int Nanos {
|
||||||
|
get { return nanos_; }
|
||||||
|
set {
|
||||||
|
nanos_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Duration other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Seconds != other.Seconds) return false;
|
||||||
|
if (Nanos != other.Nanos) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (Seconds != 0L) hash ^= Seconds.GetHashCode();
|
||||||
|
if (Nanos != 0) hash ^= Nanos.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (Seconds != 0L) {
|
||||||
|
output.WriteRawTag(8);
|
||||||
|
output.WriteInt64(Seconds);
|
||||||
|
}
|
||||||
|
if (Nanos != 0) {
|
||||||
|
output.WriteRawTag(16);
|
||||||
|
output.WriteInt32(Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (Seconds != 0L) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeInt64Size(Seconds);
|
||||||
|
}
|
||||||
|
if (Nanos != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Duration other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.Seconds != 0L) {
|
||||||
|
Seconds = other.Seconds;
|
||||||
|
}
|
||||||
|
if (other.Nanos != 0) {
|
||||||
|
Nanos = other.Nanos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 8: {
|
||||||
|
Seconds = input.ReadInt64();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 16: {
|
||||||
|
Nanos = input.ReadInt32();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
// Manually-written partial class for the Duration well-known type,
|
||||||
|
// providing a conversion to TimeSpan and convenience operators.
|
||||||
|
public partial class Duration : ICustomDiagnosticMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The number of nanoseconds in a second.
|
||||||
|
/// </summary>
|
||||||
|
public const int NanosecondsPerSecond = 1000000000;
|
||||||
|
/// <summary>
|
||||||
|
/// The number of nanoseconds in a BCL tick (as used by <see cref="TimeSpan"/> and <see cref="DateTime"/>).
|
||||||
|
/// </summary>
|
||||||
|
public const int NanosecondsPerTick = 100;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum permitted number of seconds.
|
||||||
|
/// </summary>
|
||||||
|
public const long MaxSeconds = 315576000000L;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum permitted number of seconds.
|
||||||
|
/// </summary>
|
||||||
|
public const long MinSeconds = -315576000000L;
|
||||||
|
|
||||||
|
internal const int MaxNanoseconds = NanosecondsPerSecond - 1;
|
||||||
|
internal const int MinNanoseconds = -NanosecondsPerSecond + 1;
|
||||||
|
|
||||||
|
internal static bool IsNormalized(long seconds, int nanoseconds)
|
||||||
|
{
|
||||||
|
// Simple boundaries
|
||||||
|
if (seconds < MinSeconds || seconds > MaxSeconds ||
|
||||||
|
nanoseconds < MinNanoseconds || nanoseconds > MaxNanoseconds)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We only have a problem is one is strictly negative and the other is
|
||||||
|
// strictly positive.
|
||||||
|
return Math.Sign(seconds) * Math.Sign(nanoseconds) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this <see cref="Duration"/> to a <see cref="TimeSpan"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>If the duration is not a precise number of ticks, it is truncated towards 0.</remarks>
|
||||||
|
/// <returns>The value of this duration, as a <c>TimeSpan</c>.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">This value isn't a valid normalized duration, as
|
||||||
|
/// described in the documentation.</exception>
|
||||||
|
public TimeSpan ToTimeSpan()
|
||||||
|
{
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
if (!IsNormalized(Seconds, Nanos))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Duration was not a valid normalized duration");
|
||||||
|
}
|
||||||
|
long ticks = Seconds * TimeSpan.TicksPerSecond + Nanos / NanosecondsPerTick;
|
||||||
|
return TimeSpan.FromTicks(ticks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeSpan">The <c>TimeSpan</c> to convert.</param>
|
||||||
|
/// <returns>The value of the given <c>TimeSpan</c>, as a <c>Duration</c>.</returns>
|
||||||
|
public static Duration FromTimeSpan(TimeSpan timeSpan)
|
||||||
|
{
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
long ticks = timeSpan.Ticks;
|
||||||
|
long seconds = ticks / TimeSpan.TicksPerSecond;
|
||||||
|
int nanos = (int) (ticks % TimeSpan.TicksPerSecond) * NanosecondsPerTick;
|
||||||
|
return new Duration { Seconds = seconds, Nanos = nanos };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the result of negating the duration. For example, the negation of 5 minutes is -5 minutes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The duration to negate. Must not be null.</param>
|
||||||
|
/// <returns>The negated value of this duration.</returns>
|
||||||
|
public static Duration operator -(Duration value)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return Normalize(-value.Seconds, -value.Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the two specified <see cref="Duration"/> values together.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The first value to add. Must not be null.</param>
|
||||||
|
/// <param name="rhs">The second value to add. Must not be null.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Duration operator +(Duration lhs, Duration rhs)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(lhs, "lhs");
|
||||||
|
ProtoPreconditions.CheckNotNull(rhs, "rhs");
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts one <see cref="Duration"/> from another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The duration to subtract from. Must not be null.</param>
|
||||||
|
/// <param name="rhs">The duration to subtract. Must not be null.</param>
|
||||||
|
/// <returns>The difference between the two specified durations.</returns>
|
||||||
|
public static Duration operator -(Duration lhs, Duration rhs)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(lhs, "lhs");
|
||||||
|
ProtoPreconditions.CheckNotNull(rhs, "rhs");
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a duration with the normalized values from the given number of seconds and
|
||||||
|
/// nanoseconds, conforming with the description in the proto file.
|
||||||
|
/// </summary>
|
||||||
|
internal static Duration Normalize(long seconds, int nanoseconds)
|
||||||
|
{
|
||||||
|
// Ensure that nanoseconds is in the range (-1,000,000,000, +1,000,000,000)
|
||||||
|
int extraSeconds = nanoseconds / NanosecondsPerSecond;
|
||||||
|
seconds += extraSeconds;
|
||||||
|
nanoseconds -= extraSeconds * NanosecondsPerSecond;
|
||||||
|
|
||||||
|
// Now make sure that Sign(seconds) == Sign(nanoseconds) if Sign(seconds) != 0.
|
||||||
|
if (seconds < 0 && nanoseconds > 0)
|
||||||
|
{
|
||||||
|
seconds += 1;
|
||||||
|
nanoseconds -= NanosecondsPerSecond;
|
||||||
|
}
|
||||||
|
else if (seconds > 0 && nanoseconds < 0)
|
||||||
|
{
|
||||||
|
seconds -= 1;
|
||||||
|
nanoseconds += NanosecondsPerSecond;
|
||||||
|
}
|
||||||
|
return new Duration { Seconds = seconds, Nanos = nanoseconds };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a duration specified in seconds/nanoseconds to a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the value is a normalized duration in the range described in <c>duration.proto</c>,
|
||||||
|
/// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
|
||||||
|
/// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="seconds">Seconds portion of the duration.</param>
|
||||||
|
/// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
|
||||||
|
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
|
||||||
|
/// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
|
||||||
|
internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
|
||||||
|
{
|
||||||
|
if (IsNormalized(seconds, nanoseconds))
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.Append('"');
|
||||||
|
// The seconds part will normally provide the minus sign if we need it, but not if it's 0...
|
||||||
|
if (seconds == 0 && nanoseconds < 0)
|
||||||
|
{
|
||||||
|
builder.Append('-');
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.Append(seconds.ToString("d", CultureInfo.InvariantCulture));
|
||||||
|
AppendNanoseconds(builder, Math.Abs(nanoseconds));
|
||||||
|
builder.Append("s\"");
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
if (diagnosticOnly)
|
||||||
|
{
|
||||||
|
// Note: the double braces here are escaping for braces in format strings.
|
||||||
|
return string.Format(CultureInfo.InvariantCulture,
|
||||||
|
"{{ \"@warning\": \"Invalid Duration\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
|
||||||
|
seconds,
|
||||||
|
nanoseconds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Non-normalized duration value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this <see cref="Duration"/> for diagnostic purposes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
|
||||||
|
/// when the value is non-normalized or out of range, a JSON object representation will be returned
|
||||||
|
/// instead, including a warning. This is to avoid exceptions being thrown when trying to
|
||||||
|
/// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
|
||||||
|
/// values.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>A string representation of this value.</returns>
|
||||||
|
public string ToDiagnosticString()
|
||||||
|
{
|
||||||
|
return ToJson(Seconds, Nanos, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a number of nanoseconds to a StringBuilder. Either 0 digits are added (in which
|
||||||
|
/// case no "." is appended), or 3 6 or 9 digits. This is internal for use in Timestamp as well
|
||||||
|
/// as Duration.
|
||||||
|
/// </summary>
|
||||||
|
internal static void AppendNanoseconds(StringBuilder builder, int nanos)
|
||||||
|
{
|
||||||
|
if (nanos != 0)
|
||||||
|
{
|
||||||
|
builder.Append('.');
|
||||||
|
// Output to 3, 6 or 9 digits.
|
||||||
|
if (nanos % 1000000 == 0)
|
||||||
|
{
|
||||||
|
builder.Append((nanos / 1000000).ToString("d3", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
else if (nanos % 1000 == 0)
|
||||||
|
{
|
||||||
|
builder.Append((nanos / 1000).ToString("d6", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.Append(nanos.ToString("d9", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/empty.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/empty.proto</summary>
|
||||||
|
public static partial class EmptyReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/empty.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static EmptyReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1",
|
||||||
|
"ZiIHCgVFbXB0eUJ2ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
|
||||||
|
"UAFaJ2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9lbXB0efgB",
|
||||||
|
"AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv",
|
||||||
|
"dG8z"));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Empty), global::Google.Protobuf.WellKnownTypes.Empty.Parser, null, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// A generic empty message that you can re-use to avoid defining duplicated
|
||||||
|
/// empty messages in your APIs. A typical example is to use it as the request
|
||||||
|
/// or the response type of an API method. For instance:
|
||||||
|
///
|
||||||
|
/// service Foo {
|
||||||
|
/// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// The JSON representation for `Empty` is empty JSON object `{}`.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Empty : pb::IMessage<Empty> {
|
||||||
|
private static readonly pb::MessageParser<Empty> _parser = new pb::MessageParser<Empty>(() => new Empty());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Empty> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.EmptyReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Empty() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Empty(Empty other) : this() {
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Empty Clone() {
|
||||||
|
return new Empty(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Empty other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Empty other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/field_mask.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbc = global::Google.Protobuf.Collections;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/field_mask.proto</summary>
|
||||||
|
public static partial class FieldMaskReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/field_mask.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static FieldMaskReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"CiBnb29nbGUvcHJvdG9idWYvZmllbGRfbWFzay5wcm90bxIPZ29vZ2xlLnBy",
|
||||||
|
"b3RvYnVmIhoKCUZpZWxkTWFzaxINCgVwYXRocxgBIAMoCUKJAQoTY29tLmdv",
|
||||||
|
"b2dsZS5wcm90b2J1ZkIORmllbGRNYXNrUHJvdG9QAVo5Z29vZ2xlLmdvbGFu",
|
||||||
|
"Zy5vcmcvZ2VucHJvdG8vcHJvdG9idWYvZmllbGRfbWFzaztmaWVsZF9tYXNr",
|
||||||
|
"ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90",
|
||||||
|
"bzM="));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.FieldMask), global::Google.Protobuf.WellKnownTypes.FieldMask.Parser, new[]{ "Paths" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// `FieldMask` represents a set of symbolic field paths, for example:
|
||||||
|
///
|
||||||
|
/// paths: "f.a"
|
||||||
|
/// paths: "f.b.d"
|
||||||
|
///
|
||||||
|
/// Here `f` represents a field in some root message, `a` and `b`
|
||||||
|
/// fields in the message found in `f`, and `d` a field found in the
|
||||||
|
/// message in `f.b`.
|
||||||
|
///
|
||||||
|
/// Field masks are used to specify a subset of fields that should be
|
||||||
|
/// returned by a get operation or modified by an update operation.
|
||||||
|
/// Field masks also have a custom JSON encoding (see below).
|
||||||
|
///
|
||||||
|
/// # Field Masks in Projections
|
||||||
|
///
|
||||||
|
/// When used in the context of a projection, a response message or
|
||||||
|
/// sub-message is filtered by the API to only contain those fields as
|
||||||
|
/// specified in the mask. For example, if the mask in the previous
|
||||||
|
/// example is applied to a response message as follows:
|
||||||
|
///
|
||||||
|
/// f {
|
||||||
|
/// a : 22
|
||||||
|
/// b {
|
||||||
|
/// d : 1
|
||||||
|
/// x : 2
|
||||||
|
/// }
|
||||||
|
/// y : 13
|
||||||
|
/// }
|
||||||
|
/// z: 8
|
||||||
|
///
|
||||||
|
/// The result will not contain specific values for fields x,y and z
|
||||||
|
/// (their value will be set to the default, and omitted in proto text
|
||||||
|
/// output):
|
||||||
|
///
|
||||||
|
/// f {
|
||||||
|
/// a : 22
|
||||||
|
/// b {
|
||||||
|
/// d : 1
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// A repeated field is not allowed except at the last position of a
|
||||||
|
/// paths string.
|
||||||
|
///
|
||||||
|
/// If a FieldMask object is not present in a get operation, the
|
||||||
|
/// operation applies to all fields (as if a FieldMask of all fields
|
||||||
|
/// had been specified).
|
||||||
|
///
|
||||||
|
/// Note that a field mask does not necessarily apply to the
|
||||||
|
/// top-level response message. In case of a REST get operation, the
|
||||||
|
/// field mask applies directly to the response, but in case of a REST
|
||||||
|
/// list operation, the mask instead applies to each individual message
|
||||||
|
/// in the returned resource list. In case of a REST custom method,
|
||||||
|
/// other definitions may be used. Where the mask applies will be
|
||||||
|
/// clearly documented together with its declaration in the API. In
|
||||||
|
/// any case, the effect on the returned resource/resources is required
|
||||||
|
/// behavior for APIs.
|
||||||
|
///
|
||||||
|
/// # Field Masks in Update Operations
|
||||||
|
///
|
||||||
|
/// A field mask in update operations specifies which fields of the
|
||||||
|
/// targeted resource are going to be updated. The API is required
|
||||||
|
/// to only change the values of the fields as specified in the mask
|
||||||
|
/// and leave the others untouched. If a resource is passed in to
|
||||||
|
/// describe the updated values, the API ignores the values of all
|
||||||
|
/// fields not covered by the mask.
|
||||||
|
///
|
||||||
|
/// If a repeated field is specified for an update operation, the existing
|
||||||
|
/// repeated values in the target resource will be overwritten by the new values.
|
||||||
|
/// Note that a repeated field is only allowed in the last position of a `paths`
|
||||||
|
/// string.
|
||||||
|
///
|
||||||
|
/// If a sub-message is specified in the last position of the field mask for an
|
||||||
|
/// update operation, then the existing sub-message in the target resource is
|
||||||
|
/// overwritten. Given the target message:
|
||||||
|
///
|
||||||
|
/// f {
|
||||||
|
/// b {
|
||||||
|
/// d : 1
|
||||||
|
/// x : 2
|
||||||
|
/// }
|
||||||
|
/// c : 1
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// And an update message:
|
||||||
|
///
|
||||||
|
/// f {
|
||||||
|
/// b {
|
||||||
|
/// d : 10
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// then if the field mask is:
|
||||||
|
///
|
||||||
|
/// paths: "f.b"
|
||||||
|
///
|
||||||
|
/// then the result will be:
|
||||||
|
///
|
||||||
|
/// f {
|
||||||
|
/// b {
|
||||||
|
/// d : 10
|
||||||
|
/// }
|
||||||
|
/// c : 1
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// However, if the update mask was:
|
||||||
|
///
|
||||||
|
/// paths: "f.b.d"
|
||||||
|
///
|
||||||
|
/// then the result would be:
|
||||||
|
///
|
||||||
|
/// f {
|
||||||
|
/// b {
|
||||||
|
/// d : 10
|
||||||
|
/// x : 2
|
||||||
|
/// }
|
||||||
|
/// c : 1
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// In order to reset a field's value to the default, the field must
|
||||||
|
/// be in the mask and set to the default value in the provided resource.
|
||||||
|
/// Hence, in order to reset all fields of a resource, provide a default
|
||||||
|
/// instance of the resource and set all fields in the mask, or do
|
||||||
|
/// not provide a mask as described below.
|
||||||
|
///
|
||||||
|
/// If a field mask is not present on update, the operation applies to
|
||||||
|
/// all fields (as if a field mask of all fields has been specified).
|
||||||
|
/// Note that in the presence of schema evolution, this may mean that
|
||||||
|
/// fields the client does not know and has therefore not filled into
|
||||||
|
/// the request will be reset to their default. If this is unwanted
|
||||||
|
/// behavior, a specific service may require a client to always specify
|
||||||
|
/// a field mask, producing an error if not.
|
||||||
|
///
|
||||||
|
/// As with get operations, the location of the resource which
|
||||||
|
/// describes the updated values in the request message depends on the
|
||||||
|
/// operation kind. In any case, the effect of the field mask is
|
||||||
|
/// required to be honored by the API.
|
||||||
|
///
|
||||||
|
/// ## Considerations for HTTP REST
|
||||||
|
///
|
||||||
|
/// The HTTP kind of an update operation which uses a field mask must
|
||||||
|
/// be set to PATCH instead of PUT in order to satisfy HTTP semantics
|
||||||
|
/// (PUT must only be used for full updates).
|
||||||
|
///
|
||||||
|
/// # JSON Encoding of Field Masks
|
||||||
|
///
|
||||||
|
/// In JSON, a field mask is encoded as a single string where paths are
|
||||||
|
/// separated by a comma. Fields name in each path are converted
|
||||||
|
/// to/from lower-camel naming conventions.
|
||||||
|
///
|
||||||
|
/// As an example, consider the following message declarations:
|
||||||
|
///
|
||||||
|
/// message Profile {
|
||||||
|
/// User user = 1;
|
||||||
|
/// Photo photo = 2;
|
||||||
|
/// }
|
||||||
|
/// message User {
|
||||||
|
/// string display_name = 1;
|
||||||
|
/// string address = 2;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// In proto a field mask for `Profile` may look as such:
|
||||||
|
///
|
||||||
|
/// mask {
|
||||||
|
/// paths: "user.display_name"
|
||||||
|
/// paths: "photo"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// In JSON, the same mask is represented as below:
|
||||||
|
///
|
||||||
|
/// {
|
||||||
|
/// mask: "user.displayName,photo"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # Field Masks and Oneof Fields
|
||||||
|
///
|
||||||
|
/// Field masks treat fields in oneofs just as regular fields. Consider the
|
||||||
|
/// following message:
|
||||||
|
///
|
||||||
|
/// message SampleMessage {
|
||||||
|
/// oneof test_oneof {
|
||||||
|
/// string name = 4;
|
||||||
|
/// SubMessage sub_message = 9;
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// The field mask can be:
|
||||||
|
///
|
||||||
|
/// mask {
|
||||||
|
/// paths: "name"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Or:
|
||||||
|
///
|
||||||
|
/// mask {
|
||||||
|
/// paths: "sub_message"
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// Note that oneof type names ("test_oneof" in this case) cannot be used in
|
||||||
|
/// paths.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class FieldMask : pb::IMessage<FieldMask> {
|
||||||
|
private static readonly pb::MessageParser<FieldMask> _parser = new pb::MessageParser<FieldMask>(() => new FieldMask());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<FieldMask> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.FieldMaskReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public FieldMask() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public FieldMask(FieldMask other) : this() {
|
||||||
|
paths_ = other.paths_.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public FieldMask Clone() {
|
||||||
|
return new FieldMask(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "paths" field.</summary>
|
||||||
|
public const int PathsFieldNumber = 1;
|
||||||
|
private static readonly pb::FieldCodec<string> _repeated_paths_codec
|
||||||
|
= pb::FieldCodec.ForString(10);
|
||||||
|
private readonly pbc::RepeatedField<string> paths_ = new pbc::RepeatedField<string>();
|
||||||
|
/// <summary>
|
||||||
|
/// The set of field mask paths.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::RepeatedField<string> Paths {
|
||||||
|
get { return paths_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as FieldMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(FieldMask other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(!paths_.Equals(other.paths_)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
hash ^= paths_.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
paths_.WriteTo(output, _repeated_paths_codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
size += paths_.CalculateSize(_repeated_paths_codec);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(FieldMask other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
paths_.Add(other.paths_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
paths_.AddEntriesFrom(input, _repeated_paths_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2016 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
// Manually-written partial class for the FieldMask well-known type.
|
||||||
|
public partial class FieldMask : ICustomDiagnosticMessage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a timestamp specified in seconds/nanoseconds to a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the value is a normalized duration in the range described in <c>field_mask.proto</c>,
|
||||||
|
/// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
|
||||||
|
/// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="paths">Paths in the field mask</param>
|
||||||
|
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
|
||||||
|
/// <exception cref="InvalidOperationException">The represented field mask is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
|
||||||
|
internal static string ToJson(IList<string> paths, bool diagnosticOnly)
|
||||||
|
{
|
||||||
|
var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p));
|
||||||
|
if (firstInvalid == null)
|
||||||
|
{
|
||||||
|
var writer = new StringWriter();
|
||||||
|
#if NET35
|
||||||
|
var query = paths.Select(JsonFormatter.ToJsonName);
|
||||||
|
JsonFormatter.WriteString(writer, string.Join(",", query.ToArray()));
|
||||||
|
#else
|
||||||
|
JsonFormatter.WriteString(writer, string.Join(",", paths.Select(JsonFormatter.ToJsonName)));
|
||||||
|
#endif
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (diagnosticOnly)
|
||||||
|
{
|
||||||
|
var writer = new StringWriter();
|
||||||
|
writer.Write("{ \"@warning\": \"Invalid FieldMask\", \"paths\": ");
|
||||||
|
JsonFormatter.Default.WriteList(writer, (IList)paths);
|
||||||
|
writer.Write(" }");
|
||||||
|
return writer.ToString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {firstInvalid}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the given path is valid for a field mask.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if the path is valid; false otherwise</returns>
|
||||||
|
private static bool ValidatePath(string input)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < input.Length; i++)
|
||||||
|
{
|
||||||
|
char c = input[i];
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (c == '_' && i < input.Length - 1)
|
||||||
|
{
|
||||||
|
char next = input[i + 1];
|
||||||
|
if (next < 'a' || next > 'z')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this <see cref="FieldMask"/> for diagnostic purposes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
|
||||||
|
/// when the value is non-normalized or out of range, a JSON object representation will be returned
|
||||||
|
/// instead, including a warning. This is to avoid exceptions being thrown when trying to
|
||||||
|
/// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
|
||||||
|
/// values.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>A string representation of this value.</returns>
|
||||||
|
public string ToDiagnosticString()
|
||||||
|
{
|
||||||
|
return ToJson(Paths, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/source_context.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/source_context.proto</summary>
|
||||||
|
public static partial class SourceContextReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/source_context.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static SourceContextReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"CiRnb29nbGUvcHJvdG9idWYvc291cmNlX2NvbnRleHQucHJvdG8SD2dvb2ds",
|
||||||
|
"ZS5wcm90b2J1ZiIiCg1Tb3VyY2VDb250ZXh0EhEKCWZpbGVfbmFtZRgBIAEo",
|
||||||
|
"CUKVAQoTY29tLmdvb2dsZS5wcm90b2J1ZkISU291cmNlQ29udGV4dFByb3Rv",
|
||||||
|
"UAFaQWdvb2dsZS5nb2xhbmcub3JnL2dlbnByb3RvL3Byb3RvYnVmL3NvdXJj",
|
||||||
|
"ZV9jb250ZXh0O3NvdXJjZV9jb250ZXh0ogIDR1BCqgIeR29vZ2xlLlByb3Rv",
|
||||||
|
"YnVmLldlbGxLbm93blR5cGVzYgZwcm90bzM="));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.SourceContext), global::Google.Protobuf.WellKnownTypes.SourceContext.Parser, new[]{ "FileName" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// `SourceContext` represents information about the source of a
|
||||||
|
/// protobuf element, like the file in which it is defined.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class SourceContext : pb::IMessage<SourceContext> {
|
||||||
|
private static readonly pb::MessageParser<SourceContext> _parser = new pb::MessageParser<SourceContext>(() => new SourceContext());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<SourceContext> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public SourceContext() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public SourceContext(SourceContext other) : this() {
|
||||||
|
fileName_ = other.fileName_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public SourceContext Clone() {
|
||||||
|
return new SourceContext(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "file_name" field.</summary>
|
||||||
|
public const int FileNameFieldNumber = 1;
|
||||||
|
private string fileName_ = "";
|
||||||
|
/// <summary>
|
||||||
|
/// The path-qualified name of the .proto file that contained the associated
|
||||||
|
/// protobuf element. For example: `"google/protobuf/source_context.proto"`.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string FileName {
|
||||||
|
get { return fileName_; }
|
||||||
|
set {
|
||||||
|
fileName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as SourceContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(SourceContext other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (FileName != other.FileName) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (FileName.Length != 0) hash ^= FileName.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (FileName.Length != 0) {
|
||||||
|
output.WriteRawTag(10);
|
||||||
|
output.WriteString(FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (FileName.Length != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(FileName);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(SourceContext other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.FileName.Length != 0) {
|
||||||
|
FileName = other.FileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
FileName = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,648 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/struct.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbc = global::Google.Protobuf.Collections;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/struct.proto</summary>
|
||||||
|
public static partial class StructReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/struct.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static StructReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"Chxnb29nbGUvcHJvdG9idWYvc3RydWN0LnByb3RvEg9nb29nbGUucHJvdG9i",
|
||||||
|
"dWYihAEKBlN0cnVjdBIzCgZmaWVsZHMYASADKAsyIy5nb29nbGUucHJvdG9i",
|
||||||
|
"dWYuU3RydWN0LkZpZWxkc0VudHJ5GkUKC0ZpZWxkc0VudHJ5EgsKA2tleRgB",
|
||||||
|
"IAEoCRIlCgV2YWx1ZRgCIAEoCzIWLmdvb2dsZS5wcm90b2J1Zi5WYWx1ZToC",
|
||||||
|
"OAEi6gEKBVZhbHVlEjAKCm51bGxfdmFsdWUYASABKA4yGi5nb29nbGUucHJv",
|
||||||
|
"dG9idWYuTnVsbFZhbHVlSAASFgoMbnVtYmVyX3ZhbHVlGAIgASgBSAASFgoM",
|
||||||
|
"c3RyaW5nX3ZhbHVlGAMgASgJSAASFAoKYm9vbF92YWx1ZRgEIAEoCEgAEi8K",
|
||||||
|
"DHN0cnVjdF92YWx1ZRgFIAEoCzIXLmdvb2dsZS5wcm90b2J1Zi5TdHJ1Y3RI",
|
||||||
|
"ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW",
|
||||||
|
"YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW",
|
||||||
|
"Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W",
|
||||||
|
"QUxVRRAAQoEBChNjb20uZ29vZ2xlLnByb3RvYnVmQgtTdHJ1Y3RQcm90b1AB",
|
||||||
|
"WjFnaXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wdHlwZXMvc3RydWN0O3N0",
|
||||||
|
"cnVjdHBi+AEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5",
|
||||||
|
"cGVzYgZwcm90bzM="));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Struct), global::Google.Protobuf.WellKnownTypes.Struct.Parser, new[]{ "Fields" }, null, null, new pbr::GeneratedClrTypeInfo[] { null, }),
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Value), global::Google.Protobuf.WellKnownTypes.Value.Parser, new[]{ "NullValue", "NumberValue", "StringValue", "BoolValue", "StructValue", "ListValue" }, new[]{ "Kind" }, null, null),
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.ListValue), global::Google.Protobuf.WellKnownTypes.ListValue.Parser, new[]{ "Values" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Enums
|
||||||
|
/// <summary>
|
||||||
|
/// `NullValue` is a singleton enumeration to represent the null value for the
|
||||||
|
/// `Value` type union.
|
||||||
|
///
|
||||||
|
/// The JSON representation for `NullValue` is JSON `null`.
|
||||||
|
/// </summary>
|
||||||
|
public enum NullValue {
|
||||||
|
/// <summary>
|
||||||
|
/// Null value.
|
||||||
|
/// </summary>
|
||||||
|
[pbr::OriginalName("NULL_VALUE")] NullValue = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// `Struct` represents a structured data value, consisting of fields
|
||||||
|
/// which map to dynamically typed values. In some languages, `Struct`
|
||||||
|
/// might be supported by a native representation. For example, in
|
||||||
|
/// scripting languages like JS a struct is represented as an
|
||||||
|
/// object. The details of that representation are described together
|
||||||
|
/// with the proto support for the language.
|
||||||
|
///
|
||||||
|
/// The JSON representation for `Struct` is JSON object.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Struct : pb::IMessage<Struct> {
|
||||||
|
private static readonly pb::MessageParser<Struct> _parser = new pb::MessageParser<Struct>(() => new Struct());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Struct> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Struct() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Struct(Struct other) : this() {
|
||||||
|
fields_ = other.fields_.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Struct Clone() {
|
||||||
|
return new Struct(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "fields" field.</summary>
|
||||||
|
public const int FieldsFieldNumber = 1;
|
||||||
|
private static readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec _map_fields_codec
|
||||||
|
= new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Value.Parser), 10);
|
||||||
|
private readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> fields_ = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>();
|
||||||
|
/// <summary>
|
||||||
|
/// Unordered map of dynamically typed values.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> Fields {
|
||||||
|
get { return fields_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Struct other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!Fields.Equals(other.Fields)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
hash ^= Fields.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
fields_.WriteTo(output, _map_fields_codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
size += fields_.CalculateSize(_map_fields_codec);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Struct other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fields_.Add(other.fields_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
fields_.AddEntriesFrom(input, _map_fields_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// `Value` represents a dynamically typed value which can be either
|
||||||
|
/// null, a number, a string, a boolean, a recursive struct value, or a
|
||||||
|
/// list of values. A producer of value is expected to set one of that
|
||||||
|
/// variants, absence of any variant indicates an error.
|
||||||
|
///
|
||||||
|
/// The JSON representation for `Value` is JSON value.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Value : pb::IMessage<Value> {
|
||||||
|
private static readonly pb::MessageParser<Value> _parser = new pb::MessageParser<Value>(() => new Value());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Value> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[1]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Value() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Value(Value other) : this() {
|
||||||
|
switch (other.KindCase) {
|
||||||
|
case KindOneofCase.NullValue:
|
||||||
|
NullValue = other.NullValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.NumberValue:
|
||||||
|
NumberValue = other.NumberValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.StringValue:
|
||||||
|
StringValue = other.StringValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.BoolValue:
|
||||||
|
BoolValue = other.BoolValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.StructValue:
|
||||||
|
StructValue = other.StructValue.Clone();
|
||||||
|
break;
|
||||||
|
case KindOneofCase.ListValue:
|
||||||
|
ListValue = other.ListValue.Clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Value Clone() {
|
||||||
|
return new Value(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "null_value" field.</summary>
|
||||||
|
public const int NullValueFieldNumber = 1;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a null value.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public global::Google.Protobuf.WellKnownTypes.NullValue NullValue {
|
||||||
|
get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : 0; }
|
||||||
|
set {
|
||||||
|
kind_ = value;
|
||||||
|
kindCase_ = KindOneofCase.NullValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "number_value" field.</summary>
|
||||||
|
public const int NumberValueFieldNumber = 2;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a double value.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public double NumberValue {
|
||||||
|
get { return kindCase_ == KindOneofCase.NumberValue ? (double) kind_ : 0D; }
|
||||||
|
set {
|
||||||
|
kind_ = value;
|
||||||
|
kindCase_ = KindOneofCase.NumberValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "string_value" field.</summary>
|
||||||
|
public const int StringValueFieldNumber = 3;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a string value.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public string StringValue {
|
||||||
|
get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
|
||||||
|
set {
|
||||||
|
kind_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
kindCase_ = KindOneofCase.StringValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "bool_value" field.</summary>
|
||||||
|
public const int BoolValueFieldNumber = 4;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a boolean value.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool BoolValue {
|
||||||
|
get { return kindCase_ == KindOneofCase.BoolValue ? (bool) kind_ : false; }
|
||||||
|
set {
|
||||||
|
kind_ = value;
|
||||||
|
kindCase_ = KindOneofCase.BoolValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "struct_value" field.</summary>
|
||||||
|
public const int StructValueFieldNumber = 5;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a structured value.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public global::Google.Protobuf.WellKnownTypes.Struct StructValue {
|
||||||
|
get { return kindCase_ == KindOneofCase.StructValue ? (global::Google.Protobuf.WellKnownTypes.Struct) kind_ : null; }
|
||||||
|
set {
|
||||||
|
kind_ = value;
|
||||||
|
kindCase_ = value == null ? KindOneofCase.None : KindOneofCase.StructValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "list_value" field.</summary>
|
||||||
|
public const int ListValueFieldNumber = 6;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a repeated `Value`.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public global::Google.Protobuf.WellKnownTypes.ListValue ListValue {
|
||||||
|
get { return kindCase_ == KindOneofCase.ListValue ? (global::Google.Protobuf.WellKnownTypes.ListValue) kind_ : null; }
|
||||||
|
set {
|
||||||
|
kind_ = value;
|
||||||
|
kindCase_ = value == null ? KindOneofCase.None : KindOneofCase.ListValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object kind_;
|
||||||
|
/// <summary>Enum of possible cases for the "kind" oneof.</summary>
|
||||||
|
public enum KindOneofCase {
|
||||||
|
None = 0,
|
||||||
|
NullValue = 1,
|
||||||
|
NumberValue = 2,
|
||||||
|
StringValue = 3,
|
||||||
|
BoolValue = 4,
|
||||||
|
StructValue = 5,
|
||||||
|
ListValue = 6,
|
||||||
|
}
|
||||||
|
private KindOneofCase kindCase_ = KindOneofCase.None;
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public KindOneofCase KindCase {
|
||||||
|
get { return kindCase_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void ClearKind() {
|
||||||
|
kindCase_ = KindOneofCase.None;
|
||||||
|
kind_ = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Value other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (NullValue != other.NullValue) return false;
|
||||||
|
if (NumberValue != other.NumberValue) return false;
|
||||||
|
if (StringValue != other.StringValue) return false;
|
||||||
|
if (BoolValue != other.BoolValue) return false;
|
||||||
|
if (!object.Equals(StructValue, other.StructValue)) return false;
|
||||||
|
if (!object.Equals(ListValue, other.ListValue)) return false;
|
||||||
|
if (KindCase != other.KindCase) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (kindCase_ == KindOneofCase.NullValue) hash ^= NullValue.GetHashCode();
|
||||||
|
if (kindCase_ == KindOneofCase.NumberValue) hash ^= NumberValue.GetHashCode();
|
||||||
|
if (kindCase_ == KindOneofCase.StringValue) hash ^= StringValue.GetHashCode();
|
||||||
|
if (kindCase_ == KindOneofCase.BoolValue) hash ^= BoolValue.GetHashCode();
|
||||||
|
if (kindCase_ == KindOneofCase.StructValue) hash ^= StructValue.GetHashCode();
|
||||||
|
if (kindCase_ == KindOneofCase.ListValue) hash ^= ListValue.GetHashCode();
|
||||||
|
hash ^= (int) kindCase_;
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (kindCase_ == KindOneofCase.NullValue) {
|
||||||
|
output.WriteRawTag(8);
|
||||||
|
output.WriteEnum((int) NullValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.NumberValue) {
|
||||||
|
output.WriteRawTag(17);
|
||||||
|
output.WriteDouble(NumberValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.StringValue) {
|
||||||
|
output.WriteRawTag(26);
|
||||||
|
output.WriteString(StringValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.BoolValue) {
|
||||||
|
output.WriteRawTag(32);
|
||||||
|
output.WriteBool(BoolValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.StructValue) {
|
||||||
|
output.WriteRawTag(42);
|
||||||
|
output.WriteMessage(StructValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.ListValue) {
|
||||||
|
output.WriteRawTag(50);
|
||||||
|
output.WriteMessage(ListValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (kindCase_ == KindOneofCase.NullValue) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NullValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.NumberValue) {
|
||||||
|
size += 1 + 8;
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.StringValue) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.BoolValue) {
|
||||||
|
size += 1 + 1;
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.StructValue) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeMessageSize(StructValue);
|
||||||
|
}
|
||||||
|
if (kindCase_ == KindOneofCase.ListValue) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeMessageSize(ListValue);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Value other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (other.KindCase) {
|
||||||
|
case KindOneofCase.NullValue:
|
||||||
|
NullValue = other.NullValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.NumberValue:
|
||||||
|
NumberValue = other.NumberValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.StringValue:
|
||||||
|
StringValue = other.StringValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.BoolValue:
|
||||||
|
BoolValue = other.BoolValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.StructValue:
|
||||||
|
StructValue = other.StructValue;
|
||||||
|
break;
|
||||||
|
case KindOneofCase.ListValue:
|
||||||
|
ListValue = other.ListValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 8: {
|
||||||
|
kind_ = input.ReadEnum();
|
||||||
|
kindCase_ = KindOneofCase.NullValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 17: {
|
||||||
|
NumberValue = input.ReadDouble();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 26: {
|
||||||
|
StringValue = input.ReadString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 32: {
|
||||||
|
BoolValue = input.ReadBool();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 42: {
|
||||||
|
global::Google.Protobuf.WellKnownTypes.Struct subBuilder = new global::Google.Protobuf.WellKnownTypes.Struct();
|
||||||
|
if (kindCase_ == KindOneofCase.StructValue) {
|
||||||
|
subBuilder.MergeFrom(StructValue);
|
||||||
|
}
|
||||||
|
input.ReadMessage(subBuilder);
|
||||||
|
StructValue = subBuilder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 50: {
|
||||||
|
global::Google.Protobuf.WellKnownTypes.ListValue subBuilder = new global::Google.Protobuf.WellKnownTypes.ListValue();
|
||||||
|
if (kindCase_ == KindOneofCase.ListValue) {
|
||||||
|
subBuilder.MergeFrom(ListValue);
|
||||||
|
}
|
||||||
|
input.ReadMessage(subBuilder);
|
||||||
|
ListValue = subBuilder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// `ListValue` is a wrapper around a repeated field of values.
|
||||||
|
///
|
||||||
|
/// The JSON representation for `ListValue` is JSON array.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class ListValue : pb::IMessage<ListValue> {
|
||||||
|
private static readonly pb::MessageParser<ListValue> _parser = new pb::MessageParser<ListValue>(() => new ListValue());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<ListValue> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor.MessageTypes[2]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public ListValue() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public ListValue(ListValue other) : this() {
|
||||||
|
values_ = other.values_.Clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public ListValue Clone() {
|
||||||
|
return new ListValue(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "values" field.</summary>
|
||||||
|
public const int ValuesFieldNumber = 1;
|
||||||
|
private static readonly pb::FieldCodec<global::Google.Protobuf.WellKnownTypes.Value> _repeated_values_codec
|
||||||
|
= pb::FieldCodec.ForMessage(10, global::Google.Protobuf.WellKnownTypes.Value.Parser);
|
||||||
|
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> values_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value>();
|
||||||
|
/// <summary>
|
||||||
|
/// Repeated field of dynamically typed values.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Value> Values {
|
||||||
|
get { return values_; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as ListValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(ListValue other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(!values_.Equals(other.values_)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
hash ^= values_.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
values_.WriteTo(output, _repeated_values_codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
size += values_.CalculateSize(_repeated_values_codec);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(ListValue other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
values_.Add(other.values_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 10: {
|
||||||
|
values_.AddEntriesFrom(input, _repeated_values_codec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods on BCL time-related types, converting to protobuf types.
|
||||||
|
/// </summary>
|
||||||
|
public static class TimeExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="DateTime"/> to a <see cref="Timestamp"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateTime">The date and time to convert to a timestamp.</param>
|
||||||
|
/// <exception cref="ArgumentException">The <paramref name="dateTime"/> value has a <see cref="DateTime.Kind"/>other than <c>Utc</c>.</exception>
|
||||||
|
/// <returns>The converted timestamp.</returns>
|
||||||
|
public static Timestamp ToTimestamp(this DateTime dateTime)
|
||||||
|
{
|
||||||
|
return Timestamp.FromDateTime(dateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The offset is taken into consideration when converting the value (so the same instant in time
|
||||||
|
/// is represented) but is not a separate part of the resulting value. In other words, there is no
|
||||||
|
/// roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
|
||||||
|
/// <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
|
||||||
|
/// <returns>The converted timestamp.</returns>
|
||||||
|
public static Timestamp ToTimestamp(this DateTimeOffset dateTimeOffset)
|
||||||
|
{
|
||||||
|
return Timestamp.FromDateTimeOffset(dateTimeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="TimeSpan"/> to a <see cref="Duration"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeSpan">The time span to convert.</param>
|
||||||
|
/// <returns>The converted duration.</returns>
|
||||||
|
public static Duration ToDuration(this TimeSpan timeSpan)
|
||||||
|
{
|
||||||
|
return Duration.FromTimeSpan(timeSpan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,277 @@
|
|||||||
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
// source: google/protobuf/timestamp.proto
|
||||||
|
#pragma warning disable 1591, 0612, 3021
|
||||||
|
#region Designer generated code
|
||||||
|
|
||||||
|
using pb = global::Google.Protobuf;
|
||||||
|
using pbr = global::Google.Protobuf.Reflection;
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>Holder for reflection information generated from google/protobuf/timestamp.proto</summary>
|
||||||
|
public static partial class TimestampReflection {
|
||||||
|
|
||||||
|
#region Descriptor
|
||||||
|
/// <summary>File descriptor for google/protobuf/timestamp.proto</summary>
|
||||||
|
public static pbr::FileDescriptor Descriptor {
|
||||||
|
get { return descriptor; }
|
||||||
|
}
|
||||||
|
private static pbr::FileDescriptor descriptor;
|
||||||
|
|
||||||
|
static TimestampReflection() {
|
||||||
|
byte[] descriptorData = global::System.Convert.FromBase64String(
|
||||||
|
string.Concat(
|
||||||
|
"Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv",
|
||||||
|
"dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY",
|
||||||
|
"AiABKAVCfgoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
|
||||||
|
"AVorZ2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL3RpbWVzdGFt",
|
||||||
|
"cPgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG",
|
||||||
|
"cHJvdG8z"));
|
||||||
|
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||||
|
new pbr::FileDescriptor[] { },
|
||||||
|
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||||
|
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Timestamp), global::Google.Protobuf.WellKnownTypes.Timestamp.Parser, new[]{ "Seconds", "Nanos" }, null, null, null)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
#region Messages
|
||||||
|
/// <summary>
|
||||||
|
/// A Timestamp represents a point in time independent of any time zone
|
||||||
|
/// or calendar, represented as seconds and fractions of seconds at
|
||||||
|
/// nanosecond resolution in UTC Epoch time. It is encoded using the
|
||||||
|
/// Proleptic Gregorian Calendar which extends the Gregorian calendar
|
||||||
|
/// backwards to year one. It is encoded assuming all minutes are 60
|
||||||
|
/// seconds long, i.e. leap seconds are "smeared" so that no leap second
|
||||||
|
/// table is needed for interpretation. Range is from
|
||||||
|
/// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
|
||||||
|
/// By restricting to that range, we ensure that we can convert to
|
||||||
|
/// and from RFC 3339 date strings.
|
||||||
|
/// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// Example 1: Compute Timestamp from POSIX `time()`.
|
||||||
|
///
|
||||||
|
/// Timestamp timestamp;
|
||||||
|
/// timestamp.set_seconds(time(NULL));
|
||||||
|
/// timestamp.set_nanos(0);
|
||||||
|
///
|
||||||
|
/// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||||
|
///
|
||||||
|
/// struct timeval tv;
|
||||||
|
/// gettimeofday(&tv, NULL);
|
||||||
|
///
|
||||||
|
/// Timestamp timestamp;
|
||||||
|
/// timestamp.set_seconds(tv.tv_sec);
|
||||||
|
/// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||||
|
///
|
||||||
|
/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||||
|
///
|
||||||
|
/// FILETIME ft;
|
||||||
|
/// GetSystemTimeAsFileTime(&ft);
|
||||||
|
/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||||
|
///
|
||||||
|
/// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||||
|
/// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||||
|
/// Timestamp timestamp;
|
||||||
|
/// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||||
|
/// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||||
|
///
|
||||||
|
/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||||
|
///
|
||||||
|
/// long millis = System.currentTimeMillis();
|
||||||
|
///
|
||||||
|
/// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||||
|
/// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||||
|
///
|
||||||
|
/// Example 5: Compute Timestamp from current time in Python.
|
||||||
|
///
|
||||||
|
/// timestamp = Timestamp()
|
||||||
|
/// timestamp.GetCurrentTime()
|
||||||
|
///
|
||||||
|
/// # JSON Mapping
|
||||||
|
///
|
||||||
|
/// In JSON format, the Timestamp type is encoded as a string in the
|
||||||
|
/// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||||
|
/// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||||
|
/// where {year} is always expressed using four digits while {month}, {day},
|
||||||
|
/// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||||
|
/// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||||
|
/// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||||
|
/// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||||
|
///
|
||||||
|
/// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||||
|
/// 01:30 UTC on January 15, 2017.
|
||||||
|
///
|
||||||
|
/// In JavaScript, one can convert a Date object to this format using the
|
||||||
|
/// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||||
|
/// method. In Python, a standard `datetime.datetime` object can be converted
|
||||||
|
/// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||||
|
/// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||||
|
/// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||||
|
/// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime())
|
||||||
|
/// to obtain a formatter capable of generating timestamps in this format.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class Timestamp : pb::IMessage<Timestamp> {
|
||||||
|
private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pb::MessageParser<Timestamp> Parser { get { return _parser; } }
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public static pbr::MessageDescriptor Descriptor {
|
||||||
|
get { return global::Google.Protobuf.WellKnownTypes.TimestampReflection.Descriptor.MessageTypes[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
pbr::MessageDescriptor pb::IMessage.Descriptor {
|
||||||
|
get { return Descriptor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Timestamp() {
|
||||||
|
OnConstruction();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnConstruction();
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Timestamp(Timestamp other) : this() {
|
||||||
|
seconds_ = other.seconds_;
|
||||||
|
nanos_ = other.nanos_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public Timestamp Clone() {
|
||||||
|
return new Timestamp(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "seconds" field.</summary>
|
||||||
|
public const int SecondsFieldNumber = 1;
|
||||||
|
private long seconds_;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents seconds of UTC time since Unix epoch
|
||||||
|
/// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||||
|
/// 9999-12-31T23:59:59Z inclusive.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public long Seconds {
|
||||||
|
get { return seconds_; }
|
||||||
|
set {
|
||||||
|
seconds_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Field number for the "nanos" field.</summary>
|
||||||
|
public const int NanosFieldNumber = 2;
|
||||||
|
private int nanos_;
|
||||||
|
/// <summary>
|
||||||
|
/// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||||
|
/// second values with fractions must still have non-negative nanos values
|
||||||
|
/// that count forward in time. Must be from 0 to 999,999,999
|
||||||
|
/// inclusive.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int Nanos {
|
||||||
|
get { return nanos_; }
|
||||||
|
set {
|
||||||
|
nanos_ = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override bool Equals(object other) {
|
||||||
|
return Equals(other as Timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public bool Equals(Timestamp other) {
|
||||||
|
if (ReferenceEquals(other, null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ReferenceEquals(other, this)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Seconds != other.Seconds) return false;
|
||||||
|
if (Nanos != other.Nanos) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override int GetHashCode() {
|
||||||
|
int hash = 1;
|
||||||
|
if (Seconds != 0L) hash ^= Seconds.GetHashCode();
|
||||||
|
if (Nanos != 0) hash ^= Nanos.GetHashCode();
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public override string ToString() {
|
||||||
|
return pb::JsonFormatter.ToDiagnosticString(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void WriteTo(pb::CodedOutputStream output) {
|
||||||
|
if (Seconds != 0L) {
|
||||||
|
output.WriteRawTag(8);
|
||||||
|
output.WriteInt64(Seconds);
|
||||||
|
}
|
||||||
|
if (Nanos != 0) {
|
||||||
|
output.WriteRawTag(16);
|
||||||
|
output.WriteInt32(Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public int CalculateSize() {
|
||||||
|
int size = 0;
|
||||||
|
if (Seconds != 0L) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeInt64Size(Seconds);
|
||||||
|
}
|
||||||
|
if (Nanos != 0) {
|
||||||
|
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Nanos);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(Timestamp other) {
|
||||||
|
if (other == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (other.Seconds != 0L) {
|
||||||
|
Seconds = other.Seconds;
|
||||||
|
}
|
||||||
|
if (other.Nanos != 0) {
|
||||||
|
Nanos = other.Nanos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||||
|
public void MergeFrom(pb::CodedInputStream input) {
|
||||||
|
uint tag;
|
||||||
|
while ((tag = input.ReadTag()) != 0) {
|
||||||
|
switch(tag) {
|
||||||
|
default:
|
||||||
|
input.SkipLastField();
|
||||||
|
break;
|
||||||
|
case 8: {
|
||||||
|
Seconds = input.ReadInt64();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 16: {
|
||||||
|
Nanos = input.ReadInt32();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Designer generated code
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
public partial class Timestamp : ICustomDiagnosticMessage
|
||||||
|
{
|
||||||
|
private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
// Constants determined programmatically, but then hard-coded so they can be constant expressions.
|
||||||
|
private const long BclSecondsAtUnixEpoch = 62135596800;
|
||||||
|
internal const long UnixSecondsAtBclMaxValue = 253402300799;
|
||||||
|
internal const long UnixSecondsAtBclMinValue = -BclSecondsAtUnixEpoch;
|
||||||
|
internal const int MaxNanos = Duration.NanosecondsPerSecond - 1;
|
||||||
|
|
||||||
|
private static bool IsNormalized(long seconds, int nanoseconds) =>
|
||||||
|
nanoseconds >= 0 &&
|
||||||
|
nanoseconds <= MaxNanos &&
|
||||||
|
seconds >= UnixSecondsAtBclMinValue &&
|
||||||
|
seconds <= UnixSecondsAtBclMaxValue;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the difference between one <see cref="Timestamp"/> and another, as a <see cref="Duration"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The timestamp to subtract from. Must not be null.</param>
|
||||||
|
/// <param name="rhs">The timestamp to subtract. Must not be null.</param>
|
||||||
|
/// <returns>The difference between the two specified timestamps.</returns>
|
||||||
|
public static Duration operator -(Timestamp lhs, Timestamp rhs)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(lhs, "lhs");
|
||||||
|
ProtoPreconditions.CheckNotNull(rhs, "rhs");
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return Duration.Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a <see cref="Duration"/> to a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The timestamp to add the duration to. Must not be null.</param>
|
||||||
|
/// <param name="rhs">The duration to add. Must not be null.</param>
|
||||||
|
/// <returns>The result of adding the duration to the timestamp.</returns>
|
||||||
|
public static Timestamp operator +(Timestamp lhs, Duration rhs)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(lhs, "lhs");
|
||||||
|
ProtoPreconditions.CheckNotNull(rhs, "rhs");
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return Normalize(lhs.Seconds + rhs.Seconds, lhs.Nanos + rhs.Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts a <see cref="Duration"/> from a <see cref="Timestamp"/>, to obtain another <c>Timestamp</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lhs">The timestamp to subtract the duration from. Must not be null.</param>
|
||||||
|
/// <param name="rhs">The duration to subtract.</param>
|
||||||
|
/// <returns>The result of subtracting the duration from the timestamp.</returns>
|
||||||
|
public static Timestamp operator -(Timestamp lhs, Duration rhs)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(lhs, "lhs");
|
||||||
|
ProtoPreconditions.CheckNotNull(rhs, "rhs");
|
||||||
|
checked
|
||||||
|
{
|
||||||
|
return Normalize(lhs.Seconds - rhs.Seconds, lhs.Nanos - rhs.Nanos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this timestamp into a <see cref="DateTime"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The resulting <c>DateTime</c> will always have a <c>Kind</c> of <c>Utc</c>.
|
||||||
|
/// If the timestamp is not a precise number of ticks, it will be truncated towards the start
|
||||||
|
/// of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
|
||||||
|
/// <see cref="DateTime"/> value precisely on a second.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>This timestamp as a <c>DateTime</c>.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
|
||||||
|
/// incorrectly normalized or is outside the valid range.</exception>
|
||||||
|
public DateTime ToDateTime()
|
||||||
|
{
|
||||||
|
if (!IsNormalized(Seconds, Nanos))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(@"Timestamp contains invalid values: Seconds={Seconds}; Nanos={Nanos}");
|
||||||
|
}
|
||||||
|
return UnixEpoch.AddSeconds(Seconds).AddTicks(Nanos / Duration.NanosecondsPerTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts this timestamp into a <see cref="DateTimeOffset"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The resulting <c>DateTimeOffset</c> will always have an <c>Offset</c> of zero.
|
||||||
|
/// If the timestamp is not a precise number of ticks, it will be truncated towards the start
|
||||||
|
/// of time. For example, a timestamp with a <see cref="Nanos"/> value of 99 will result in a
|
||||||
|
/// <see cref="DateTimeOffset"/> value precisely on a second.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>This timestamp as a <c>DateTimeOffset</c>.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">The timestamp contains invalid values; either it is
|
||||||
|
/// incorrectly normalized or is outside the valid range.</exception>
|
||||||
|
public DateTimeOffset ToDateTimeOffset()
|
||||||
|
{
|
||||||
|
return new DateTimeOffset(ToDateTime(), TimeSpan.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the specified <see cref="DateTime"/> to a <see cref="Timestamp"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dateTime"></param>
|
||||||
|
/// <exception cref="ArgumentException">The <c>Kind</c> of <paramref name="dateTime"/> is not <c>DateTimeKind.Utc</c>.</exception>
|
||||||
|
/// <returns>The converted timestamp.</returns>
|
||||||
|
public static Timestamp FromDateTime(DateTime dateTime)
|
||||||
|
{
|
||||||
|
if (dateTime.Kind != DateTimeKind.Utc)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Conversion from DateTime to Timestamp requires the DateTime kind to be Utc", "dateTime");
|
||||||
|
}
|
||||||
|
// Do the arithmetic using DateTime.Ticks, which is always non-negative, making things simpler.
|
||||||
|
long secondsSinceBclEpoch = dateTime.Ticks / TimeSpan.TicksPerSecond;
|
||||||
|
int nanoseconds = (int) (dateTime.Ticks % TimeSpan.TicksPerSecond) * Duration.NanosecondsPerTick;
|
||||||
|
return new Timestamp { Seconds = secondsSinceBclEpoch - BclSecondsAtUnixEpoch, Nanos = nanoseconds };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts the given <see cref="DateTimeOffset"/> to a <see cref="Timestamp"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The offset is taken into consideration when converting the value (so the same instant in time
|
||||||
|
/// is represented) but is not a separate part of the resulting value. In other words, there is no
|
||||||
|
/// roundtrip operation to retrieve the original <c>DateTimeOffset</c>.</remarks>
|
||||||
|
/// <param name="dateTimeOffset">The date and time (with UTC offset) to convert to a timestamp.</param>
|
||||||
|
/// <returns>The converted timestamp.</returns>
|
||||||
|
public static Timestamp FromDateTimeOffset(DateTimeOffset dateTimeOffset)
|
||||||
|
{
|
||||||
|
// We don't need to worry about this having negative ticks: DateTimeOffset is constrained to handle
|
||||||
|
// values whose *UTC* value is in the range of DateTime.
|
||||||
|
return FromDateTime(dateTimeOffset.UtcDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Timestamp Normalize(long seconds, int nanoseconds)
|
||||||
|
{
|
||||||
|
int extraSeconds = nanoseconds / Duration.NanosecondsPerSecond;
|
||||||
|
seconds += extraSeconds;
|
||||||
|
nanoseconds -= extraSeconds * Duration.NanosecondsPerSecond;
|
||||||
|
|
||||||
|
if (nanoseconds < 0)
|
||||||
|
{
|
||||||
|
nanoseconds += Duration.NanosecondsPerSecond;
|
||||||
|
seconds--;
|
||||||
|
}
|
||||||
|
return new Timestamp { Seconds = seconds, Nanos = nanoseconds };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a timestamp specified in seconds/nanoseconds to a string.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If the value is a normalized duration in the range described in <c>timestamp.proto</c>,
|
||||||
|
/// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
|
||||||
|
/// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="seconds">Seconds portion of the duration.</param>
|
||||||
|
/// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
|
||||||
|
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
|
||||||
|
/// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
|
||||||
|
internal static string ToJson(long seconds, int nanoseconds, bool diagnosticOnly)
|
||||||
|
{
|
||||||
|
if (IsNormalized(seconds, nanoseconds))
|
||||||
|
{
|
||||||
|
// Use .NET's formatting for the value down to the second, including an opening double quote (as it's a string value)
|
||||||
|
DateTime dateTime = UnixEpoch.AddSeconds(seconds);
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
builder.Append('"');
|
||||||
|
builder.Append(dateTime.ToString("yyyy'-'MM'-'dd'T'HH:mm:ss", CultureInfo.InvariantCulture));
|
||||||
|
Duration.AppendNanoseconds(builder, nanoseconds);
|
||||||
|
builder.Append("Z\"");
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
if (diagnosticOnly)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture,
|
||||||
|
"{{ \"@warning\": \"Invalid Timestamp\", \"seconds\": \"{0}\", \"nanos\": {1} }}",
|
||||||
|
seconds,
|
||||||
|
nanoseconds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Non-normalized timestamp value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a string representation of this <see cref="Timestamp"/> for diagnostic purposes.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Normally the returned value will be a JSON string value (including leading and trailing quotes) but
|
||||||
|
/// when the value is non-normalized or out of range, a JSON object representation will be returned
|
||||||
|
/// instead, including a warning. This is to avoid exceptions being thrown when trying to
|
||||||
|
/// diagnose problems - the regular JSON formatter will still throw an exception for non-normalized
|
||||||
|
/// values.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>A string representation of this value.</returns>
|
||||||
|
public string ToDiagnosticString()
|
||||||
|
{
|
||||||
|
return ToJson(Seconds, Nanos, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,99 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
public partial class Value
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to create a Value message with a string value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value to set for the StringValue property.</param>
|
||||||
|
/// <returns>A newly-created Value message with the given value.</returns>
|
||||||
|
public static Value ForString(string value)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
return new Value { StringValue = value };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to create a Value message with a number value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value to set for the NumberValue property.</param>
|
||||||
|
/// <returns>A newly-created Value message with the given value.</returns>
|
||||||
|
public static Value ForNumber(double value)
|
||||||
|
{
|
||||||
|
return new Value { NumberValue = value };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to create a Value message with a Boolean value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">Value to set for the BoolValue property.</param>
|
||||||
|
/// <returns>A newly-created Value message with the given value.</returns>
|
||||||
|
public static Value ForBool(bool value)
|
||||||
|
{
|
||||||
|
return new Value { BoolValue = value };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to create a Value message with a null initial value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A newly-created Value message a null initial value.</returns>
|
||||||
|
public static Value ForNull()
|
||||||
|
{
|
||||||
|
return new Value { NullValue = 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to create a Value message with an initial list of values.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The values provided are not cloned; the references are copied directly.</remarks>
|
||||||
|
/// <returns>A newly-created Value message an initial list value.</returns>
|
||||||
|
public static Value ForList(params Value[] values)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(values, "values");
|
||||||
|
return new Value { ListValue = new ListValue { Values = { values } } };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience method to create a Value message with an initial struct value
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The value provided is not cloned; the reference is copied directly.</remarks>
|
||||||
|
/// <returns>A newly-created Value message an initial struct value.</returns>
|
||||||
|
public static Value ForStruct(Struct value)
|
||||||
|
{
|
||||||
|
ProtoPreconditions.CheckNotNull(value, "value");
|
||||||
|
return new Value { StructValue = value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf.WellKnownTypes
|
||||||
|
{
|
||||||
|
public static partial class WrappersReflection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Field number for the single "value" field in all wrapper types.
|
||||||
|
/// </summary>
|
||||||
|
internal const int WrapperValueFieldNumber = Int32Value.ValueFieldNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
#region Copyright notice and license
|
||||||
|
// Protocol Buffers - Google's data interchange format
|
||||||
|
// Copyright 2008 Google Inc. All rights reserved.
|
||||||
|
// https://developers.google.com/protocol-buffers/
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * Redistributions in binary form must reproduce the above
|
||||||
|
// copyright notice, this list of conditions and the following disclaimer
|
||||||
|
// in the documentation and/or other materials provided with the
|
||||||
|
// distribution.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace Google.Protobuf
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class is used internally by the Protocol Buffer Library and generated
|
||||||
|
/// message implementations. It is public only for the sake of those generated
|
||||||
|
/// messages. Others should not use this class directly.
|
||||||
|
/// <para>
|
||||||
|
/// This class contains constants and helper functions useful for dealing with
|
||||||
|
/// the Protocol Buffer wire format.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
public static class WireFormat
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Wire types within protobuf encoding.
|
||||||
|
/// </summary>
|
||||||
|
public enum WireType : uint
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Variable-length integer.
|
||||||
|
/// </summary>
|
||||||
|
Varint = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// A fixed-length 64-bit value.
|
||||||
|
/// </summary>
|
||||||
|
Fixed64 = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// A length-delimited value, i.e. a length followed by that many bytes of data.
|
||||||
|
/// </summary>
|
||||||
|
LengthDelimited = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// A "start group" value - not supported by this implementation.
|
||||||
|
/// </summary>
|
||||||
|
StartGroup = 3,
|
||||||
|
/// <summary>
|
||||||
|
/// An "end group" value - not supported by this implementation.
|
||||||
|
/// </summary>
|
||||||
|
EndGroup = 4,
|
||||||
|
/// <summary>
|
||||||
|
/// A fixed-length 32-bit value.
|
||||||
|
/// </summary>
|
||||||
|
Fixed32 = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int TagTypeBits = 3;
|
||||||
|
private const uint TagTypeMask = (1 << TagTypeBits) - 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a tag value, determines the wire type (lower 3 bits).
|
||||||
|
/// </summary>
|
||||||
|
public static WireType GetTagWireType(uint tag)
|
||||||
|
{
|
||||||
|
return (WireType) (tag & TagTypeMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a tag value, determines the field number (the upper 29 bits).
|
||||||
|
/// </summary>
|
||||||
|
public static int GetTagFieldNumber(uint tag)
|
||||||
|
{
|
||||||
|
return (int) tag >> TagTypeBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes a tag value given a field number and wire type.
|
||||||
|
/// </summary>
|
||||||
|
public static uint MakeTag(int fieldNumber, WireType wireType)
|
||||||
|
{
|
||||||
|
return (uint) (fieldNumber << TagTypeBits) | (uint) wireType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>Framework</RootNamespace>
|
|
||||||
<AssemblyName>Framework</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\Debug\</OutputPath>
|
|
||||||
<DefineConstants>TRACE;DEBUG</DefineConstants>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
|
||||||
<OutputPath>..\Build\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\x64\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
|
||||||
<OutputPath>..\Build\x64\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Google.Protobuf, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\Libs\Google.Protobuf.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\Libs\MySql.Data.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Data.Linq" />
|
|
||||||
<Reference Include="System.Numerics" />
|
|
||||||
<Reference Include="System.Runtime.Serialization" />
|
|
||||||
<Reference Include="System.Transactions" />
|
|
||||||
<Reference Include="System.Web.Extensions" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Collections\Array.cs" />
|
|
||||||
<Compile Include="Collections\BitSet.cs" />
|
|
||||||
<Compile Include="Configuration\ConfigManager.cs" />
|
|
||||||
<Compile Include="Constants\AccountConst.cs" />
|
|
||||||
<Compile Include="Constants\AchievementConst.cs" />
|
|
||||||
<Compile Include="Constants\AreaTriggerConst.cs" />
|
|
||||||
<Compile Include="Constants\AuctionConst.cs" />
|
|
||||||
<Compile Include="Constants\Authentication\AuthConst.cs" />
|
|
||||||
<Compile Include="Constants\Authentication\BattlenetConst.cs" />
|
|
||||||
<Compile Include="Constants\Authentication\RealmConst.cs" />
|
|
||||||
<Compile Include="Constants\BattleFieldConst.cs" />
|
|
||||||
<Compile Include="Constants\BattleGroundsConst.cs" />
|
|
||||||
<Compile Include="Constants\BattlePetConst.cs" />
|
|
||||||
<Compile Include="Constants\BlackMarketConst.cs" />
|
|
||||||
<Compile Include="Constants\CalendarConst.cs" />
|
|
||||||
<Compile Include="Constants\ChatConst.cs" />
|
|
||||||
<Compile Include="Constants\CliDBConst.cs" />
|
|
||||||
<Compile Include="Constants\ConditionConst.cs" />
|
|
||||||
<Compile Include="Constants\ConnectConst.cs" />
|
|
||||||
<Compile Include="Constants\CreatureConst.cs" />
|
|
||||||
<Compile Include="Constants\GameObjectConst.cs" />
|
|
||||||
<Compile Include="Constants\GarrisonConst.cs" />
|
|
||||||
<Compile Include="Constants\GossipConst.cs" />
|
|
||||||
<Compile Include="Constants\GroupConst.cs" />
|
|
||||||
<Compile Include="Constants\GuildConst.cs" />
|
|
||||||
<Compile Include="Constants\ItemConst.cs" />
|
|
||||||
<Compile Include="Constants\Language.cs" />
|
|
||||||
<Compile Include="Constants\LFGConst.cs" />
|
|
||||||
<Compile Include="Constants\LootConst.cs" />
|
|
||||||
<Compile Include="Constants\MailConst.cs" />
|
|
||||||
<Compile Include="Constants\MapConst.cs" />
|
|
||||||
<Compile Include="Constants\Movement\MovementConst.cs" />
|
|
||||||
<Compile Include="Constants\Movement\MovementFlags.cs" />
|
|
||||||
<Compile Include="Constants\Movement\SplineConst.cs" />
|
|
||||||
<Compile Include="Constants\Network\NetworkConst.cs" />
|
|
||||||
<Compile Include="Constants\Network\Opcodes.cs" />
|
|
||||||
<Compile Include="Constants\ObjectConst.cs" />
|
|
||||||
<Compile Include="Constants\OutdoorPvPConst.cs" />
|
|
||||||
<Compile Include="Constants\PetConst.cs" />
|
|
||||||
<Compile Include="Constants\PlayerConst.cs" />
|
|
||||||
<Compile Include="Constants\QuestConst.cs" />
|
|
||||||
<Compile Include="Constants\ScriptsConst.cs" />
|
|
||||||
<Compile Include="Constants\SharedConst.cs" />
|
|
||||||
<Compile Include="Constants\SmartAIConst.cs" />
|
|
||||||
<Compile Include="Constants\Spells\SkillConst.cs" />
|
|
||||||
<Compile Include="Constants\Spells\SpellAuraConst.cs" />
|
|
||||||
<Compile Include="Constants\Spells\SpellConst.cs" />
|
|
||||||
<Compile Include="Constants\SupportSystemConst.cs" />
|
|
||||||
<Compile Include="Constants\UnitConst.cs" />
|
|
||||||
<Compile Include="Constants\Update\UpdateFieldFlags.cs" />
|
|
||||||
<Compile Include="Constants\Update\UpdateFields.cs" />
|
|
||||||
<Compile Include="Constants\Update\UpdateFlags.cs" />
|
|
||||||
<Compile Include="Constants\Update\UpdateType.cs" />
|
|
||||||
<Compile Include="Constants\VehicleConst.cs" />
|
|
||||||
<Compile Include="Cryptography\PacketCrypt.cs" />
|
|
||||||
<Compile Include="Cryptography\RsaCrypt.cs" />
|
|
||||||
<Compile Include="Cryptography\SARC4.cs" />
|
|
||||||
<Compile Include="Cryptography\SessionKeyGeneration.cs" />
|
|
||||||
<Compile Include="Cryptography\ShaHmac.cs" />
|
|
||||||
<Compile Include="Database\DatabaseLoader.cs" />
|
|
||||||
<Compile Include="Database\Databases\CharacterDatabase.cs" />
|
|
||||||
<Compile Include="Database\DatabaseUpdater.cs" />
|
|
||||||
<Compile Include="Database\DB.cs" />
|
|
||||||
<Compile Include="Database\Databases\HotfixDatabase.cs" />
|
|
||||||
<Compile Include="Database\Databases\LoginDatabase.cs" />
|
|
||||||
<Compile Include="Database\MySqlBase.cs" />
|
|
||||||
<Compile Include="Database\PreparedStatement.cs" />
|
|
||||||
<Compile Include="Database\QueryCallback.cs" />
|
|
||||||
<Compile Include="Database\QueryCallbackProcessor.cs" />
|
|
||||||
<Compile Include="Database\SQLQueryHolder.cs" />
|
|
||||||
<Compile Include="Database\SQLResult.cs" />
|
|
||||||
<Compile Include="Database\SQLTransaction.cs" />
|
|
||||||
<Compile Include="Database\Databases\WorldDatabase.cs" />
|
|
||||||
<Compile Include="Dynamic\EventMap.cs" />
|
|
||||||
<Compile Include="Dynamic\EventSystem.cs" />
|
|
||||||
<Compile Include="Dynamic\FlagArray.cs" />
|
|
||||||
<Compile Include="Collections\IMultiMap.cs" />
|
|
||||||
<Compile Include="Collections\LinkedListElement.cs" />
|
|
||||||
<Compile Include="Collections\MultiMap.cs" />
|
|
||||||
<Compile Include="Collections\MultiMapEnumerator.cs" />
|
|
||||||
<Compile Include="Dynamic\OptionalType.cs" />
|
|
||||||
<Compile Include="Dynamic\Reference.cs" />
|
|
||||||
<Compile Include="Dynamic\TaskScheduler.cs" />
|
|
||||||
<Compile Include="GameMath\Plane.cs" />
|
|
||||||
<Compile Include="GameMath\Vector2.cs" />
|
|
||||||
<Compile Include="GameMath\Vector3.cs" />
|
|
||||||
<Compile Include="GameMath\Vector4.cs" />
|
|
||||||
<Compile Include="IO\ByteBuffer.cs" />
|
|
||||||
<Compile Include="Collections\StringArray.cs" />
|
|
||||||
<Compile Include="IO\Zlib\Adler32.cs" />
|
|
||||||
<Compile Include="IO\Zlib\compress.cs" />
|
|
||||||
<Compile Include="IO\Zlib\Crc32.cs" />
|
|
||||||
<Compile Include="IO\Zlib\Deflate.cs" />
|
|
||||||
<Compile Include="IO\Zlib\Trees.cs" />
|
|
||||||
<Compile Include="IO\Zlib\ZLib.cs" />
|
|
||||||
<Compile Include="IO\Zlib\ZUtil.cs" />
|
|
||||||
<Compile Include="Logging\Appender.cs" />
|
|
||||||
<Compile Include="Logging\Log.cs" />
|
|
||||||
<Compile Include="Logging\Logger.cs" />
|
|
||||||
<Compile Include="Networking\AsyncAcceptor.cs" />
|
|
||||||
<Compile Include="Util\NetworkExtensions.cs" />
|
|
||||||
<Compile Include="Networking\NetworkThread.cs" />
|
|
||||||
<Compile Include="Networking\SocketBase.cs" />
|
|
||||||
<Compile Include="Networking\SocketManager.cs" />
|
|
||||||
<Compile Include="GameMath\AxisAlignedBox.cs" />
|
|
||||||
<Compile Include="GameMath\CollisionDetection.cs" />
|
|
||||||
<Compile Include="GameMath\Matrix2.cs" />
|
|
||||||
<Compile Include="GameMath\Matrix3.cs" />
|
|
||||||
<Compile Include="GameMath\Matrix4.cs" />
|
|
||||||
<Compile Include="GameMath\Quaternion.cs" />
|
|
||||||
<Compile Include="GameMath\Ray.cs" />
|
|
||||||
<Compile Include="Networking\SSLSocket.cs" />
|
|
||||||
<Compile Include="Constants\ServiceHash.cs" />
|
|
||||||
<Compile Include="Proto\AccountService.cs" />
|
|
||||||
<Compile Include="Proto\AccountTypes.cs" />
|
|
||||||
<Compile Include="Proto\AttributeTypes.cs" />
|
|
||||||
<Compile Include="Proto\AuthenticationService.cs" />
|
|
||||||
<Compile Include="Proto\ChallengeService.cs" />
|
|
||||||
<Compile Include="Proto\ChannelService.cs" />
|
|
||||||
<Compile Include="Proto\ChannelTypes.cs" />
|
|
||||||
<Compile Include="Proto\ConnectionService.cs" />
|
|
||||||
<Compile Include="Proto\ContentHandleTypes.cs" />
|
|
||||||
<Compile Include="Proto\EntityTypes.cs" />
|
|
||||||
<Compile Include="Proto\FriendsService.cs" />
|
|
||||||
<Compile Include="Proto\FriendsTypes.cs" />
|
|
||||||
<Compile Include="Proto\GameUtilitiesService.cs" />
|
|
||||||
<Compile Include="Proto\GameUtilitiesTypes.cs" />
|
|
||||||
<Compile Include="Proto\GlobalExtensions\FieldOptions.cs" />
|
|
||||||
<Compile Include="Proto\GlobalExtensions\MethodOptions.cs" />
|
|
||||||
<Compile Include="Proto\GlobalExtensions\ServiceOptions.cs" />
|
|
||||||
<Compile Include="Proto\InvitationTypes.cs" />
|
|
||||||
<Compile Include="Proto\NotificationTypes.cs" />
|
|
||||||
<Compile Include="Proto\PresenceService.cs" />
|
|
||||||
<Compile Include="Proto\PresenceTypes.cs" />
|
|
||||||
<Compile Include="Proto\ProfanityFilterConfig.cs" />
|
|
||||||
<Compile Include="Proto\ReportService.cs" />
|
|
||||||
<Compile Include="Proto\ResourceService.cs" />
|
|
||||||
<Compile Include="Proto\RoleTypes.cs" />
|
|
||||||
<Compile Include="Proto\RpcConfig.cs" />
|
|
||||||
<Compile Include="Proto\RpcTypes.cs" />
|
|
||||||
<Compile Include="Proto\UserManagerService.cs" />
|
|
||||||
<Compile Include="Proto\UserManagerTypes.cs" />
|
|
||||||
<Compile Include="Realm\Realm.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<Compile Include="Realm\RealmManager.cs" />
|
|
||||||
<Compile Include="RecastDetour\Detour\DetourCommon.cs" />
|
|
||||||
<Compile Include="RecastDetour\Detour\DetourNavMesh.cs" />
|
|
||||||
<Compile Include="RecastDetour\Detour\DetourNavMeshBuilder.cs" />
|
|
||||||
<Compile Include="RecastDetour\Detour\DetourNavMeshQuery.cs" />
|
|
||||||
<Compile Include="RecastDetour\Detour\DetourNode.cs" />
|
|
||||||
<Compile Include="RecastDetour\Detour\DetourStatus.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\Recast.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastArea.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastContour.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastFilter.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastLayers.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastMesh.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastMeshDetail.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastRasterization.cs" />
|
|
||||||
<Compile Include="RecastDetour\Recast\RecastRegion.cs" />
|
|
||||||
<Compile Include="Rest\Authentication\LogonData.cs" />
|
|
||||||
<Compile Include="Rest\Authentication\LogonResult.cs" />
|
|
||||||
<Compile Include="Rest\Forms\FormInput.cs" />
|
|
||||||
<Compile Include="Rest\Forms\FormInputs.cs" />
|
|
||||||
<Compile Include="Rest\Forms\FormInputValue.cs" />
|
|
||||||
<Compile Include="Rest\Misc\Address.cs" />
|
|
||||||
<Compile Include="Rest\Misc\AddressFamily.cs" />
|
|
||||||
<Compile Include="Rest\Misc\ClientVersion.cs" />
|
|
||||||
<Compile Include="Rest\Misc\RealmCharacterCountEntry.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmCharacterCountList.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmEntry.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmListServerIPAddresses.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmListTicketClientInformation.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmListTicketIdentity.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmListTicketInformation.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmListUpdate.cs" />
|
|
||||||
<Compile Include="Rest\Realmlist\RealmListUpdates.cs" />
|
|
||||||
<Compile Include="Runtime\ApplicationSignal.cs" />
|
|
||||||
<Compile Include="Serialization\Json.cs" />
|
|
||||||
<Compile Include="Singleton\Singleton.cs" />
|
|
||||||
<Compile Include="Util\CollectionExtensions.cs" />
|
|
||||||
<Compile Include="Util\Extensions.cs" />
|
|
||||||
<Compile Include="Util\MathFunctions.cs" />
|
|
||||||
<Compile Include="Util\RandomHelper.cs" />
|
|
||||||
<Compile Include="IO\StringArguments.cs" />
|
|
||||||
<Compile Include="Util\Time.cs" />
|
|
||||||
<Compile Include="Web\Http.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Service Include="{3259AA49-8AA1-44D3-9025-A0B520596A8C}" />
|
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup />
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<PostBuildEvent>
|
|
||||||
</PostBuildEvent>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<PreBuildEvent>
|
|
||||||
</PreBuildEvent>
|
|
||||||
</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>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Framework")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Framework")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("87ef8e2a-ee21-44b8-946a-97f78d2e54f2")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2012-2017 CypherCore <http://github.com/CypherCore>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Framework.Runtime
|
|
||||||
{
|
|
||||||
public delegate bool EventHandler(CtrlType sig);
|
|
||||||
|
|
||||||
public class ApplicationSignal
|
|
||||||
{
|
|
||||||
[DllImport("Kernel32")]
|
|
||||||
public static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
|
||||||
static extern IntPtr GetStdHandle(int nStdHandle);
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
|
||||||
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
|
||||||
static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
|
|
||||||
|
|
||||||
public static void RemoveConsoleQuickEditMode()
|
|
||||||
{
|
|
||||||
IntPtr handle = GetStdHandle(-10);
|
|
||||||
|
|
||||||
// get current console mode
|
|
||||||
uint consoleMode;
|
|
||||||
if (!GetConsoleMode(handle, out consoleMode))
|
|
||||||
{
|
|
||||||
// ERROR: Unable to get console mode.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the quick edit bit in the mode flags
|
|
||||||
consoleMode &= ~0x0040u;
|
|
||||||
|
|
||||||
// set the new mode
|
|
||||||
SetConsoleMode(handle, consoleMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum CtrlType
|
|
||||||
{
|
|
||||||
CTRL_C_EVENT = 0,
|
|
||||||
CTRL_BREAK_EVENT = 1,
|
|
||||||
CTRL_CLOSE_EVENT = 2,
|
|
||||||
CTRL_LOGOFF_EVENT = 5,
|
|
||||||
CTRL_SHUTDOWN_EVENT = 6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,521 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>Game</RootNamespace>
|
|
||||||
<AssemblyName>Game</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
|
||||||
<OutputPath>..\Build\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\x64\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<CodeAnalysisIgnoreGeneratedCode>false</CodeAnalysisIgnoreGeneratedCode>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
|
||||||
<OutputPath>..\Build\x64\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Google.Protobuf">
|
|
||||||
<HintPath>..\Libs\Google.Protobuf.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Numerics" />
|
|
||||||
<Reference Include="System.Runtime.Serialization" />
|
|
||||||
<Reference Include="System.ServiceModel" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Accounts\AccountManager.cs" />
|
|
||||||
<Compile Include="Accounts\BNetAccountManager.cs" />
|
|
||||||
<Compile Include="Accounts\RoleAccessControl.cs" />
|
|
||||||
<Compile Include="Achievements\AchievementManager.cs" />
|
|
||||||
<Compile Include="Achievements\CriteriaHandler.cs" />
|
|
||||||
<Compile Include="AI\AISelector.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\AreaTriggerAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\CombatAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\CreatureAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\GameObjectAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\TotemAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\GuardAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\PassiveAI.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\PetAI.cs" />
|
|
||||||
<Compile Include="AI\PlayerAI\PlayerAI.cs" />
|
|
||||||
<Compile Include="AI\ScriptedAI\ScriptedAI.cs" />
|
|
||||||
<Compile Include="AI\ScriptedAI\ScriptedFollowerAI.cs" />
|
|
||||||
<Compile Include="AI\ScriptedAI\ScriptedEscortAI.cs" />
|
|
||||||
<Compile Include="AI\SmartScripts\SmartAI.cs" />
|
|
||||||
<Compile Include="AI\SmartScripts\SmartAIManager.cs" />
|
|
||||||
<Compile Include="AI\SmartScripts\SmartScript.cs" />
|
|
||||||
<Compile Include="AI\CoreAI\UnitAI.cs" />
|
|
||||||
<Compile Include="Arenas\Arena.cs" />
|
|
||||||
<Compile Include="Arenas\ArenaScore.cs" />
|
|
||||||
<Compile Include="Arenas\ArenaTeam.cs" />
|
|
||||||
<Compile Include="Arenas\ArenaTeamManager.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\DalaranSewers.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\NagrandArena.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\RingofValor.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\RuinsofLordaeron.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\TigersPeak.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\TolvironArena.cs" />
|
|
||||||
<Compile Include="BattleFields\BattleField.cs" />
|
|
||||||
<Compile Include="BattleFields\BattleFieldManager.cs" />
|
|
||||||
<Compile Include="BattleFields\Zones\WinterGrasp.cs" />
|
|
||||||
<Compile Include="BattleFields\Zones\WinterGraspConst.cs" />
|
|
||||||
<Compile Include="BattleGrounds\BattleGround.cs" />
|
|
||||||
<Compile Include="BattleGrounds\BattleGroundManager.cs" />
|
|
||||||
<Compile Include="BattleGrounds\BattleGroundQueue.cs" />
|
|
||||||
<Compile Include="BattleGrounds\BattleGroundScore.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\AlteracValley.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\ArathiBasin.cs" />
|
|
||||||
<Compile Include="Arenas\Zones\BladesEdgeArena.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\BattleforGilneas.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\DeepwindGorge.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\EyeofStorm.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\IsleofConquest.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\SilvershardMines.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\StrandofAncients.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\TempleofKotmogu.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\TwinPeaks.cs" />
|
|
||||||
<Compile Include="BattleGrounds\Zones\WarsongGluch.cs" />
|
|
||||||
<Compile Include="BattlePets\BattlePetManager.cs" />
|
|
||||||
<Compile Include="BlackMarket\BlackMarketEntry.cs" />
|
|
||||||
<Compile Include="BlackMarket\BlackMarketManager.cs" />
|
|
||||||
<Compile Include="Chat\Channels\ChannelAppenders.cs" />
|
|
||||||
<Compile Include="Chat\Channels\ChannelManager.cs" />
|
|
||||||
<Compile Include="Chat\Channels\Channel.cs" />
|
|
||||||
<Compile Include="Chat\Commands\SceneCommands.cs" />
|
|
||||||
<Compile Include="Collision\BoundingIntervalHierarchy.cs" />
|
|
||||||
<Compile Include="Collision\BoundingIntervalHierarchyWrap.cs" />
|
|
||||||
<Compile Include="Collision\Callbacks.cs" />
|
|
||||||
<Compile Include="Collision\DynamicTree.cs" />
|
|
||||||
<Compile Include="Collision\Management\VMapManager.cs" />
|
|
||||||
<Compile Include="Collision\Maps\MapTree.cs" />
|
|
||||||
<Compile Include="Collision\Models\GameObjectModel.cs" />
|
|
||||||
<Compile Include="Collision\Models\IModel.cs" />
|
|
||||||
<Compile Include="Collision\Models\ModelInstance.cs" />
|
|
||||||
<Compile Include="Collision\Models\WorldModel.cs" />
|
|
||||||
<Compile Include="Collision\RegularGrid2D.cs" />
|
|
||||||
<Compile Include="Combat\HostileRegManager.cs" />
|
|
||||||
<Compile Include="DataStorage\ClientReader\DB6Meta.cs" />
|
|
||||||
<Compile Include="DataStorage\ConversationDataStorage.cs" />
|
|
||||||
<Compile Include="DataStorage\M2Storage.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\GameTablesRecords.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\M2Structure.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\R_Records.cs" />
|
|
||||||
<Compile Include="Entities\AreaTrigger\AreaTriggerTemplate.cs" />
|
|
||||||
<Compile Include="Entities\Conversation.cs" />
|
|
||||||
<Compile Include="Entities\Creature\CreatureData.cs" />
|
|
||||||
<Compile Include="Entities\Creature\Trainer.cs" />
|
|
||||||
<Compile Include="Entities\GameObject\GameObjectData.cs" />
|
|
||||||
<Compile Include="Entities\Player\CinematicManager.cs" />
|
|
||||||
<Compile Include="Entities\Player\CollectionManager.cs" />
|
|
||||||
<Compile Include="Entities\Player\KillRewarder.cs" />
|
|
||||||
<Compile Include="Entities\Player\PlayerTaxi.cs" />
|
|
||||||
<Compile Include="Entities\Player\RestMgr.cs" />
|
|
||||||
<Compile Include="Entities\Player\SceneMgr.cs" />
|
|
||||||
<Compile Include="Entities\Player\TradeData.cs" />
|
|
||||||
<Compile Include="Entities\Taxi\Graph.cs" />
|
|
||||||
<Compile Include="Entities\Taxi\TaxiPathGraph.cs" />
|
|
||||||
<Compile Include="DataStorage\AreaTriggerDataStorage.cs" />
|
|
||||||
<Compile Include="DataStorage\CharacterTemplateDataStorage.cs" />
|
|
||||||
<Compile Include="Handlers\ArtifactHandler.cs" />
|
|
||||||
<Compile Include="Handlers\BattlenetHandler.cs" />
|
|
||||||
<Compile Include="Handlers\BlackMarketHandlers.cs" />
|
|
||||||
<Compile Include="Handlers\CollectionsHandler.cs" />
|
|
||||||
<Compile Include="Handlers\HotfixHandler.cs" />
|
|
||||||
<Compile Include="Handlers\ScenarioHandler.cs" />
|
|
||||||
<Compile Include="Handlers\SceneHandler.cs" />
|
|
||||||
<Compile Include="Handlers\TransmogrificationHandler.cs" />
|
|
||||||
<Compile Include="Loot\Loot.cs" />
|
|
||||||
<Compile Include="Maps\AreaBoundary.cs" />
|
|
||||||
<Compile Include="Maps\MMapManager.cs" />
|
|
||||||
<Compile Include="Movement\Generators\PathGenerator.cs" />
|
|
||||||
<Compile Include="Movement\Generators\SplineChainMovementGenerator.cs" />
|
|
||||||
<Compile Include="Network\PacketLog.cs" />
|
|
||||||
<Compile Include="Network\Packets\AreaTriggerPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ArtifactPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\BattlefieldPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\BattlenetPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\BlackMarketPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\CollectionPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\GuildFinderPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\HotfixPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\PetPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ScenarioPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TaxiPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TransmogrificationPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\WardenPackets.cs" />
|
|
||||||
<Compile Include="Quest\QuestObjectiveCriteriaManager.cs" />
|
|
||||||
<Compile Include="Scenarios\InstanceScenario.cs" />
|
|
||||||
<Compile Include="Scenarios\Scenario.cs" />
|
|
||||||
<Compile Include="Scenarios\ScenarioManager.cs" />
|
|
||||||
<Compile Include="Services\GameUtilitiesService.cs" />
|
|
||||||
<Compile Include="Services\ServiceDispatcher.cs" />
|
|
||||||
<Compile Include="Text\ChatTextBuilder.cs" />
|
|
||||||
<Compile Include="Chat\CommandAttribute.cs" />
|
|
||||||
<Compile Include="Chat\CommandHandler.cs" />
|
|
||||||
<Compile Include="Chat\CommandManager.cs" />
|
|
||||||
<Compile Include="Chat\Commands\AccountCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\AhBotCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\ArenaCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\BanCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\BattleFieldCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\BNetAccountCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\CastCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\CharacterCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\CheatCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\DebugCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\DeserterCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\DisableCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\EventCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\GameObjectCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\GMCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\GoCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\GroupCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\GuildCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\HonorCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\InstanceCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\LearnCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\LFGCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\ListCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\LookupCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\MessageCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\MiscCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\MMapsCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\ModifyCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\NPCCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\PetCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\QuestCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\RbacCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\ReloadCommand.cs" />
|
|
||||||
<Compile Include="Chat\Commands\ResetCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\SendCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\ServerCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\SpellCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\TeleCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\TicketCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\TitleCommands.cs" />
|
|
||||||
<Compile Include="Chat\Commands\WPCommands.cs" />
|
|
||||||
<Compile Include="Conditions\Condition.cs" />
|
|
||||||
<Compile Include="Conditions\ConditionManager.cs" />
|
|
||||||
<Compile Include="DataStorage\DB2Manager.cs" />
|
|
||||||
<Compile Include="DataStorage\ClientReader\DB6Storage.cs" />
|
|
||||||
<Compile Include="DataStorage\CliDB.cs" />
|
|
||||||
<Compile Include="DataStorage\ClientReader\CliDBReader.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\A_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\B_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\C_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\D_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\G_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\H_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\I_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\K_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\M_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\N_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\O_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\P_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\Q_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\S_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\T_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\U_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\W_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\E_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\F_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\L_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\V_Records.cs" />
|
|
||||||
<Compile Include="DataStorage\ClientReader\GameTables.cs" />
|
|
||||||
<Compile Include="DataStorage\Structs\MiscStructs.cs" />
|
|
||||||
<Compile Include="DungeonFinding\LFGGroupData.cs" />
|
|
||||||
<Compile Include="DungeonFinding\LFGManager.cs" />
|
|
||||||
<Compile Include="DungeonFinding\LFGPlayerData.cs" />
|
|
||||||
<Compile Include="DungeonFinding\LFGQueue.cs" />
|
|
||||||
<Compile Include="DungeonFinding\LFGScripts.cs" />
|
|
||||||
<Compile Include="Entities\AreaTrigger\AreaTrigger.cs" />
|
|
||||||
<Compile Include="Entities\Corpse.cs" />
|
|
||||||
<Compile Include="Entities\Creature\Creature.cs" />
|
|
||||||
<Compile Include="Entities\Creature\Creature.Fields.cs" />
|
|
||||||
<Compile Include="Entities\Creature\CreatureGroups.cs" />
|
|
||||||
<Compile Include="Entities\DynamicObject.cs" />
|
|
||||||
<Compile Include="Entities\GameObject\GameObject.cs" />
|
|
||||||
<Compile Include="Entities\Item\Bag.cs" />
|
|
||||||
<Compile Include="Entities\Item\Item.cs" />
|
|
||||||
<Compile Include="Entities\Item\ItemEnchantment.cs" />
|
|
||||||
<Compile Include="Entities\Item\ItemTemplate.cs" />
|
|
||||||
<Compile Include="Entities\Object\ObjectGuid.cs" />
|
|
||||||
<Compile Include="Entities\Pet.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Achievement.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Combat.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.DB.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Fields.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Groups.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Items.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Map.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.PvP.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Quest.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Spells.cs" />
|
|
||||||
<Compile Include="Entities\Player\Player.Talents.cs" />
|
|
||||||
<Compile Include="Entities\Player\SocialMgr.cs" />
|
|
||||||
<Compile Include="Entities\Object\Position.cs" />
|
|
||||||
<Compile Include="Entities\StatSystem.cs" />
|
|
||||||
<Compile Include="Entities\TemporarySummon.cs" />
|
|
||||||
<Compile Include="Entities\Totem.cs" />
|
|
||||||
<Compile Include="Entities\Transport.cs" />
|
|
||||||
<Compile Include="Entities\Unit\CharmInfo.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Comparer.cs" />
|
|
||||||
<Compile Include="Combat\Events.cs" />
|
|
||||||
<Compile Include="Combat\ThreatManager.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Unit.Combat.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Unit.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Unit.Fields.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Unit.Movement.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Unit.Pets.cs" />
|
|
||||||
<Compile Include="Entities\Unit\Unit.Spells.cs" />
|
|
||||||
<Compile Include="Entities\Object\Update\UpdateData.cs" />
|
|
||||||
<Compile Include="Entities\Object\Update\UpdateMask.cs" />
|
|
||||||
<Compile Include="Entities\Vehicle.cs" />
|
|
||||||
<Compile Include="Entities\Object\WorldObject.cs" />
|
|
||||||
<Compile Include="Garrisons\GarrisonManager.cs" />
|
|
||||||
<Compile Include="Garrisons\GarrisonMap.cs" />
|
|
||||||
<Compile Include="Garrisons\Garrisons.cs" />
|
|
||||||
<Compile Include="Groups\Group.cs" />
|
|
||||||
<Compile Include="Groups\GroupManager.cs" />
|
|
||||||
<Compile Include="Groups\GroupReference.cs" />
|
|
||||||
<Compile Include="Guilds\Guild.cs" />
|
|
||||||
<Compile Include="Guilds\GuildFinderManager.cs" />
|
|
||||||
<Compile Include="Guilds\GuildManager.cs" />
|
|
||||||
<Compile Include="Handlers\ArenaHandler.cs" />
|
|
||||||
<Compile Include="Handlers\AuctionHandler.cs" />
|
|
||||||
<Compile Include="Handlers\AuthenticationHandler.cs" />
|
|
||||||
<Compile Include="Handlers\BankHandler.cs" />
|
|
||||||
<Compile Include="Handlers\BattleFieldHandler.cs" />
|
|
||||||
<Compile Include="Handlers\BattleGroundHandler.cs" />
|
|
||||||
<Compile Include="Handlers\BattlePetHandler.cs" />
|
|
||||||
<Compile Include="Handlers\CalendarHandler.cs" />
|
|
||||||
<Compile Include="Handlers\ChannelHandler.cs" />
|
|
||||||
<Compile Include="Handlers\CharacterHandler.cs" />
|
|
||||||
<Compile Include="Handlers\ChatHandler.cs" />
|
|
||||||
<Compile Include="Handlers\CombatHandler.cs" />
|
|
||||||
<Compile Include="Handlers\DuelHandler.cs" />
|
|
||||||
<Compile Include="Handlers\GarrisonHandler.cs" />
|
|
||||||
<Compile Include="Handlers\GroupHandler.cs" />
|
|
||||||
<Compile Include="Handlers\GuildFinderHandler.cs" />
|
|
||||||
<Compile Include="Handlers\GuildHandler.cs" />
|
|
||||||
<Compile Include="Handlers\InspectHandler.cs" />
|
|
||||||
<Compile Include="Handlers\ItemHandler.cs" />
|
|
||||||
<Compile Include="Handlers\LFGHandler.cs" />
|
|
||||||
<Compile Include="Handlers\LogoutHandler.cs" />
|
|
||||||
<Compile Include="Handlers\LootHandler.cs" />
|
|
||||||
<Compile Include="Handlers\MailHandler.cs" />
|
|
||||||
<Compile Include="Handlers\MiscHandler.cs" />
|
|
||||||
<Compile Include="Handlers\MovementHandler.cs" />
|
|
||||||
<Compile Include="Handlers\NPCHandler.cs" />
|
|
||||||
<Compile Include="Handlers\PetHandler.cs" />
|
|
||||||
<Compile Include="Handlers\PetitionsHandler.cs" />
|
|
||||||
<Compile Include="Handlers\QueryHandler.cs" />
|
|
||||||
<Compile Include="Handlers\QuestHandler.cs" />
|
|
||||||
<Compile Include="Handlers\RAFHandler.cs" />
|
|
||||||
<Compile Include="Handlers\SkillHandler.cs" />
|
|
||||||
<Compile Include="Handlers\SocialHandler.cs" />
|
|
||||||
<Compile Include="Handlers\SpellHandler.cs" />
|
|
||||||
<Compile Include="Handlers\TaxiHandler.cs" />
|
|
||||||
<Compile Include="Handlers\TicketHandler.cs" />
|
|
||||||
<Compile Include="Handlers\TimeHandler.cs" />
|
|
||||||
<Compile Include="Handlers\TokenHandler.cs" />
|
|
||||||
<Compile Include="Handlers\ToyHandler.cs" />
|
|
||||||
<Compile Include="Handlers\TradeHandler.cs" />
|
|
||||||
<Compile Include="Handlers\VehicleHandler.cs" />
|
|
||||||
<Compile Include="Handlers\VoidStorageHandler.cs" />
|
|
||||||
<Compile Include="Loot\LootManager.cs" />
|
|
||||||
<Compile Include="Loot\LootStorage.cs" />
|
|
||||||
<Compile Include="Mails\Mail.cs" />
|
|
||||||
<Compile Include="Mails\MailDraft.cs" />
|
|
||||||
<Compile Include="AuctionHouse\AuctionManager.cs" />
|
|
||||||
<Compile Include="Calendar\CalendarManager.cs" />
|
|
||||||
<Compile Include="Text\CreatureTextManager.cs" />
|
|
||||||
<Compile Include="Conditions\DisableManager.cs" />
|
|
||||||
<Compile Include="Events\GameEventManager.cs" />
|
|
||||||
<Compile Include="Globals\Global.cs" />
|
|
||||||
<Compile Include="Globals\ObjectAccessor.cs" />
|
|
||||||
<Compile Include="Globals\ObjectManager.cs" />
|
|
||||||
<Compile Include="Pools\PoolManager.cs" />
|
|
||||||
<Compile Include="Reputation\ReputationManager.cs" />
|
|
||||||
<Compile Include="Warden\Warden.cs" />
|
|
||||||
<Compile Include="Warden\WardenKeyGeneration.cs" />
|
|
||||||
<Compile Include="Warden\WardenModuleWin.cs" />
|
|
||||||
<Compile Include="Warden\WardenWin.cs" />
|
|
||||||
<Compile Include="Warden\WargenCheckManager.cs" />
|
|
||||||
<Compile Include="Weather\WeatherManager.cs" />
|
|
||||||
<Compile Include="Server\WorldManager.cs" />
|
|
||||||
<Compile Include="Maps\Cell.cs" />
|
|
||||||
<Compile Include="Maps\MapUpdater.cs" />
|
|
||||||
<Compile Include="Maps\Grid.cs" />
|
|
||||||
<Compile Include="Maps\GridDefines.cs" />
|
|
||||||
<Compile Include="Maps\GridMap.cs" />
|
|
||||||
<Compile Include="Maps\GridNotifiers.cs" />
|
|
||||||
<Compile Include="Maps\Instances\InstanceSaveManager.cs" />
|
|
||||||
<Compile Include="Maps\Instances\InstanceScript.cs" />
|
|
||||||
<Compile Include="Maps\Instances\MapInstance.cs" />
|
|
||||||
<Compile Include="Maps\Map.cs" />
|
|
||||||
<Compile Include="Maps\MapManager.cs" />
|
|
||||||
<Compile Include="Maps\ObjectGridLoader.cs" />
|
|
||||||
<Compile Include="Maps\TransportManager.cs" />
|
|
||||||
<Compile Include="Maps\ZoneScript.cs" />
|
|
||||||
<Compile Include="Miscellaneous\Formulas.cs" />
|
|
||||||
<Compile Include="Entities\Creature\Gossip.cs" />
|
|
||||||
<Compile Include="Movement\Generators\ConfusedGenerator.cs" />
|
|
||||||
<Compile Include="Movement\Generators\FleeingGenerator.cs" />
|
|
||||||
<Compile Include="Movement\Generators\HomeMovement.cs" />
|
|
||||||
<Compile Include="Movement\Generators\IdleMovement.cs" />
|
|
||||||
<Compile Include="Movement\Generators\MovementGenerators.cs" />
|
|
||||||
<Compile Include="Movement\Generators\PointMovement.cs" />
|
|
||||||
<Compile Include="Movement\Generators\RandomMovement.cs" />
|
|
||||||
<Compile Include="Movement\Generators\TargetMovement.cs" />
|
|
||||||
<Compile Include="Movement\Generators\WaypointMovement.cs" />
|
|
||||||
<Compile Include="Movement\MotionMaster.cs" />
|
|
||||||
<Compile Include="Movement\MoveSpline.cs" />
|
|
||||||
<Compile Include="Movement\MoveSplineFlags.cs" />
|
|
||||||
<Compile Include="Movement\MoveSplineInit.cs" />
|
|
||||||
<Compile Include="Movement\MoveSplineInitArgs.cs" />
|
|
||||||
<Compile Include="Movement\Spline.cs" />
|
|
||||||
<Compile Include="Movement\WaypointManager.cs" />
|
|
||||||
<Compile Include="Network\Packets\BattlePetPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ToyPackets.cs" />
|
|
||||||
<Compile Include="Network\WorldSocketManager.cs" />
|
|
||||||
<Compile Include="OutdoorPVP\OutdoorPvP.cs" />
|
|
||||||
<Compile Include="OutdoorPVP\OutdoorPvPManager.cs" />
|
|
||||||
<Compile Include="OutdoorPVP\Zones\HellfirePeninsulaPvP.cs" />
|
|
||||||
<Compile Include="Network\Packets\AchievementPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\AuctionHousePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\BankPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\BattleGroundPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\CalendarPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ChannelPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\CharacterPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ChatPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ClientConfigPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\CombatLogPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\CombatPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\DuelPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\EquipmentPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\GameObjectPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\GarrisonPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\PartyPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\GuildPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\InspectPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\InstancePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ItemPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\LFGPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\LootPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\MailPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\MovementPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\NPCPackets.cs" />
|
|
||||||
<Compile Include="Network\PacketUtilities.cs" />
|
|
||||||
<Compile Include="Network\Packets\PetitionPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\QueryPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\QuestPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ReferAFriendPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ReputationPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\ScenePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\SocialPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\SpellPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\SystemPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TalentPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TicketPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TokenPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TotemPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\TradePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\UpdatePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\VehiclePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\VoidStoragePackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\WhoPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\WorldStatePackets.cs" />
|
|
||||||
<Compile Include="Quest\Quest.cs" />
|
|
||||||
<Compile Include="Scripting\CoreScripts.cs" />
|
|
||||||
<Compile Include="Scripting\ScriptManager.cs" />
|
|
||||||
<Compile Include="Scripting\SpellScript.cs" />
|
|
||||||
<Compile Include="Server\WorldConfig.cs" />
|
|
||||||
<Compile Include="Server\WorldSession.cs" />
|
|
||||||
<Compile Include="Network\Packet.cs" />
|
|
||||||
<Compile Include="Network\PacketManager.cs" />
|
|
||||||
<Compile Include="Network\WorldSocket.cs" />
|
|
||||||
<Compile Include="Network\Packets\AuthenticationPackets.cs" />
|
|
||||||
<Compile Include="Network\Packets\MiscPackets.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<Compile Include="Spells\Auras\Aura.cs" />
|
|
||||||
<Compile Include="Spells\Auras\AuraEffect.cs" />
|
|
||||||
<Compile Include="Spells\Skills\SkillDiscovery.cs" />
|
|
||||||
<Compile Include="Spells\Skills\SkillExtraItems.cs" />
|
|
||||||
<Compile Include="Spells\Spell.cs" />
|
|
||||||
<Compile Include="Spells\SpellCastTargets.cs" />
|
|
||||||
<Compile Include="Spells\SpellEffects.cs" />
|
|
||||||
<Compile Include="Spells\SpellHistory.cs" />
|
|
||||||
<Compile Include="Spells\SpellInfo.cs" />
|
|
||||||
<Compile Include="Spells\SpellManager.cs" />
|
|
||||||
<Compile Include="SupportSystem\SupportTickets.cs" />
|
|
||||||
<Compile Include="SupportSystem\SupportManager.cs" />
|
|
||||||
<Compile Include="Tools\CharacterDatabaseCleaner.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Framework\Framework.csproj">
|
|
||||||
<Project>{82d442a9-18c0-4c59-8ec6-0dfe3e34d334}</Project>
|
|
||||||
<Name>Framework</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup />
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<PostBuildEvent>
|
|
||||||
</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>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Game")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Game")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("631fea1e-2b00-436a-b20b-ac5c9921ef2e")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB |
Binary file not shown.
@@ -1,36 +0,0 @@
|
|||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Scripts")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Scripts")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("92f1ec3f-c8fc-4423-91ee-00ec1b5c5272")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{9E28B9C1-E473-4DAE-813F-3243CE318736}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>Scripts</RootNamespace>
|
|
||||||
<AssemblyName>Scripts</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
|
||||||
<OutputPath>..\Build\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>..\Build\x64\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
|
||||||
<OutputPath>..\Build\x64\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="EasternKingdoms\Deadmines\InstanceDeadmines.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\TheStockade\BossHogger.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\TheStockade\InstanceTheStockade.cs" />
|
|
||||||
<Compile Include="Events\HallowsEnd.cs" />
|
|
||||||
<Compile Include="Kalimdor\ZoneAshenvale.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\AzjolNerub\BossAnubarak.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\AzjolNerub\BossKrikthirTheGatewatcher.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\AzjolNerub\BossNadronox.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\AzjolNerub\InstanceAzjolNerub.cs" />
|
|
||||||
<Compile Include="Northrend\DraktharonKeep\BossKingDred.cs" />
|
|
||||||
<Compile Include="Northrend\DraktharonKeep\BossNovos.cs" />
|
|
||||||
<Compile Include="Northrend\DraktharonKeep\BossTharonJa.cs" />
|
|
||||||
<Compile Include="Northrend\DraktharonKeep\BossTrollgore.cs" />
|
|
||||||
<Compile Include="Northrend\DraktharonKeep\InstanceDrakTharonKeep.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\ForgeOfSouls\BossBronjahm.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\ForgeOfSouls\BossDevourerOfSouls.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\ForgeOfSouls\InstanceForgeOfSouls.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\PitOfSaron\BossForgemasterGarfrost.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\PitOfSaron\BossKrickAndIck.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\PitOfSaron\InstancePitOfSaron.cs" />
|
|
||||||
<Compile Include="Northrend\FrozenHalls\PitOfSaron\PitOfSaron.cs" />
|
|
||||||
<Compile Include="Northrend\Gundrak\BossDrakkariColossus.cs" />
|
|
||||||
<Compile Include="Northrend\Gundrak\BossEck.cs" />
|
|
||||||
<Compile Include="Northrend\Gundrak\InstanceGundrak.cs" />
|
|
||||||
<Compile Include="Northrend\Naxxramas\BossAnubrekhan.cs" />
|
|
||||||
<Compile Include="Smart\SmartAI.cs" />
|
|
||||||
<Compile Include="Spells\DemonHunter.cs" />
|
|
||||||
<Compile Include="Spells\Warlock.cs" />
|
|
||||||
<Compile Include="World\BossEmeraldDragons.cs" />
|
|
||||||
<Compile Include="World\DuelReset.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\Karazhan\Curator.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\Karazhan\InstanceKarazhan.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\Karazhan\AttumenMidnight.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\Karazhan\Moroes.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\Karazhan\OperaEvent.cs" />
|
|
||||||
<Compile Include="EasternKingdoms\ScarletEnclave\Chapter1.cs" />
|
|
||||||
<Compile Include="Kalimdor\ZoneDurotar.cs" />
|
|
||||||
<Compile Include="Kalimdor\RagefireChasm\InstanceRageFireChasm.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\Ahnkahet\BossAmanitar.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\Ahnkahet\BossElderNadox.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\Ahnkahet\BossHeraldVolazj.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\Ahnkahet\BossJedogaShadowseeker.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\Ahnkahet\BossPrinceTaldaram.cs" />
|
|
||||||
<Compile Include="Northrend\AzjolNerub\Ahnkahet\InstanceAhnahet.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheChampion\GrandChampions.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheChampion\InstanceTrialOfTheChampion.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheChampion\TrialOfTheChampion.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\EyeOfEternity\BossMalygos.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\EyeOfEternity\EyeOfEternity.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Nexus\BossAnomalus.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Nexus\BossKeristrasza.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Nexus\BossMagusTelestra.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Nexus\BossNexusCommanders.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Nexus\BossOrmorok.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Nexus\InstanceNexus.cs" />
|
|
||||||
<Compile Include="Northrend\Nexus\Oculus\InstanceOculus.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\Mimiron.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\Razorscale.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\Xt002.cs" />
|
|
||||||
<Compile Include="Spells\Holiday.cs" />
|
|
||||||
<Compile Include="Spells\Items.cs" />
|
|
||||||
<Compile Include="Spells\Monk.cs" />
|
|
||||||
<Compile Include="World\Achievements.cs" />
|
|
||||||
<Compile Include="World\AreaTrigger.cs" />
|
|
||||||
<Compile Include="World\GameObjects.cs" />
|
|
||||||
<Compile Include="World\Guards.cs" />
|
|
||||||
<Compile Include="World\ItemScripts.cs" />
|
|
||||||
<Compile Include="World\MobGenericCreature.cs" />
|
|
||||||
<Compile Include="World\NpcProfessions.cs" />
|
|
||||||
<Compile Include="World\NpcSpecial.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheCrusader\LordJaraxxus.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheCrusader\NorthrendBeasts.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheCrusader\TrialOfTheCrusader.cs" />
|
|
||||||
<Compile Include="Northrend\CrusadersColiseum\TrialOfTheCrusader\TrialOfTheCrusaderConst.cs" />
|
|
||||||
<Compile Include="Northrend\WinterGrasp.cs" />
|
|
||||||
<Compile Include="Pets\Shaman.cs" />
|
|
||||||
<Compile Include="Pets\Priest.cs" />
|
|
||||||
<Compile Include="Pets\Mage.cs" />
|
|
||||||
<Compile Include="Pets\Hunter.cs" />
|
|
||||||
<Compile Include="Pets\DeathKinght.cs" />
|
|
||||||
<Compile Include="Pets\Generic.cs" />
|
|
||||||
<Compile Include="Northrend\Dalaran.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\GunshipBattle.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\IcecrownCitadel.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\IcecrownCitadelConst.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\IcecrownCitadelTeleport.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\InstanceIcecrownCitadel.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\LadyDeathwhisper.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\LordMarrowgar.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\Sindragosa.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\TheLichKing.cs" />
|
|
||||||
<Compile Include="Northrend\IcecrownCitadel\ValithriaDreamwalker.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\AlgalonTheObserver.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\FlameLeviathan.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\UlduarConst.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\UlduarInstance.cs" />
|
|
||||||
<Compile Include="Northrend\Ulduar\YoggSaron.cs" />
|
|
||||||
<Compile Include="Outlands\HellfirePeninsula.cs" />
|
|
||||||
<Compile Include="Outlands\Zangarmarsh.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<Compile Include="Spells\DeathKnight.cs" />
|
|
||||||
<Compile Include="Spells\Druid.cs" />
|
|
||||||
<Compile Include="Spells\Generic.cs" />
|
|
||||||
<Compile Include="Spells\Hunter.cs" />
|
|
||||||
<Compile Include="Spells\Mage.cs" />
|
|
||||||
<Compile Include="Spells\Paladin.cs" />
|
|
||||||
<Compile Include="Spells\Priest.cs" />
|
|
||||||
<Compile Include="Spells\Quest.cs" />
|
|
||||||
<Compile Include="Spells\Rogue.cs" />
|
|
||||||
<Compile Include="Spells\Shaman.cs" />
|
|
||||||
<Compile Include="Spells\Warrior.cs" />
|
|
||||||
<Compile Include="Northrend\VioletHold\VioletHold.cs" />
|
|
||||||
<Compile Include="World\SceneScripts.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Framework\Framework.csproj">
|
|
||||||
<Project>{82d442a9-18c0-4c59-8ec6-0dfe3e34d334}</Project>
|
|
||||||
<Name>Framework</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
<ProjectReference Include="..\Game\Game.csproj">
|
|
||||||
<Project>{83ef8d5c-afa1-4546-bcdd-6422d55b1515}</Project>
|
|
||||||
<Name>Game</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Custom\" />
|
|
||||||
<Folder Include="Northrend\FrozenHalls\HallsOfReflection\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<PropertyGroup>
|
|
||||||
<PostBuildEvent>
|
|
||||||
</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,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="..\..\default.props" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp2.0</TargetFramework>
|
||||||
|
<StartupObject>BNetServer.Server</StartupObject>
|
||||||
|
<ApplicationIcon>Red.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Framework\Framework.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="BNetServer.conf.dist">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Update="BNetServer.pfx">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -15,15 +15,10 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using BNetServer.Networking;
|
|
||||||
using Framework.Configuration;
|
using Framework.Configuration;
|
||||||
using Framework.Rest;
|
using Framework.Rest;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace BNetServer
|
namespace BNetServer
|
||||||
{
|
{
|
||||||
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
@@ -19,7 +19,6 @@ using BNetServer.Networking;
|
|||||||
using Framework.Configuration;
|
using Framework.Configuration;
|
||||||
using Framework.Database;
|
using Framework.Database;
|
||||||
using Framework.Networking;
|
using Framework.Networking;
|
||||||
using Framework.Runtime;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
|
||||||
@@ -29,14 +28,17 @@ namespace BNetServer
|
|||||||
{
|
{
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
ApplicationSignal.SetConsoleCtrlHandler(AbortHandler, true);
|
Console.CancelKeyPress += (o, e) =>
|
||||||
ApplicationSignal.RemoveConsoleQuickEditMode();
|
{
|
||||||
|
Global.RealmMgr.Close();
|
||||||
|
|
||||||
|
Log.outInfo(LogFilter.Server, "Halting process...");
|
||||||
|
Environment.Exit(-1);
|
||||||
|
};
|
||||||
|
|
||||||
if (!ConfigMgr.Load(System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".conf"))
|
if (!ConfigMgr.Load(System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".conf"))
|
||||||
ExitNow();
|
ExitNow();
|
||||||
|
|
||||||
testing();
|
|
||||||
|
|
||||||
// Initialize the database connection
|
// Initialize the database connection
|
||||||
if (!StartDB())
|
if (!StartDB())
|
||||||
ExitNow();
|
ExitNow();
|
||||||
@@ -108,21 +110,6 @@ namespace BNetServer
|
|||||||
DB.Login.Execute(DB.Login.GetPreparedStatement(LoginStatements.DEL_BNET_EXPIRED_ACCOUNT_BANNED));
|
DB.Login.Execute(DB.Login.GetPreparedStatement(LoginStatements.DEL_BNET_EXPIRED_ACCOUNT_BANNED));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool AbortHandler(CtrlType sig)
|
|
||||||
{
|
|
||||||
Global.RealmMgr.Close();
|
|
||||||
|
|
||||||
Log.outInfo(LogFilter.Server, "Halting process...");
|
|
||||||
Environment.Exit(-1);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void testing()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static Timer _banExpiryCheckTimer;
|
static Timer _banExpiryCheckTimer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user