mirror of
https://e.coding.net/circlecloud/CTZLauncher.git
synced 2024-11-23 02:18: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