1
0
mirror of https://e.coding.net/circlecloud/CTZLauncher.git synced 2024-11-14 00:48:48 +00:00

首次提交项目文件...

Signed-off-by: j502647092 <jtb1@163.com>
This commit is contained in:
j502647092 2015-07-29 19:56:27 +08:00
commit 6e0fa413d2
47 changed files with 7991 additions and 0 deletions

63
.gitattributes vendored Normal file
View 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
View 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
View 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
View 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
View 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
{
}
}

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View 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>

View 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);
}
}
}

View 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")]

View 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;
}
}
}
}

View 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>

View 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;
}
}
}
}

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

View 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; }
}
}

View 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);
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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
View 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>

View 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; }
}
}

View 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
}
}

View 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);
}
}

View 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);
}
}
}

View 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
}
}

View 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
}
}

View 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);
}
}
}

View 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);
}
}

File diff suppressed because it is too large Load Diff

View 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)
{
}
}
}

View 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 ();
}
}
}

View 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) {}
}
}

View 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;
}
}
}

View 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]);
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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
}
}

View 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; }
}
}

View 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;
}
}
}

View 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();
}
}
}

View 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")]

View 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";
}
}
}

View 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
}
}

View 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; }
}
}