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:
Fabian
2017-10-26 17:23:44 +02:00
parent 227702e19c
commit a3dc7b3f48
844 changed files with 26064 additions and 1824 deletions
-171
View File
@@ -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>
-36
View File
@@ -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
View File
@@ -1,115 +1,119 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.12
VisualStudioVersion = 15.0.26730.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorldServer", "WorldServer\WorldServer.csproj", "{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}"
ProjectSection(ProjectDependencies) = postProject
{9E28B9C1-E473-4DAE-813F-3243CE318736} = {9E28B9C1-E473-4DAE-813F-3243CE318736}
EndProjectSection
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BNetServer", "Source\BNetServer\BNetServer.csproj", "{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}"
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
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
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
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
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
DebugMono|x64 = DebugMono|x64
DebugMono|x86 = DebugMono|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
ReleaseMono|x64 = ReleaseMono|x64
ReleaseMono|x86 = ReleaseMono|x86
Debug|linux-x64 = Debug|linux-x64
Debug|mac-x64 = Debug|mac-x64
Debug|win-x64 = Debug|win-x64
Release|linux-x64 = Release|linux-x64
Release|mac-x64 = Release|mac-x64
Release|win-x64 = Release|win-x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x64.ActiveCfg = Debug|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x64.Build.0 = Debug|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x86.ActiveCfg = Debug|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Debug|x86.Build.0 = Debug|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x64.ActiveCfg = Debug|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x64.Build.0 = Debug|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x86.ActiveCfg = Debug|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.DebugMono|x86.Build.0 = Debug|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x64.ActiveCfg = Release|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x64.Build.0 = Release|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x86.ActiveCfg = Release|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.Release|x86.Build.0 = Release|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x64.ActiveCfg = Release|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x64.Build.0 = Release|x64
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x86.ActiveCfg = Release|x86
{D157534F-86F1-4E8E-80B0-ECAD321ECAA6}.ReleaseMono|x86.Build.0 = Release|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x64.ActiveCfg = Debug|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x64.Build.0 = Debug|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x86.ActiveCfg = Debug|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Debug|x86.Build.0 = Debug|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x64.ActiveCfg = Debug|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x64.Build.0 = Debug|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x86.ActiveCfg = Debug|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.DebugMono|x86.Build.0 = Debug|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x64.ActiveCfg = Release|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x64.Build.0 = Release|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x86.ActiveCfg = Release|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.Release|x86.Build.0 = Release|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x64.ActiveCfg = Release|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x64.Build.0 = Release|x64
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x86.ActiveCfg = Release|x86
{668E1664-FB63-47DA-9EA1-93B59851BF1E}.ReleaseMono|x86.Build.0 = Release|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x64.ActiveCfg = Debug|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x64.Build.0 = Debug|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x86.ActiveCfg = Debug|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Debug|x86.Build.0 = Debug|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x64.ActiveCfg = Debug|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x64.Build.0 = Debug|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x86.ActiveCfg = Debug|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.DebugMono|x86.Build.0 = Debug|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x64.ActiveCfg = Release|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x64.Build.0 = Release|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x86.ActiveCfg = Release|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.Release|x86.Build.0 = Release|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x64.ActiveCfg = Release|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x64.Build.0 = Release|x64
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x86.ActiveCfg = Release|x86
{83EF8D5C-AFA1-4546-BCDD-6422D55B1515}.ReleaseMono|x86.Build.0 = Release|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x64.ActiveCfg = Debug|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x64.Build.0 = Debug|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x86.ActiveCfg = Debug|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Debug|x86.Build.0 = Debug|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x64.ActiveCfg = Debug|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x64.Build.0 = Debug|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x86.ActiveCfg = Debug|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.DebugMono|x86.Build.0 = Debug|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x64.ActiveCfg = Release|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x64.Build.0 = Release|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x86.ActiveCfg = Release|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.Release|x86.Build.0 = Release|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x64.ActiveCfg = Release|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x64.Build.0 = Release|x64
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x86.ActiveCfg = Release|x86
{9E28B9C1-E473-4DAE-813F-3243CE318736}.ReleaseMono|x86.Build.0 = Release|x86
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x64.ActiveCfg = Debug|x64
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x64.Build.0 = Debug|x64
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x86.ActiveCfg = Debug|x86
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.Debug|x86.Build.0 = Debug|x86
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x64.ActiveCfg = Debug|x64
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x64.Build.0 = Debug|x64
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x86.ActiveCfg = Debug|x86
{82D442A9-18C0-4C59-8EC6-0DFE3E34D334}.DebugMono|x86.Build.0 = Debug|x86
{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
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|linux-x64.ActiveCfg = Debug|linux-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|linux-x64.Build.0 = Debug|linux-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|mac-x64.ActiveCfg = Debug|mac-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|mac-x64.Build.0 = Debug|mac-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|win-x64.ActiveCfg = Debug|win-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Debug|win-x64.Build.0 = Debug|win-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|linux-x64.ActiveCfg = Release|linux-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|linux-x64.Build.0 = Release|linux-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|mac-x64.ActiveCfg = Release|mac-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|mac-x64.Build.0 = Release|mac-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|win-x64.ActiveCfg = Release|win-x64
{EEBFCEE3-CFAC-4D2E-927F-8E24E07A4218}.Release|win-x64.Build.0 = Release|win-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|linux-x64.ActiveCfg = Debug|linux-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|linux-x64.Build.0 = Debug|linux-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|mac-x64.ActiveCfg = Debug|mac-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|mac-x64.Build.0 = Debug|mac-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|win-x64.ActiveCfg = Debug|win-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Debug|win-x64.Build.0 = Debug|win-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|linux-x64.ActiveCfg = Release|linux-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|linux-x64.Build.0 = Release|linux-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|mac-x64.ActiveCfg = Release|mac-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|mac-x64.Build.0 = Release|mac-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|win-x64.ActiveCfg = Release|win-x64
{E5DF8709-16D8-4357-976A-DF54AD3DDD66}.Release|win-x64.Build.0 = Release|win-x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|linux-x64.ActiveCfg = Debug|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|linux-x64.Build.0 = Debug|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|mac-x64.ActiveCfg = Debug|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|mac-x64.Build.0 = Debug|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|win-x64.ActiveCfg = Debug|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Debug|win-x64.Build.0 = Debug|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|linux-x64.ActiveCfg = Release|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|linux-x64.Build.0 = Release|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|mac-x64.ActiveCfg = Release|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|mac-x64.Build.0 = Release|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|win-x64.ActiveCfg = Release|x64
{3B8C9AB8-2DC3-4655-BF67-AE2001D3B4F6}.Release|win-x64.Build.0 = Release|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|linux-x64.ActiveCfg = Debug|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|linux-x64.Build.0 = Debug|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|mac-x64.ActiveCfg = Debug|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|mac-x64.Build.0 = Debug|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|win-x64.ActiveCfg = Debug|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Debug|win-x64.Build.0 = Debug|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|linux-x64.ActiveCfg = Release|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|linux-x64.Build.0 = Release|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|mac-x64.ActiveCfg = Release|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|mac-x64.Build.0 = Release|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|win-x64.ActiveCfg = Release|x64
{1899C17C-1FA4-4807-B90E-0336C5748C1A}.Release|win-x64.Build.0 = Release|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|linux-x64.ActiveCfg = Debug|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|linux-x64.Build.0 = Debug|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|mac-x64.ActiveCfg = Debug|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|mac-x64.Build.0 = Debug|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|win-x64.ActiveCfg = Debug|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Debug|win-x64.Build.0 = Debug|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|linux-x64.ActiveCfg = Release|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|linux-x64.Build.0 = Release|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|mac-x64.ActiveCfg = Release|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|mac-x64.Build.0 = Release|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|win-x64.ActiveCfg = Release|x64
{2F7515AD-18E3-4ACA-A14B-1929F76299E7}.Release|win-x64.Build.0 = Release|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|linux-x64.ActiveCfg = Debug|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|linux-x64.Build.0 = Debug|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|mac-x64.ActiveCfg = Debug|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|mac-x64.Build.0 = Debug|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|win-x64.ActiveCfg = Debug|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Debug|win-x64.Build.0 = Debug|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|linux-x64.ActiveCfg = Release|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|linux-x64.Build.0 = Release|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|mac-x64.ActiveCfg = Release|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|mac-x64.Build.0 = Release|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|win-x64.ActiveCfg = Release|x64
{54EBBA35-DEFE-4967-8B87-4FBA47FDC33D}.Release|win-x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
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
+79
View File
@@ -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;
}
}
}
}
+401
View File
@@ -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&lt;T&gt;</c>
/// and <c>MapField&lt;TKey, TValue&gt;</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
+473
View File
@@ -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();
}
}
+87
View File
@@ -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
+166
View File
@@ -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(&amp;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 := &amp;pb.Foo{...}
/// any, err := ptypes.MarshalAny(foo)
/// ...
/// foo := &amp;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": &lt;string>,
/// "lastName": &lt;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&lt;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 &lt; 0 &amp;&amp; duration.nanos > 0) {
/// duration.seconds += 1;
/// duration.nanos -= 1000000000;
/// } else if (durations.seconds > 0 &amp;&amp; duration.nanos &lt; 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 &lt; 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(&amp;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(&amp;ft);
/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) &lt;&lt; 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;
}
}
+104
View File
@@ -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;
}
}
}
-284
View File
@@ -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>
-36
View File
@@ -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")]
-68
View File
@@ -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
}
}
-521
View File
@@ -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>
-36
View File
@@ -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.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.
-36
View File
@@ -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")]
-200
View File
@@ -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>
+23
View File
@@ -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/>.
*/
using BNetServer.Networking;
using Framework.Configuration;
using Framework.Rest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
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.Database;
using Framework.Networking;
using Framework.Runtime;
using System;
using System.Timers;
@@ -29,14 +28,17 @@ namespace BNetServer
{
static void Main()
{
ApplicationSignal.SetConsoleCtrlHandler(AbortHandler, true);
ApplicationSignal.RemoveConsoleQuickEditMode();
Console.CancelKeyPress += (o, e) =>
{
Global.RealmMgr.Close();
Log.outInfo(LogFilter.Server, "Halting process...");
Environment.Exit(-1);
};
if (!ConfigMgr.Load(System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".conf"))
ExitNow();
testing();
// Initialize the database connection
if (!StartDB())
ExitNow();
@@ -108,21 +110,6 @@ namespace BNetServer
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;
}
}

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