mirror of
https://e.coding.net/circlecloud/CTZLauncher.git
synced 2024-11-24 02:28:49 +00:00
首次提交项目文件...
Signed-off-by: j502647092 <jtb1@163.com>
This commit is contained in:
commit
6e0fa413d2
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
156
.gitignore
vendored
Normal file
156
.gitignore
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
|
||||||
|
[Dd]ebug/
|
||||||
|
[Rr]elease/
|
||||||
|
x64/
|
||||||
|
build/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
|
||||||
|
# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
|
||||||
|
!packages/*/build/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.log
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
*.ncrunch*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.Publish.xml
|
||||||
|
|
||||||
|
# NuGet Packages Directory
|
||||||
|
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
|
||||||
|
#packages/
|
||||||
|
|
||||||
|
# Windows Azure Build Output
|
||||||
|
csx
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Windows Store app package directory
|
||||||
|
AppPackages/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
sql/
|
||||||
|
*.Cache
|
||||||
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file to a newer
|
||||||
|
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
App_Data/*.mdf
|
||||||
|
App_Data/*.ldf
|
||||||
|
|
||||||
|
|
||||||
|
#LightSwitch generated files
|
||||||
|
GeneratedArtifacts/
|
||||||
|
_Pvt_Extensions/
|
||||||
|
ModelManifest.xml
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# Windows detritus
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Mac desktop service store files
|
||||||
|
.DS_Store
|
28
CTZLauncher.sln
Normal file
28
CTZLauncher.sln
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 2013
|
||||||
|
VisualStudioVersion = 12.0.21005.1
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KMCCC", "KMCCC.Shared\KMCCC.csproj", "{52E292BB-FC7A-46E6-A8E8-B71E46FAF54E}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CTZLauncher", "CTZLauncher\CTZLauncher.csproj", "{EC25362D-5BA7-4CB3-BDA2-C575B9318086}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{52E292BB-FC7A-46E6-A8E8-B71E46FAF54E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{52E292BB-FC7A-46E6-A8E8-B71E46FAF54E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{52E292BB-FC7A-46E6-A8E8-B71E46FAF54E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{52E292BB-FC7A-46E6-A8E8-B71E46FAF54E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EC25362D-5BA7-4CB3-BDA2-C575B9318086}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EC25362D-5BA7-4CB3-BDA2-C575B9318086}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EC25362D-5BA7-4CB3-BDA2-C575B9318086}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EC25362D-5BA7-4CB3-BDA2-C575B9318086}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
8
CTZLauncher/App.xaml
Normal file
8
CTZLauncher/App.xaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<Application x:Class="CTZLauncher.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
16
CTZLauncher/App.xaml.cs
Normal file
16
CTZLauncher/App.xaml.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace CTZLauncher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// App.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
119
CTZLauncher/CTZLauncher.csproj
Normal file
119
CTZLauncher/CTZLauncher.csproj
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
<?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>{EC25362D-5BA7-4CB3-BDA2-C575B9318086}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>CTZLauncher</RootNamespace>
|
||||||
|
<AssemblyName>CTZLauncher</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationIcon>ico.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<StartupObject />
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xaml" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
<Page Include="MainWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="HttpHelper.cs" />
|
||||||
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
<AppDesigner Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="ico.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\KMCCC.Shared\KMCCC.csproj">
|
||||||
|
<Project>{52e292bb-fc7a-46e6-a8e8-b71e46faf54e}</Project>
|
||||||
|
<Name>KMCCC</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="IZ.ico" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- 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>
|
364
CTZLauncher/HttpHelper.cs
Normal file
364
CTZLauncher/HttpHelper.cs
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Authentication;
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace CityCraft
|
||||||
|
{
|
||||||
|
public class HttpArgs
|
||||||
|
{
|
||||||
|
public enum HttpMethod
|
||||||
|
{
|
||||||
|
GET,
|
||||||
|
POST
|
||||||
|
}
|
||||||
|
public string Url { get; set; }
|
||||||
|
public string Host { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
public string Accept { get; set; }
|
||||||
|
public string Referer { get; set; }
|
||||||
|
public string Cookie { get; set; }
|
||||||
|
public string Data { get; set; }
|
||||||
|
public string UA { get; set; }
|
||||||
|
public HttpMethod Method { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HttpHelper
|
||||||
|
{
|
||||||
|
public static int State = 0;
|
||||||
|
public static string ErrMsg = string.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// 提交方法
|
||||||
|
/// </summary>
|
||||||
|
#region HttpWebRequest & HttpWebResponse
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="geturl">请求地址</param>
|
||||||
|
/// <param name="cookieser">Cookies存储器</param>
|
||||||
|
/// <returns>请求返回的Stream</returns>
|
||||||
|
public string Get(string url)
|
||||||
|
{
|
||||||
|
HttpArgs args = ParseURL(url);
|
||||||
|
args.Method = HttpArgs.HttpMethod.GET;
|
||||||
|
string strhtml = InternalSocketHttp(args);
|
||||||
|
return strhtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Post方法
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="posturl">请求地址</param>
|
||||||
|
/// <param name="bytes">Post数据</param>
|
||||||
|
/// <param name="cookieser">Cllkies存储器</param>
|
||||||
|
/// <returns>请求返回的流</returns>
|
||||||
|
public string Post(string url,
|
||||||
|
byte[] bytes,
|
||||||
|
CookieContainer cookies,
|
||||||
|
Encoding encoding)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据Url得到host
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strUrl">url字符串</param>
|
||||||
|
/// <returns>host字符串</returns>
|
||||||
|
private HttpArgs ParseURL(string strUrl)
|
||||||
|
{
|
||||||
|
HttpArgs args = new HttpArgs();
|
||||||
|
|
||||||
|
args.Host = "";
|
||||||
|
args.Port = 80;
|
||||||
|
args.Referer = "";
|
||||||
|
args.Cookie = "";
|
||||||
|
args.Url = "";
|
||||||
|
args.Accept = "text/html";//,application/xhtml+xml,application/xml,application/json;";
|
||||||
|
args.UA = "Mozilla/5.0+(Compatible;+Baiduspider/2.0;++http://www.baidu.com/search/spider.html)";
|
||||||
|
|
||||||
|
//http://www.alibaba.com/products/Egg_Laying_Block_Machine/1.html
|
||||||
|
int iIndex = strUrl.IndexOf(@"//");
|
||||||
|
if (iIndex <= 0)
|
||||||
|
return null;
|
||||||
|
//www.alibaba.com:80/products/Egg_Laying_Block_Machine/1.html
|
||||||
|
string nohttpurl = strUrl.Substring(iIndex + 2);
|
||||||
|
string address = nohttpurl;
|
||||||
|
iIndex = nohttpurl.IndexOf(@"/");
|
||||||
|
if (iIndex > 0)
|
||||||
|
{
|
||||||
|
//www.alibaba.com:80
|
||||||
|
address = nohttpurl.Substring(0, iIndex);
|
||||||
|
args.Url = nohttpurl.Substring(iIndex);
|
||||||
|
}
|
||||||
|
iIndex = nohttpurl.IndexOf(@":");
|
||||||
|
if (iIndex > 0)
|
||||||
|
{
|
||||||
|
string[] tempargs = address.Trim().Split(char.Parse(":"));
|
||||||
|
args.Host = tempargs[0];
|
||||||
|
args.Port = int.Parse(tempargs[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//www.alibaba.com:80
|
||||||
|
args.Host = address;
|
||||||
|
args.Port = 80;
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Socket
|
||||||
|
|
||||||
|
string InternalSocketHttp(HttpArgs args)
|
||||||
|
{
|
||||||
|
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
|
||||||
|
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);
|
||||||
|
socket.Connect(args.Host, args.Port);
|
||||||
|
if (socket.Connected)
|
||||||
|
{
|
||||||
|
byte[] buff = ParseHttpArgs(args);
|
||||||
|
if (socket.Send(buff) > 0)
|
||||||
|
{
|
||||||
|
List<byte> responseBytes = new List<byte>();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int iNumber = socket.Receive(buffer, buffer.Length, SocketFlags.None);
|
||||||
|
while (iNumber > 0)//使用了Connection: Close 所以判断长度为0 时停止接受
|
||||||
|
{
|
||||||
|
responseBytes.AddRange(new List<byte>(buffer));//添加数据到List
|
||||||
|
iNumber = socket.Receive(buffer, buffer.Length, SocketFlags.None);//继续接收数据
|
||||||
|
}
|
||||||
|
return ParseResponse(responseBytes.ToArray()/*转换List为数组*/, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
ErrMsg = e.Message;
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ParseResponse(byte[] responseBytes, HttpArgs args)
|
||||||
|
{
|
||||||
|
string responseStr = Encoding.UTF8.GetString(responseBytes);
|
||||||
|
string[] splitStr = responseStr.Split(new char[4] { '\r', '\n', '\r', '\n' }, 2);
|
||||||
|
if (splitStr.Length == 2)
|
||||||
|
{
|
||||||
|
string responseHeader = splitStr[0];
|
||||||
|
string responseBody = splitStr[1];
|
||||||
|
|
||||||
|
if (responseHeader.StartsWith("HTTP/1.1 400"))
|
||||||
|
{
|
||||||
|
State = 400;
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
else if (responseHeader.StartsWith("HTTP/1.1 404"))
|
||||||
|
{
|
||||||
|
State = 404;
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
else if (responseHeader.StartsWith("HTTP/1.1 302") || responseHeader.StartsWith("HTTP/1.1 301"))
|
||||||
|
{
|
||||||
|
State = 302;
|
||||||
|
int start = responseHeader.ToUpper().IndexOf("LOCATION");
|
||||||
|
if (start > 0)
|
||||||
|
{
|
||||||
|
string temp = responseHeader.Substring(start, responseHeader.Length - start);
|
||||||
|
string[] sArry = Regex.Split(temp, "\r\n");
|
||||||
|
args.Url = sArry[0].Remove(0, 10);
|
||||||
|
if (args.Url == "")
|
||||||
|
return string.Empty;
|
||||||
|
return InternalSocketHttp(args); //注意:302协议需要重定向
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (responseHeader.StartsWith("HTTP/1.1 200")) //读取内容
|
||||||
|
{
|
||||||
|
State = 200;
|
||||||
|
DecompressWebPage(ref responseBytes, responseHeader);
|
||||||
|
//转码
|
||||||
|
responseBody = DecodeWebStringByHttpHeader(responseBytes, responseHeader);
|
||||||
|
responseBody = DecodeWebStringByHtmlPageInfo(responseBytes, responseBody);
|
||||||
|
}
|
||||||
|
int splitindex = responseBody.IndexOf("\r\n\r\n");
|
||||||
|
if (splitindex > 0)
|
||||||
|
responseBody = responseBody.Substring(splitindex + 4);
|
||||||
|
else
|
||||||
|
responseBody = string.Empty;
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Helper
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解压网页
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="responseBytes">网页字节数组含http头</param>
|
||||||
|
/// <param name="iTotalCount">数组长度</param>
|
||||||
|
/// <param name="strHeader">Http头字符串</param>
|
||||||
|
/// <param name="iStart">网页正文开始位置</param>
|
||||||
|
private void DecompressWebPage(ref byte[] responseBytes, string strHeader)
|
||||||
|
{
|
||||||
|
Regex regZip = new Regex(@"Content-Encoding:\s+gzip[^\n]*\r\n", RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
|
if (regZip.IsMatch(strHeader))
|
||||||
|
{
|
||||||
|
responseBytes = Decompress(responseBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解压gzip网页
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="szSource">压缩过的字符串字节数组</param>
|
||||||
|
/// <returns>解压后的字节数组</returns>
|
||||||
|
private byte[] Decompress(byte[] szSource)
|
||||||
|
{
|
||||||
|
MemoryStream msSource = new MemoryStream(szSource);
|
||||||
|
//DeflateStream 也可以这儿
|
||||||
|
GZipStream stream = new GZipStream(msSource, CompressionMode.Decompress);
|
||||||
|
byte[] szTotal = new byte[40 * 1024];
|
||||||
|
long lTotal = 0;
|
||||||
|
byte[] buffer = new byte[8];
|
||||||
|
int iCount = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
iCount = stream.Read(buffer, 0, 8);
|
||||||
|
if (szTotal.Length <= lTotal + iCount) //放大数组
|
||||||
|
{
|
||||||
|
byte[] temp = new byte[szTotal.Length * 10];
|
||||||
|
szTotal.CopyTo(temp, 0);
|
||||||
|
szTotal = temp;
|
||||||
|
}
|
||||||
|
buffer.CopyTo(szTotal, lTotal);
|
||||||
|
lTotal += iCount;
|
||||||
|
} while (iCount != 0);
|
||||||
|
byte[] szDest = new byte[lTotal];
|
||||||
|
Array.Copy(szTotal, 0, szDest, 0, lTotal);
|
||||||
|
return szDest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据Http头标记里面的字符编码解析字符串
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="responseBytes">网页内容字节数组(除http头以外的内容)</param>
|
||||||
|
/// <param name="iTotalCount">网页内容字节数组长度</param>
|
||||||
|
/// <param name="strHeader">http头的字符串</param>
|
||||||
|
/// <returns>转好的字符串</returns>
|
||||||
|
private string DecodeWebStringByHttpHeader(byte[] responseBytes, string strHeader)
|
||||||
|
{
|
||||||
|
string strResponse = "";
|
||||||
|
if (strHeader.Contains("charset=GBK") || strHeader.Contains("charset=gb2312"))
|
||||||
|
{
|
||||||
|
strResponse = Encoding.GetEncoding("GBK").GetString(responseBytes);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strResponse = Encoding.UTF8.GetString(responseBytes);
|
||||||
|
return strResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据网页meta标记里面的字符编码解析字符串
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="responseBytes">网页内容字节数组(除http头以外的内容)</param>
|
||||||
|
/// <param name="iTotalCount">网页内容字节数组长度</param>
|
||||||
|
/// <param name="strResponse">网页内容字符串, 可能已经根据其它转码要求转换过的字符串</param>
|
||||||
|
/// <returns>转好的字符串</returns>
|
||||||
|
private string DecodeWebStringByHtmlPageInfo(byte[] responseBytes, string strResponse)
|
||||||
|
{
|
||||||
|
Regex regGB2312 = new Regex(@"<meta[^>]+Content-Type[^>]+gb2312[^>]*>", RegexOptions.IgnoreCase);
|
||||||
|
Regex regGBK = new Regex(@"<meta[^>]+Content-Type[^>]+gbk[^>]*>", RegexOptions.IgnoreCase);
|
||||||
|
Regex regBig5 = new Regex(@"<meta[^>]+Content-Type[^>]+Big5[^>]*>", RegexOptions.IgnoreCase);
|
||||||
|
if (regGB2312.IsMatch(strResponse) || regGBK.IsMatch(strResponse))
|
||||||
|
strResponse = Encoding.GetEncoding("GBK").GetString(responseBytes);
|
||||||
|
if (regBig5.IsMatch(strResponse))
|
||||||
|
strResponse = Encoding.GetEncoding("Big5").GetString(responseBytes);
|
||||||
|
return strResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] ParseHttpArgs(HttpArgs args)
|
||||||
|
{
|
||||||
|
StringBuilder bulider = new StringBuilder();
|
||||||
|
if (args.Method == HttpArgs.HttpMethod.POST)
|
||||||
|
{
|
||||||
|
bulider.AppendLine(string.Format("POST {0} HTTP/1.1", args.Url));
|
||||||
|
bulider.AppendLine("Content-Type: application/x-www-form-urlencoded");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulider.AppendLine(string.Format("GET {0} HTTP/1.1", args.Url));
|
||||||
|
}
|
||||||
|
|
||||||
|
bulider.AppendLine(string.Format("Host: {0}:{1}", args.Host, args.Port));
|
||||||
|
|
||||||
|
bulider.AppendLine("User-Agent: " + args.UA);
|
||||||
|
//"User-Agent: Mozilla/5.0+(Compatible;+Baiduspider/2.0;++http://www.baidu.com/search/spider.html)";Mozilla/5.0 (Windows NT 6.1; IE 9.0)
|
||||||
|
if (!string.IsNullOrEmpty(args.Referer))
|
||||||
|
bulider.AppendLine(string.Format("Referer: {0}", args.Referer));
|
||||||
|
|
||||||
|
//bulider.AppendLine("Connection: close");
|
||||||
|
|
||||||
|
bulider.AppendLine("Connection: Close");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(args.Accept))
|
||||||
|
bulider.AppendLine(string.Format("Accept: {0}", args.Accept));
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(args.Cookie))
|
||||||
|
bulider.AppendLine(string.Format("Cookie: {0}", args.Cookie));
|
||||||
|
|
||||||
|
if (args.Method == HttpArgs.HttpMethod.POST)
|
||||||
|
{
|
||||||
|
bulider.AppendLine(string.Format("Content-Length: {0}\r\n", Encoding.Default.GetBytes(args.Data).Length));
|
||||||
|
bulider.Append(args.Data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bulider.Append("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
string header = bulider.ToString();
|
||||||
|
return Encoding.Default.GetBytes(header);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MilliTimer
|
||||||
|
{
|
||||||
|
private static double times { get; set; }
|
||||||
|
public static void start()
|
||||||
|
{
|
||||||
|
times = getTotalMilliseconds();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getTimes()
|
||||||
|
{
|
||||||
|
return getTotalMilliseconds() - times;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static double getTotalMilliseconds()
|
||||||
|
{
|
||||||
|
return DateTime.Now.Subtract(DateTime.Parse("1970-1-1")).TotalMilliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
CTZLauncher/IZ.ico
Normal file
BIN
CTZLauncher/IZ.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
99
CTZLauncher/MainWindow.xaml
Normal file
99
CTZLauncher/MainWindow.xaml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<Window x:Class="CTZLauncher.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
ResizeMode = "NoResize"
|
||||||
|
MouseMove="Window_MouseMove"
|
||||||
|
Title="MainWindow" Height="768" Width="1024" Background="#FF3A3A3A" AllowsTransparency="True" WindowStyle="None" Visibility="Visible" HorizontalContentAlignment="Center" HorizontalAlignment="Center" Icon="E:\JTB\Project\CTZLauncher\CTZLauncher\ico.ico" VerticalAlignment="Center" VerticalContentAlignment="Center" WindowStartupLocation="CenterScreen">
|
||||||
|
<Window.Resources>
|
||||||
|
<ControlTemplate x:Key="CornerButton" TargetType="{x:Type Button}">
|
||||||
|
<Border BorderBrush="#FFA1A1A1" BorderThickness="1" CornerRadius="10" Background="{TemplateBinding Background}">
|
||||||
|
<ContentPresenter Content="{TemplateBinding ContentControl.Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
<ControlTemplate x:Key="CornerTextBox" TargetType="{x:Type TextBox}">
|
||||||
|
<Border BorderBrush="#FFA1A1A1" BorderThickness="3" CornerRadius="10" Background="#FFA1A1A1">
|
||||||
|
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center" Background="#FFA1A1A1"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid Background="#FF3A3A3A" Height="768" Width="1024" VerticalAlignment="Top">
|
||||||
|
<Grid Margin="20,0" Background="#FF3A3A3A" Height="60" VerticalAlignment="Top">
|
||||||
|
<Label x:Name="barl1" Content="主导航" HorizontalAlignment="Left" Margin="15,15,0,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barl2" Content="主导航" HorizontalAlignment="Left" Margin="120,15,0,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barl3" Content="主导航" HorizontalAlignment="Left" Margin="220,15,0,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barl4" Content="主导航" HorizontalAlignment="Left" Margin="325,15,0,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barr4" Content="主导航" HorizontalAlignment="Right" Margin="0,15,15,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barr3" Content="主导航" HorizontalAlignment="Right" Margin="0,15,120,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barr2" Content="主导航" HorizontalAlignment="Right" Margin="0,15,220,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Label x:Name="barr1" Content="主导航" HorizontalAlignment="Right" Margin="0,15,325,0" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="White" MouseDown="barclick_MouseDown"/>
|
||||||
|
<Image HorizontalAlignment="Left" Height="50" Margin="430,5,0,0" VerticalAlignment="Top" Width="50" Source="IZ.ico" MouseLeftButtonDown="Image_MouseLeftButtonDown" RenderTransformOrigin="0.56,0.24"/>
|
||||||
|
<Label Content="IZ" HorizontalAlignment="Left" Height="50" Margin="480,7,0,0" VerticalAlignment="Top" Width="74" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="Sui Generis" Foreground="White" FontSize="35" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Margin="20,60,20,20" Background="White">
|
||||||
|
<Grid Margin="0,0,0,300">
|
||||||
|
<Grid Margin="30,20,0,20" HorizontalAlignment="Left" Width="550" >
|
||||||
|
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="5"/>
|
||||||
|
<Image Margin="0,0" Source="ico.ico" Height="200"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid Margin="0,20,30,20" HorizontalAlignment="Right" Width="350">
|
||||||
|
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="5"/>
|
||||||
|
<Grid>
|
||||||
|
<Grid Margin="30,20,30,0" Height="200" VerticalAlignment="Top">
|
||||||
|
<Label Content="————— XX XX 帐 号 —————" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,0" HorizontalContentAlignment="Center" FontFamily="微软雅黑" FontSize="15"/>
|
||||||
|
<TextBox Name="username" Template="{StaticResource CornerTextBox}" Height="34" Width="220" TextWrapping="Wrap" Text="" VerticalAlignment="Center" HorizontalAlignment="Center" HorizontalContentAlignment="Center" FontFamily="微软雅黑" Foreground="White" FontSize="20" Margin="33,40,33,126" />
|
||||||
|
<Label Content="————— XX XX 密 码 —————" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,80" HorizontalContentAlignment="Center" FontFamily="微软雅黑" FontSize="15"/>
|
||||||
|
<TextBox Name="password" Template="{StaticResource CornerTextBox}" Height="34" Width="220" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center" HorizontalContentAlignment="Center" FontFamily="微软雅黑" Foreground="White" FontSize="20" Margin="33,110,33,56" />
|
||||||
|
<Button Margin="225,110,35,56" Template="{StaticResource CornerButton}" Height="30" Width="30" HorizontalAlignment="Center" Content="?" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Margin="30,20,30,30" Height="100" VerticalAlignment="Bottom">
|
||||||
|
<Button Margin="10,35,165,35" Template="{StaticResource CornerButton}" Width="111" HorizontalAlignment="Center" Content="登录" Click="Login_Click" />
|
||||||
|
<Button Margin="165,35,10,35" Template="{StaticResource CornerButton}" Width="111" HorizontalAlignment="Center" Content="注册" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Grid Margin="0,400,0,0">
|
||||||
|
<Grid Margin="30,20,0,20" HorizontalAlignment="Left" Width="550" >
|
||||||
|
<TabControl Background="White" BorderThickness="0">
|
||||||
|
<TabItem Header="动态" Background="White" BorderThickness="0" Margin="0" Height="30" FontSize="20" >
|
||||||
|
<ListBox BorderThickness="0">
|
||||||
|
<ListBoxItem Content="动态" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="动态" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="动态" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="动态" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="动态" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="动态" Height="30" FontSize="25"/>
|
||||||
|
</ListBox>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem Header="新闻" Background="White" BorderThickness="0" Margin="0" Height="30" FontSize="20" >
|
||||||
|
<ListBox BorderThickness="0">
|
||||||
|
<ListBoxItem Content="新闻" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="新闻" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="新闻" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="新闻" Height="30" FontSize="25"/>
|
||||||
|
<ListBoxItem Content="新闻" Height="30" FontSize="25"/>
|
||||||
|
|
||||||
|
</ListBox>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem Header="公告" Background="White" BorderThickness="0" Margin="0" Height="30" FontSize="20" />
|
||||||
|
<TabItem Header="活动" Background="White" BorderThickness="0" Margin="0" Height="30" FontSize="20" />
|
||||||
|
</TabControl>
|
||||||
|
</Grid>
|
||||||
|
<Grid Margin="0,20,30,20" HorizontalAlignment="Right" Width="350" Grid.ShowGridLines="True">
|
||||||
|
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="5"/>
|
||||||
|
<Button Name="StartGame" Content="启动游戏" Template="{StaticResource CornerButton}" Background="Gray" HorizontalAlignment="Right" Margin="0,0,30,30" Width="120" Height="70" VerticalAlignment="Bottom" FontSize="20" MouseDown="StartGame_MouseDown" Click="StartGame_Click"/>
|
||||||
|
<ComboBox Name="javacombo" Height="30" Width="200" Margin="120,65,30,0" VerticalAlignment="Top"/>
|
||||||
|
<Label Margin="0,65,240,0" Content="JAVA版本" HorizontalAlignment="Right" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="Black"/>
|
||||||
|
<ComboBox Name="gamecombo" Height="30" Width="200" Margin="120,100,30,0" VerticalAlignment="Top"/>
|
||||||
|
<Label Margin="0,100,240,0" Content="游戏版本" HorizontalAlignment="Right" VerticalAlignment="Top" Width="100" Height="30" FontSize="20" Background="{x:Null}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="STXingkai" Foreground="Black"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Window>
|
131
CTZLauncher/MainWindow.xaml.cs
Normal file
131
CTZLauncher/MainWindow.xaml.cs
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using KMCCC.Authentication;
|
||||||
|
using KMCCC.Launcher;
|
||||||
|
using KMCCC.Tools;
|
||||||
|
using KMCCC.Modules;
|
||||||
|
using KMCCC.Modules.JVersion;
|
||||||
|
using CityCraft;
|
||||||
|
|
||||||
|
namespace CTZLauncher
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// MainWindow.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
LauncherCore launcher = null;
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Window_Initialized(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
launcher = LauncherCore.Create(".minecraft");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Window_MouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void barclick_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
Label bar = (Label)sender;
|
||||||
|
MessageBox.Show(bar.Name);
|
||||||
|
switch (bar.Name.Substring(4))
|
||||||
|
{
|
||||||
|
case "l1":
|
||||||
|
break;
|
||||||
|
case "l2":
|
||||||
|
break;
|
||||||
|
case "l3":
|
||||||
|
break;
|
||||||
|
case "l4":
|
||||||
|
break;
|
||||||
|
case "r1":
|
||||||
|
break;
|
||||||
|
case "r2":
|
||||||
|
break;
|
||||||
|
case "r3":
|
||||||
|
break;
|
||||||
|
case "r4":
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Button_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
IAuthenticator auth = new YggdrasilLogin("jtb1@163.com", "jtb325325", false);
|
||||||
|
AuthenticationInfo result = auth.Do();
|
||||||
|
MessageBox.Show(result.UUID.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Login_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
HttpHelper http = new HttpHelper();
|
||||||
|
String result = http.Get("http://127.0.0.1:2000/isregistered?username=" + username.Text);
|
||||||
|
Console.WriteLine("服务器返回结果" + result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
|
this.DragMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartGame_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartGame_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("StartGame");
|
||||||
|
|
||||||
|
foreach (var item in SystemTools.FindJava())
|
||||||
|
{
|
||||||
|
Console.WriteLine("addjava");
|
||||||
|
javacombo.Items.Add(item);
|
||||||
|
}
|
||||||
|
foreach (var item in launcher.GetVersions())
|
||||||
|
{
|
||||||
|
Console.WriteLine("addgame");
|
||||||
|
gamecombo.Items.Add(item.Id);
|
||||||
|
}
|
||||||
|
//LauncherCoreCreationOption option = new LauncherCoreCreationOption("E:\\JTB\\Project\\CTZLauncher\\CTZLauncher\\bin\\Debug\\.minecraft",SystemTools.FindJava().First());
|
||||||
|
//LauncherCore launcher = LauncherCore.Create(option);
|
||||||
|
//launcher.GameLog += launcher_GameLog;
|
||||||
|
//var result = launcher.Launch(new LaunchOptions
|
||||||
|
// {
|
||||||
|
// Version = option.VersionLocator.GetAllVersions().First(),
|
||||||
|
// Authenticator = new OfflineAuthenticator("Mr_jtb"), // offline
|
||||||
|
// //Authenticator = new YggdrasilLogin("*@*.*", "***", true), // online
|
||||||
|
// MaxMemory = 2048, // optional
|
||||||
|
// MinMemory = 2048, // optional
|
||||||
|
// Mode = LaunchMode.MCLauncher, // optional
|
||||||
|
// Size = new WindowSize { Height = 768, Width = 1280 } //optional
|
||||||
|
// }, (Action<MinecraftLaunchArguments>)(x => { })); // optional ( modify arguments before launching
|
||||||
|
//Console.WriteLine(result.ErrorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void launcher_GameLog(LaunchHandle arg1, string arg2)
|
||||||
|
{
|
||||||
|
Console.WriteLine(arg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
55
CTZLauncher/Properties/AssemblyInfo.cs
Normal file
55
CTZLauncher/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
// 有关程序集的常规信息通过以下
|
||||||
|
// 特性集控制。更改这些特性值可修改
|
||||||
|
// 与程序集关联的信息。
|
||||||
|
[assembly: AssemblyTitle("CTZLauncher")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Microsoft")]
|
||||||
|
[assembly: AssemblyProduct("CTZLauncher")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||||
|
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||||
|
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
//若要开始生成可本地化的应用程序,请在
|
||||||
|
//<PropertyGroup> 中的 .csproj 文件中
|
||||||
|
//设置 <UICulture>CultureYouAreCodingWith</UICulture>。 例如,如果您在源文件中
|
||||||
|
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
|
||||||
|
//对以下 NeutralResourceLanguage 特性的注释。 更新
|
||||||
|
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
|
||||||
|
|
||||||
|
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||||
|
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
|
||||||
|
//(在页面或应用程序资源词典中
|
||||||
|
// 未找到某个资源的情况下使用)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
|
||||||
|
//(在页面、应用程序或任何主题特定资源词典中
|
||||||
|
// 未找到某个资源的情况下使用)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
// 程序集的版本信息由下面四个值组成:
|
||||||
|
//
|
||||||
|
// 主版本
|
||||||
|
// 次版本
|
||||||
|
// 生成号
|
||||||
|
// 修订号
|
||||||
|
//
|
||||||
|
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||||
|
// 方法是按如下所示使用“*”:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
63
CTZLauncher/Properties/Resources.Designer.cs
generated
Normal file
63
CTZLauncher/Properties/Resources.Designer.cs
generated
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// 此代码由工具生成。
|
||||||
|
// 运行时版本:4.0.30319.18444
|
||||||
|
//
|
||||||
|
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||||
|
// 重新生成代码,这些更改将会丢失。
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace CTZLauncher.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||||
|
/// </summary>
|
||||||
|
// 此类是由 StronglyTypedResourceBuilder
|
||||||
|
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||||
|
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||||
|
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CTZLauncher.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用此强类型资源类,为所有资源查找
|
||||||
|
/// 重写当前线程的 CurrentUICulture 属性。
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
117
CTZLauncher/Properties/Resources.resx
Normal file
117
CTZLauncher/Properties/Resources.resx
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
26
CTZLauncher/Properties/Settings.Designer.cs
generated
Normal file
26
CTZLauncher/Properties/Settings.Designer.cs
generated
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// 此代码由工具生成。
|
||||||
|
// 运行时版本:4.0.30319.18444
|
||||||
|
//
|
||||||
|
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||||
|
// 重新生成代码,这些更改将会丢失。
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace CTZLauncher.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
CTZLauncher/Properties/Settings.settings
Normal file
7
CTZLauncher/Properties/Settings.settings
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
3
CTZLauncher/app.config
Normal file
3
CTZLauncher/app.config
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
|
BIN
CTZLauncher/ico.ico
Normal file
BIN
CTZLauncher/ico.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 281 KiB |
50
KMCCC.Shared/Authentication/AuthenticationInfo.cs
Normal file
50
KMCCC.Shared/Authentication/AuthenticationInfo.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
namespace KMCCC.Authentication
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示验证信息
|
||||||
|
/// </summary>
|
||||||
|
public class AuthenticationInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 玩家的名字
|
||||||
|
/// </summary>
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// UUID不解释
|
||||||
|
/// </summary>
|
||||||
|
public Guid UUID { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Session不解释
|
||||||
|
/// </summary>
|
||||||
|
public Guid AccessToken { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 各种属性(比如Twitch的Session)
|
||||||
|
/// </summary>
|
||||||
|
public string Properties { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误信息,无错误则为null
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户类型:Legacy or Mojang
|
||||||
|
/// </summary>
|
||||||
|
public string UserType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 其他验证信息,一边用不着
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, string> AdvancedInfo { get; set; }
|
||||||
|
}
|
||||||
|
}
|
32
KMCCC.Shared/Authentication/IAuthenticator.cs
Normal file
32
KMCCC.Shared/Authentication/IAuthenticator.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
namespace KMCCC.Authentication
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证器接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IAuthenticator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取验证器的类型
|
||||||
|
/// </summary>
|
||||||
|
string Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 同步方式调用
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>验证信息</returns>
|
||||||
|
AuthenticationInfo Do();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步方式调用
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>验证信息</returns>
|
||||||
|
Task<AuthenticationInfo> DoAsync(CancellationToken token);
|
||||||
|
}
|
||||||
|
}
|
70
KMCCC.Shared/Authentication/OfflineAuthenticator.cs
Normal file
70
KMCCC.Shared/Authentication/OfflineAuthenticator.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
namespace KMCCC.Authentication
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 离线验证器
|
||||||
|
/// </summary>
|
||||||
|
public class OfflineAuthenticator : IAuthenticator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 玩家的名字
|
||||||
|
/// </summary>
|
||||||
|
public readonly string DisplayName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造离线验证器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="displayName">玩家的名字</param>
|
||||||
|
public OfflineAuthenticator(string displayName)
|
||||||
|
{
|
||||||
|
DisplayName = displayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标注离线验证器
|
||||||
|
/// </summary>
|
||||||
|
public string Type
|
||||||
|
{
|
||||||
|
get { return "KMCCC.Offline"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationInfo Do()
|
||||||
|
{
|
||||||
|
if (String.IsNullOrWhiteSpace(DisplayName))
|
||||||
|
{
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
Error = "DisplayName不符合规范"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (DisplayName.Count(char.IsWhiteSpace) > 0)
|
||||||
|
{
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
Error = "DisplayName不符合规范"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
AccessToken = Guid.NewGuid(),
|
||||||
|
DisplayName = DisplayName,
|
||||||
|
UUID = Guid.NewGuid(),
|
||||||
|
Properties = "{}",
|
||||||
|
UserType = "Mojang"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AuthenticationInfo> DoAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
return Task.Factory.StartNew((Func<AuthenticationInfo>)Do, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
KMCCC.Shared/Authentication/WarpedAuhenticator.cs
Normal file
45
KMCCC.Shared/Authentication/WarpedAuhenticator.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
namespace KMCCC.Authentication
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反常验证器,只是用来包装验证信息让它看上去像是从验证器里出来的一样^_^
|
||||||
|
/// PS: 不要吐槽名字
|
||||||
|
/// </summary>
|
||||||
|
public class WarpedAuhenticator : IAuthenticator
|
||||||
|
{
|
||||||
|
private readonly AuthenticationInfo _info;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建反常验证器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">要包装的验证信息</param>
|
||||||
|
public WarpedAuhenticator(AuthenticationInfo info)
|
||||||
|
{
|
||||||
|
_info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标注包装验证器
|
||||||
|
/// </summary>
|
||||||
|
public string Type
|
||||||
|
{
|
||||||
|
get { return "KMCCCWarped"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationInfo Do()
|
||||||
|
{
|
||||||
|
return _info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AuthenticationInfo> DoAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
return Task.Factory.StartNew(() => _info, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
193
KMCCC.Shared/Authentication/Yggdrasil.cs
Normal file
193
KMCCC.Shared/Authentication/Yggdrasil.cs
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
namespace KMCCC.Authentication
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Modules.Yggdrasil;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Login
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 正版验证器(直接登陆)
|
||||||
|
/// </summary>
|
||||||
|
public class YggdrasilLogin : IAuthenticator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 新建正版验证器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email">电子邮件地址</param>
|
||||||
|
/// <param name="password">密码</param>
|
||||||
|
/// <param name="twitchEnabled">是否启用Twitch</param>
|
||||||
|
/// <param name="clientToken">clientToken</param>
|
||||||
|
public YggdrasilLogin(string email, string password, bool twitchEnabled, Guid clientToken)
|
||||||
|
{
|
||||||
|
Email = email;
|
||||||
|
Password = password;
|
||||||
|
TwitchEnabled = twitchEnabled;
|
||||||
|
ClientToken = clientToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新建正版验证器(随机的新ClientToken)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="email">电子邮件地址</param>
|
||||||
|
/// <param name="password">密码</param>
|
||||||
|
/// <param name="twitchEnabled">是否启用Twitch</param>
|
||||||
|
public YggdrasilLogin(string email, string password, bool twitchEnabled) : this(email, password, twitchEnabled, Guid.NewGuid())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 电子邮件地址
|
||||||
|
/// </summary>
|
||||||
|
public string Email { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 密码
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用Twitch
|
||||||
|
/// </summary>
|
||||||
|
public bool TwitchEnabled { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public Guid ClientToken { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回Yggdrasil验证器类型
|
||||||
|
/// </summary>
|
||||||
|
public string Type
|
||||||
|
{
|
||||||
|
get { return "KMCCC.Yggdrasil"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationInfo Do()
|
||||||
|
{
|
||||||
|
var client = new YggdrasilClient(ClientToken);
|
||||||
|
if (client.Authenticate(Email, Password, TwitchEnabled))
|
||||||
|
{
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
AccessToken = client.AccessToken,
|
||||||
|
UserType = client.AccountType,
|
||||||
|
DisplayName = client.DisplayName,
|
||||||
|
Properties = client.Properties,
|
||||||
|
UUID = client.UUID
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
Error = "验证错误"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AuthenticationInfo> DoAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
var client = new YggdrasilClient(ClientToken);
|
||||||
|
return client.AuthenticateAsync(Email, Password, TwitchEnabled, token).ContinueWith(task =>
|
||||||
|
{
|
||||||
|
if ((task.Exception == null) && (task.Result))
|
||||||
|
{
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
AccessToken = client.AccessToken,
|
||||||
|
UserType = client.AccountType,
|
||||||
|
DisplayName = client.DisplayName,
|
||||||
|
Properties = client.Properties,
|
||||||
|
UUID = client.UUID
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
Error = "验证错误"
|
||||||
|
};
|
||||||
|
}, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Refresh
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 正版验证器(直接登陆)
|
||||||
|
/// </summary>
|
||||||
|
public class YggdrasilRefresh : IAuthenticator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 新建正版验证器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accessToken">合法的Token</param>
|
||||||
|
/// <param name="twitchEnabled">是否启用Twitch</param>
|
||||||
|
/// <param name="clientToken">clientToken</param>
|
||||||
|
public YggdrasilRefresh(Guid accessToken, bool twitchEnabled, Guid clientToken)
|
||||||
|
{
|
||||||
|
AccessToken = accessToken;
|
||||||
|
TwitchEnabled = twitchEnabled;
|
||||||
|
ClientToken = clientToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新建正版验证器(随机的新ClientToken)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="accessToken">合法的Token</param>
|
||||||
|
/// <param name="twitchEnabled">是否启用Twitch</param>
|
||||||
|
public YggdrasilRefresh(Guid accessToken, bool twitchEnabled)
|
||||||
|
: this(accessToken, twitchEnabled, Guid.NewGuid())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid AccessToken { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用Twitch
|
||||||
|
/// </summary>
|
||||||
|
public bool TwitchEnabled { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// </summary>
|
||||||
|
public Guid ClientToken { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回Yggdrasil验证器类型
|
||||||
|
/// </summary>
|
||||||
|
public string Type
|
||||||
|
{
|
||||||
|
get { return "KMCCC.Yggdrasil"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationInfo Do()
|
||||||
|
{
|
||||||
|
var client = new YggdrasilClient(ClientToken);
|
||||||
|
if (client.Refresh(AccessToken, TwitchEnabled))
|
||||||
|
{
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
AccessToken = client.AccessToken,
|
||||||
|
UserType = client.AccountType,
|
||||||
|
DisplayName = client.DisplayName,
|
||||||
|
Properties = client.Properties,
|
||||||
|
UUID = client.UUID
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new AuthenticationInfo
|
||||||
|
{
|
||||||
|
Error = "验证错误"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AuthenticationInfo> DoAsync(CancellationToken token)
|
||||||
|
{
|
||||||
|
return Task<AuthenticationInfo>.Factory.StartNew(Do, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
84
KMCCC.Shared/KMCCC.csproj
Normal file
84
KMCCC.Shared/KMCCC.csproj
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
<?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>{52E292BB-FC7A-46E6-A8E8-B71E46FAF54E}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>KMCCC.Shared</RootNamespace>
|
||||||
|
<AssemblyName>KMCCC.Shared</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.VisualBasic" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Authentication\AuthenticationInfo.cs" />
|
||||||
|
<Compile Include="Authentication\IAuthenticator.cs" />
|
||||||
|
<Compile Include="Authentication\OfflineAuthenticator.cs" />
|
||||||
|
<Compile Include="Authentication\WarpedAuhenticator.cs" />
|
||||||
|
<Compile Include="Authentication\Yggdrasil.cs" />
|
||||||
|
<Compile Include="Launcher\LaunchArguments.cs" />
|
||||||
|
<Compile Include="Launcher\LauncherCore.cs" />
|
||||||
|
<Compile Include="Launcher\LauncherCoreInternal.cs" />
|
||||||
|
<Compile Include="Launcher\LaunchHandle.cs" />
|
||||||
|
<Compile Include="Launcher\LaunchHandleExtensions.cs" />
|
||||||
|
<Compile Include="Launcher\LaunchMode.cs" />
|
||||||
|
<Compile Include="Launcher\Version.cs" />
|
||||||
|
<Compile Include="LitJson\IJsonWrapper.cs" />
|
||||||
|
<Compile Include="LitJson\JsonData.cs" />
|
||||||
|
<Compile Include="LitJson\JsonException.cs" />
|
||||||
|
<Compile Include="LitJson\JsonMapper.cs" />
|
||||||
|
<Compile Include="LitJson\JsonMockWrapper.cs" />
|
||||||
|
<Compile Include="LitJson\JsonPropertyName.cs" />
|
||||||
|
<Compile Include="LitJson\JsonReader.cs" />
|
||||||
|
<Compile Include="LitJson\JsonWriter.cs" />
|
||||||
|
<Compile Include="LitJson\Lexer.cs" />
|
||||||
|
<Compile Include="LitJson\ParserToken.cs" />
|
||||||
|
<Compile Include="Modules\JVersion\JVersion.cs" />
|
||||||
|
<Compile Include="Modules\JVersion\JVersionLocator.cs" />
|
||||||
|
<Compile Include="Modules\Yggdrasil\YggdrasilClient.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Tools\SystemTools.cs" />
|
||||||
|
<Compile Include="Tools\UsefulTools.cs" />
|
||||||
|
<Compile Include="Tools\ZipTools.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- 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>
|
181
KMCCC.Shared/Launcher/LaunchArguments.cs
Normal file
181
KMCCC.Shared/Launcher/LaunchArguments.cs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using Authentication;
|
||||||
|
using Tools;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Launch Arguments
|
||||||
|
/// </summary>
|
||||||
|
public class MinecraftLaunchArguments
|
||||||
|
{
|
||||||
|
internal AuthenticationInfo Authentication;
|
||||||
|
internal Version Version;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 新建启动参数
|
||||||
|
/// </summary>
|
||||||
|
public MinecraftLaunchArguments()
|
||||||
|
{
|
||||||
|
CGCEnabled = true;
|
||||||
|
Tokens = new Dictionary<string, string>();
|
||||||
|
AdvencedArguments = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主类
|
||||||
|
/// </summary>
|
||||||
|
public string MainClass { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 库文件列表(推荐绝对路径)
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Libraries { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大内存
|
||||||
|
/// </summary>
|
||||||
|
public int MaxMemory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最小内存,推荐不设置
|
||||||
|
/// </summary>
|
||||||
|
public int MinMemory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认true,不要作死去设置成false
|
||||||
|
/// </summary>
|
||||||
|
public bool CGCEnabled { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地dll文件地址
|
||||||
|
/// </summary>
|
||||||
|
public string NativePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MC主参数(将由Token进行替换操作)
|
||||||
|
/// </summary>
|
||||||
|
public string MinecraftArguments { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对MC主参数要进行的替换操作表
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, string> Tokens { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动后直接连接到服务器
|
||||||
|
/// </summary>
|
||||||
|
public ServerInfo Server { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动后的窗口大小设置
|
||||||
|
/// </summary>
|
||||||
|
public WindowSize Size { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 附加参数
|
||||||
|
/// </summary>
|
||||||
|
public List<string> AdvencedArguments { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 转化为String参数
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>转化后的参数</returns>
|
||||||
|
public string ToArguments()
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
if (CGCEnabled)
|
||||||
|
{
|
||||||
|
sb.Append("-Xincgc");
|
||||||
|
}
|
||||||
|
if (MinMemory > 0)
|
||||||
|
{
|
||||||
|
sb.Append(" -Xms").Append(MinMemory).Append("M ");
|
||||||
|
}
|
||||||
|
if (MaxMemory > 0)
|
||||||
|
{
|
||||||
|
sb.Append(" -Xmx").Append(MaxMemory).Append("M");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append("-Xmx2048M ");
|
||||||
|
}
|
||||||
|
foreach (var adv in AdvencedArguments)
|
||||||
|
{
|
||||||
|
sb.Append(' ').Append(adv);
|
||||||
|
}
|
||||||
|
sb.Append(" -Djava.library.path=\"").Append(NativePath);
|
||||||
|
sb.Append("\" -cp \"");
|
||||||
|
foreach (var lib in Libraries)
|
||||||
|
{
|
||||||
|
sb.Append(lib).Append(';');
|
||||||
|
}
|
||||||
|
sb.Append("\" ").Append(MainClass).Append(' ').Append(MinecraftArguments.DoReplace(Tokens));
|
||||||
|
if (Server != null)
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrWhiteSpace(Server.Address))
|
||||||
|
{
|
||||||
|
sb.Append(" --server " + Server.Address);
|
||||||
|
if (Server.Port == 0)
|
||||||
|
{
|
||||||
|
sb.Append(" --port 25565");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(" --port " + Server.Port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Size != null)
|
||||||
|
{
|
||||||
|
if (Size.FullScreen == true)
|
||||||
|
{
|
||||||
|
sb.Append(" --fullscreen");
|
||||||
|
}
|
||||||
|
if (Size.Height != null)
|
||||||
|
{
|
||||||
|
var height = (ushort) Size.Height;
|
||||||
|
if (height > 0)
|
||||||
|
{
|
||||||
|
sb.Append(String.Format(" --height {0}", height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Size.Width != null)
|
||||||
|
{
|
||||||
|
var width = (ushort) Size.Width;
|
||||||
|
if (width > 0)
|
||||||
|
{
|
||||||
|
sb.Append(String.Format(" --width {0}", width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ServerInfo
|
||||||
|
{
|
||||||
|
public string Address { get; set; }
|
||||||
|
public ushort Port { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("{0}:{1}", Address, Port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class WindowSize
|
||||||
|
{
|
||||||
|
public bool? FullScreen { get; set; }
|
||||||
|
|
||||||
|
public ushort? Height { get; set; }
|
||||||
|
|
||||||
|
public ushort? Width { get; set; }
|
||||||
|
}
|
||||||
|
}
|
165
KMCCC.Shared/Launcher/LaunchHandle.cs
Normal file
165
KMCCC.Shared/Launcher/LaunchHandle.cs
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Authentication;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动选项
|
||||||
|
/// </summary>
|
||||||
|
public sealed class LaunchOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 最大内存
|
||||||
|
/// </summary>
|
||||||
|
public int MaxMemory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最小内存
|
||||||
|
/// </summary>
|
||||||
|
public int MinMemory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动的版本
|
||||||
|
/// </summary>
|
||||||
|
public Version Version { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用的验证器
|
||||||
|
/// </summary>
|
||||||
|
public IAuthenticator Authenticator { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动模式
|
||||||
|
/// </summary>
|
||||||
|
public LaunchMode Mode { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 直接连接的服务器
|
||||||
|
/// </summary>
|
||||||
|
public ServerInfo Server { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置窗口大小
|
||||||
|
/// </summary>
|
||||||
|
public WindowSize Size { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动句柄,基本上也就比较用
|
||||||
|
/// </summary>
|
||||||
|
public sealed class LaunchHandle
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 只读的验证信息
|
||||||
|
/// </summary>
|
||||||
|
public readonly AuthenticationInfo Info;
|
||||||
|
|
||||||
|
internal int Code;
|
||||||
|
|
||||||
|
internal LauncherCore Core;
|
||||||
|
|
||||||
|
internal Process Process;
|
||||||
|
|
||||||
|
internal MinecraftLaunchArguments Arguments { get; set; }
|
||||||
|
|
||||||
|
internal LaunchHandle(AuthenticationInfo info)
|
||||||
|
{
|
||||||
|
Info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Output(object sender, DataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Data == null)
|
||||||
|
{
|
||||||
|
Process.OutputDataReceived -= Output;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Core.Log(this, e.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Error(object sender, DataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Data == null)
|
||||||
|
{
|
||||||
|
Process.OutputDataReceived -= Error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Core.Log(this, e.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Work()
|
||||||
|
{
|
||||||
|
Process.BeginOutputReadLine();
|
||||||
|
Process.OutputDataReceived += Output;
|
||||||
|
Process.BeginErrorReadLine();
|
||||||
|
Process.ErrorDataReceived += Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动异常(未启用)
|
||||||
|
/// </summary>
|
||||||
|
public class LaunchException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 启动异常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">异常类型</param>
|
||||||
|
/// <param name="message">异常信息</param>
|
||||||
|
public LaunchException(LaunchExceptionType type, string message) : base(message)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动异常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">异常类型</param>
|
||||||
|
/// <param name="message">异常信息</param>
|
||||||
|
/// <param name="innerException">内部异常</param>
|
||||||
|
public LaunchException(LaunchExceptionType type, string message, Exception innerException) : base(message, innerException)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异常类型
|
||||||
|
/// </summary>
|
||||||
|
public LaunchExceptionType Type { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异常类型
|
||||||
|
/// </summary>
|
||||||
|
public enum LaunchExceptionType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 验证器错误
|
||||||
|
/// </summary>
|
||||||
|
Authenticator,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动参数操作器错误
|
||||||
|
/// </summary>
|
||||||
|
ArguementsOperator,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动时错误
|
||||||
|
/// </summary>
|
||||||
|
LaunchTime,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 未知
|
||||||
|
/// </summary>
|
||||||
|
Unknow
|
||||||
|
}
|
||||||
|
}
|
46
KMCCC.Shared/Launcher/LaunchHandleExtensions.cs
Normal file
46
KMCCC.Shared/Launcher/LaunchHandleExtensions.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static class LaunchHandleExtensions
|
||||||
|
{
|
||||||
|
public static bool SetTitle(this LaunchHandle handle, string title)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SetWindowText(handle.Process.MainWindowHandle, title);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetTile(this LaunchHandle handle)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return handle.Process.MainWindowTitle;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Kill(this LaunchHandle handle)
|
||||||
|
{
|
||||||
|
handle.Process.Kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("User32.dll")]
|
||||||
|
public static extern int SetWindowText(IntPtr winHandle, string title);
|
||||||
|
}
|
||||||
|
}
|
68
KMCCC.Shared/Launcher/LaunchMode.cs
Normal file
68
KMCCC.Shared/Launcher/LaunchMode.cs
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动模式
|
||||||
|
/// </summary>
|
||||||
|
public abstract class LaunchMode
|
||||||
|
{
|
||||||
|
public static readonly BmclLaunchMode BmclMode = new BmclLaunchMode();
|
||||||
|
|
||||||
|
public static readonly MCLauncherMode MCLauncher = new MCLauncherMode();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动模式
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>模式是否应用成功</returns>
|
||||||
|
public abstract bool Operate(LauncherCore core, MinecraftLaunchArguments args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模仿BMCL的启动模式
|
||||||
|
/// </summary>
|
||||||
|
public class BmclLaunchMode : LaunchMode
|
||||||
|
{
|
||||||
|
public override bool Operate(LauncherCore core, MinecraftLaunchArguments args)
|
||||||
|
{
|
||||||
|
core.CopyVersionDirectory("mods", args.Version.Id);
|
||||||
|
core.CopyVersionDirectory("coremods", args.Version.Id);
|
||||||
|
core.CopyVersionDirectories(core.GetVersionRootPath(args.Version));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模仿MCLauncher的启动模式
|
||||||
|
/// </summary>
|
||||||
|
public class MCLauncherMode : LaunchMode
|
||||||
|
{
|
||||||
|
public override bool Operate(LauncherCore core, MinecraftLaunchArguments args)
|
||||||
|
{
|
||||||
|
args.Tokens["game_directory"] = String.Format(@".\versions\{0}\", args.Version.Id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 简单的映射启动模式
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleWarpedMode : LaunchMode
|
||||||
|
{
|
||||||
|
private readonly Func<LauncherCore, MinecraftLaunchArguments, bool> _operatorMethod;
|
||||||
|
|
||||||
|
public SimpleWarpedMode(Func<LauncherCore, MinecraftLaunchArguments, bool> operatorMethod)
|
||||||
|
{
|
||||||
|
_operatorMethod = operatorMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Operate(LauncherCore core, MinecraftLaunchArguments args)
|
||||||
|
{
|
||||||
|
return _operatorMethod.Invoke(core, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
230
KMCCC.Shared/Launcher/LauncherCore.cs
Normal file
230
KMCCC.Shared/Launcher/LauncherCore.cs
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Modules.JVersion;
|
||||||
|
using Tools;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动器核心
|
||||||
|
/// </summary>
|
||||||
|
public partial class LauncherCore
|
||||||
|
{
|
||||||
|
internal int CurrentCode;
|
||||||
|
|
||||||
|
internal Random Random = new Random();
|
||||||
|
private IVersionLocator _versionLocator;
|
||||||
|
|
||||||
|
#region GetVersion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回包含全部版本数组
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>版本数组</returns>
|
||||||
|
public IEnumerable<Version> GetVersions()
|
||||||
|
{
|
||||||
|
return (VersionLocator == null)
|
||||||
|
? new Version[0]
|
||||||
|
: _versionLocator.GetAllVersions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回指定id的版本
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">要指定的ID</param>
|
||||||
|
/// <returns>指定的版本</returns>
|
||||||
|
public Version GetVersion(string id)
|
||||||
|
{
|
||||||
|
return (VersionLocator == null)
|
||||||
|
? null
|
||||||
|
: _versionLocator.Locate(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private LauncherCore()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏根目录
|
||||||
|
/// </summary>
|
||||||
|
public string GameRootPath { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JAVA目录
|
||||||
|
/// </summary>
|
||||||
|
public string JavaPath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 版本定位器
|
||||||
|
/// </summary>
|
||||||
|
public IVersionLocator VersionLocator
|
||||||
|
{
|
||||||
|
get { return _versionLocator; }
|
||||||
|
set { (_versionLocator = value).Core = this; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从CreationOption创建启动器核心
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="option">启动器创建选项</param>
|
||||||
|
/// <returns>创建的启动器核心</returns>
|
||||||
|
public static LauncherCore Create(LauncherCoreCreationOption option)
|
||||||
|
{
|
||||||
|
var launcherCore = new LauncherCore
|
||||||
|
{
|
||||||
|
GameRootPath = option.GameRootPath,
|
||||||
|
JavaPath = option.JavaPath,
|
||||||
|
VersionLocator = option.VersionLocator
|
||||||
|
};
|
||||||
|
return launcherCore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LauncherCore Create(string gameRootPath = null)
|
||||||
|
{
|
||||||
|
return Create(new LauncherCoreCreationOption(gameRootPath ?? @".minecraft"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动函数
|
||||||
|
/// 过程:
|
||||||
|
/// 1. 运行验证器(authenticator),出错返回null
|
||||||
|
/// 2. 继续构造启动参数
|
||||||
|
/// 3. 遍历Operators对启动参数进行修改
|
||||||
|
/// 4. 启动
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">启动选项</param>
|
||||||
|
/// <param name="argumentsOperators">启动参数的修改器</param>
|
||||||
|
/// <returns>启动结果</returns>
|
||||||
|
public LaunchResult Launch(LaunchOptions options, params Action<MinecraftLaunchArguments>[] argumentsOperators)
|
||||||
|
{
|
||||||
|
return LaunchInternal(options, argumentsOperators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏退出事件
|
||||||
|
/// </summary>
|
||||||
|
public event Action<LaunchHandle, int> GameExit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏Log事件
|
||||||
|
/// </summary>
|
||||||
|
public event Action<LaunchHandle, string> GameLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动器核心选项
|
||||||
|
/// 以后可能包含更多内容
|
||||||
|
/// </summary>
|
||||||
|
public class LauncherCoreCreationOption
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 核心选项
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="gameRootPath">游戏根目录,默认为 ./.minecraft </param>
|
||||||
|
/// <param name="javaPath">JAVA地址,默认为自动搜寻所的第一个</param>
|
||||||
|
/// <param name="versionLocator">Version定位器,默认为 JVersionLoacator</param>
|
||||||
|
public LauncherCoreCreationOption(string gameRootPath = null, string javaPath = null, IVersionLocator versionLocator = null)
|
||||||
|
{
|
||||||
|
GameRootPath = new DirectoryInfo(gameRootPath ?? ".minecraft").FullName;
|
||||||
|
JavaPath = javaPath ?? SystemTools.FindJava().FirstOrDefault();
|
||||||
|
VersionLocator = versionLocator ?? new JVersionLocator();
|
||||||
|
if (!Directory.Exists(GameRootPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(GameRootPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏根目录
|
||||||
|
/// </summary>
|
||||||
|
public string GameRootPath { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// JAVA地址
|
||||||
|
/// </summary>
|
||||||
|
public string JavaPath { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Version定位器
|
||||||
|
/// </summary>
|
||||||
|
public IVersionLocator VersionLocator { get; internal set; }
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
|
public static LauncherCoreCreationOption Create(string gameRootPath = null, string javaPath = null, IVersionLocator versionLocator = null)
|
||||||
|
{
|
||||||
|
return new LauncherCoreCreationOption(gameRootPath, javaPath, versionLocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动后返回的启动结果
|
||||||
|
/// </summary>
|
||||||
|
public class LaunchResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取是否启动成功
|
||||||
|
/// </summary>
|
||||||
|
public bool Success { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取发生的错误类型
|
||||||
|
/// </summary>
|
||||||
|
public ErrorType ErrorType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取错误信息
|
||||||
|
/// </summary>
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动时发生异常
|
||||||
|
/// </summary>
|
||||||
|
public Exception Exception { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取启动句柄
|
||||||
|
/// </summary>
|
||||||
|
public LaunchHandle Handle { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ErrorType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 没有错误
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 没有找到JAVA
|
||||||
|
/// </summary>
|
||||||
|
NoJAVA,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证失败
|
||||||
|
/// </summary>
|
||||||
|
AuthenticationFailed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操作器出现故障
|
||||||
|
/// </summary>
|
||||||
|
OperatorException,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 未知
|
||||||
|
/// </summary>
|
||||||
|
Unknown,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解压错误
|
||||||
|
/// </summary>
|
||||||
|
UncompressingFailed
|
||||||
|
}
|
||||||
|
}
|
217
KMCCC.Shared/Launcher/LauncherCoreInternal.cs
Normal file
217
KMCCC.Shared/Launcher/LauncherCoreInternal.cs
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Tools;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
partial class LauncherCore
|
||||||
|
{
|
||||||
|
internal object Locker = new object();
|
||||||
|
|
||||||
|
private LaunchResult GenerateArguments(LaunchOptions options, ref MinecraftLaunchArguments args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var authentication = options.Authenticator.Do();
|
||||||
|
if (!string.IsNullOrWhiteSpace(authentication.Error))
|
||||||
|
return new LaunchResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
ErrorType = ErrorType.AuthenticationFailed,
|
||||||
|
ErrorMessage = "验证错误: " + authentication.Error
|
||||||
|
};
|
||||||
|
args.CGCEnabled = true;
|
||||||
|
args.MainClass = options.Version.MainClass;
|
||||||
|
args.MaxMemory = options.MaxMemory;
|
||||||
|
args.MinMemory = options.MinMemory;
|
||||||
|
args.NativePath = GameRootPath + options.Version.Id + @"\\" + options.Version.Id + @"-natives";
|
||||||
|
foreach (var native in options.Version.Natives)
|
||||||
|
{
|
||||||
|
var exp = ZipTools.UnzipFile(this.GetNativePath(native), args.NativePath, native.Options);
|
||||||
|
if (exp == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return new LaunchResult
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
ErrorType = ErrorType.UncompressingFailed,
|
||||||
|
ErrorMessage = string.Format("解压错误: {0}:{1}:{2}", native.NS, native.Name, native.Version),
|
||||||
|
Exception = exp
|
||||||
|
};
|
||||||
|
}
|
||||||
|
args.Server = options.Server;
|
||||||
|
args.Size = options.Size;
|
||||||
|
args.Libraries = options.Version.Libraries.Select(this.GetLibPath).ToList();
|
||||||
|
args.Libraries.Add(this.GetVersionJarPath(options.Version.JarId));
|
||||||
|
args.MinecraftArguments = options.Version.MinecraftArguments;
|
||||||
|
|
||||||
|
args.Tokens.Add("auth_access_token", authentication.AccessToken.GoString());
|
||||||
|
args.Tokens.Add("auth_session", authentication.AccessToken.GoString());
|
||||||
|
args.Tokens.Add("auth_player_name", authentication.DisplayName);
|
||||||
|
args.Tokens.Add("version_name", options.Version.Id);
|
||||||
|
args.Tokens.Add("game_directory", ".");
|
||||||
|
args.Tokens.Add("game_assets", "assets");
|
||||||
|
args.Tokens.Add("assets_root", "assets");
|
||||||
|
args.Tokens.Add("assets_index_name", options.Version.Assets);
|
||||||
|
args.Tokens.Add("auth_uuid", authentication.UUID.GoString());
|
||||||
|
args.Tokens.Add("user_properties", authentication.Properties);
|
||||||
|
args.Tokens.Add("user_type", authentication.UserType);
|
||||||
|
|
||||||
|
args.AdvencedArguments = new List<string> { "-Dfml.ignoreInvalidMinecraftCertificates=true -Dfml.ignorePatchDiscrepancies=true" };
|
||||||
|
|
||||||
|
args.Authentication = authentication;
|
||||||
|
args.Version = options.Version;
|
||||||
|
if (options.Mode != null)
|
||||||
|
{
|
||||||
|
options.Mode.Operate(this, args);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception exp)
|
||||||
|
{
|
||||||
|
Console.WriteLine(exp.Message);
|
||||||
|
Console.WriteLine(exp.Source);
|
||||||
|
Console.WriteLine(exp.StackTrace);
|
||||||
|
return new LaunchResult { Success = false, ErrorType = ErrorType.Unknown, ErrorMessage = "在生成参数时发生了意外的错误", Exception = exp };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LaunchResult LaunchInternal(LaunchOptions options, params Action<MinecraftLaunchArguments>[] argumentsOperators)
|
||||||
|
{
|
||||||
|
lock (Locker)
|
||||||
|
{
|
||||||
|
if (!File.Exists(JavaPath))
|
||||||
|
{
|
||||||
|
return new LaunchResult { Success = false, ErrorType = ErrorType.NoJAVA, ErrorMessage = "指定的JAVA位置不存在" };
|
||||||
|
}
|
||||||
|
CurrentCode = Random.Next();
|
||||||
|
var args = new MinecraftLaunchArguments();
|
||||||
|
var result = GenerateArguments(options, ref args);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (argumentsOperators == null) return LaunchGame(args);
|
||||||
|
foreach (var opt in argumentsOperators)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (opt != null)
|
||||||
|
{
|
||||||
|
opt(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception exp)
|
||||||
|
{
|
||||||
|
return new LaunchResult { Success = false, ErrorType = ErrorType.OperatorException, ErrorMessage = "指定的操作器引发了异常", Exception = exp };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LaunchGame(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LaunchResult LaunchGame(MinecraftLaunchArguments args)
|
||||||
|
{
|
||||||
|
Console.WriteLine(args.ToArguments());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var handle = new LaunchHandle(args.Authentication)
|
||||||
|
{
|
||||||
|
Code = CurrentCode,
|
||||||
|
Core = this,
|
||||||
|
Arguments = args,
|
||||||
|
Process = Process.Start(new ProcessStartInfo(JavaPath)
|
||||||
|
{
|
||||||
|
Arguments = args.ToArguments(),
|
||||||
|
UseShellExecute = false,
|
||||||
|
WorkingDirectory = GameRootPath,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
RedirectStandardOutput = true
|
||||||
|
})
|
||||||
|
};
|
||||||
|
handle.Work();
|
||||||
|
Task.Factory.StartNew(handle.Process.WaitForExit).ContinueWith(t => Exit(handle, handle.Process.ExitCode));
|
||||||
|
return new LaunchResult { Success = true, Handle = handle };
|
||||||
|
}
|
||||||
|
catch (Exception exp)
|
||||||
|
{
|
||||||
|
return new LaunchResult { Success = false, ErrorType = ErrorType.Unknown, ErrorMessage = "启动时出现了异常", Exception = exp };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 复制文件夹
|
||||||
|
|
||||||
|
public void CopyVersionDirectory(string directoryName, string versionId)
|
||||||
|
{
|
||||||
|
CopyDirectory(string.Format(@"{0}\versions\{2}\{1}", GameRootPath, directoryName, versionId),
|
||||||
|
string.Format(@"{0}\{1}", GameRootPath, directoryName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyDirectory(string source, string target)
|
||||||
|
{
|
||||||
|
var code = CurrentCode;
|
||||||
|
if (!Directory.Exists(source)) return;
|
||||||
|
if (Directory.Exists(target))
|
||||||
|
{
|
||||||
|
Directory.Delete(target, true);
|
||||||
|
}
|
||||||
|
UsefulTools.Dircopy(source, target);
|
||||||
|
Action<LaunchHandle, int> handler = null;
|
||||||
|
handler = (handle, c) =>
|
||||||
|
{
|
||||||
|
if (handle.Code == code)
|
||||||
|
{
|
||||||
|
Directory.Delete(source, true);
|
||||||
|
UsefulTools.Dircopy(target, source);
|
||||||
|
Directory.Delete(target, true);
|
||||||
|
}
|
||||||
|
GameExit -= handler;
|
||||||
|
};
|
||||||
|
GameExit += handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyVersionDirectories(string ver)
|
||||||
|
{
|
||||||
|
var root = string.Format(@"{0}\versions\{1}\moddir", GameRootPath, ver);
|
||||||
|
if (!Directory.Exists(root))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach (var dir in new DirectoryInfo(root).EnumerateDirectories())
|
||||||
|
{
|
||||||
|
CopyDirectory(dir.FullName, string.Format(@"{0}\{1}", GameRootPath, dir.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 事件
|
||||||
|
|
||||||
|
internal void Log(LaunchHandle handle, string line)
|
||||||
|
{
|
||||||
|
if (GameLog != null)
|
||||||
|
{
|
||||||
|
GameLog(handle, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Exit(LaunchHandle handle, int code)
|
||||||
|
{
|
||||||
|
if (GameExit != null)
|
||||||
|
{
|
||||||
|
GameExit(handle, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
175
KMCCC.Shared/Launcher/Version.cs
Normal file
175
KMCCC.Shared/Launcher/Version.cs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
namespace KMCCC.Launcher
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Tools;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 版本定位器接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IVersionLocator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 设置定位器基于的核心
|
||||||
|
/// </summary>
|
||||||
|
LauncherCore Core { set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取对应Id的Version,若不存在应返回null
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="versionId">对应的Id</param>
|
||||||
|
/// <returns>对应的Version</returns>
|
||||||
|
Version Locate(string versionId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有可找到Version
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>所有Version</returns>
|
||||||
|
IEnumerable<Version> GetAllVersions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示版本
|
||||||
|
/// </summary>
|
||||||
|
public sealed class Version
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ID
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主启动参数
|
||||||
|
/// </summary>
|
||||||
|
public string MinecraftArguments { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 资源名
|
||||||
|
/// </summary>
|
||||||
|
public string Assets { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主类
|
||||||
|
/// </summary>
|
||||||
|
public string MainClass { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 库列表
|
||||||
|
/// </summary>
|
||||||
|
public List<Library> Libraries { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地实现表
|
||||||
|
/// </summary>
|
||||||
|
public List<Native> Natives { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Jar文件(Id)
|
||||||
|
/// </summary>
|
||||||
|
public string JarId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示库
|
||||||
|
/// </summary>
|
||||||
|
public class Library
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NS
|
||||||
|
/// </summary>
|
||||||
|
public string NS { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Version
|
||||||
|
/// </summary>
|
||||||
|
public string Version { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 表示本机实现
|
||||||
|
/// </summary>
|
||||||
|
public class Native
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NS
|
||||||
|
/// </summary>
|
||||||
|
public string NS { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Version
|
||||||
|
/// </summary>
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本机实现后缀
|
||||||
|
/// </summary>
|
||||||
|
public string NativeSuffix { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解压参数
|
||||||
|
/// </summary>
|
||||||
|
public UnzipOptions Options { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 找Item,自己看我不加注释了
|
||||||
|
/// </summary>
|
||||||
|
public static class LauncherCoreItemResolverExtensions
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string GetVersionRootPath(this LauncherCore core, Version version)
|
||||||
|
{
|
||||||
|
return GetVersionRootPath(core, version.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetVersionRootPath(this LauncherCore core, string versionId)
|
||||||
|
{
|
||||||
|
return String.Format(@"{0}\versions\{1}\", core.GameRootPath, versionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetVersionJarPath(this LauncherCore core, Version version)
|
||||||
|
{
|
||||||
|
return GetVersionJarPath(core, version.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetVersionJarPath(this LauncherCore core, string versionId)
|
||||||
|
{
|
||||||
|
return String.Format(@"{0}\versions\{1}\{1}.jar", core.GameRootPath, versionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetVersionJsonPath(this LauncherCore core, Version version)
|
||||||
|
{
|
||||||
|
return GetVersionJsonPath(core, version.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetVersionJsonPath(this LauncherCore core, string versionId)
|
||||||
|
{
|
||||||
|
return String.Format(@"{0}\versions\{1}\{1}.json", core.GameRootPath, versionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetLibPath(this LauncherCore core, Library lib)
|
||||||
|
{
|
||||||
|
return String.Format(@"{0}\libraries\{1}\{2}\{3}\{2}-{3}.jar", core.GameRootPath, lib.NS.Replace(".", "\\"), lib.Name, lib.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetNativePath(this LauncherCore core, Native native)
|
||||||
|
{
|
||||||
|
return String.Format(@"{0}\libraries\{1}\{2}\{3}\{2}-{3}-{4}.jar", core.GameRootPath, native.NS.Replace(".", "\\"), native.Name, native.Version,
|
||||||
|
native.NativeSuffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
KMCCC.Shared/LitJson/IJsonWrapper.cs
Normal file
60
KMCCC.Shared/LitJson/IJsonWrapper.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* IJsonWrapper.cs
|
||||||
|
* Interface that represents a type capable of handling all kinds of JSON
|
||||||
|
* data. This is mainly used when mapping objects through JsonMapper, and
|
||||||
|
* it's implemented by JsonData.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
public enum JsonType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
|
||||||
|
Object,
|
||||||
|
Array,
|
||||||
|
String,
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
Double,
|
||||||
|
Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IJsonWrapper : IList, IOrderedDictionary
|
||||||
|
{
|
||||||
|
bool IsArray { get; }
|
||||||
|
bool IsBoolean { get; }
|
||||||
|
bool IsDouble { get; }
|
||||||
|
bool IsInt { get; }
|
||||||
|
bool IsLong { get; }
|
||||||
|
bool IsObject { get; }
|
||||||
|
bool IsString { get; }
|
||||||
|
|
||||||
|
bool GetBoolean ();
|
||||||
|
double GetDouble ();
|
||||||
|
int GetInt ();
|
||||||
|
JsonType GetJsonType ();
|
||||||
|
long GetLong ();
|
||||||
|
string GetString ();
|
||||||
|
|
||||||
|
void SetBoolean (bool val);
|
||||||
|
void SetDouble (double val);
|
||||||
|
void SetInt (int val);
|
||||||
|
void SetJsonType (JsonType type);
|
||||||
|
void SetLong (long val);
|
||||||
|
void SetString (string val);
|
||||||
|
|
||||||
|
string ToJson ();
|
||||||
|
void ToJson (JsonWriter writer);
|
||||||
|
}
|
||||||
|
}
|
1002
KMCCC.Shared/LitJson/JsonData.cs
Normal file
1002
KMCCC.Shared/LitJson/JsonData.cs
Normal file
File diff suppressed because it is too large
Load Diff
60
KMCCC.Shared/LitJson/JsonException.cs
Normal file
60
KMCCC.Shared/LitJson/JsonException.cs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* JsonException.cs
|
||||||
|
* Base class throwed by LitJSON when a parsing error occurs.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
public class JsonException : ApplicationException
|
||||||
|
{
|
||||||
|
public JsonException () : base ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JsonException (ParserToken token) :
|
||||||
|
base (String.Format (
|
||||||
|
"Invalid token '{0}' in input string", token))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JsonException (ParserToken token,
|
||||||
|
Exception inner_exception) :
|
||||||
|
base (String.Format (
|
||||||
|
"Invalid token '{0}' in input string", token),
|
||||||
|
inner_exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JsonException (int c) :
|
||||||
|
base (String.Format (
|
||||||
|
"Invalid character '{0}' in input string", (char) c))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal JsonException (int c, Exception inner_exception) :
|
||||||
|
base (String.Format (
|
||||||
|
"Invalid character '{0}' in input string", (char) c),
|
||||||
|
inner_exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public JsonException (string message) : base (message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonException (string message, Exception inner_exception) :
|
||||||
|
base (message, inner_exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
987
KMCCC.Shared/LitJson/JsonMapper.cs
Normal file
987
KMCCC.Shared/LitJson/JsonMapper.cs
Normal file
@ -0,0 +1,987 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* JsonMapper.cs
|
||||||
|
* JSON to .Net object and object to JSON conversions.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
internal struct PropertyMetadata
|
||||||
|
{
|
||||||
|
public MemberInfo Info;
|
||||||
|
public bool IsField;
|
||||||
|
public Type Type;
|
||||||
|
public String Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal struct ArrayMetadata
|
||||||
|
{
|
||||||
|
private Type element_type;
|
||||||
|
private bool is_array;
|
||||||
|
private bool is_list;
|
||||||
|
|
||||||
|
|
||||||
|
public Type ElementType {
|
||||||
|
get {
|
||||||
|
if (element_type == null)
|
||||||
|
return typeof (JsonData);
|
||||||
|
|
||||||
|
return element_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
set { element_type = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsArray {
|
||||||
|
get { return is_array; }
|
||||||
|
set { is_array = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsList {
|
||||||
|
get { return is_list; }
|
||||||
|
set { is_list = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal struct ObjectMetadata
|
||||||
|
{
|
||||||
|
private Type element_type;
|
||||||
|
private bool is_dictionary;
|
||||||
|
|
||||||
|
private IDictionary<string, PropertyMetadata> properties;
|
||||||
|
|
||||||
|
|
||||||
|
public Type ElementType {
|
||||||
|
get {
|
||||||
|
if (element_type == null)
|
||||||
|
return typeof (JsonData);
|
||||||
|
|
||||||
|
return element_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
set { element_type = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDictionary {
|
||||||
|
get { return is_dictionary; }
|
||||||
|
set { is_dictionary = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDictionary<string, PropertyMetadata> Properties {
|
||||||
|
get { return properties; }
|
||||||
|
set { properties = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal delegate void ExporterFunc (object obj, JsonWriter writer);
|
||||||
|
public delegate void ExporterFunc<T> (T obj, JsonWriter writer);
|
||||||
|
|
||||||
|
internal delegate object ImporterFunc (object input);
|
||||||
|
public delegate TValue ImporterFunc<TJson, TValue> (TJson input);
|
||||||
|
|
||||||
|
public delegate IJsonWrapper WrapperFactory ();
|
||||||
|
|
||||||
|
|
||||||
|
public class JsonMapper
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private static int max_nesting_depth;
|
||||||
|
|
||||||
|
private static IFormatProvider datetime_format;
|
||||||
|
|
||||||
|
private static IDictionary<Type, ExporterFunc> base_exporters_table;
|
||||||
|
private static IDictionary<Type, ExporterFunc> custom_exporters_table;
|
||||||
|
|
||||||
|
private static IDictionary<Type,
|
||||||
|
IDictionary<Type, ImporterFunc>> base_importers_table;
|
||||||
|
private static IDictionary<Type,
|
||||||
|
IDictionary<Type, ImporterFunc>> custom_importers_table;
|
||||||
|
|
||||||
|
private static IDictionary<Type, ArrayMetadata> array_metadata;
|
||||||
|
private static readonly object array_metadata_lock = new Object ();
|
||||||
|
|
||||||
|
private static IDictionary<Type,
|
||||||
|
IDictionary<Type, MethodInfo>> conv_ops;
|
||||||
|
private static readonly object conv_ops_lock = new Object ();
|
||||||
|
|
||||||
|
private static IDictionary<Type, ObjectMetadata> object_metadata;
|
||||||
|
private static readonly object object_metadata_lock = new Object ();
|
||||||
|
|
||||||
|
private static IDictionary<Type,
|
||||||
|
IList<PropertyMetadata>> type_properties;
|
||||||
|
private static readonly object type_properties_lock = new Object ();
|
||||||
|
|
||||||
|
private static JsonWriter static_writer;
|
||||||
|
private static readonly object static_writer_lock = new Object ();
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
static JsonMapper ()
|
||||||
|
{
|
||||||
|
max_nesting_depth = 100;
|
||||||
|
|
||||||
|
array_metadata = new Dictionary<Type, ArrayMetadata> ();
|
||||||
|
conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> ();
|
||||||
|
object_metadata = new Dictionary<Type, ObjectMetadata> ();
|
||||||
|
type_properties = new Dictionary<Type,
|
||||||
|
IList<PropertyMetadata>> ();
|
||||||
|
|
||||||
|
static_writer = new JsonWriter ();
|
||||||
|
|
||||||
|
datetime_format = DateTimeFormatInfo.InvariantInfo;
|
||||||
|
|
||||||
|
base_exporters_table = new Dictionary<Type, ExporterFunc> ();
|
||||||
|
custom_exporters_table = new Dictionary<Type, ExporterFunc> ();
|
||||||
|
|
||||||
|
base_importers_table = new Dictionary<Type,
|
||||||
|
IDictionary<Type, ImporterFunc>> ();
|
||||||
|
custom_importers_table = new Dictionary<Type,
|
||||||
|
IDictionary<Type, ImporterFunc>> ();
|
||||||
|
|
||||||
|
RegisterBaseExporters ();
|
||||||
|
RegisterBaseImporters ();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
private static void AddArrayMetadata (Type type)
|
||||||
|
{
|
||||||
|
if (array_metadata.ContainsKey (type))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ArrayMetadata data = new ArrayMetadata ();
|
||||||
|
|
||||||
|
data.IsArray = type.IsArray;
|
||||||
|
|
||||||
|
if (type.GetInterface ("System.Collections.IList") != null)
|
||||||
|
data.IsList = true;
|
||||||
|
|
||||||
|
foreach (PropertyInfo p_info in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
if (p_info.Name != "Item")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ParameterInfo[] parameters = p_info.GetIndexParameters ();
|
||||||
|
|
||||||
|
if (parameters.Length != 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (parameters[0].ParameterType == typeof (int))
|
||||||
|
data.ElementType = p_info.PropertyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (array_metadata_lock) {
|
||||||
|
try {
|
||||||
|
array_metadata.Add (type, data);
|
||||||
|
} catch (ArgumentException) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddObjectMetadata (Type type)
|
||||||
|
{
|
||||||
|
if (object_metadata.ContainsKey (type))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ObjectMetadata data = new ObjectMetadata ();
|
||||||
|
|
||||||
|
if (type.GetInterface ("System.Collections.IDictionary") != null)
|
||||||
|
data.IsDictionary = true;
|
||||||
|
|
||||||
|
data.Properties = new Dictionary<string, PropertyMetadata> ();
|
||||||
|
|
||||||
|
foreach (PropertyInfo p_info in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
if (p_info.Name == "Item") {
|
||||||
|
ParameterInfo[] parameters = p_info.GetIndexParameters ();
|
||||||
|
|
||||||
|
if (parameters.Length == 1)
|
||||||
|
{
|
||||||
|
if (parameters[0].ParameterType == typeof(string))
|
||||||
|
data.ElementType = p_info.PropertyType;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parameters.Length > 1)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMetadata p_data = new PropertyMetadata ();
|
||||||
|
p_data.Info = p_info;
|
||||||
|
p_data.Type = p_info.PropertyType;
|
||||||
|
|
||||||
|
if (p_info.IsDefined(typeof(JsonPropertyName),true))
|
||||||
|
{
|
||||||
|
var att = (JsonPropertyName)p_info.GetCustomAttributes(typeof(JsonPropertyName), true)[0];
|
||||||
|
data.Properties.Add(att.Name, p_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.Properties.Add(p_info.Name, p_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FieldInfo f_info in type.GetFields(BindingFlags.Instance | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
PropertyMetadata p_data = new PropertyMetadata ();
|
||||||
|
p_data.Info = f_info;
|
||||||
|
p_data.IsField = true;
|
||||||
|
p_data.Type = f_info.FieldType;
|
||||||
|
|
||||||
|
if (f_info.IsDefined(typeof(JsonPropertyName), true))
|
||||||
|
{
|
||||||
|
var att = (JsonPropertyName)f_info.GetCustomAttributes(typeof(JsonPropertyName), true)[0];
|
||||||
|
data.Properties.Add(att.Name, p_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.Properties.Add(f_info.Name, p_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (object_metadata_lock) {
|
||||||
|
try {
|
||||||
|
object_metadata.Add (type, data);
|
||||||
|
} catch (ArgumentException) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddTypeProperties (Type type)
|
||||||
|
{
|
||||||
|
if (type_properties.ContainsKey (type))
|
||||||
|
return;
|
||||||
|
|
||||||
|
IList<PropertyMetadata> props = new List<PropertyMetadata> ();
|
||||||
|
|
||||||
|
foreach (PropertyInfo p_info in type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
if (p_info.Name == "Item")
|
||||||
|
{
|
||||||
|
if (p_info.GetIndexParameters().Length > 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyMetadata p_data = new PropertyMetadata();
|
||||||
|
p_data.Info = p_info;
|
||||||
|
p_data.IsField = false;
|
||||||
|
if (p_info.IsDefined(typeof(JsonPropertyName), true))
|
||||||
|
{
|
||||||
|
var att = (JsonPropertyName)p_info.GetCustomAttributes(typeof(JsonPropertyName), true)[0];
|
||||||
|
p_data.Name = att.Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p_data.Name = p_info.Name;
|
||||||
|
}
|
||||||
|
props.Add (p_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FieldInfo f_info in type.GetFields(BindingFlags.Instance | BindingFlags.Public))
|
||||||
|
{
|
||||||
|
PropertyMetadata p_data = new PropertyMetadata ();
|
||||||
|
p_data.Info = f_info;
|
||||||
|
p_data.IsField = true;
|
||||||
|
if (f_info.IsDefined(typeof(JsonPropertyName), true))
|
||||||
|
{
|
||||||
|
var att = (JsonPropertyName)f_info.GetCustomAttributes(typeof(JsonPropertyName), true)[0];
|
||||||
|
p_data.Name = att.Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p_data.Name = f_info.Name;
|
||||||
|
}
|
||||||
|
props.Add (p_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (type_properties_lock) {
|
||||||
|
try {
|
||||||
|
type_properties.Add (type, props);
|
||||||
|
} catch (ArgumentException) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodInfo GetConvOp (Type t1, Type t2)
|
||||||
|
{
|
||||||
|
lock (conv_ops_lock) {
|
||||||
|
if (! conv_ops.ContainsKey (t1))
|
||||||
|
conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conv_ops[t1].ContainsKey (t2))
|
||||||
|
return conv_ops[t1][t2];
|
||||||
|
|
||||||
|
MethodInfo op = t1.GetMethod (
|
||||||
|
"op_Implicit", new Type[] { t2 });
|
||||||
|
|
||||||
|
lock (conv_ops_lock) {
|
||||||
|
try {
|
||||||
|
conv_ops[t1].Add (t2, op);
|
||||||
|
} catch (ArgumentException) {
|
||||||
|
return conv_ops[t1][t2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object ReadValue (Type inst_type, JsonReader reader)
|
||||||
|
{
|
||||||
|
reader.Read ();
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.ArrayEnd)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.Null) {
|
||||||
|
|
||||||
|
if (! inst_type.IsClass)
|
||||||
|
throw new JsonException (String.Format (
|
||||||
|
"Can't assign null to an instance of type {0}",
|
||||||
|
inst_type));
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.Double ||
|
||||||
|
reader.Token == JsonToken.Int ||
|
||||||
|
reader.Token == JsonToken.Long ||
|
||||||
|
reader.Token == JsonToken.String ||
|
||||||
|
reader.Token == JsonToken.Boolean) {
|
||||||
|
|
||||||
|
Type json_type = reader.Value.GetType ();
|
||||||
|
|
||||||
|
if (inst_type.IsAssignableFrom (json_type))
|
||||||
|
return reader.Value;
|
||||||
|
|
||||||
|
// If there's a custom importer that fits, use it
|
||||||
|
if (custom_importers_table.ContainsKey (json_type) &&
|
||||||
|
custom_importers_table[json_type].ContainsKey (
|
||||||
|
inst_type)) {
|
||||||
|
|
||||||
|
ImporterFunc importer =
|
||||||
|
custom_importers_table[json_type][inst_type];
|
||||||
|
|
||||||
|
return importer (reader.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe there's a base importer that works
|
||||||
|
if (base_importers_table.ContainsKey (json_type) &&
|
||||||
|
base_importers_table[json_type].ContainsKey (
|
||||||
|
inst_type)) {
|
||||||
|
|
||||||
|
ImporterFunc importer =
|
||||||
|
base_importers_table[json_type][inst_type];
|
||||||
|
|
||||||
|
return importer (reader.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maybe it's an enum
|
||||||
|
if (inst_type.IsEnum)
|
||||||
|
return Enum.ToObject (inst_type, reader.Value);
|
||||||
|
|
||||||
|
// Try using an implicit conversion operator
|
||||||
|
MethodInfo conv_op = GetConvOp (inst_type, json_type);
|
||||||
|
|
||||||
|
if (conv_op != null)
|
||||||
|
return conv_op.Invoke (null,
|
||||||
|
new object[] { reader.Value });
|
||||||
|
|
||||||
|
// No luck
|
||||||
|
throw new JsonException (String.Format (
|
||||||
|
"Can't assign value '{0}' (type {1}) to type {2}",
|
||||||
|
reader.Value, json_type, inst_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
object instance = null;
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.ArrayStart) {
|
||||||
|
|
||||||
|
AddArrayMetadata (inst_type);
|
||||||
|
ArrayMetadata t_data = array_metadata[inst_type];
|
||||||
|
|
||||||
|
if (! t_data.IsArray && ! t_data.IsList)
|
||||||
|
throw new JsonException (String.Format (
|
||||||
|
"Type {0} can't act as an array",
|
||||||
|
inst_type));
|
||||||
|
|
||||||
|
IList list;
|
||||||
|
Type elem_type;
|
||||||
|
|
||||||
|
if (! t_data.IsArray) {
|
||||||
|
list = (IList) Activator.CreateInstance (inst_type);
|
||||||
|
elem_type = t_data.ElementType;
|
||||||
|
} else {
|
||||||
|
list = new ArrayList ();
|
||||||
|
elem_type = inst_type.GetElementType ();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
object item = ReadValue (elem_type, reader);
|
||||||
|
if (item == null && reader.Token == JsonToken.ArrayEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
list.Add (item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t_data.IsArray) {
|
||||||
|
int n = list.Count;
|
||||||
|
instance = Array.CreateInstance (elem_type, n);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
((Array) instance).SetValue (list[i], i);
|
||||||
|
} else
|
||||||
|
instance = list;
|
||||||
|
|
||||||
|
} else if (reader.Token == JsonToken.ObjectStart) {
|
||||||
|
|
||||||
|
AddObjectMetadata (inst_type);
|
||||||
|
ObjectMetadata t_data = object_metadata[inst_type];
|
||||||
|
|
||||||
|
instance = Activator.CreateInstance (inst_type);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
reader.Read ();
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.ObjectEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
string property = (string) reader.Value;
|
||||||
|
|
||||||
|
if (t_data.Properties.ContainsKey (property)) {
|
||||||
|
PropertyMetadata prop_data =
|
||||||
|
t_data.Properties[property];
|
||||||
|
|
||||||
|
if (prop_data.IsField) {
|
||||||
|
((FieldInfo) prop_data.Info).SetValue (
|
||||||
|
instance, ReadValue (prop_data.Type, reader));
|
||||||
|
} else {
|
||||||
|
PropertyInfo p_info =
|
||||||
|
(PropertyInfo) prop_data.Info;
|
||||||
|
|
||||||
|
if (p_info.CanWrite)
|
||||||
|
p_info.SetValue (
|
||||||
|
instance,
|
||||||
|
ReadValue (prop_data.Type, reader),
|
||||||
|
null);
|
||||||
|
else
|
||||||
|
ReadValue (prop_data.Type, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (! t_data.IsDictionary) {
|
||||||
|
|
||||||
|
if (! reader.SkipNonMembers) {
|
||||||
|
throw new JsonException (String.Format (
|
||||||
|
"The type {0} doesn't have the " +
|
||||||
|
"property '{1}'",
|
||||||
|
inst_type, property));
|
||||||
|
} else {
|
||||||
|
ReadSkip (reader);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
((IDictionary) instance).Add (
|
||||||
|
property, ReadValue (
|
||||||
|
t_data.ElementType, reader));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IJsonWrapper ReadValue (WrapperFactory factory,
|
||||||
|
JsonReader reader)
|
||||||
|
{
|
||||||
|
reader.Read ();
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.ArrayEnd ||
|
||||||
|
reader.Token == JsonToken.Null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
IJsonWrapper instance = factory ();
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.String) {
|
||||||
|
instance.SetString ((string) reader.Value);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.Double) {
|
||||||
|
instance.SetDouble ((double) reader.Value);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.Int) {
|
||||||
|
instance.SetInt ((int) reader.Value);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.Long) {
|
||||||
|
instance.SetLong ((long) reader.Value);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.Boolean) {
|
||||||
|
instance.SetBoolean ((bool) reader.Value);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.ArrayStart) {
|
||||||
|
instance.SetJsonType (JsonType.Array);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
IJsonWrapper item = ReadValue (factory, reader);
|
||||||
|
if (item == null && reader.Token == JsonToken.ArrayEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
((IList) instance).Add (item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reader.Token == JsonToken.ObjectStart) {
|
||||||
|
instance.SetJsonType (JsonType.Object);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
reader.Read ();
|
||||||
|
|
||||||
|
if (reader.Token == JsonToken.ObjectEnd)
|
||||||
|
break;
|
||||||
|
|
||||||
|
string property = (string) reader.Value;
|
||||||
|
|
||||||
|
((IDictionary) instance)[property] = ReadValue (
|
||||||
|
factory, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReadSkip (JsonReader reader)
|
||||||
|
{
|
||||||
|
ToWrapper (
|
||||||
|
delegate { return new JsonMockWrapper (); }, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterBaseExporters ()
|
||||||
|
{
|
||||||
|
base_exporters_table[typeof (byte)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToInt32 ((byte) obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (char)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToString ((char) obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (DateTime)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToString ((DateTime) obj,
|
||||||
|
datetime_format));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (decimal)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write ((decimal) obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (sbyte)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToInt32 ((sbyte) obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (short)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToInt32 ((short) obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (ushort)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToInt32 ((ushort) obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (uint)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write (Convert.ToUInt64 ((uint) obj));
|
||||||
|
};
|
||||||
|
|
||||||
|
base_exporters_table[typeof (ulong)] =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
writer.Write ((ulong) obj);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterBaseImporters ()
|
||||||
|
{
|
||||||
|
ImporterFunc importer;
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToByte ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (byte), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToUInt64 ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (ulong), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToSByte ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (sbyte), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToInt16 ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (short), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToUInt16 ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (ushort), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToUInt32 ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (uint), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToSingle ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (float), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToDouble ((int) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (int),
|
||||||
|
typeof (double), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToDecimal ((double) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (double),
|
||||||
|
typeof (decimal), importer);
|
||||||
|
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToUInt32 ((long) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (long),
|
||||||
|
typeof (uint), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToChar ((string) input);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (string),
|
||||||
|
typeof (char), importer);
|
||||||
|
|
||||||
|
importer = delegate (object input) {
|
||||||
|
return Convert.ToDateTime ((string) input, datetime_format);
|
||||||
|
};
|
||||||
|
RegisterImporter (base_importers_table, typeof (string),
|
||||||
|
typeof (DateTime), importer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterImporter (
|
||||||
|
IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
|
||||||
|
Type json_type, Type value_type, ImporterFunc importer)
|
||||||
|
{
|
||||||
|
if (! table.ContainsKey (json_type))
|
||||||
|
table.Add (json_type, new Dictionary<Type, ImporterFunc> ());
|
||||||
|
|
||||||
|
table[json_type][value_type] = importer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteValue (object obj, JsonWriter writer,
|
||||||
|
bool writer_is_private,
|
||||||
|
int depth)
|
||||||
|
{
|
||||||
|
if (depth > max_nesting_depth)
|
||||||
|
throw new JsonException (
|
||||||
|
String.Format ("Max allowed object depth reached while " +
|
||||||
|
"trying to export from type {0}",
|
||||||
|
obj.GetType ()));
|
||||||
|
|
||||||
|
if (obj == null) {
|
||||||
|
writer.Write (null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is IJsonWrapper) {
|
||||||
|
if (writer_is_private)
|
||||||
|
writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
|
||||||
|
else
|
||||||
|
((IJsonWrapper) obj).ToJson (writer);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is String) {
|
||||||
|
writer.Write ((string) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is Double) {
|
||||||
|
writer.Write ((double) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is Int32) {
|
||||||
|
writer.Write ((int) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is Boolean) {
|
||||||
|
writer.Write ((bool) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is Int64) {
|
||||||
|
writer.Write ((long) obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is Array) {
|
||||||
|
writer.WriteArrayStart ();
|
||||||
|
|
||||||
|
foreach (object elem in (Array) obj)
|
||||||
|
WriteValue (elem, writer, writer_is_private, depth + 1);
|
||||||
|
|
||||||
|
writer.WriteArrayEnd ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is IList) {
|
||||||
|
writer.WriteArrayStart ();
|
||||||
|
foreach (object elem in (IList) obj)
|
||||||
|
WriteValue (elem, writer, writer_is_private, depth + 1);
|
||||||
|
writer.WriteArrayEnd ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj is IDictionary) {
|
||||||
|
writer.WriteObjectStart ();
|
||||||
|
foreach (DictionaryEntry entry in (IDictionary) obj) {
|
||||||
|
writer.WritePropertyName ((string) entry.Key);
|
||||||
|
WriteValue (entry.Value, writer, writer_is_private,
|
||||||
|
depth + 1);
|
||||||
|
}
|
||||||
|
writer.WriteObjectEnd ();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type obj_type = obj.GetType ();
|
||||||
|
|
||||||
|
// See if there's a custom exporter for the object
|
||||||
|
if (custom_exporters_table.ContainsKey (obj_type)) {
|
||||||
|
ExporterFunc exporter = custom_exporters_table[obj_type];
|
||||||
|
exporter (obj, writer);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not, maybe there's a base exporter
|
||||||
|
if (base_exporters_table.ContainsKey (obj_type)) {
|
||||||
|
ExporterFunc exporter = base_exporters_table[obj_type];
|
||||||
|
exporter (obj, writer);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last option, let's see if it's an enum
|
||||||
|
if (obj is Enum) {
|
||||||
|
Type e_type = Enum.GetUnderlyingType (obj_type);
|
||||||
|
|
||||||
|
if (e_type == typeof (long)
|
||||||
|
|| e_type == typeof (uint)
|
||||||
|
|| e_type == typeof (ulong))
|
||||||
|
writer.Write ((ulong) obj);
|
||||||
|
else
|
||||||
|
writer.Write ((int) obj);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, so it looks like the input should be exported as an
|
||||||
|
// object
|
||||||
|
AddTypeProperties (obj_type);
|
||||||
|
IList<PropertyMetadata> props = type_properties[obj_type];
|
||||||
|
|
||||||
|
writer.WriteObjectStart ();
|
||||||
|
foreach (PropertyMetadata p_data in props) {
|
||||||
|
if (p_data.IsField) {
|
||||||
|
writer.WritePropertyName (p_data.Name);
|
||||||
|
WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
|
||||||
|
writer, writer_is_private, depth + 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PropertyInfo p_info = (PropertyInfo) p_data.Info;
|
||||||
|
|
||||||
|
if (p_info.CanRead) {
|
||||||
|
writer.WritePropertyName (p_data.Name);
|
||||||
|
WriteValue (p_info.GetValue (obj, null),
|
||||||
|
writer, writer_is_private, depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.WriteObjectEnd ();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
public static string ToJson (object obj)
|
||||||
|
{
|
||||||
|
lock (static_writer_lock) {
|
||||||
|
static_writer.Reset ();
|
||||||
|
|
||||||
|
WriteValue (obj, static_writer, true, 0);
|
||||||
|
|
||||||
|
return static_writer.ToString ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ToJson (object obj, JsonWriter writer)
|
||||||
|
{
|
||||||
|
WriteValue (obj, writer, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonData ToObject (JsonReader reader)
|
||||||
|
{
|
||||||
|
return (JsonData) ToWrapper (
|
||||||
|
delegate { return new JsonData (); }, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonData ToObject (TextReader reader)
|
||||||
|
{
|
||||||
|
JsonReader json_reader = new JsonReader (reader);
|
||||||
|
|
||||||
|
return (JsonData) ToWrapper (
|
||||||
|
delegate { return new JsonData (); }, json_reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonData ToObject (string json)
|
||||||
|
{
|
||||||
|
return (JsonData) ToWrapper (
|
||||||
|
delegate { return new JsonData (); }, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T ToObject<T> (JsonReader reader)
|
||||||
|
{
|
||||||
|
return (T) ReadValue (typeof (T), reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T ToObject<T> (TextReader reader)
|
||||||
|
{
|
||||||
|
JsonReader json_reader = new JsonReader (reader);
|
||||||
|
|
||||||
|
return (T) ReadValue (typeof (T), json_reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T ToObject<T> (string json)
|
||||||
|
{
|
||||||
|
JsonReader reader = new JsonReader (json);
|
||||||
|
|
||||||
|
return (T) ReadValue (typeof (T), reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static dynamic ToObject(JsonReader reader, Type type)
|
||||||
|
{
|
||||||
|
return ReadValue(type, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static dynamic ToObject(TextReader reader, Type type)
|
||||||
|
{
|
||||||
|
JsonReader json_reader = new JsonReader(reader);
|
||||||
|
return ReadValue(type, json_reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static dynamic ToObject(string json, Type type)
|
||||||
|
{
|
||||||
|
JsonReader json_reader = new JsonReader(json);
|
||||||
|
return ReadValue(type, json_reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IJsonWrapper ToWrapper (WrapperFactory factory,
|
||||||
|
JsonReader reader)
|
||||||
|
{
|
||||||
|
return ReadValue (factory, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IJsonWrapper ToWrapper (WrapperFactory factory,
|
||||||
|
string json)
|
||||||
|
{
|
||||||
|
JsonReader reader = new JsonReader (json);
|
||||||
|
|
||||||
|
return ReadValue (factory, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterExporter<T> (ExporterFunc<T> exporter)
|
||||||
|
{
|
||||||
|
ExporterFunc exporter_wrapper =
|
||||||
|
delegate (object obj, JsonWriter writer) {
|
||||||
|
exporter ((T) obj, writer);
|
||||||
|
};
|
||||||
|
|
||||||
|
custom_exporters_table[typeof (T)] = exporter_wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterImporter<TJson, TValue> (
|
||||||
|
ImporterFunc<TJson, TValue> importer)
|
||||||
|
{
|
||||||
|
ImporterFunc importer_wrapper =
|
||||||
|
delegate (object input) {
|
||||||
|
return importer ((TJson) input);
|
||||||
|
};
|
||||||
|
|
||||||
|
RegisterImporter (custom_importers_table, typeof (TJson),
|
||||||
|
typeof (TValue), importer_wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnregisterExporters ()
|
||||||
|
{
|
||||||
|
custom_exporters_table.Clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UnregisterImporters ()
|
||||||
|
{
|
||||||
|
custom_importers_table.Clear ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
KMCCC.Shared/LitJson/JsonMockWrapper.cs
Normal file
105
KMCCC.Shared/LitJson/JsonMockWrapper.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* JsonMockWrapper.cs
|
||||||
|
* Mock object implementing IJsonWrapper, to facilitate actions like
|
||||||
|
* skipping data more efficiently.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
public class JsonMockWrapper : IJsonWrapper
|
||||||
|
{
|
||||||
|
public bool IsArray { get { return false; } }
|
||||||
|
public bool IsBoolean { get { return false; } }
|
||||||
|
public bool IsDouble { get { return false; } }
|
||||||
|
public bool IsInt { get { return false; } }
|
||||||
|
public bool IsLong { get { return false; } }
|
||||||
|
public bool IsObject { get { return false; } }
|
||||||
|
public bool IsString { get { return false; } }
|
||||||
|
|
||||||
|
public bool GetBoolean () { return false; }
|
||||||
|
public double GetDouble () { return 0.0; }
|
||||||
|
public int GetInt () { return 0; }
|
||||||
|
public JsonType GetJsonType () { return JsonType.None; }
|
||||||
|
public long GetLong () { return 0L; }
|
||||||
|
public string GetString () { return ""; }
|
||||||
|
|
||||||
|
public void SetBoolean (bool val) {}
|
||||||
|
public void SetDouble (double val) {}
|
||||||
|
public void SetInt (int val) {}
|
||||||
|
public void SetJsonType (JsonType type) {}
|
||||||
|
public void SetLong (long val) {}
|
||||||
|
public void SetString (string val) {}
|
||||||
|
|
||||||
|
public string ToJson () { return ""; }
|
||||||
|
public void ToJson (JsonWriter writer) {}
|
||||||
|
|
||||||
|
|
||||||
|
bool IList.IsFixedSize { get { return true; } }
|
||||||
|
bool IList.IsReadOnly { get { return true; } }
|
||||||
|
|
||||||
|
object IList.this[int index] {
|
||||||
|
get { return null; }
|
||||||
|
set {}
|
||||||
|
}
|
||||||
|
|
||||||
|
int IList.Add (object value) { return 0; }
|
||||||
|
void IList.Clear () {}
|
||||||
|
bool IList.Contains (object value) { return false; }
|
||||||
|
int IList.IndexOf (object value) { return -1; }
|
||||||
|
void IList.Insert (int i, object v) {}
|
||||||
|
void IList.Remove (object value) {}
|
||||||
|
void IList.RemoveAt (int index) {}
|
||||||
|
|
||||||
|
|
||||||
|
int ICollection.Count { get { return 0; } }
|
||||||
|
bool ICollection.IsSynchronized { get { return false; } }
|
||||||
|
object ICollection.SyncRoot { get { return null; } }
|
||||||
|
|
||||||
|
void ICollection.CopyTo (Array array, int index) {}
|
||||||
|
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator () { return null; }
|
||||||
|
|
||||||
|
|
||||||
|
bool IDictionary.IsFixedSize { get { return true; } }
|
||||||
|
bool IDictionary.IsReadOnly { get { return true; } }
|
||||||
|
|
||||||
|
ICollection IDictionary.Keys { get { return null; } }
|
||||||
|
ICollection IDictionary.Values { get { return null; } }
|
||||||
|
|
||||||
|
object IDictionary.this[object key] {
|
||||||
|
get { return null; }
|
||||||
|
set {}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IDictionary.Add (object k, object v) {}
|
||||||
|
void IDictionary.Clear () {}
|
||||||
|
bool IDictionary.Contains (object key) { return false; }
|
||||||
|
void IDictionary.Remove (object key) {}
|
||||||
|
|
||||||
|
IDictionaryEnumerator IDictionary.GetEnumerator () { return null; }
|
||||||
|
|
||||||
|
|
||||||
|
object IOrderedDictionary.this[int idx] {
|
||||||
|
get { return null; }
|
||||||
|
set {}
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionaryEnumerator IOrderedDictionary.GetEnumerator () {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
void IOrderedDictionary.Insert (int i, object k, object v) {}
|
||||||
|
void IOrderedDictionary.RemoveAt (int i) {}
|
||||||
|
}
|
||||||
|
}
|
18
KMCCC.Shared/LitJson/JsonPropertyName.cs
Normal file
18
KMCCC.Shared/LitJson/JsonPropertyName.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
|
||||||
|
public class JsonPropertyName : Attribute
|
||||||
|
{
|
||||||
|
public String Name { get; private set; }
|
||||||
|
|
||||||
|
public JsonPropertyName(String name)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
464
KMCCC.Shared/LitJson/JsonReader.cs
Normal file
464
KMCCC.Shared/LitJson/JsonReader.cs
Normal file
@ -0,0 +1,464 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* JsonReader.cs
|
||||||
|
* Stream-like access to JSON text.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
public enum JsonToken
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
|
||||||
|
ObjectStart,
|
||||||
|
PropertyName,
|
||||||
|
ObjectEnd,
|
||||||
|
|
||||||
|
ArrayStart,
|
||||||
|
ArrayEnd,
|
||||||
|
|
||||||
|
Int,
|
||||||
|
Long,
|
||||||
|
Double,
|
||||||
|
|
||||||
|
String,
|
||||||
|
|
||||||
|
Boolean,
|
||||||
|
Null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class JsonReader
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private static IDictionary<int, IDictionary<int, int[]>> parse_table;
|
||||||
|
|
||||||
|
private Stack<int> automaton_stack;
|
||||||
|
private int current_input;
|
||||||
|
private int current_symbol;
|
||||||
|
private bool end_of_json;
|
||||||
|
private bool end_of_input;
|
||||||
|
private Lexer lexer;
|
||||||
|
private bool parser_in_string;
|
||||||
|
private bool parser_return;
|
||||||
|
private bool read_started;
|
||||||
|
private TextReader reader;
|
||||||
|
private bool reader_is_owned;
|
||||||
|
private bool skip_non_members;
|
||||||
|
private object token_value;
|
||||||
|
private JsonToken token;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Public Properties
|
||||||
|
public bool AllowComments {
|
||||||
|
get { return lexer.AllowComments; }
|
||||||
|
set { lexer.AllowComments = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AllowSingleQuotedStrings {
|
||||||
|
get { return lexer.AllowSingleQuotedStrings; }
|
||||||
|
set { lexer.AllowSingleQuotedStrings = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SkipNonMembers {
|
||||||
|
get { return skip_non_members; }
|
||||||
|
set { skip_non_members = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EndOfInput {
|
||||||
|
get { return end_of_input; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EndOfJson {
|
||||||
|
get { return end_of_json; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonToken Token {
|
||||||
|
get { return token; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Value {
|
||||||
|
get { return token_value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
static JsonReader ()
|
||||||
|
{
|
||||||
|
PopulateParseTable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonReader (string json_text) :
|
||||||
|
this (new StringReader (json_text), true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonReader (TextReader reader) :
|
||||||
|
this (reader, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonReader (TextReader reader, bool owned)
|
||||||
|
{
|
||||||
|
if (reader == null)
|
||||||
|
throw new ArgumentNullException ("reader");
|
||||||
|
|
||||||
|
parser_in_string = false;
|
||||||
|
parser_return = false;
|
||||||
|
|
||||||
|
read_started = false;
|
||||||
|
automaton_stack = new Stack<int> ();
|
||||||
|
automaton_stack.Push ((int) ParserToken.End);
|
||||||
|
automaton_stack.Push ((int) ParserToken.Text);
|
||||||
|
|
||||||
|
lexer = new Lexer (reader);
|
||||||
|
|
||||||
|
end_of_input = false;
|
||||||
|
end_of_json = false;
|
||||||
|
|
||||||
|
skip_non_members = true;
|
||||||
|
|
||||||
|
this.reader = reader;
|
||||||
|
reader_is_owned = owned;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Static Methods
|
||||||
|
private static void PopulateParseTable ()
|
||||||
|
{
|
||||||
|
// See section A.2. of the manual for details
|
||||||
|
parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.Array);
|
||||||
|
TableAddCol (ParserToken.Array, '[',
|
||||||
|
'[',
|
||||||
|
(int) ParserToken.ArrayPrime);
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.ArrayPrime);
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, '"',
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, '[',
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, ']',
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, '{',
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number,
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True,
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False,
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null,
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest,
|
||||||
|
']');
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.Object);
|
||||||
|
TableAddCol (ParserToken.Object, '{',
|
||||||
|
'{',
|
||||||
|
(int) ParserToken.ObjectPrime);
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.ObjectPrime);
|
||||||
|
TableAddCol (ParserToken.ObjectPrime, '"',
|
||||||
|
(int) ParserToken.Pair,
|
||||||
|
(int) ParserToken.PairRest,
|
||||||
|
'}');
|
||||||
|
TableAddCol (ParserToken.ObjectPrime, '}',
|
||||||
|
'}');
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.Pair);
|
||||||
|
TableAddCol (ParserToken.Pair, '"',
|
||||||
|
(int) ParserToken.String,
|
||||||
|
':',
|
||||||
|
(int) ParserToken.Value);
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.PairRest);
|
||||||
|
TableAddCol (ParserToken.PairRest, ',',
|
||||||
|
',',
|
||||||
|
(int) ParserToken.Pair,
|
||||||
|
(int) ParserToken.PairRest);
|
||||||
|
TableAddCol (ParserToken.PairRest, '}',
|
||||||
|
(int) ParserToken.Epsilon);
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.String);
|
||||||
|
TableAddCol (ParserToken.String, '"',
|
||||||
|
'"',
|
||||||
|
(int) ParserToken.CharSeq,
|
||||||
|
'"');
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.Text);
|
||||||
|
TableAddCol (ParserToken.Text, '[',
|
||||||
|
(int) ParserToken.Array);
|
||||||
|
TableAddCol (ParserToken.Text, '{',
|
||||||
|
(int) ParserToken.Object);
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.Value);
|
||||||
|
TableAddCol (ParserToken.Value, '"',
|
||||||
|
(int) ParserToken.String);
|
||||||
|
TableAddCol (ParserToken.Value, '[',
|
||||||
|
(int) ParserToken.Array);
|
||||||
|
TableAddCol (ParserToken.Value, '{',
|
||||||
|
(int) ParserToken.Object);
|
||||||
|
TableAddCol (ParserToken.Value, (int) ParserToken.Number,
|
||||||
|
(int) ParserToken.Number);
|
||||||
|
TableAddCol (ParserToken.Value, (int) ParserToken.True,
|
||||||
|
(int) ParserToken.True);
|
||||||
|
TableAddCol (ParserToken.Value, (int) ParserToken.False,
|
||||||
|
(int) ParserToken.False);
|
||||||
|
TableAddCol (ParserToken.Value, (int) ParserToken.Null,
|
||||||
|
(int) ParserToken.Null);
|
||||||
|
|
||||||
|
TableAddRow (ParserToken.ValueRest);
|
||||||
|
TableAddCol (ParserToken.ValueRest, ',',
|
||||||
|
',',
|
||||||
|
(int) ParserToken.Value,
|
||||||
|
(int) ParserToken.ValueRest);
|
||||||
|
TableAddCol (ParserToken.ValueRest, ']',
|
||||||
|
(int) ParserToken.Epsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TableAddCol (ParserToken row, int col,
|
||||||
|
params int[] symbols)
|
||||||
|
{
|
||||||
|
parse_table[(int) row].Add (col, symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TableAddRow (ParserToken rule)
|
||||||
|
{
|
||||||
|
parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
private void ProcessNumber (string number)
|
||||||
|
{
|
||||||
|
if (number.IndexOf ('.') != -1 ||
|
||||||
|
number.IndexOf ('e') != -1 ||
|
||||||
|
number.IndexOf ('E') != -1) {
|
||||||
|
|
||||||
|
double n_double;
|
||||||
|
if (Double.TryParse (number, out n_double)) {
|
||||||
|
token = JsonToken.Double;
|
||||||
|
token_value = n_double;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int n_int32;
|
||||||
|
if (Int32.TryParse (number, out n_int32)) {
|
||||||
|
token = JsonToken.Int;
|
||||||
|
token_value = n_int32;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long n_int64;
|
||||||
|
if (Int64.TryParse (number, out n_int64)) {
|
||||||
|
token = JsonToken.Long;
|
||||||
|
token_value = n_int64;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shouldn't happen, but just in case, return something
|
||||||
|
token = JsonToken.Int;
|
||||||
|
token_value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessSymbol ()
|
||||||
|
{
|
||||||
|
if (current_symbol == '[') {
|
||||||
|
token = JsonToken.ArrayStart;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == ']') {
|
||||||
|
token = JsonToken.ArrayEnd;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == '{') {
|
||||||
|
token = JsonToken.ObjectStart;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == '}') {
|
||||||
|
token = JsonToken.ObjectEnd;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == '"') {
|
||||||
|
if (parser_in_string) {
|
||||||
|
parser_in_string = false;
|
||||||
|
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (token == JsonToken.None)
|
||||||
|
token = JsonToken.String;
|
||||||
|
|
||||||
|
parser_in_string = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (current_symbol == (int) ParserToken.CharSeq) {
|
||||||
|
token_value = lexer.StringValue;
|
||||||
|
|
||||||
|
} else if (current_symbol == (int) ParserToken.False) {
|
||||||
|
token = JsonToken.Boolean;
|
||||||
|
token_value = false;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == (int) ParserToken.Null) {
|
||||||
|
token = JsonToken.Null;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == (int) ParserToken.Number) {
|
||||||
|
ProcessNumber (lexer.StringValue);
|
||||||
|
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
} else if (current_symbol == (int) ParserToken.Pair) {
|
||||||
|
token = JsonToken.PropertyName;
|
||||||
|
|
||||||
|
} else if (current_symbol == (int) ParserToken.True) {
|
||||||
|
token = JsonToken.Boolean;
|
||||||
|
token_value = true;
|
||||||
|
parser_return = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadToken ()
|
||||||
|
{
|
||||||
|
if (end_of_input)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lexer.NextToken ();
|
||||||
|
|
||||||
|
if (lexer.EndOfInput) {
|
||||||
|
Close ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_input = lexer.Token;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
public void Close ()
|
||||||
|
{
|
||||||
|
if (end_of_input)
|
||||||
|
return;
|
||||||
|
|
||||||
|
end_of_input = true;
|
||||||
|
end_of_json = true;
|
||||||
|
|
||||||
|
if (reader_is_owned)
|
||||||
|
reader.Close ();
|
||||||
|
|
||||||
|
reader = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Read ()
|
||||||
|
{
|
||||||
|
if (end_of_input)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (end_of_json) {
|
||||||
|
end_of_json = false;
|
||||||
|
automaton_stack.Clear ();
|
||||||
|
automaton_stack.Push ((int) ParserToken.End);
|
||||||
|
automaton_stack.Push ((int) ParserToken.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
parser_in_string = false;
|
||||||
|
parser_return = false;
|
||||||
|
|
||||||
|
token = JsonToken.None;
|
||||||
|
token_value = null;
|
||||||
|
|
||||||
|
if (! read_started) {
|
||||||
|
read_started = true;
|
||||||
|
|
||||||
|
if (! ReadToken ())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int[] entry_symbols;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (parser_return) {
|
||||||
|
if (automaton_stack.Peek () == (int) ParserToken.End)
|
||||||
|
end_of_json = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_symbol = automaton_stack.Pop ();
|
||||||
|
|
||||||
|
ProcessSymbol ();
|
||||||
|
|
||||||
|
if (current_symbol == current_input) {
|
||||||
|
if (! ReadToken ()) {
|
||||||
|
if (automaton_stack.Peek () != (int) ParserToken.End)
|
||||||
|
throw new JsonException (
|
||||||
|
"Input doesn't evaluate to proper JSON text");
|
||||||
|
|
||||||
|
if (parser_return)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
entry_symbols =
|
||||||
|
parse_table[current_symbol][current_input];
|
||||||
|
|
||||||
|
} catch (KeyNotFoundException e) {
|
||||||
|
throw new JsonException ((ParserToken) current_input, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry_symbols[0] == (int) ParserToken.Epsilon)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int i = entry_symbols.Length - 1; i >= 0; i--)
|
||||||
|
automaton_stack.Push (entry_symbols[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
462
KMCCC.Shared/LitJson/JsonWriter.cs
Normal file
462
KMCCC.Shared/LitJson/JsonWriter.cs
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* JsonWriter.cs
|
||||||
|
* Stream-like facility to output JSON text.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
internal enum Condition
|
||||||
|
{
|
||||||
|
InArray,
|
||||||
|
InObject,
|
||||||
|
NotAProperty,
|
||||||
|
Property,
|
||||||
|
Value
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class WriterContext
|
||||||
|
{
|
||||||
|
public int Count;
|
||||||
|
public bool InArray;
|
||||||
|
public bool InObject;
|
||||||
|
public bool ExpectingValue;
|
||||||
|
public int Padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JsonWriter
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private static NumberFormatInfo number_format;
|
||||||
|
|
||||||
|
private WriterContext context;
|
||||||
|
private Stack<WriterContext> ctx_stack;
|
||||||
|
private bool has_reached_end;
|
||||||
|
private char[] hex_seq;
|
||||||
|
private int indentation;
|
||||||
|
private int indent_value;
|
||||||
|
private StringBuilder inst_string_builder;
|
||||||
|
private bool pretty_print;
|
||||||
|
private bool validate;
|
||||||
|
private TextWriter writer;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public int IndentValue {
|
||||||
|
get { return indent_value; }
|
||||||
|
set {
|
||||||
|
indentation = (indentation / indent_value) * value;
|
||||||
|
indent_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PrettyPrint {
|
||||||
|
get { return pretty_print; }
|
||||||
|
set { pretty_print = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextWriter TextWriter {
|
||||||
|
get { return writer; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Validate {
|
||||||
|
get { return validate; }
|
||||||
|
set { validate = value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
static JsonWriter ()
|
||||||
|
{
|
||||||
|
number_format = NumberFormatInfo.InvariantInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonWriter ()
|
||||||
|
{
|
||||||
|
inst_string_builder = new StringBuilder ();
|
||||||
|
writer = new StringWriter (inst_string_builder);
|
||||||
|
|
||||||
|
Init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonWriter (StringBuilder sb) :
|
||||||
|
this (new StringWriter (sb))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonWriter (TextWriter writer)
|
||||||
|
{
|
||||||
|
if (writer == null)
|
||||||
|
throw new ArgumentNullException ("writer");
|
||||||
|
|
||||||
|
this.writer = writer;
|
||||||
|
|
||||||
|
Init ();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
private void DoValidation (Condition cond)
|
||||||
|
{
|
||||||
|
if (! context.ExpectingValue)
|
||||||
|
context.Count++;
|
||||||
|
|
||||||
|
if (! validate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (has_reached_end)
|
||||||
|
throw new JsonException (
|
||||||
|
"A complete JSON symbol has already been written");
|
||||||
|
|
||||||
|
switch (cond) {
|
||||||
|
case Condition.InArray:
|
||||||
|
if (! context.InArray)
|
||||||
|
throw new JsonException (
|
||||||
|
"Can't close an array here");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition.InObject:
|
||||||
|
if (! context.InObject || context.ExpectingValue)
|
||||||
|
throw new JsonException (
|
||||||
|
"Can't close an object here");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition.NotAProperty:
|
||||||
|
if (context.InObject && ! context.ExpectingValue)
|
||||||
|
throw new JsonException (
|
||||||
|
"Expected a property");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition.Property:
|
||||||
|
if (! context.InObject || context.ExpectingValue)
|
||||||
|
throw new JsonException (
|
||||||
|
"Can't add a property here");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition.Value:
|
||||||
|
if (! context.InArray &&
|
||||||
|
(! context.InObject || ! context.ExpectingValue))
|
||||||
|
throw new JsonException (
|
||||||
|
"Can't add a value here");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init ()
|
||||||
|
{
|
||||||
|
has_reached_end = false;
|
||||||
|
hex_seq = new char[4];
|
||||||
|
indentation = 0;
|
||||||
|
indent_value = 4;
|
||||||
|
pretty_print = false;
|
||||||
|
validate = true;
|
||||||
|
|
||||||
|
ctx_stack = new Stack<WriterContext> ();
|
||||||
|
context = new WriterContext ();
|
||||||
|
ctx_stack.Push (context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void IntToHex (int n, char[] hex)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
num = n % 16;
|
||||||
|
|
||||||
|
if (num < 10)
|
||||||
|
hex[3 - i] = (char) ('0' + num);
|
||||||
|
else
|
||||||
|
hex[3 - i] = (char) ('A' + (num - 10));
|
||||||
|
|
||||||
|
n >>= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Indent ()
|
||||||
|
{
|
||||||
|
if (pretty_print)
|
||||||
|
indentation += indent_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void Put (string str)
|
||||||
|
{
|
||||||
|
if (pretty_print && ! context.ExpectingValue)
|
||||||
|
for (int i = 0; i < indentation; i++)
|
||||||
|
writer.Write (' ');
|
||||||
|
|
||||||
|
writer.Write (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PutNewline ()
|
||||||
|
{
|
||||||
|
PutNewline (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PutNewline (bool add_comma)
|
||||||
|
{
|
||||||
|
if (add_comma && ! context.ExpectingValue &&
|
||||||
|
context.Count > 1)
|
||||||
|
writer.Write (',');
|
||||||
|
|
||||||
|
if (pretty_print && ! context.ExpectingValue)
|
||||||
|
writer.Write ('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PutString (string str)
|
||||||
|
{
|
||||||
|
Put (String.Empty);
|
||||||
|
|
||||||
|
writer.Write ('"');
|
||||||
|
|
||||||
|
int n = str.Length;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
switch (str[i]) {
|
||||||
|
case '\n':
|
||||||
|
writer.Write ("\\n");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\r':
|
||||||
|
writer.Write ("\\r");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
writer.Write ("\\t");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
writer.Write ('\\');
|
||||||
|
writer.Write (str[i]);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\f':
|
||||||
|
writer.Write ("\\f");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '\b':
|
||||||
|
writer.Write ("\\b");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int) str[i] >= 32 && (int) str[i] <= 126) {
|
||||||
|
writer.Write (str[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default, turn into a \uXXXX sequence
|
||||||
|
IntToHex ((int) str[i], hex_seq);
|
||||||
|
writer.Write ("\\u");
|
||||||
|
writer.Write (hex_seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.Write ('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Unindent ()
|
||||||
|
{
|
||||||
|
if (pretty_print)
|
||||||
|
indentation -= indent_value;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
public override string ToString ()
|
||||||
|
{
|
||||||
|
if (inst_string_builder == null)
|
||||||
|
return String.Empty;
|
||||||
|
|
||||||
|
return inst_string_builder.ToString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset ()
|
||||||
|
{
|
||||||
|
has_reached_end = false;
|
||||||
|
|
||||||
|
ctx_stack.Clear ();
|
||||||
|
context = new WriterContext ();
|
||||||
|
ctx_stack.Push (context);
|
||||||
|
|
||||||
|
if (inst_string_builder != null)
|
||||||
|
inst_string_builder.Remove (0, inst_string_builder.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (bool boolean)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put (boolean ? "true" : "false");
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (decimal number)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put (Convert.ToString (number, number_format));
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (double number)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
string str = Convert.ToString (number, number_format);
|
||||||
|
Put (str);
|
||||||
|
|
||||||
|
if (str.IndexOf ('.') == -1 &&
|
||||||
|
str.IndexOf ('E') == -1)
|
||||||
|
writer.Write (".0");
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (int number)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put (Convert.ToString (number, number_format));
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (long number)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put (Convert.ToString (number, number_format));
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (string str)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
if (str == null)
|
||||||
|
Put ("null");
|
||||||
|
else
|
||||||
|
PutString (str);
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write (ulong number)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Value);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put (Convert.ToString (number, number_format));
|
||||||
|
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteArrayEnd ()
|
||||||
|
{
|
||||||
|
DoValidation (Condition.InArray);
|
||||||
|
PutNewline (false);
|
||||||
|
|
||||||
|
ctx_stack.Pop ();
|
||||||
|
if (ctx_stack.Count == 1)
|
||||||
|
has_reached_end = true;
|
||||||
|
else {
|
||||||
|
context = ctx_stack.Peek ();
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unindent ();
|
||||||
|
Put ("]");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteArrayStart ()
|
||||||
|
{
|
||||||
|
DoValidation (Condition.NotAProperty);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put ("[");
|
||||||
|
|
||||||
|
context = new WriterContext ();
|
||||||
|
context.InArray = true;
|
||||||
|
ctx_stack.Push (context);
|
||||||
|
|
||||||
|
Indent ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteObjectEnd ()
|
||||||
|
{
|
||||||
|
DoValidation (Condition.InObject);
|
||||||
|
PutNewline (false);
|
||||||
|
|
||||||
|
ctx_stack.Pop ();
|
||||||
|
if (ctx_stack.Count == 1)
|
||||||
|
has_reached_end = true;
|
||||||
|
else {
|
||||||
|
context = ctx_stack.Peek ();
|
||||||
|
context.ExpectingValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unindent ();
|
||||||
|
Put ("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteObjectStart ()
|
||||||
|
{
|
||||||
|
DoValidation (Condition.NotAProperty);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
Put ("{");
|
||||||
|
|
||||||
|
context = new WriterContext ();
|
||||||
|
context.InObject = true;
|
||||||
|
ctx_stack.Push (context);
|
||||||
|
|
||||||
|
Indent ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WritePropertyName (string property_name)
|
||||||
|
{
|
||||||
|
DoValidation (Condition.Property);
|
||||||
|
PutNewline ();
|
||||||
|
|
||||||
|
PutString (property_name);
|
||||||
|
|
||||||
|
if (pretty_print) {
|
||||||
|
if (property_name.Length > context.Padding)
|
||||||
|
context.Padding = property_name.Length;
|
||||||
|
|
||||||
|
for (int i = context.Padding - property_name.Length;
|
||||||
|
i >= 0; i--)
|
||||||
|
writer.Write (' ');
|
||||||
|
|
||||||
|
writer.Write (": ");
|
||||||
|
} else
|
||||||
|
writer.Write (':');
|
||||||
|
|
||||||
|
context.ExpectingValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
912
KMCCC.Shared/LitJson/Lexer.cs
Normal file
912
KMCCC.Shared/LitJson/Lexer.cs
Normal file
@ -0,0 +1,912 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* Lexer.cs
|
||||||
|
* JSON lexer implementation based on a finite state machine.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
internal class FsmContext
|
||||||
|
{
|
||||||
|
public bool Return;
|
||||||
|
public int NextState;
|
||||||
|
public Lexer L;
|
||||||
|
public int StateStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal class Lexer
|
||||||
|
{
|
||||||
|
#region Fields
|
||||||
|
private delegate bool StateHandler (FsmContext ctx);
|
||||||
|
|
||||||
|
private static int[] fsm_return_table;
|
||||||
|
private static StateHandler[] fsm_handler_table;
|
||||||
|
|
||||||
|
private bool allow_comments;
|
||||||
|
private bool allow_single_quoted_strings;
|
||||||
|
private bool end_of_input;
|
||||||
|
private FsmContext fsm_context;
|
||||||
|
private int input_buffer;
|
||||||
|
private int input_char;
|
||||||
|
private TextReader reader;
|
||||||
|
private int state;
|
||||||
|
private StringBuilder string_buffer;
|
||||||
|
private string string_value;
|
||||||
|
private int token;
|
||||||
|
private int unichar;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public bool AllowComments {
|
||||||
|
get { return allow_comments; }
|
||||||
|
set { allow_comments = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AllowSingleQuotedStrings {
|
||||||
|
get { return allow_single_quoted_strings; }
|
||||||
|
set { allow_single_quoted_strings = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EndOfInput {
|
||||||
|
get { return end_of_input; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Token {
|
||||||
|
get { return token; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StringValue {
|
||||||
|
get { return string_value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
static Lexer ()
|
||||||
|
{
|
||||||
|
PopulateFsmTables ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Lexer (TextReader reader)
|
||||||
|
{
|
||||||
|
allow_comments = true;
|
||||||
|
allow_single_quoted_strings = true;
|
||||||
|
|
||||||
|
input_buffer = 0;
|
||||||
|
string_buffer = new StringBuilder (128);
|
||||||
|
state = 1;
|
||||||
|
end_of_input = false;
|
||||||
|
this.reader = reader;
|
||||||
|
|
||||||
|
fsm_context = new FsmContext ();
|
||||||
|
fsm_context.L = this;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Static Methods
|
||||||
|
private static int HexValue (int digit)
|
||||||
|
{
|
||||||
|
switch (digit) {
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
|
return 10;
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
return 11;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
case 'C':
|
||||||
|
return 12;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
case 'D':
|
||||||
|
return 13;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
return 14;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
return 15;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return digit - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PopulateFsmTables ()
|
||||||
|
{
|
||||||
|
// See section A.1. of the manual for details of the finite
|
||||||
|
// state machine.
|
||||||
|
fsm_handler_table = new StateHandler[28] {
|
||||||
|
State1,
|
||||||
|
State2,
|
||||||
|
State3,
|
||||||
|
State4,
|
||||||
|
State5,
|
||||||
|
State6,
|
||||||
|
State7,
|
||||||
|
State8,
|
||||||
|
State9,
|
||||||
|
State10,
|
||||||
|
State11,
|
||||||
|
State12,
|
||||||
|
State13,
|
||||||
|
State14,
|
||||||
|
State15,
|
||||||
|
State16,
|
||||||
|
State17,
|
||||||
|
State18,
|
||||||
|
State19,
|
||||||
|
State20,
|
||||||
|
State21,
|
||||||
|
State22,
|
||||||
|
State23,
|
||||||
|
State24,
|
||||||
|
State25,
|
||||||
|
State26,
|
||||||
|
State27,
|
||||||
|
State28
|
||||||
|
};
|
||||||
|
|
||||||
|
fsm_return_table = new int[28] {
|
||||||
|
(int) ParserToken.Char,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.Number,
|
||||||
|
(int) ParserToken.Number,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.Number,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.Number,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.True,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.False,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.Null,
|
||||||
|
(int) ParserToken.CharSeq,
|
||||||
|
(int) ParserToken.Char,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
(int) ParserToken.CharSeq,
|
||||||
|
(int) ParserToken.Char,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char ProcessEscChar (int esc_char)
|
||||||
|
{
|
||||||
|
switch (esc_char) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
return Convert.ToChar (esc_char);
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
return '\n';
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
return '\t';
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
return '\r';
|
||||||
|
|
||||||
|
case 'b':
|
||||||
|
return '\b';
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
return '\f';
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unreachable
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State1 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char == ' ' ||
|
||||||
|
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 3;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '"':
|
||||||
|
ctx.NextState = 19;
|
||||||
|
ctx.Return = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case ',':
|
||||||
|
case ':':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
ctx.NextState = 1;
|
||||||
|
ctx.Return = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 2;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '0':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 4;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
ctx.NextState = 12;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
ctx.NextState = 16;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
ctx.NextState = 9;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '\'':
|
||||||
|
if (! ctx.L.allow_single_quoted_strings)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ctx.L.input_char = '"';
|
||||||
|
ctx.NextState = 23;
|
||||||
|
ctx.Return = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
if (! ctx.L.allow_comments)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ctx.NextState = 25;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State2 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 3;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '0':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 4;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State3 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.L.input_char == ' ' ||
|
||||||
|
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case ',':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
ctx.L.UngetChar ();
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 5;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 7;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State4 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
if (ctx.L.input_char == ' ' ||
|
||||||
|
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case ',':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
ctx.L.UngetChar ();
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 5;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 7;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State5 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 6;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State6 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.L.input_char == ' ' ||
|
||||||
|
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case ',':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
ctx.L.UngetChar ();
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 7;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State7 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
ctx.NextState = 8;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State8 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctx.L.input_char == ' ' ||
|
||||||
|
ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') {
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case ',':
|
||||||
|
case ']':
|
||||||
|
case '}':
|
||||||
|
ctx.L.UngetChar ();
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State9 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'r':
|
||||||
|
ctx.NextState = 10;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State10 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'u':
|
||||||
|
ctx.NextState = 11;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State11 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'e':
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State12 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'a':
|
||||||
|
ctx.NextState = 13;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State13 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'l':
|
||||||
|
ctx.NextState = 14;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State14 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 's':
|
||||||
|
ctx.NextState = 15;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State15 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'e':
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State16 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'u':
|
||||||
|
ctx.NextState = 17;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State17 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'l':
|
||||||
|
ctx.NextState = 18;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State18 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'l':
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State19 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '"':
|
||||||
|
ctx.L.UngetChar ();
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 20;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
ctx.StateStack = 19;
|
||||||
|
ctx.NextState = 21;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State20 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '"':
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State21 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case 'u':
|
||||||
|
ctx.NextState = 22;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case '/':
|
||||||
|
case '\\':
|
||||||
|
case 'b':
|
||||||
|
case 'f':
|
||||||
|
case 'n':
|
||||||
|
case 'r':
|
||||||
|
case 't':
|
||||||
|
ctx.L.string_buffer.Append (
|
||||||
|
ProcessEscChar (ctx.L.input_char));
|
||||||
|
ctx.NextState = ctx.StateStack;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State22 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
int mult = 4096;
|
||||||
|
|
||||||
|
ctx.L.unichar = 0;
|
||||||
|
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
|
||||||
|
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
|
||||||
|
ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
|
||||||
|
ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') {
|
||||||
|
|
||||||
|
ctx.L.unichar += HexValue (ctx.L.input_char) * mult;
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
mult /= 16;
|
||||||
|
|
||||||
|
if (counter == 4) {
|
||||||
|
ctx.L.string_buffer.Append (
|
||||||
|
Convert.ToChar (ctx.L.unichar));
|
||||||
|
ctx.NextState = ctx.StateStack;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State23 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '\'':
|
||||||
|
ctx.L.UngetChar ();
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 24;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
ctx.StateStack = 23;
|
||||||
|
ctx.NextState = 21;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State24 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '\'':
|
||||||
|
ctx.L.input_char = '"';
|
||||||
|
ctx.Return = true;
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State25 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
ctx.L.GetChar ();
|
||||||
|
|
||||||
|
switch (ctx.L.input_char) {
|
||||||
|
case '*':
|
||||||
|
ctx.NextState = 27;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '/':
|
||||||
|
ctx.NextState = 26;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State26 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char == '\n') {
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State27 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char == '*') {
|
||||||
|
ctx.NextState = 28;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool State28 (FsmContext ctx)
|
||||||
|
{
|
||||||
|
while (ctx.L.GetChar ()) {
|
||||||
|
if (ctx.L.input_char == '*')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (ctx.L.input_char == '/') {
|
||||||
|
ctx.NextState = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.NextState = 27;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
private bool GetChar ()
|
||||||
|
{
|
||||||
|
if ((input_char = NextChar ()) != -1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
end_of_input = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int NextChar ()
|
||||||
|
{
|
||||||
|
if (input_buffer != 0) {
|
||||||
|
int tmp = input_buffer;
|
||||||
|
input_buffer = 0;
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reader.Read ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NextToken ()
|
||||||
|
{
|
||||||
|
StateHandler handler;
|
||||||
|
fsm_context.Return = false;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
handler = fsm_handler_table[state - 1];
|
||||||
|
|
||||||
|
if (! handler (fsm_context))
|
||||||
|
throw new JsonException (input_char);
|
||||||
|
|
||||||
|
if (end_of_input)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (fsm_context.Return) {
|
||||||
|
string_value = string_buffer.ToString ();
|
||||||
|
string_buffer.Remove (0, string_buffer.Length);
|
||||||
|
token = fsm_return_table[state - 1];
|
||||||
|
|
||||||
|
if (token == (int) ParserToken.Char)
|
||||||
|
token = input_char;
|
||||||
|
|
||||||
|
state = fsm_context.NextState;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = fsm_context.NextState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UngetChar ()
|
||||||
|
{
|
||||||
|
input_buffer = input_char;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
KMCCC.Shared/LitJson/ParserToken.cs
Normal file
44
KMCCC.Shared/LitJson/ParserToken.cs
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#region Header
|
||||||
|
/**
|
||||||
|
* ParserToken.cs
|
||||||
|
* Internal representation of the tokens used by the lexer and the parser.
|
||||||
|
*
|
||||||
|
* The authors disclaim copyright to this source code. For more details, see
|
||||||
|
* the COPYING file included with this distribution.
|
||||||
|
**/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
namespace LitJson
|
||||||
|
{
|
||||||
|
internal enum ParserToken
|
||||||
|
{
|
||||||
|
// Lexer tokens (see section A.1.1. of the manual)
|
||||||
|
None = System.Char.MaxValue + 1,
|
||||||
|
Number,
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
Null,
|
||||||
|
CharSeq,
|
||||||
|
// Single char
|
||||||
|
Char,
|
||||||
|
|
||||||
|
// Parser Rules (see section A.2.1 of the manual)
|
||||||
|
Text,
|
||||||
|
Object,
|
||||||
|
ObjectPrime,
|
||||||
|
Pair,
|
||||||
|
PairRest,
|
||||||
|
Array,
|
||||||
|
ArrayPrime,
|
||||||
|
Value,
|
||||||
|
ValueRest,
|
||||||
|
String,
|
||||||
|
|
||||||
|
// End of input
|
||||||
|
End,
|
||||||
|
|
||||||
|
// The empty rule
|
||||||
|
Epsilon
|
||||||
|
}
|
||||||
|
}
|
85
KMCCC.Shared/Modules/JVersion/JVersion.cs
Normal file
85
KMCCC.Shared/Modules/JVersion/JVersion.cs
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
namespace KMCCC.Modules.JVersion
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LitJson;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用来Json的实体类
|
||||||
|
/// </summary>
|
||||||
|
public class JVersion
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("time")]
|
||||||
|
public DateTime Time { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("releaseTime")]
|
||||||
|
public DateTime ReleaseTime { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("type")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("minecraftArguments")]
|
||||||
|
public string MinecraftArguments { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("minimumLauncherVersion")]
|
||||||
|
public int MinimumLauncherVersion { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("libraries")]
|
||||||
|
public List<JLibrary> Libraries { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("mainClass")]
|
||||||
|
public string MainClass { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("assets")]
|
||||||
|
public string Assets { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("inheritsFrom")]
|
||||||
|
public string InheritsVersion { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("jar")]
|
||||||
|
public string JarId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JLibrary
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("natives")]
|
||||||
|
public Dictionary<string, string> Natives { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("rules")]
|
||||||
|
public List<JRule> Rules { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("extract")]
|
||||||
|
public JExtract Extract { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JRule
|
||||||
|
{
|
||||||
|
[JsonPropertyName("action")]
|
||||||
|
public string Action { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("os")]
|
||||||
|
public JOperatingSystem OS { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JOperatingSystem
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class JExtract
|
||||||
|
{
|
||||||
|
[JsonPropertyName("exclude")]
|
||||||
|
public List<string> Exculde { get; set; }
|
||||||
|
}
|
||||||
|
}
|
239
KMCCC.Shared/Modules/JVersion/JVersionLocator.cs
Normal file
239
KMCCC.Shared/Modules/JVersion/JVersionLocator.cs
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
namespace KMCCC.Modules.JVersion
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Launcher;
|
||||||
|
using LitJson;
|
||||||
|
using Tools;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认的版本定位器
|
||||||
|
/// </summary>
|
||||||
|
public class JVersionLocator : IVersionLocator
|
||||||
|
{
|
||||||
|
private readonly HashSet<string> _locatingVersion;
|
||||||
|
|
||||||
|
private readonly Dictionary<string, Version> _versions;
|
||||||
|
|
||||||
|
public JVersionLocator()
|
||||||
|
{
|
||||||
|
_versions = new Dictionary<string, Version>();
|
||||||
|
_locatingVersion = new HashSet<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GameRootPath { get; set; }
|
||||||
|
|
||||||
|
private LauncherCore _core;
|
||||||
|
|
||||||
|
public LauncherCore Core
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
GameRootPath = value.GameRootPath;
|
||||||
|
_core = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version Locate(string id)
|
||||||
|
{
|
||||||
|
lock (_locatingVersion)
|
||||||
|
{
|
||||||
|
return GetVersionInternal(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Version> GetAllVersions()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lock (_locatingVersion)
|
||||||
|
{
|
||||||
|
return new DirectoryInfo(GameRootPath + @"\versions").EnumerateDirectories()
|
||||||
|
.Select(dir => GetVersionInternal(dir.Name)).Where(item => item != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new Version[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取Version信息,当出现错误时会返回null
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">版本id</param>
|
||||||
|
/// <returns>Version的信息</returns>
|
||||||
|
internal Version GetVersionInternal(string id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_locatingVersion.Contains(id))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
_locatingVersion.Add(id);
|
||||||
|
|
||||||
|
Version version;
|
||||||
|
if (_versions.TryGetValue(id, out version))
|
||||||
|
{
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
var jver = LoadVersion(_core.GetVersionJsonPath(id));
|
||||||
|
if (jver == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
version = new Version();
|
||||||
|
if (string.IsNullOrWhiteSpace(jver.Id))
|
||||||
|
{
|
||||||
|
jver.Id = id;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(jver.MinecraftArguments))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(jver.MainClass))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(jver.Assets))
|
||||||
|
{
|
||||||
|
jver.Assets = "legacy";
|
||||||
|
}
|
||||||
|
if (jver.Libraries == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
version.Id = jver.Id;
|
||||||
|
version.MinecraftArguments = jver.MinecraftArguments;
|
||||||
|
version.Assets = jver.Assets;
|
||||||
|
version.MainClass = jver.MainClass;
|
||||||
|
version.JarId = jver.JarId;
|
||||||
|
version.Libraries = new List<Library>();
|
||||||
|
version.Natives = new List<Native>();
|
||||||
|
foreach (var lib in jver.Libraries)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(lib.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var names = lib.Name.Split(':');
|
||||||
|
if (names.Length != 3)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lib.Natives == null)
|
||||||
|
{
|
||||||
|
if (!IfAllowed(lib.Rules))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
version.Libraries.Add(new Library
|
||||||
|
{
|
||||||
|
NS = names[0],
|
||||||
|
Name = names[1],
|
||||||
|
Version = names[2]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!IfAllowed(lib.Rules))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var native = new Native
|
||||||
|
{
|
||||||
|
NS = names[0],
|
||||||
|
Name = names[1],
|
||||||
|
Version = names[2],
|
||||||
|
NativeSuffix = lib.Natives["windows"].Replace("${arch}", SystemTools.GetArch())
|
||||||
|
};
|
||||||
|
version.Natives.Add(native);
|
||||||
|
if (lib.Extract != null)
|
||||||
|
{
|
||||||
|
native.Options = new UnzipOptions {Exclude = lib.Extract.Exculde};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jver.InheritsVersion != null)
|
||||||
|
{
|
||||||
|
var target = GetVersionInternal(jver.InheritsVersion);
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
version.Assets = version.Assets ?? target.Assets;
|
||||||
|
version.JarId = version.JarId ?? target.JarId;
|
||||||
|
version.MainClass = version.MainClass ?? target.MainClass;
|
||||||
|
version.MinecraftArguments = version.MinecraftArguments ?? target.MinecraftArguments;
|
||||||
|
version.Natives.AddRange(target.Natives);
|
||||||
|
version.Libraries.AddRange(target.Libraries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
version.JarId = version.JarId ?? version.Id;
|
||||||
|
_versions.Add(version.Id, version);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_locatingVersion.Remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JVersion LoadVersion(string jsonPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return JsonMapper.ToObject<JVersion>(File.ReadAllText(jsonPath));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断一系列规则后是否启用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rules">规则们</param>
|
||||||
|
/// <returns>是否启用</returns>
|
||||||
|
public bool IfAllowed(List<JRule> rules)
|
||||||
|
{
|
||||||
|
if (rules == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (rules.Count == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var allowed = false;
|
||||||
|
foreach (var rule in rules)
|
||||||
|
{
|
||||||
|
if (rule.OS == null)
|
||||||
|
{
|
||||||
|
allowed = rule.Action == "allow";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rule.OS.Name == "windows")
|
||||||
|
{
|
||||||
|
allowed = rule.Action == "allow";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
351
KMCCC.Shared/Modules/Yggdrasil/YggdrasilClient.cs
Normal file
351
KMCCC.Shared/Modules/Yggdrasil/YggdrasilClient.cs
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
namespace KMCCC.Modules.Yggdrasil
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LitJson;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Yggdrasil(正版验证)客户端
|
||||||
|
/// </summary>
|
||||||
|
public class YggdrasilClient
|
||||||
|
{
|
||||||
|
public const string MojnagAuthServer = @"https://authserver.mojang.com";
|
||||||
|
public const string Auth_Authentication = MojnagAuthServer + "/authenticate";
|
||||||
|
public const string Auth_Refresh = MojnagAuthServer + "/refresh";
|
||||||
|
private readonly object _locker = new object();
|
||||||
|
|
||||||
|
public YggdrasilClient() : this(Guid.NewGuid())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public YggdrasilClient(Guid clientToken)
|
||||||
|
{
|
||||||
|
ClientToken = clientToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ClientToken { get; private set; }
|
||||||
|
public Guid AccessToken { get; private set; }
|
||||||
|
public Guid UUID { get; private set; }
|
||||||
|
public string DisplayName { get; private set; }
|
||||||
|
public string Properties { get; private set; }
|
||||||
|
public string AccountType { get; private set; }
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
AccessToken = Guid.Empty;
|
||||||
|
UUID = Guid.Empty;
|
||||||
|
DisplayName = string.Empty;
|
||||||
|
Properties = string.Empty;
|
||||||
|
AccountType = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFomrResponse(AuthenticationResponse response)
|
||||||
|
{
|
||||||
|
AccessToken = Guid.Parse(response.AccessToken);
|
||||||
|
if (response.User != null)
|
||||||
|
{
|
||||||
|
AccountType = response.User.Legacy ? "Legacy" : "Mojang";
|
||||||
|
Properties = response.User.Properties != null
|
||||||
|
? response.User.Properties.ToJson()
|
||||||
|
: "{}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AccountType = "Mojang";
|
||||||
|
Properties = "{}";
|
||||||
|
}
|
||||||
|
DisplayName = response.SelectedProfile.Name;
|
||||||
|
UUID = Guid.Parse(response.SelectedProfile.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Refresh
|
||||||
|
|
||||||
|
public bool Refresh(bool twitchEnabled = true)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wc = new WebClient();
|
||||||
|
var requestBody = JsonMapper.ToJson(new RefreshRequest
|
||||||
|
{
|
||||||
|
Agent = Agent.Minecraft,
|
||||||
|
AccessToken = AccessToken.ToString("N"),
|
||||||
|
RequestUser = twitchEnabled,
|
||||||
|
ClientToken = ClientToken.ToString("N")
|
||||||
|
});
|
||||||
|
var responseBody = wc.UploadString(new Uri(Auth_Refresh), requestBody);
|
||||||
|
var response = JsonMapper.ToObject<AuthenticationResponse>(responseBody);
|
||||||
|
if (response.AccessToken == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (response.SelectedProfile == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UpdateFomrResponse(response);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Refresh(Guid accessToken, bool twitchEnabled = true)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wc = new WebClient();
|
||||||
|
var requestBody = JsonMapper.ToJson(new RefreshRequest
|
||||||
|
{
|
||||||
|
Agent = Agent.Minecraft,
|
||||||
|
AccessToken = accessToken.ToString("N"),
|
||||||
|
RequestUser = twitchEnabled,
|
||||||
|
ClientToken = ClientToken.ToString("N")
|
||||||
|
});
|
||||||
|
var responseBody = wc.UploadString(new Uri(Auth_Refresh), requestBody);
|
||||||
|
var response = JsonMapper.ToObject<AuthenticationResponse>(responseBody);
|
||||||
|
if (response.AccessToken == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (response.SelectedProfile == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UpdateFomrResponse(response);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Authenticate
|
||||||
|
|
||||||
|
public bool Authenticate(string email, string password, bool twitchEnabled = true)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wc = new WebClient();
|
||||||
|
var requestBody = JsonMapper.ToJson(new AuthenticationRequest
|
||||||
|
{
|
||||||
|
Agent = Agent.Minecraft,
|
||||||
|
Email = email,
|
||||||
|
Password = password,
|
||||||
|
RequestUser = twitchEnabled,
|
||||||
|
ClientToken = ClientToken.ToString("N")
|
||||||
|
});
|
||||||
|
var responseBody = wc.UploadString(new Uri(Auth_Authentication), requestBody);
|
||||||
|
var response = JsonMapper.ToObject<AuthenticationResponse>(responseBody);
|
||||||
|
if (response.AccessToken == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (response.SelectedProfile == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UpdateFomrResponse(response);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> AuthenticateAsync(string email, string password, bool twitchEnabled = true, CancellationToken token = default(CancellationToken))
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
var task = new TaskCompletionSource<bool>(token);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var wc = new WebClient();
|
||||||
|
var requestBody = JsonMapper.ToJson(new AuthenticationRequest
|
||||||
|
{
|
||||||
|
Agent = Agent.Minecraft,
|
||||||
|
Email = email,
|
||||||
|
Password = password,
|
||||||
|
RequestUser = twitchEnabled,
|
||||||
|
ClientToken = ClientToken.ToString("N")
|
||||||
|
});
|
||||||
|
wc.UploadStringCompleted += (sender, e) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (e.Error != null)
|
||||||
|
{
|
||||||
|
task.SetException(e.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var response = JsonMapper.ToObject<AuthenticationResponse>(e.Result);
|
||||||
|
if ((response.AccessToken == null) || (response.SelectedProfile == null))
|
||||||
|
{
|
||||||
|
task.SetResult(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UpdateFomrResponse(response);
|
||||||
|
task.SetResult(true);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
task.SetException(exception);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
wc.UploadStringAsync(new Uri(Auth_Authentication), requestBody);
|
||||||
|
return task.Task;
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
task.SetException(exception);
|
||||||
|
return task.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Request & Response
|
||||||
|
|
||||||
|
public class RefreshRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("agent")]
|
||||||
|
public Agent Agent { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("accessToken")]
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("requestUser")]
|
||||||
|
public bool RequestUser { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("clientToken")]
|
||||||
|
public string ClientToken { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthenticationRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("agent")]
|
||||||
|
public Agent Agent { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("password")]
|
||||||
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("requestUser")]
|
||||||
|
public bool RequestUser { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("clientToken")]
|
||||||
|
public string ClientToken { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AuthenticationResponse
|
||||||
|
{
|
||||||
|
[JsonPropertyName("clientToken")]
|
||||||
|
public string ClientToken { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("accessToken")]
|
||||||
|
public string AccessToken { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("availableProfiles")]
|
||||||
|
public List<GameProfile> AvailableProfiles { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("selectedProfile")]
|
||||||
|
public GameProfile SelectedProfile { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("user")]
|
||||||
|
public User User { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("error")]
|
||||||
|
public string Error { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("errorMessage")]
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("cause")]
|
||||||
|
public string Cause { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public class Agent
|
||||||
|
{
|
||||||
|
public static readonly Agent Minecraft = new Agent {Name = "Minecraft", Version = 1};
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("version")]
|
||||||
|
public int Version { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("properties")]
|
||||||
|
public List<Property> Properties { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("legacy")]
|
||||||
|
public bool Legacy { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Property
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("value")]
|
||||||
|
public string Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GameProfile
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class Extensions
|
||||||
|
{
|
||||||
|
internal static string ToJson(this List<Property> properties)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder().Append('{');
|
||||||
|
foreach (var item in properties)
|
||||||
|
{
|
||||||
|
sb.Append('\"').Append(item.Name).Append("\":[\"").Append(item.Value).Append("\"]");
|
||||||
|
}
|
||||||
|
return sb.Append("}").ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
KMCCC.Shared/Properties/AssemblyInfo.cs
Normal file
36
KMCCC.Shared/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// 有关程序集的常规信息通过以下
|
||||||
|
// 特性集控制。更改这些特性值可修改
|
||||||
|
// 与程序集关联的信息。
|
||||||
|
[assembly: AssemblyTitle("KMCCC.Shared1")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("Microsoft")]
|
||||||
|
[assembly: AssemblyProduct("KMCCC.Shared1")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// 将 ComVisible 设置为 false 使此程序集中的类型
|
||||||
|
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
|
||||||
|
// 则将该类型上的 ComVisible 特性设置为 true。
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
|
||||||
|
[assembly: Guid("d0579b0a-ee5b-40a1-991b-43a418097a09")]
|
||||||
|
|
||||||
|
// 程序集的版本信息由下面四个值组成:
|
||||||
|
//
|
||||||
|
// 主版本
|
||||||
|
// 次版本
|
||||||
|
// 生成号
|
||||||
|
// 修订号
|
||||||
|
//
|
||||||
|
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
|
||||||
|
// 方法是按如下所示使用“*”:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
76
KMCCC.Shared/Tools/SystemTools.cs
Normal file
76
KMCCC.Shared/Tools/SystemTools.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
namespace KMCCC.Tools
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.VisualBasic.Devices;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public class SystemTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 从注册表中查找可能的javaw.exe位置
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>JAVA地址列表</returns>
|
||||||
|
public static IEnumerable<string> FindJava()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var rootReg = Registry.LocalMachine.OpenSubKey("SOFTWARE");
|
||||||
|
return rootReg == null
|
||||||
|
? new string[0]
|
||||||
|
: FindJavaInternal(rootReg).Union(FindJavaInternal(rootReg.OpenSubKey("Wow6432Node")));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<string> FindJavaInternal(RegistryKey registry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var registryKey = registry.OpenSubKey("JavaSoft");
|
||||||
|
if ((registryKey == null) || ((registry = registryKey.OpenSubKey("Java Runtime Environment")) == null)) return new string[0];
|
||||||
|
return (from ver in registry.GetSubKeyNames()
|
||||||
|
select registry.OpenSubKey(ver)
|
||||||
|
into command
|
||||||
|
where command != null
|
||||||
|
select command.GetValue("JavaHome")
|
||||||
|
into javaHomes
|
||||||
|
where javaHomes != null
|
||||||
|
select javaHomes.ToString()
|
||||||
|
into str
|
||||||
|
where !String.IsNullOrWhiteSpace(str)
|
||||||
|
select str + @"\bin\javaw.exe");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 取物理内存
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>物理内存</returns>
|
||||||
|
public static ulong GetTotalMemory()
|
||||||
|
{
|
||||||
|
return new Computer().Info.TotalPhysicalMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取x86 or x64
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>32 or 64</returns>
|
||||||
|
public static string GetArch()
|
||||||
|
{
|
||||||
|
return Environment.Is64BitOperatingSystem ? "64" : "32";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
KMCCC.Shared/Tools/UsefulTools.cs
Normal file
52
KMCCC.Shared/Tools/UsefulTools.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
namespace KMCCC.Tools
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 有用的东西
|
||||||
|
/// </summary>
|
||||||
|
public static class UsefulTools
|
||||||
|
{
|
||||||
|
public static string DoReplace(this string source, IDictionary<string, string> dic)
|
||||||
|
{
|
||||||
|
return dic.Aggregate(source, (current, pair) => current.Replace("${" + pair.Key + "}", pair.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GoString(this Guid guid)
|
||||||
|
{
|
||||||
|
return guid.ToString().Replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Dircopy(string source, string target)
|
||||||
|
{
|
||||||
|
var sourceDir = new DirectoryInfo(source);
|
||||||
|
if (!Directory.Exists(target))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(target);
|
||||||
|
}
|
||||||
|
foreach (var file in sourceDir.GetFiles())
|
||||||
|
{
|
||||||
|
File.Copy(file.FullName, target + "\\" + file.Name, true);
|
||||||
|
}
|
||||||
|
foreach (var subdir in sourceDir.GetDirectories())
|
||||||
|
{
|
||||||
|
Dircopy(subdir.FullName, target + "\\" + subdir.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
public static string Print(this string str)
|
||||||
|
{
|
||||||
|
Console.WriteLine(str);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
227
KMCCC.Shared/Tools/ZipTools.cs
Normal file
227
KMCCC.Shared/Tools/ZipTools.cs
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
namespace KMCCC.Tools
|
||||||
|
{
|
||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Packaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 操蛋的通过反射调用Zip解压
|
||||||
|
/// </summary>
|
||||||
|
public static class ZipTools
|
||||||
|
{
|
||||||
|
public static readonly Boolean Enabled;
|
||||||
|
|
||||||
|
public static readonly Type ZipArchive;
|
||||||
|
|
||||||
|
public static readonly MethodInfo ZipArchive_OpenOnFile;
|
||||||
|
|
||||||
|
public static readonly MethodInfo ZipArchive_GetFiles;
|
||||||
|
|
||||||
|
public static readonly FieldInfo ZipArchive_ZipIOBlockManager;
|
||||||
|
|
||||||
|
public static readonly Type ZipFileInfo;
|
||||||
|
|
||||||
|
public static readonly MethodInfo ZipFileInfo_GetStream;
|
||||||
|
|
||||||
|
public static readonly PropertyInfo ZipFileInfo_Name;
|
||||||
|
|
||||||
|
public static readonly PropertyInfo ZipFileInfo_FolderFlag;
|
||||||
|
|
||||||
|
public static readonly Type ZipIOBlockManager;
|
||||||
|
|
||||||
|
public static readonly FieldInfo ZipIOBlockManager_Encoding;
|
||||||
|
|
||||||
|
static ZipTools()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var windowsBase = typeof (Package).Assembly;
|
||||||
|
ZipArchive = windowsBase.GetType("MS.Internal.IO.Zip.ZipArchive");
|
||||||
|
ZipArchive_OpenOnFile = ZipArchive.GetMethod("OpenOnFile", BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
ZipArchive_GetFiles = ZipArchive.GetMethod("GetFiles", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
ZipArchive_ZipIOBlockManager = ZipArchive.GetField("_blockManager", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
ZipFileInfo = windowsBase.GetType("MS.Internal.IO.Zip.ZipFileInfo");
|
||||||
|
ZipFileInfo_GetStream = ZipFileInfo.GetMethod("GetStream", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
ZipFileInfo_Name = ZipFileInfo.GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
ZipFileInfo_FolderFlag = ZipFileInfo.GetProperty("FolderFlag", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
ZipIOBlockManager = windowsBase.GetType("MS.Internal.IO.Zip.ZipIOBlockManager");
|
||||||
|
ZipIOBlockManager_Encoding = ZipIOBlockManager.GetField("_encoding", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
Enabled = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Unzip(string zipFile, string outputDirectory, UnzipOptions options)
|
||||||
|
{
|
||||||
|
return UnzipFile(zipFile, outputDirectory, options) == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Exception UnzipFile(string zipFile, string outputDirectory, UnzipOptions options)
|
||||||
|
{
|
||||||
|
options = options ?? new UnzipOptions();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var root = new DirectoryInfo(outputDirectory);
|
||||||
|
root.Create();
|
||||||
|
var rootPath = root.FullName + "/";
|
||||||
|
using (var zip = (IDisposable) ZipArchive_OpenOnFile.Invoke(null, new object[] {zipFile, FileMode.Open, FileAccess.Read, FileShare.Read, false}))
|
||||||
|
{
|
||||||
|
var ioManager = ZipArchive_ZipIOBlockManager.GetValue(zip);
|
||||||
|
ZipIOBlockManager_Encoding.SetValue(ioManager, new WarpedEncoding(options.Encoding ?? Encoding.Default));
|
||||||
|
|
||||||
|
var files = (IEnumerable) ZipArchive_GetFiles.Invoke(zip, new object[] {});
|
||||||
|
IEnumerable<string> exclude = (options.Exclude ?? new List<string>());
|
||||||
|
if (exclude.Count() > 1000)
|
||||||
|
{
|
||||||
|
exclude = exclude.AsParallel();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var item in files)
|
||||||
|
{
|
||||||
|
var name = (string) ZipFileInfo_Name.GetValue(item, null);
|
||||||
|
if (exclude.Any(name.StartsWith))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((bool) ZipFileInfo_FolderFlag.GetValue(item, null))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(rootPath + name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
using (var stream = (Stream) ZipFileInfo_GetStream.Invoke(item, new object[] {FileMode.Open, FileAccess.Read}))
|
||||||
|
{
|
||||||
|
var filePath = rootPath + name;
|
||||||
|
var directoryInfo = new FileInfo(filePath).Directory;
|
||||||
|
if (directoryInfo != null) directoryInfo.Create();
|
||||||
|
using (var fs = new FileStream(filePath, FileMode.Create))
|
||||||
|
{
|
||||||
|
stream.CopyTo(fs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception exp)
|
||||||
|
{
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 编码大法
|
||||||
|
|
||||||
|
public class WarpedEncoding : ASCIIEncoding
|
||||||
|
{
|
||||||
|
private readonly Encoding _innerEncoding;
|
||||||
|
|
||||||
|
public WarpedEncoding(Encoding encoding)
|
||||||
|
{
|
||||||
|
_innerEncoding = encoding ?? Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object value)
|
||||||
|
{
|
||||||
|
return _innerEncoding.Equals(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetByteCount(char[] chars, int index, int count)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetByteCount(chars, index, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetByteCount(string chars)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetByteCount(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetBytes(chars, charIndex, charCount, bytes, byteIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetBytes(string s, int charIndex, int charCount, byte[] bytes, int byteIndex)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetBytes(s, charIndex, charCount, bytes, byteIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetCharCount(byte[] bytes, int index, int count)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetCharCount(bytes, index, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetChars(bytes, byteIndex, byteCount, chars, charIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Decoder GetDecoder()
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetDecoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Encoder GetEncoder()
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMaxByteCount(int charCount)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetMaxByteCount(charCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetMaxCharCount(int byteCount)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetMaxCharCount(byteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte[] GetPreamble()
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetPreamble();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetString(byte[] bytes, int index, int count)
|
||||||
|
{
|
||||||
|
return _innerEncoding.GetString(bytes, index, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解压选项
|
||||||
|
/// </summary>
|
||||||
|
public class UnzipOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 排除的文件(夹)
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Exclude { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 文件(夹)名使用的编码
|
||||||
|
/// </summary>
|
||||||
|
public Encoding Encoding { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user