├── .gitignore ├── CLEAN.BAT ├── GenMarkdown.py ├── README.md ├── binaries ├── .gitignore ├── tun2socks_x64.exe └── tun2socks_x86.exe ├── modes ├── Cloudflare.txt ├── Steam.txt ├── Telegram.txt └── Warframe.txt ├── screenshots ├── four.png ├── one.png ├── three.png └── two.png ├── v2tap.sln └── v2tap ├── .gitignore ├── 3rd ├── IniParser │ ├── Exceptions │ │ └── ParsingException.cs │ ├── FileIniParser.cs │ ├── Helpers │ │ └── Assert.cs │ ├── Model │ │ ├── Configuration │ │ │ ├── ConcatenateDuplicatedKeysIniParserConfiguration.cs │ │ │ └── IniParserConfiguration.cs │ │ ├── Formatting │ │ │ ├── DefaultIniDataFormatter.cs │ │ │ └── IIniDataFormatter.cs │ │ ├── IniData.cs │ │ ├── IniDataCaseInsensitive.cs │ │ ├── KeyData.cs │ │ ├── KeyDataCollection.cs │ │ ├── SectionData.cs │ │ └── SectionDataCollection.cs │ ├── Parser │ │ ├── ConcatenateDuplicatedKeysIniDataParser.cs │ │ └── IniDataParser.cs │ ├── StreamIniDataParser.cs │ └── StringIniParser.cs ├── SimpleJSON │ └── SimpleJSON.cs └── v2ray │ └── Stats │ ├── Command.cs │ └── CommandGrpc.cs ├── App.config ├── Forms ├── AdvancedForm.Designer.cs ├── AdvancedForm.cs ├── AdvancedForm.resx ├── EditForm.Designer.cs ├── EditForm.cs ├── EditForm.resx ├── ImportForm.Designer.cs ├── ImportForm.cs ├── ImportForm.resx ├── MainForm.Designer.cs ├── MainForm.cs └── MainForm.resx ├── Global.cs ├── Objects ├── Mode.cs └── Server.cs ├── Override └── WebClient.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings ├── Resources ├── defaultConfig.ini ├── defaultServerConfig.json ├── v2ray.json └── v2rayNotBypassChina.json ├── Utils └── Util.cs ├── packages.config ├── v2tap.cs ├── v2tap.csproj └── v2tap.manifest /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs 2 | /packages -------------------------------------------------------------------------------- /CLEAN.BAT: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | CD v2tap 3 | RD /S /Q bin 4 | RD /S /Q obj 5 | -------------------------------------------------------------------------------- /GenMarkdown.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import hashlib 4 | 5 | def md5sum(filename): 6 | hash_md5 = hashlib.md5() 7 | with open(filename, 'rb') as f: 8 | for chunk in iter(lambda: f.read(4096), b''): 9 | hash_md5.update(chunk) 10 | return hash_md5.hexdigest() 11 | 12 | def sha1sum(filename): 13 | hash_sha1 = hashlib.sha1() 14 | with open(filename, 'rb') as f: 15 | for chunk in iter(lambda: f.read(4096), b''): 16 | hash_sha1.update(chunk) 17 | return hash_sha1.hexdigest() 18 | 19 | def sha256sum(filename): 20 | hash_sha256 = hashlib.sha256() 21 | with open(filename, 'rb') as f: 22 | for chunk in iter(lambda: f.read(4096), b''): 23 | hash_sha256.update(chunk) 24 | return hash_sha256.hexdigest() 25 | 26 | print('v2tap 版本:1.1.3-STABLE') 27 | print('v2ray-core 版本:4.13.0') 28 | print('') 29 | print('此包中附带 TUN/TAP 驱动程序!') 30 | print('') 31 | print('警告:32 位版本没有经过测试(手上没有 32 位系统的机器)') 32 | print('') 33 | print('| 文件名 | md5sum | sha1sum | sha256sum |') 34 | print('| :-- | :-- | :-- | :-- |') 35 | 36 | v2tap_x64_md5 = md5sum('v2tap\\bin\\Release_x64\\v2tap_x64\\v2tap_x64.7z') 37 | v2tap_x64_sha1 = sha1sum('v2tap\\bin\\Release_x64\\v2tap_x64\\v2tap_x64.7z') 38 | v2tap_x64_sha256 = sha256sum('v2tap\\bin\\Release_x64\\v2tap_x64\\v2tap_x64.7z') 39 | print('| v2tap_x64.7z | ' + v2tap_x64_md5 + ' | ' + v2tap_x64_sha1 + ' | ' + v2tap_x64_sha256 + ' |') 40 | 41 | v2tap_x86_md5 = md5sum('v2tap\\bin\\Release_x86\\v2tap_x86\\v2tap_x86.7z') 42 | v2tap_x86_sha1 = sha1sum('v2tap\\bin\\Release_x86\\v2tap_x86\\v2tap_x86.7z') 43 | v2tap_x86_sha256 = sha256sum('v2tap\\bin\\Release_x86\\v2tap_x86\\v2tap_x86.7z') 44 | print('| v2tap_x86.7z | ' + v2tap_x86_md5 + ' | ' + v2tap_x86_sha1 + ' | ' + v2tap_x86_sha256 + ' |') -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![](https://img.shields.io/badge/%E8%81%94%E7%B3%BB%E6%96%B9%E5%BC%8F-Telegram-blue.svg)](https://t.me/Holli_Freed) 2 | 3 | # 此项目已更名 x2tap 继续开发:[x2tap](https://github.com/hacking001/x2tap) 4 | 5 | # v2tap 6 | 基于 TUN/TAP + tun2socks + v2ray 实现的 VPN 工具 7 | 8 | # TODO 9 | - [x] 多代理配置支持 10 | - [x] 可以导入订阅(自动保存上一次的订阅链接,方便更新) 11 | - [x] 流量信息显示(当前速度和已使用总流量) 12 | - [x] VMess 协议支持 + 多种传输方式 + TCP、mKCP、QUIC 的伪装支持 + 支持 UDP 转发 13 | - [x] 像 SSTap 那样的外置规则列表(如何创建规则参见 [wiki](https://github.com/hacking001/v2tap/wiki/CreateMode)) 14 | - [ ] 本地 DNS 代理(目前考虑 DoH 来拒绝污染,也支持普通 UDP 查询代理) 15 | - [ ] 给 v2tap 上一个图标 16 | - [ ] 导入界面有待改进 17 | 18 | # 依赖文件 19 | - [TAP Windows](https://build.openvpn.net/downloads/releases/latest/tap-windows-latest-stable.exe) 20 | - [v2ray-core](https://github.com/v2ray/v2ray-core/releases) 21 | - [tun2socks](https://github.com/hacking001/v2tap/tree/master/binaries) 22 | 23 | # 准备工作 24 | 1. 从 [releases](https://github.com/hacking001/v2tap/releases) 中下载最新版的包 25 | 2. 安装 `tap-windows-latest-stable.exe`,请务必一路 next,不懂请不要乱点 26 | 3. 可用的 v2ray 服务器(暂时不支持伪装) 27 | 28 | # 正式开始 29 | 1. 打开 `v2tap.exe` 点击添加按钮增加一个配置信息 30 | 31 | ![](screenshots/one.png) 32 | 33 | ![](screenshots/two.png) 34 | 35 | 2. 选择新添加的配置信息 36 | 37 | ![](screenshots/three.png) 38 | 39 | 3. 检查 [Google](https://www.google.com/ncr) 是否可以正常访问 40 | 41 | ![](screenshots/four.png) 42 | -------------------------------------------------------------------------------- /binaries/.gitignore: -------------------------------------------------------------------------------- 1 | /tap-windows-latest-stable.exe 2 | /v2ray -------------------------------------------------------------------------------- /binaries/tun2socks_x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leitianya/v2tap/eda922f5ff0c0b7a14414d0c9a864de6be6b3e15/binaries/tun2socks_x64.exe -------------------------------------------------------------------------------- /binaries/tun2socks_x86.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leitianya/v2tap/eda922f5ff0c0b7a14414d0c9a864de6be6b3e15/binaries/tun2socks_x86.exe -------------------------------------------------------------------------------- /modes/Cloudflare.txt: -------------------------------------------------------------------------------- 1 | 103.21.244.0/22 2 | 103.22.200.0/22 3 | 103.31.4.0/22 4 | 104.16.0.0/12 5 | 108.162.192.0/18 6 | 131.0.72.0/22 7 | 141.101.64.0/18 8 | 162.158.0.0/15 9 | 172.64.0.0/13 10 | 173.245.48.0/20 11 | 188.114.96.0/20 12 | 190.93.240.0/20 13 | 197.234.240.0/22 14 | 198.41.128.0/17 -------------------------------------------------------------------------------- /modes/Telegram.txt: -------------------------------------------------------------------------------- 1 | 91.108.56.0/23 2 | 91.108.56.0/22 3 | 91.108.4.0/22 4 | 149.154.172.0/22 5 | 149.154.168.0/22 6 | 149.154.164.0/22 7 | 109.239.140.0/24 -------------------------------------------------------------------------------- /screenshots/four.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leitianya/v2tap/eda922f5ff0c0b7a14414d0c9a864de6be6b3e15/screenshots/four.png -------------------------------------------------------------------------------- /screenshots/one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leitianya/v2tap/eda922f5ff0c0b7a14414d0c9a864de6be6b3e15/screenshots/one.png -------------------------------------------------------------------------------- /screenshots/three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leitianya/v2tap/eda922f5ff0c0b7a14414d0c9a864de6be6b3e15/screenshots/three.png -------------------------------------------------------------------------------- /screenshots/two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leitianya/v2tap/eda922f5ff0c0b7a14414d0c9a864de6be6b3e15/screenshots/two.png -------------------------------------------------------------------------------- /v2tap.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.271 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "v2tap", "v2tap\v2tap.csproj", "{53132DC3-8A46-4558-978C-605A643D1300}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release x64|Any CPU = Release x64|Any CPU 12 | Release x86|Any CPU = Release x86|Any CPU 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {53132DC3-8A46-4558-978C-605A643D1300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 16 | {53132DC3-8A46-4558-978C-605A643D1300}.Debug|Any CPU.Build.0 = Debug|Any CPU 17 | {53132DC3-8A46-4558-978C-605A643D1300}.Release x64|Any CPU.ActiveCfg = Release x64|Any CPU 18 | {53132DC3-8A46-4558-978C-605A643D1300}.Release x64|Any CPU.Build.0 = Release x64|Any CPU 19 | {53132DC3-8A46-4558-978C-605A643D1300}.Release x86|Any CPU.ActiveCfg = Release x86|Any CPU 20 | {53132DC3-8A46-4558-978C-605A643D1300}.Release x86|Any CPU.Build.0 = Release x86|Any CPU 21 | EndGlobalSection 22 | GlobalSection(SolutionProperties) = preSolution 23 | HideSolutionNode = FALSE 24 | EndGlobalSection 25 | GlobalSection(ExtensibilityGlobals) = postSolution 26 | SolutionGuid = {F99FB451-F677-4A31-9F3C-4BA7BD189AF5} 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /v2tap/.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /obj -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Exceptions/ParsingException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace IniParser.Exceptions 4 | { 5 | /// 6 | /// Represents an error ococcurred while parsing data 7 | /// 8 | public class ParsingException : Exception 9 | { 10 | public Version LibVersion {get; private set;} 11 | public int LineNumber {get; private set;} 12 | public string LineValue {get; private set;} 13 | 14 | public ParsingException(string msg) 15 | :this(msg, 0, string.Empty, null) 16 | {} 17 | 18 | public ParsingException(string msg, Exception innerException) 19 | :this(msg, 0, string.Empty, innerException) 20 | {} 21 | 22 | public ParsingException(string msg, int lineNumber, string lineValue) 23 | :this(msg, lineNumber, lineValue, null) 24 | {} 25 | 26 | public ParsingException(string msg, int lineNumber, string lineValue, Exception innerException) 27 | : base( 28 | string.Format( 29 | "{0} while parsing line number {1} with value \'{2}\' - IniParser version: {3}", 30 | msg, lineNumber, lineValue, System.Reflection.Assembly.GetExecutingAssembly().GetName().Version), 31 | innerException) 32 | { 33 | LibVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; 34 | LineNumber = lineNumber; 35 | LineValue = lineValue; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/FileIniParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using IniParser.Exceptions; 5 | using IniParser.Model; 6 | using IniParser.Parser; 7 | 8 | namespace IniParser 9 | { 10 | /// 11 | /// Represents an INI data parser for files. 12 | /// 13 | public class FileIniDataParser : StreamIniDataParser 14 | { 15 | /// 16 | /// Ctor 17 | /// 18 | public FileIniDataParser() {} 19 | 20 | /// 21 | /// Ctor 22 | /// 23 | /// 24 | public FileIniDataParser(IniDataParser parser) : base(parser) 25 | { 26 | Parser = parser; 27 | } 28 | 29 | #region Deprecated methods 30 | 31 | [Obsolete("Please use ReadFile method instead of this one as is more semantically accurate")] 32 | public IniData LoadFile(string filePath) 33 | { 34 | return ReadFile(filePath); 35 | } 36 | 37 | [Obsolete("Please use ReadFile method instead of this one as is more semantically accurate")] 38 | public IniData LoadFile(string filePath, Encoding fileEncoding) 39 | { 40 | return ReadFile(filePath, fileEncoding); 41 | } 42 | #endregion 43 | 44 | /// 45 | /// Implements reading ini data from a file. 46 | /// 47 | /// 48 | /// Uses codification for the file. 49 | /// 50 | /// 51 | /// Path to the file 52 | /// 53 | public IniData ReadFile(string filePath) 54 | { 55 | return ReadFile(filePath, Encoding.ASCII); 56 | } 57 | 58 | /// 59 | /// Implements reading ini data from a file. 60 | /// 61 | /// 62 | /// Path to the file 63 | /// 64 | /// 65 | /// File's encoding. 66 | /// 67 | public IniData ReadFile(string filePath, Encoding fileEncoding) 68 | { 69 | if (filePath == string.Empty) 70 | throw new ArgumentException("Bad filename."); 71 | 72 | try 73 | { 74 | // (FileAccess.Read) we want to open the ini only for reading 75 | // (FileShare.ReadWrite) any other process should still have access to the ini file 76 | using (FileStream fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) 77 | { 78 | using (StreamReader sr = new StreamReader(fs, fileEncoding)) 79 | { 80 | return ReadData(sr); 81 | } 82 | } 83 | } 84 | catch (IOException ex) 85 | { 86 | throw new ParsingException(String.Format("Could not parse file {0}", filePath), ex); 87 | } 88 | 89 | } 90 | 91 | /// 92 | /// Saves INI data to a file. 93 | /// 94 | /// 95 | /// Creats an ASCII encoded file by default. 96 | /// 97 | /// 98 | /// Path to the file. 99 | /// 100 | /// 101 | /// IniData to be saved as an INI file. 102 | /// 103 | [Obsolete("Please use WriteFile method instead of this one as is more semantically accurate")] 104 | public void SaveFile(string filePath, IniData parsedData) 105 | { 106 | WriteFile(filePath, parsedData, Encoding.UTF8); 107 | } 108 | 109 | /// 110 | /// Writes INI data to a text file. 111 | /// 112 | /// 113 | /// Path to the file. 114 | /// 115 | /// 116 | /// IniData to be saved as an INI file. 117 | /// 118 | /// 119 | /// Specifies the encoding used to create the file. 120 | /// 121 | public void WriteFile(string filePath, IniData parsedData, Encoding fileEncoding = null) 122 | { 123 | // The default value can't be assigned as a default parameter value because it is not 124 | // a constant expression. 125 | if (fileEncoding == null) 126 | fileEncoding = Encoding.UTF8; 127 | 128 | if (string.IsNullOrEmpty(filePath)) 129 | throw new ArgumentException("Bad filename."); 130 | 131 | if (parsedData == null) 132 | throw new ArgumentNullException("parsedData"); 133 | 134 | using (FileStream fs = File.Open(filePath, FileMode.Create, FileAccess.Write)) 135 | { 136 | using (StreamWriter sr = new StreamWriter(fs, fileEncoding)) 137 | { 138 | WriteData(sr, parsedData); 139 | } 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Helpers/Assert.cs: -------------------------------------------------------------------------------- 1 | namespace IniParser.Helpers 2 | { 3 | internal static class Assert 4 | { 5 | /// 6 | /// Asserts that a strings has no blank spaces. 7 | /// 8 | /// The string to be checked. 9 | /// 10 | internal static bool StringHasNoBlankSpaces(string s) 11 | { 12 | return !s.Contains(" "); 13 | } 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/Configuration/ConcatenateDuplicatedKeysIniParserConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using IniParser.Parser; 4 | 5 | namespace IniParser.Model.Configuration 6 | { 7 | public class ConcatenateDuplicatedKeysIniParserConfiguration : IniParserConfiguration 8 | { 9 | public new bool AllowDuplicateKeys { get {return true; }} 10 | public ConcatenateDuplicatedKeysIniParserConfiguration() 11 | :base() 12 | { 13 | this.ConcatenateSeparator = ";"; 14 | } 15 | 16 | public ConcatenateDuplicatedKeysIniParserConfiguration(ConcatenateDuplicatedKeysIniParserConfiguration ori) 17 | :base(ori) 18 | { 19 | this.ConcatenateSeparator = ori.ConcatenateSeparator; 20 | } 21 | 22 | /// 23 | /// Gets or sets the string used to concatenate duplicated keys. 24 | /// 25 | /// Defaults to ';'. 26 | /// 27 | public string ConcatenateSeparator { get; set; } 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/Configuration/IniParserConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text.RegularExpressions; 3 | using IniParser.Parser; 4 | 5 | namespace IniParser.Model.Configuration 6 | { 7 | [Obsolete("Kept for backward compatibility, just use IniParserConfiguration class")] 8 | public class DefaultIniParserConfiguration : ConcatenateDuplicatedKeysIniParserConfiguration {} 9 | 10 | /// 11 | /// Defines data for a Parser configuration object. 12 | /// 13 | /// With a configuration object you can redefine how the parser 14 | /// will detect special items in the ini file by defining new regex 15 | /// (e.g. you can redefine the comment regex so it just treat text as 16 | /// a comment iff the comment caracter is the first in the line) 17 | /// or changing the set of characters used to define elements in 18 | /// the ini file (e.g. change the 'comment' caracter from ';' to '#') 19 | /// You can also define how the parser should treat errors, or how liberal 20 | /// or conservative should it be when parsing files with "strange" formats. 21 | public class IniParserConfiguration : ICloneable 22 | { 23 | #region Initialization 24 | /// 25 | /// Default values used if an instance of 26 | /// is created without specifying a configuration. 27 | /// 28 | /// 29 | /// By default the various delimiters for the data are setted: 30 | /// ';' for one-line comments 31 | /// '[' ']' for delimiting a section 32 | /// '=' for linking key / value pairs 33 | /// 34 | /// An example of well formed data with the default values: 35 | /// 36 | /// ;section comment
37 | /// [section] ; section comment
38 | ///
39 | /// ; key comment
40 | /// key = value ;key comment
41 | ///
42 | /// ;key2 comment
43 | /// key2 = value
44 | ///
45 | ///
46 | ///
47 | public IniParserConfiguration() 48 | { 49 | CommentString = ";"; 50 | SectionStartChar = '['; 51 | SectionEndChar = ']'; 52 | KeyValueAssigmentChar = '='; 53 | AssigmentSpacer = " "; 54 | NewLineStr = Environment.NewLine; 55 | ConcatenateDuplicateKeys = false; 56 | AllowKeysWithoutSection = true; 57 | AllowDuplicateKeys = false; 58 | AllowDuplicateSections = false; 59 | AllowCreateSectionsOnFly = true; 60 | ThrowExceptionsOnError = true; 61 | SkipInvalidLines = false; 62 | } 63 | 64 | /// 65 | /// Copy ctor. 66 | /// 67 | /// 68 | /// Original instance to be copied. 69 | /// 70 | public IniParserConfiguration(IniParserConfiguration ori) 71 | { 72 | AllowDuplicateKeys = ori.AllowDuplicateKeys; 73 | OverrideDuplicateKeys = ori.OverrideDuplicateKeys; 74 | AllowDuplicateSections = ori.AllowDuplicateSections; 75 | AllowKeysWithoutSection = ori.AllowKeysWithoutSection; 76 | AllowCreateSectionsOnFly = ori.AllowCreateSectionsOnFly; 77 | 78 | SectionStartChar = ori.SectionStartChar; 79 | SectionEndChar = ori.SectionEndChar; 80 | CommentString = ori.CommentString; 81 | ThrowExceptionsOnError = ori.ThrowExceptionsOnError; 82 | 83 | // Regex values should recreate themselves. 84 | } 85 | #endregion 86 | 87 | #region IniParserConfiguration 88 | 89 | public Regex CommentRegex { get; set; } 90 | 91 | public Regex SectionRegex { get; set; } 92 | 93 | /// 94 | /// Sets the char that defines the start of a section name. 95 | /// 96 | /// 97 | /// Defaults to character '[' 98 | /// 99 | public char SectionStartChar 100 | { 101 | get { return _sectionStartChar; } 102 | set 103 | { 104 | _sectionStartChar = value; 105 | RecreateSectionRegex(_sectionStartChar); 106 | } 107 | } 108 | 109 | /// 110 | /// Sets the char that defines the end of a section name. 111 | /// 112 | /// 113 | /// Defaults to character ']' 114 | /// 115 | public char SectionEndChar 116 | { 117 | get { return _sectionEndChar; } 118 | set 119 | { 120 | _sectionEndChar = value; 121 | RecreateSectionRegex(_sectionEndChar); 122 | } 123 | } 124 | 125 | /// 126 | /// Retrieving section / keys by name is done with a case-insensitive 127 | /// search. 128 | /// 129 | /// 130 | /// Defaults to false (case sensitive search) 131 | /// 132 | public bool CaseInsensitive{ get; set; } 133 | 134 | /// 135 | /// Sets the char that defines the start of a comment. 136 | /// A comment spans from the comment character to the end of the line. 137 | /// 138 | /// 139 | /// Defaults to character ';' 140 | /// 141 | [Obsolete("Please use the CommentString property")] 142 | public char CommentChar 143 | { 144 | get { return CommentString[0]; } 145 | set { CommentString = value.ToString(); } 146 | } 147 | 148 | /// 149 | /// Sets the string that defines the start of a comment. 150 | /// A comment spans from the mirst matching comment string 151 | /// to the end of the line. 152 | /// 153 | /// 154 | /// Defaults to string ";" 155 | /// 156 | public string CommentString 157 | { 158 | 159 | get { return _commentString ?? string.Empty; } 160 | set 161 | { 162 | // Sanitarize special characters for a regex 163 | foreach (var specialChar in _strSpecialRegexChars) 164 | { 165 | value = value.Replace(new String(specialChar, 1), @"\" + specialChar); 166 | } 167 | 168 | CommentRegex = new Regex(string.Format(_strCommentRegex, value)); 169 | _commentString = value; 170 | } 171 | } 172 | 173 | /// 174 | /// Gets or sets the string to use as new line string when formating an IniData structure using a 175 | /// IIniDataFormatter. Parsing an ini-file accepts any new line character (Unix/windows) 176 | /// 177 | /// 178 | /// This allows to write a file with unix new line characters on windows (and vice versa) 179 | /// 180 | /// Defaults to value Environment.NewLine 181 | public string NewLineStr 182 | { 183 | get; set; 184 | } 185 | /// 186 | /// Sets the char that defines a value assigned to a key 187 | /// 188 | /// 189 | /// Defaults to character '=' 190 | /// 191 | public char KeyValueAssigmentChar { get; set; } 192 | 193 | /// 194 | /// Sets the string around KeyValuesAssignmentChar 195 | /// 196 | /// 197 | /// Defaults to string ' ' 198 | /// 199 | public string AssigmentSpacer { get; set; } 200 | 201 | /// 202 | /// Allows having keys in the file that don't belong to any section. 203 | /// i.e. allows defining keys before defining a section. 204 | /// If set to false and keys without a section are defined, 205 | /// the will stop with an error. 206 | /// 207 | /// 208 | /// Defaults to true. 209 | /// 210 | public bool AllowKeysWithoutSection { get; set; } 211 | 212 | /// 213 | /// If set to false and the finds duplicate keys in a 214 | /// section the parser will stop with an error. 215 | /// If set to true, duplicated keys are allowed in the file. The value 216 | /// of the duplicate key will be the last value asigned to the key in the file. 217 | /// 218 | /// 219 | /// Defaults to false. 220 | /// 221 | public bool AllowDuplicateKeys { get; set; } 222 | 223 | /// 224 | /// Only used if is also true 225 | /// If set to true when the parser finds a duplicate key, it overrites 226 | /// the previous value, so the key will always contain the value of the 227 | /// last key readed in the file 228 | /// If set to false the first readed value is preserved, so the key will 229 | /// always contain the value of the first key readed in the file 230 | /// 231 | /// 232 | /// Defaults to false. 233 | /// 234 | public bool OverrideDuplicateKeys { get; set; } 235 | 236 | /// 237 | /// Gets or sets a value indicating whether duplicate keys are concatenate 238 | /// together by . 239 | /// 240 | /// 241 | /// Defaults to false. 242 | /// 243 | public bool ConcatenateDuplicateKeys { get; set; } 244 | 245 | /// 246 | /// If true the instance will thrown an exception 247 | /// if an error is found. 248 | /// If false the parser will just stop execution and return a null value. 249 | /// 250 | /// 251 | /// Defaults to true. 252 | /// 253 | public bool ThrowExceptionsOnError { get; set; } 254 | 255 | /// 256 | /// If set to false and the finds a duplicate section 257 | /// the parser will stop with an error. 258 | /// If set to true, duplicated sections are allowed in the file, but only a 259 | /// element will be created in the 260 | /// collection. 261 | /// 262 | /// 263 | /// Defaults to false. 264 | /// 265 | public bool AllowDuplicateSections { get; set; } 266 | 267 | /// 268 | /// If set to false, the stop with a error if you try 269 | /// to access a section that was not created previously and the parser will stop with an error. 270 | /// If set to true, inexistents sections are created, always returning a valid 271 | /// element. 272 | /// 273 | /// 274 | /// Defaults to false. 275 | /// 276 | public bool AllowCreateSectionsOnFly { get; set; } 277 | 278 | public bool SkipInvalidLines { get; set; } 279 | 280 | #endregion 281 | 282 | #region Fields 283 | private char _sectionStartChar; 284 | private char _sectionEndChar; 285 | private string _commentString; 286 | #endregion 287 | 288 | #region Constants 289 | protected const string _strCommentRegex = @"^{0}(.*)"; 290 | protected const string _strSectionRegexStart = @"^(\s*?)"; 291 | protected const string _strSectionRegexMiddle = @"{1}\s*[\p{L}\p{P}\p{M}_\""\'\{\}\#\+\;\*\%\(\)\=\?\&\$\,\:\/\.\-\w\d\s\\\~]+\s*"; 292 | protected const string _strSectionRegexEnd = @"(\s*?)$"; 293 | protected const string _strKeyRegex = @"^(\s*[_\.\d\w]*\s*)"; 294 | protected const string _strValueRegex = @"([\s\d\w\W\.]*)$"; 295 | protected const string _strSpecialRegexChars = @"[]\^$.|?*+()"; 296 | #endregion 297 | 298 | #region Helpers 299 | private void RecreateSectionRegex(char value) 300 | { 301 | if (char.IsControl(value) 302 | || char.IsWhiteSpace(value) 303 | || CommentString.Contains(new string(new [] {value})) 304 | || value == KeyValueAssigmentChar) 305 | throw new Exception(string.Format("Invalid character for section delimiter: '{0}", value)); 306 | 307 | string builtRegexString = _strSectionRegexStart; 308 | 309 | if (_strSpecialRegexChars.Contains(new string(_sectionStartChar, 1))) 310 | builtRegexString += "\\" + _sectionStartChar; 311 | else builtRegexString += _sectionStartChar; 312 | 313 | builtRegexString += _strSectionRegexMiddle; 314 | 315 | if (_strSpecialRegexChars.Contains(new string(_sectionEndChar, 1))) 316 | builtRegexString += "\\" + _sectionEndChar; 317 | else 318 | builtRegexString += _sectionEndChar; 319 | 320 | builtRegexString += _strSectionRegexEnd; 321 | 322 | SectionRegex = new Regex(builtRegexString); 323 | } 324 | #endregion 325 | 326 | public override int GetHashCode() 327 | { 328 | var hash = 27; 329 | foreach (var property in GetType().GetProperties()) 330 | { 331 | hash = (hash * 7) + property.GetValue(this, null).GetHashCode(); 332 | } 333 | 334 | return hash; 335 | } 336 | 337 | public override bool Equals(object obj) 338 | { 339 | var copyObj = obj as IniParserConfiguration; 340 | if (copyObj == null) return false; 341 | 342 | var oriType = this.GetType(); 343 | try 344 | { 345 | foreach (var property in oriType.GetProperties()) 346 | { 347 | if (property.GetValue(copyObj, null).Equals(property.GetValue(this, null))) 348 | { 349 | return false; 350 | } 351 | } 352 | } 353 | catch 354 | { 355 | return false; 356 | } 357 | 358 | return true; 359 | } 360 | 361 | #region ICloneable Members 362 | /// 363 | /// Creates a new object that is a copy of the current instance. 364 | /// 365 | /// 366 | /// A new object that is a copy of this instance. 367 | /// 368 | /// 2 369 | public IniParserConfiguration Clone() 370 | { 371 | return this.MemberwiseClone() as IniParserConfiguration; 372 | } 373 | 374 | object ICloneable.Clone() 375 | { 376 | return this.Clone(); 377 | } 378 | 379 | #endregion 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/Formatting/DefaultIniDataFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using IniParser.Model.Configuration; 5 | 6 | namespace IniParser.Model.Formatting 7 | { 8 | 9 | public class DefaultIniDataFormatter : IIniDataFormatter 10 | { 11 | IniParserConfiguration _configuration; 12 | 13 | #region Initialization 14 | public DefaultIniDataFormatter():this(new IniParserConfiguration()) {} 15 | 16 | public DefaultIniDataFormatter(IniParserConfiguration configuration) 17 | { 18 | if (configuration == null) 19 | throw new ArgumentNullException("configuration"); 20 | this.Configuration = configuration; 21 | } 22 | #endregion 23 | 24 | public virtual string IniDataToString(IniData iniData) 25 | { 26 | var sb = new StringBuilder(); 27 | 28 | if (Configuration.AllowKeysWithoutSection) 29 | { 30 | // Write global key/value data 31 | WriteKeyValueData(iniData.Global, sb); 32 | } 33 | 34 | //Write sections 35 | foreach (SectionData section in iniData.Sections) 36 | { 37 | //Write current section 38 | WriteSection(section, sb); 39 | } 40 | 41 | return sb.ToString(); 42 | } 43 | 44 | /// 45 | /// Configuration used to write an ini file with the proper 46 | /// delimiter characters and data. 47 | /// 48 | /// 49 | /// If the instance was created by a parser, 50 | /// this instance is a copy of the used 51 | /// by the parser (i.e. different objects instances) 52 | /// If this instance is created programatically without using a parser, this 53 | /// property returns an instance of 54 | /// 55 | public IniParserConfiguration Configuration 56 | { 57 | get { return _configuration; } 58 | set { _configuration = value.Clone(); } 59 | } 60 | 61 | #region Helpers 62 | 63 | private void WriteSection(SectionData section, StringBuilder sb) 64 | { 65 | // Write blank line before section, but not if it is the first line 66 | if (sb.Length > 0) sb.Append(Configuration.NewLineStr); 67 | 68 | // Leading comments 69 | WriteComments(section.LeadingComments, sb); 70 | 71 | //Write section name 72 | sb.Append(string.Format("{0}{1}{2}{3}", 73 | Configuration.SectionStartChar, 74 | section.SectionName, 75 | Configuration.SectionEndChar, 76 | Configuration.NewLineStr)); 77 | 78 | WriteKeyValueData(section.Keys, sb); 79 | 80 | // Trailing comments 81 | WriteComments(section.TrailingComments, sb); 82 | } 83 | 84 | private void WriteKeyValueData(KeyDataCollection keyDataCollection, StringBuilder sb) 85 | { 86 | 87 | foreach (KeyData keyData in keyDataCollection) 88 | { 89 | // Add a blank line if the key value pair has comments 90 | if (keyData.Comments.Count > 0) sb.Append(Configuration.NewLineStr); 91 | 92 | // Write key comments 93 | WriteComments(keyData.Comments, sb); 94 | 95 | //Write key and value 96 | sb.Append(string.Format("{0}{3}{1}{3}{2}{4}", 97 | keyData.KeyName, 98 | Configuration.KeyValueAssigmentChar, 99 | keyData.Value, 100 | Configuration.AssigmentSpacer, 101 | Configuration.NewLineStr)); 102 | } 103 | } 104 | 105 | private void WriteComments(List comments, StringBuilder sb) 106 | { 107 | foreach (string comment in comments) 108 | sb.Append(string.Format("{0}{1}{2}", Configuration.CommentString, comment, Configuration.NewLineStr)); 109 | } 110 | #endregion 111 | 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/Formatting/IIniDataFormatter.cs: -------------------------------------------------------------------------------- 1 | using IniParser.Model.Configuration; 2 | 3 | namespace IniParser.Model.Formatting 4 | { 5 | /// 6 | /// Formats a IniData structure to an string 7 | /// 8 | public interface IIniDataFormatter 9 | { 10 | /// 11 | /// Produces an string given 12 | /// 13 | /// The data to string. 14 | /// Ini data. 15 | string IniDataToString(IniData iniData); 16 | 17 | /// 18 | /// Configuration used by this formatter when converting IniData 19 | /// to an string 20 | /// 21 | IniParserConfiguration Configuration {get;set;} 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/IniData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IniParser.Model.Configuration; 3 | using IniParser.Model.Formatting; 4 | 5 | namespace IniParser.Model 6 | { 7 | /// 8 | /// Represents all data from an INI file 9 | /// 10 | public class IniData : ICloneable 11 | { 12 | #region Non-Public Members 13 | /// 14 | /// Represents all sections from an INI file 15 | /// 16 | private SectionDataCollection _sections; 17 | #endregion 18 | 19 | #region Initialization 20 | 21 | /// 22 | /// Initializes an empty IniData instance. 23 | /// 24 | public IniData() 25 | : this(new SectionDataCollection()) 26 | { } 27 | 28 | /// 29 | /// Initializes a new IniData instance using a previous 30 | /// . 31 | /// 32 | /// 33 | /// object containing the 34 | /// data with the sections of the file 35 | /// 36 | public IniData(SectionDataCollection sdc) 37 | { 38 | _sections = (SectionDataCollection)sdc.Clone(); 39 | Global = new KeyDataCollection(); 40 | SectionKeySeparator = '.'; 41 | } 42 | 43 | public IniData(IniData ori): this((SectionDataCollection)ori.Sections) 44 | { 45 | Global = (KeyDataCollection)ori.Global.Clone(); 46 | Configuration = ori.Configuration.Clone(); 47 | } 48 | #endregion 49 | 50 | #region Properties 51 | 52 | /// 53 | /// Configuration used to write an ini file with the proper 54 | /// delimiter characters and data. 55 | /// 56 | /// 57 | /// If the instance was created by a parser, 58 | /// this instance is a copy of the used 59 | /// by the parser (i.e. different objects instances) 60 | /// If this instance is created programatically without using a parser, this 61 | /// property returns an instance of 62 | /// 63 | public IniParserConfiguration Configuration 64 | { 65 | get 66 | { 67 | // Lazy initialization 68 | if (_configuration == null) 69 | _configuration = new IniParserConfiguration(); 70 | 71 | return _configuration; 72 | } 73 | 74 | set { _configuration = value.Clone(); } 75 | } 76 | 77 | /// 78 | /// Global sections. Contains key/value pairs which are not 79 | /// enclosed in any section (i.e. they are defined at the beginning 80 | /// of the file, before any section. 81 | /// 82 | public KeyDataCollection Global { get; protected set; } 83 | 84 | /// 85 | /// Gets the instance 86 | /// with the specified section name. 87 | /// 88 | public KeyDataCollection this[string sectionName] 89 | { 90 | get 91 | { 92 | if (!_sections.ContainsSection(sectionName)) 93 | if (Configuration.AllowCreateSectionsOnFly) 94 | _sections.AddSection(sectionName); 95 | else 96 | return null; 97 | 98 | return _sections[sectionName]; 99 | } 100 | } 101 | 102 | /// 103 | /// Gets or sets all the 104 | /// for this IniData instance. 105 | /// 106 | public SectionDataCollection Sections 107 | { 108 | get { return _sections; } 109 | set { _sections = value; } 110 | } 111 | 112 | /// 113 | /// Used to mark the separation between the section name and the key name 114 | /// when using . 115 | /// 116 | /// 117 | /// Defaults to '.'. 118 | /// 119 | public char SectionKeySeparator { get; set; } 120 | #endregion 121 | 122 | #region Object Methods 123 | public override string ToString() 124 | { 125 | return ToString(new DefaultIniDataFormatter(Configuration)); 126 | } 127 | 128 | public virtual string ToString(IIniDataFormatter formatter) 129 | { 130 | return formatter.IniDataToString(this); 131 | } 132 | #endregion 133 | 134 | #region ICloneable Members 135 | 136 | /// 137 | /// Creates a new object that is a copy of the current instance. 138 | /// 139 | /// 140 | /// A new object that is a copy of this instance. 141 | /// 142 | public object Clone() 143 | { 144 | return new IniData(this); 145 | } 146 | 147 | #endregion 148 | 149 | #region Fields 150 | /// 151 | /// See property for more information. 152 | /// 153 | private IniParserConfiguration _configuration; 154 | #endregion 155 | 156 | /// 157 | /// Deletes all comments in all sections and key values 158 | /// 159 | public void ClearAllComments() 160 | { 161 | Global.ClearComments(); 162 | 163 | foreach(var section in Sections) 164 | { 165 | section.ClearComments(); 166 | } 167 | } 168 | 169 | /// 170 | /// Merges the other iniData into this one by overwriting existing values. 171 | /// Comments get appended. 172 | /// 173 | /// 174 | /// IniData instance to merge into this. 175 | /// If it is null this operation does nothing. 176 | /// 177 | public void Merge(IniData toMergeIniData) 178 | { 179 | 180 | if (toMergeIniData == null) return; 181 | 182 | Global.Merge(toMergeIniData.Global); 183 | 184 | Sections.Merge(toMergeIniData.Sections); 185 | 186 | } 187 | 188 | /// 189 | /// Attempts to retrieve a key, using a single string combining section and 190 | /// key name. 191 | /// 192 | /// 193 | /// The section and key name to retrieve, separated by . 194 | /// 195 | /// If key contains no separator, it is treated as a key in the section. 196 | /// 197 | /// Key may contain no more than one separator character. 198 | /// 199 | /// 200 | /// If true is returned, is set to the value retrieved. Otherwise, is set 201 | /// to an empty string. 202 | /// 203 | /// 204 | /// True if key was found, otherwise false. 205 | /// 206 | /// 207 | /// key contained multiple separators. 208 | /// 209 | public bool TryGetKey(string key, out string value) 210 | { 211 | value = string.Empty; 212 | if (string.IsNullOrEmpty(key)) 213 | return false; 214 | 215 | var splitKey = key.Split(SectionKeySeparator); 216 | var separatorCount = splitKey.Length - 1; 217 | if (separatorCount > 1) 218 | throw new ArgumentException("key contains multiple separators", "key"); 219 | 220 | if (separatorCount == 0) 221 | { 222 | if (!Global.ContainsKey(key)) 223 | return false; 224 | 225 | value = Global[key]; 226 | return true; 227 | } 228 | 229 | var section = splitKey[0]; 230 | key = splitKey[1]; 231 | 232 | if (!_sections.ContainsSection(section)) 233 | return false; 234 | var sectionData = _sections[section]; 235 | if (!sectionData.ContainsKey(key)) 236 | return false; 237 | 238 | value = sectionData[key]; 239 | return true; 240 | } 241 | 242 | /// 243 | /// Retrieves a key using a single input string combining section and key name. 244 | /// 245 | /// 246 | /// The section and key name to retrieve, separated by . 247 | /// 248 | /// If key contains no separator, it is treated as a key in the section. 249 | /// 250 | /// Key may contain no more than one separator character. 251 | /// 252 | /// 253 | /// The key's value if it was found, otherwise null. 254 | /// 255 | /// 256 | /// key contained multiple separators. 257 | /// 258 | public string GetKey(string key) 259 | { 260 | string result; 261 | return TryGetKey(key, out result) ? result : null; 262 | } 263 | 264 | /// 265 | /// Merge the sections into this by overwriting this sections. 266 | /// 267 | private void MergeSection(SectionData otherSection) 268 | { 269 | // no overlap -> create no section 270 | if (!Sections.ContainsSection(otherSection.SectionName)) 271 | { 272 | Sections.AddSection(otherSection.SectionName); 273 | } 274 | 275 | // merge section into the new one 276 | Sections.GetSectionData(otherSection.SectionName).Merge(otherSection); 277 | } 278 | 279 | /// 280 | /// Merges the given global values into this globals by overwriting existing values. 281 | /// 282 | private void MergeGlobal(KeyDataCollection globals) 283 | { 284 | foreach (var globalValue in globals) 285 | { 286 | Global[globalValue.KeyName] = globalValue.Value; 287 | } 288 | } 289 | } 290 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/IniDataCaseInsensitive.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IniParser.Model.Configuration; 3 | using IniParser.Model.Formatting; 4 | 5 | namespace IniParser.Model 6 | { 7 | /// 8 | /// Represents all data from an INI file exactly as the 9 | /// class, but searching for sections and keys names is done with 10 | /// a case insensitive search. 11 | /// 12 | public class IniDataCaseInsensitive : IniData 13 | { 14 | /// 15 | /// Initializes an empty IniData instance. 16 | /// 17 | public IniDataCaseInsensitive() 18 | : base (new SectionDataCollection(StringComparer.OrdinalIgnoreCase)) 19 | { 20 | Global = new KeyDataCollection(StringComparer.OrdinalIgnoreCase); 21 | } 22 | 23 | /// 24 | /// Initializes a new IniData instance using a previous 25 | /// . 26 | /// 27 | /// 28 | /// object containing the 29 | /// data with the sections of the file 30 | /// 31 | public IniDataCaseInsensitive(SectionDataCollection sdc) 32 | : base (new SectionDataCollection(sdc, StringComparer.OrdinalIgnoreCase)) 33 | { 34 | Global = new KeyDataCollection(StringComparer.OrdinalIgnoreCase); 35 | } 36 | 37 | /// 38 | /// Copies an instance of the class 39 | /// 40 | /// Original 41 | public IniDataCaseInsensitive(IniData ori) 42 | : this(new SectionDataCollection(ori.Sections, StringComparer.OrdinalIgnoreCase)) 43 | { 44 | Global = (KeyDataCollection) ori.Global.Clone(); 45 | Configuration = ori.Configuration.Clone(); 46 | } 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/KeyData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace IniParser.Model 5 | { 6 | /// 7 | /// Information associated to a key from an INI file. 8 | /// Includes both the value and the comments associated to the key. 9 | /// 10 | public class KeyData : ICloneable 11 | { 12 | #region Initialization 13 | 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | public KeyData(string keyName) 18 | { 19 | if(string.IsNullOrEmpty(keyName)) 20 | throw new ArgumentException("key name can not be empty"); 21 | 22 | _comments = new List(); 23 | _value = string.Empty; 24 | _keyName = keyName; 25 | } 26 | 27 | /// 28 | /// Initializes a new instance of the class 29 | /// from a previous instance of . 30 | /// 31 | /// 32 | /// Data is deeply copied 33 | /// 34 | /// 35 | /// The instance of the class 36 | /// used to create the new instance. 37 | /// 38 | public KeyData(KeyData ori) 39 | { 40 | _value = ori._value; 41 | _keyName = ori._keyName; 42 | _comments = new List(ori._comments); 43 | } 44 | 45 | #endregion Constructors 46 | 47 | #region Properties 48 | 49 | /// 50 | /// Gets or sets the comment list associated to this key. 51 | /// 52 | public List Comments 53 | { 54 | get { return _comments; } 55 | set { _comments = new List (value) ; } 56 | } 57 | 58 | /// 59 | /// Gets or sets the value associated to this key. 60 | /// 61 | public string Value 62 | { 63 | get { return _value; } 64 | set { _value = value; } 65 | } 66 | 67 | /// 68 | /// Gets or sets the name of the key. 69 | /// 70 | public string KeyName 71 | { 72 | get 73 | { 74 | return _keyName; 75 | } 76 | 77 | set 78 | { 79 | if (value != string.Empty) 80 | _keyName = value; 81 | } 82 | 83 | } 84 | 85 | #endregion Properties 86 | 87 | #region ICloneable Members 88 | 89 | /// 90 | /// Creates a new object that is a copy of the current instance. 91 | /// 92 | /// 93 | /// A new object that is a copy of this instance. 94 | /// 95 | public object Clone() 96 | { 97 | return new KeyData(this); 98 | } 99 | 100 | #endregion 101 | 102 | #region Non-public Members 103 | 104 | // List with comment lines associated to this key 105 | private List _comments; 106 | 107 | // Unique value associated to this key 108 | private string _value; 109 | 110 | // Name of the current key 111 | private string _keyName; 112 | 113 | #endregion 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/KeyDataCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace IniParser.Model 6 | { 7 | /// 8 | /// Represents a collection of Keydata. 9 | /// 10 | public class KeyDataCollection : ICloneable, IEnumerable 11 | { 12 | IEqualityComparer _searchComparer; 13 | #region Initialization 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public KeyDataCollection() 19 | : this(EqualityComparer.Default) 20 | { } 21 | 22 | /// 23 | /// Initializes a new instance of the class with a given 24 | /// search comparer 25 | /// 26 | /// 27 | /// Search comparer used to find the key by name in the collection 28 | /// 29 | public KeyDataCollection(IEqualityComparer searchComparer) 30 | { 31 | _searchComparer = searchComparer; 32 | _keyData = new Dictionary(_searchComparer); 33 | } 34 | 35 | /// 36 | /// Initializes a new instance of the class 37 | /// from a previous instance of . 38 | /// 39 | /// 40 | /// Data from the original KeyDataCollection instance is deeply copied 41 | /// 42 | /// 43 | /// The instance of the class 44 | /// used to create the new instance. 45 | /// 46 | public KeyDataCollection(KeyDataCollection ori, IEqualityComparer searchComparer) 47 | : this(searchComparer) 48 | { 49 | foreach (KeyData key in ori) 50 | { 51 | if (_keyData.ContainsKey(key.KeyName)) 52 | { 53 | _keyData[key.KeyName] = (KeyData)key.Clone(); 54 | } 55 | else 56 | { 57 | _keyData.Add(key.KeyName, (KeyData)key.Clone()); 58 | } 59 | } 60 | } 61 | 62 | #endregion 63 | 64 | #region Properties 65 | 66 | /// 67 | /// Gets or sets the value of a concrete key. 68 | /// 69 | /// 70 | /// If we try to assign the value of a key which doesn't exists, 71 | /// a new key is added with the name and the value is assigned to it. 72 | /// 73 | /// 74 | /// Name of the key 75 | /// 76 | /// 77 | /// The string with key's value or null if the key was not found. 78 | /// 79 | public string this[string keyName] 80 | { 81 | get 82 | { 83 | if (_keyData.ContainsKey(keyName)) 84 | return _keyData[keyName].Value; 85 | 86 | return null; 87 | } 88 | 89 | set 90 | { 91 | if (!_keyData.ContainsKey(keyName)) 92 | { 93 | this.AddKey(keyName); 94 | } 95 | 96 | _keyData[keyName].Value = value; 97 | 98 | } 99 | } 100 | 101 | /// 102 | /// Return the number of keys in the collection 103 | /// 104 | public int Count 105 | { 106 | get { return _keyData.Count; } 107 | } 108 | 109 | #endregion 110 | 111 | #region Operations 112 | 113 | /// 114 | /// Adds a new key with the specified name and empty value and comments 115 | /// 116 | /// 117 | /// New key to be added. 118 | /// 119 | /// true if the key was added false if a key with the same name already exist 120 | /// in the collection 121 | /// 122 | public bool AddKey(string keyName) 123 | { 124 | if (!_keyData.ContainsKey(keyName)) 125 | { 126 | _keyData.Add(keyName, new KeyData(keyName)); 127 | return true; 128 | } 129 | 130 | return false; 131 | } 132 | 133 | [Obsolete("Pottentially buggy method! Use AddKey(KeyData keyData) instead (See comments in code for an explanation of the bug)")] 134 | public bool AddKey(string keyName, KeyData keyData) 135 | { 136 | // BUG: this actually can allow you to add the keyData having 137 | // keyData.KeyName different from the argument 'keyName' in this method 138 | // which doesn't make any sense 139 | if (AddKey(keyName)) 140 | { 141 | _keyData[keyName] = keyData; 142 | return true; 143 | } 144 | 145 | return false; 146 | 147 | } 148 | 149 | /// 150 | /// Adds a new key to the collection 151 | /// 152 | /// 153 | /// KeyData instance. 154 | /// 155 | /// 156 | /// true if the key was added false if a key with the same name already exist 157 | /// in the collection 158 | /// 159 | public bool AddKey(KeyData keyData) 160 | { 161 | if (AddKey(keyData.KeyName)) 162 | { 163 | _keyData[keyData.KeyName] = keyData; 164 | return true; 165 | } 166 | 167 | return false; 168 | } 169 | /// 170 | /// Adds a new key with the specified name and value to the collection 171 | /// 172 | /// 173 | /// Name of the new key to be added. 174 | /// 175 | /// 176 | /// Value associated to the key. 177 | /// 178 | /// 179 | /// true if the key was added false if a key with the same name already exist 180 | /// in the collection. 181 | /// 182 | public bool AddKey(string keyName, string keyValue) 183 | { 184 | if (AddKey(keyName)) 185 | { 186 | _keyData[keyName].Value = keyValue; 187 | return true; 188 | } 189 | 190 | return false; 191 | 192 | } 193 | 194 | /// 195 | /// Clears all comments of this section 196 | /// 197 | public void ClearComments() 198 | { 199 | foreach (var keydata in this) 200 | { 201 | keydata.Comments.Clear(); 202 | } 203 | } 204 | 205 | /// 206 | /// Gets if a specifyed key name exists in the collection. 207 | /// 208 | /// Key name to search 209 | /// true if a key with the specified name exists in the collectoin 210 | /// false otherwise 211 | public bool ContainsKey(string keyName) 212 | { 213 | return _keyData.ContainsKey(keyName); 214 | } 215 | 216 | /// 217 | /// Retrieves the data for a specified key given its name 218 | /// 219 | /// Name of the key to retrieve. 220 | /// 221 | /// A instance holding 222 | /// the key information or null if the key wasn't found. 223 | /// 224 | public KeyData GetKeyData(string keyName) 225 | { 226 | if (_keyData.ContainsKey(keyName)) 227 | return _keyData[keyName]; 228 | return null; 229 | } 230 | 231 | public void Merge(KeyDataCollection keyDataToMerge) 232 | { 233 | foreach (var keyData in keyDataToMerge) 234 | { 235 | AddKey(keyData.KeyName); 236 | GetKeyData(keyData.KeyName).Comments.AddRange(keyData.Comments); 237 | this[keyData.KeyName] = keyData.Value; 238 | } 239 | 240 | } 241 | 242 | /// 243 | /// Deletes all keys in this collection. 244 | /// 245 | public void RemoveAllKeys() 246 | { 247 | _keyData.Clear(); 248 | } 249 | 250 | /// 251 | /// Deletes a previously existing key, including its associated data. 252 | /// 253 | /// The key to be removed. 254 | /// 255 | /// true if a key with the specified name was removed 256 | /// false otherwise. 257 | /// 258 | public bool RemoveKey(string keyName) 259 | { 260 | return _keyData.Remove(keyName); 261 | } 262 | /// 263 | /// Sets the key data associated to a specified key. 264 | /// 265 | /// The new for the key. 266 | public void SetKeyData(KeyData data) 267 | { 268 | if (data == null) return; 269 | 270 | if (_keyData.ContainsKey(data.KeyName)) 271 | RemoveKey(data.KeyName); 272 | 273 | AddKey(data); 274 | } 275 | 276 | #endregion 277 | 278 | #region IEnumerable Members 279 | 280 | /// 281 | /// Allows iteration througt the collection. 282 | /// 283 | /// A strong-typed IEnumerator 284 | public IEnumerator GetEnumerator() 285 | { 286 | foreach (string key in _keyData.Keys) 287 | yield return _keyData[key]; 288 | } 289 | 290 | #region IEnumerable Members 291 | 292 | /// 293 | /// Implementation needed 294 | /// 295 | /// A weak-typed IEnumerator. 296 | IEnumerator IEnumerable.GetEnumerator() 297 | { 298 | return _keyData.GetEnumerator(); 299 | } 300 | 301 | #endregion 302 | 303 | #endregion 304 | 305 | #region ICloneable Members 306 | 307 | 308 | /// 309 | /// Creates a new object that is a copy of the current instance. 310 | /// 311 | /// 312 | /// A new object that is a copy of this instance. 313 | /// 314 | public object Clone() 315 | { 316 | return new KeyDataCollection(this, _searchComparer); 317 | } 318 | 319 | #endregion 320 | 321 | #region Non-public Members 322 | // Hack for getting the last key value (if exists) w/out using LINQ 323 | // and maintain support for earlier versions of .NET 324 | internal KeyData GetLast() 325 | { 326 | KeyData result = null; 327 | if (_keyData.Keys.Count <= 0) return result; 328 | 329 | 330 | foreach (var k in _keyData.Keys) result = _keyData[k]; 331 | return result; 332 | } 333 | 334 | /// 335 | /// Collection of KeyData for a given section 336 | /// 337 | private readonly Dictionary _keyData; 338 | 339 | #endregion 340 | 341 | } 342 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/SectionData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace IniParser.Model 5 | { 6 | /// 7 | /// Information associated to a section in a INI File 8 | /// Includes both the value and the comments associated to the key. 9 | /// 10 | public class SectionData : ICloneable 11 | { 12 | IEqualityComparer _searchComparer; 13 | #region Initialization 14 | 15 | public SectionData(string sectionName) 16 | :this(sectionName, EqualityComparer.Default) 17 | { 18 | 19 | } 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | public SectionData(string sectionName, IEqualityComparer searchComparer) 24 | { 25 | _searchComparer = searchComparer; 26 | 27 | if (string.IsNullOrEmpty(sectionName)) 28 | throw new ArgumentException("section name can not be empty"); 29 | 30 | _leadingComments = new List(); 31 | _keyDataCollection = new KeyDataCollection(_searchComparer); 32 | SectionName = sectionName; 33 | } 34 | 35 | 36 | /// 37 | /// Initializes a new instance of the class 38 | /// from a previous instance of . 39 | /// 40 | /// 41 | /// Data is deeply copied 42 | /// 43 | /// 44 | /// The instance of the class 45 | /// used to create the new instance. 46 | /// 47 | /// 48 | /// Search comparer. 49 | /// 50 | public SectionData(SectionData ori, IEqualityComparer searchComparer = null) 51 | { 52 | SectionName = ori.SectionName; 53 | 54 | _searchComparer = searchComparer; 55 | _leadingComments = new List(ori._leadingComments); 56 | _keyDataCollection = new KeyDataCollection(ori._keyDataCollection, searchComparer ?? ori._searchComparer); 57 | } 58 | 59 | #endregion 60 | 61 | #region Operations 62 | 63 | /// 64 | /// Deletes all comments in this section and key/value pairs 65 | /// 66 | public void ClearComments() 67 | { 68 | LeadingComments.Clear(); 69 | TrailingComments.Clear(); 70 | Keys.ClearComments(); 71 | } 72 | 73 | /// 74 | /// Deletes all the key-value pairs in this section. 75 | /// 76 | public void ClearKeyData() 77 | { 78 | Keys.RemoveAllKeys(); 79 | } 80 | 81 | /// 82 | /// Merges otherSection into this, adding new keys if they don't exists 83 | /// or overwriting values if the key already exists. 84 | /// Comments get appended. 85 | /// 86 | /// 87 | /// Comments are also merged but they are always added, not overwritten. 88 | /// 89 | /// 90 | public void Merge(SectionData toMergeSection) 91 | { 92 | foreach (var comment in toMergeSection.LeadingComments) 93 | LeadingComments.Add(comment); 94 | 95 | Keys.Merge(toMergeSection.Keys); 96 | 97 | foreach(var comment in toMergeSection.TrailingComments) 98 | TrailingComments.Add(comment); 99 | } 100 | 101 | #endregion 102 | 103 | #region Properties 104 | 105 | /// 106 | /// Gets or sets the name of the section. 107 | /// 108 | /// 109 | /// The name of the section 110 | /// 111 | public string SectionName 112 | { 113 | get 114 | { 115 | return _sectionName; 116 | } 117 | 118 | set 119 | { 120 | if (!string.IsNullOrEmpty(value)) 121 | _sectionName = value; 122 | } 123 | } 124 | 125 | 126 | [Obsolete("Do not use this property, use property Comments instead")] 127 | public List LeadingComments 128 | { 129 | get 130 | { 131 | return _leadingComments; 132 | } 133 | 134 | internal set 135 | { 136 | _leadingComments = new List(value); 137 | } 138 | } 139 | 140 | /// 141 | /// Gets or sets the comment list associated to this section. 142 | /// 143 | /// 144 | /// A list of strings. 145 | /// 146 | public List Comments 147 | { 148 | get 149 | { 150 | return _leadingComments; 151 | } 152 | 153 | 154 | } 155 | 156 | [Obsolete("Do not use this property, use property Comments instead")] 157 | public List TrailingComments 158 | { 159 | get 160 | { 161 | return _trailingComments; 162 | } 163 | 164 | internal set 165 | { 166 | _trailingComments = new List(value); 167 | } 168 | } 169 | /// 170 | /// Gets or sets the keys associated to this section. 171 | /// 172 | /// 173 | /// A collection of KeyData objects. 174 | /// 175 | public KeyDataCollection Keys 176 | { 177 | get 178 | { 179 | return _keyDataCollection; 180 | } 181 | 182 | set 183 | { 184 | _keyDataCollection = value; 185 | } 186 | } 187 | 188 | #endregion 189 | 190 | #region ICloneable Members 191 | 192 | /// 193 | /// Creates a new object that is a copy of the current instance. 194 | /// 195 | /// 196 | /// A new object that is a copy of this instance. 197 | /// 198 | public object Clone() 199 | { 200 | return new SectionData(this); 201 | } 202 | 203 | #endregion 204 | 205 | #region Non-public members 206 | 207 | // Comments associated to this section 208 | private List _leadingComments; 209 | private List _trailingComments = new List(); 210 | 211 | // Keys associated to this section 212 | private KeyDataCollection _keyDataCollection; 213 | 214 | private string _sectionName; 215 | #endregion 216 | 217 | 218 | 219 | } 220 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Model/SectionDataCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | 5 | namespace IniParser.Model 6 | { 7 | /// 8 | /// Represents a collection of SectionData. 9 | /// 10 | public class SectionDataCollection : ICloneable, IEnumerable 11 | { 12 | IEqualityComparer _searchComparer; 13 | #region Initialization 14 | 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public SectionDataCollection() 19 | :this(EqualityComparer.Default) 20 | {} 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// 26 | /// StringComparer used when accessing section names 27 | /// 28 | public SectionDataCollection(IEqualityComparer searchComparer) 29 | { 30 | _searchComparer = searchComparer; 31 | 32 | _sectionData = new Dictionary(_searchComparer); 33 | } 34 | 35 | /// 36 | /// Initializes a new instance of the class 37 | /// from a previous instance of . 38 | /// 39 | /// 40 | /// Data is deeply copied 41 | /// 42 | /// 43 | /// The instance of the class 44 | /// used to create the new instance. 45 | public SectionDataCollection(SectionDataCollection ori, IEqualityComparer searchComparer) 46 | { 47 | _searchComparer = searchComparer ?? EqualityComparer.Default; 48 | 49 | _sectionData = new Dictionary(_searchComparer); 50 | foreach(var sectionData in ori) 51 | { 52 | _sectionData.Add(sectionData.SectionName, (SectionData)sectionData.Clone()); 53 | }; 54 | } 55 | 56 | #endregion 57 | 58 | #region Properties 59 | 60 | /// 61 | /// Returns the number of SectionData elements in the collection 62 | /// 63 | public int Count { get { return _sectionData.Count; } } 64 | 65 | /// 66 | /// Gets the key data associated to a specified section name. 67 | /// 68 | /// An instance of as class 69 | /// holding the key data from the current parsed INI data, or a null 70 | /// value if the section doesn't exist. 71 | public KeyDataCollection this[string sectionName] 72 | { 73 | get 74 | { 75 | if ( _sectionData.ContainsKey(sectionName) ) 76 | return _sectionData[sectionName].Keys; 77 | 78 | return null; 79 | } 80 | } 81 | 82 | #endregion 83 | 84 | #region Public Members 85 | 86 | /// 87 | /// Creates a new section with empty data. 88 | /// 89 | /// 90 | /// If a section with the same name exists, this operation has no effect. 91 | /// 92 | /// Name of the section to be created 93 | /// true if the a new section with the specified name was added, 94 | /// false otherwise 95 | /// If the section name is not valid. 96 | public bool AddSection(string keyName) 97 | { 98 | //Checks valid section name 99 | //if ( !Assert.StringHasNoBlankSpaces(keyName) ) 100 | // throw new ArgumentException("Section name contain whitespaces"); 101 | 102 | if ( !ContainsSection(keyName) ) 103 | { 104 | _sectionData.Add( keyName, new SectionData(keyName, _searchComparer) ); 105 | return true; 106 | } 107 | 108 | return false; 109 | } 110 | 111 | /// 112 | /// Adds a new SectionData instance to the collection 113 | /// 114 | /// Data. 115 | public void Add(SectionData data) 116 | { 117 | if (ContainsSection(data.SectionName)) 118 | { 119 | SetSectionData(data.SectionName, new SectionData(data, _searchComparer)); 120 | } 121 | else 122 | { 123 | _sectionData.Add(data.SectionName, new SectionData(data, _searchComparer)); 124 | } 125 | } 126 | /// 127 | /// Removes all entries from this collection 128 | /// 129 | public void Clear() 130 | { 131 | _sectionData.Clear(); 132 | } 133 | 134 | 135 | /// 136 | /// Gets if a section with a specified name exists in the collection. 137 | /// 138 | /// Name of the section to search 139 | /// 140 | /// true if a section with the specified name exists in the 141 | /// collection false otherwise 142 | /// 143 | public bool ContainsSection(string keyName) 144 | { 145 | return _sectionData.ContainsKey(keyName); 146 | } 147 | 148 | /// 149 | /// Returns the section data from a specify section given its name. 150 | /// 151 | /// Name of the section. 152 | /// 153 | /// An instance of a class 154 | /// holding the section data for the currently INI data 155 | /// 156 | public SectionData GetSectionData(string sectionName) 157 | { 158 | if (_sectionData.ContainsKey(sectionName)) 159 | return _sectionData[sectionName]; 160 | 161 | return null; 162 | } 163 | 164 | public void Merge(SectionDataCollection sectionsToMerge) 165 | { 166 | foreach(var sectionDataToMerge in sectionsToMerge) 167 | { 168 | var sectionDataInThis = GetSectionData(sectionDataToMerge.SectionName); 169 | 170 | if (sectionDataInThis == null) 171 | { 172 | AddSection(sectionDataToMerge.SectionName); 173 | } 174 | 175 | this[sectionDataToMerge.SectionName].Merge(sectionDataToMerge.Keys); 176 | } 177 | } 178 | 179 | /// 180 | /// Sets the section data for given a section name. 181 | /// 182 | /// 183 | /// The new instance. 184 | public void SetSectionData(string sectionName, SectionData data) 185 | { 186 | if ( data != null ) 187 | _sectionData[sectionName] = data; 188 | } 189 | 190 | /// 191 | /// 192 | /// 193 | /// 194 | /// true if the section with the specified name was removed, 195 | /// false otherwise 196 | public bool RemoveSection(string keyName) 197 | { 198 | return _sectionData.Remove(keyName); 199 | } 200 | 201 | 202 | #endregion 203 | 204 | #region IEnumerable Members 205 | 206 | /// 207 | /// Returns an enumerator that iterates through the collection. 208 | /// 209 | /// 210 | /// A that can be used to iterate through the collection. 211 | /// 212 | public IEnumerator GetEnumerator() 213 | { 214 | foreach (string sectionName in _sectionData.Keys) 215 | yield return _sectionData[sectionName]; 216 | } 217 | 218 | #endregion 219 | 220 | #region IEnumerable Members 221 | 222 | /// 223 | /// Returns an enumerator that iterates through a collection. 224 | /// 225 | /// 226 | /// An object that can be used to iterate through the collection. 227 | /// 228 | IEnumerator IEnumerable.GetEnumerator() 229 | { 230 | return GetEnumerator(); 231 | } 232 | 233 | #endregion 234 | 235 | #region ICloneable Members 236 | 237 | /// 238 | /// Creates a new object that is a copy of the current instance. 239 | /// 240 | /// 241 | /// A new object that is a copy of this instance. 242 | /// 243 | public object Clone() 244 | { 245 | return new SectionDataCollection(this, _searchComparer); 246 | } 247 | 248 | #endregion 249 | 250 | #region Non-public Members 251 | 252 | /// 253 | /// Data associated to this section 254 | /// 255 | private readonly Dictionary _sectionData; 256 | 257 | #endregion 258 | 259 | } 260 | } -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/Parser/ConcatenateDuplicatedKeysIniDataParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using IniParser.Exceptions; 4 | using IniParser.Model; 5 | using IniParser.Model.Configuration; 6 | 7 | namespace IniParser.Parser 8 | { 9 | 10 | public class ConcatenateDuplicatedKeysIniDataParser : IniDataParser 11 | { 12 | public new ConcatenateDuplicatedKeysIniParserConfiguration Configuration 13 | { 14 | get 15 | { 16 | return (ConcatenateDuplicatedKeysIniParserConfiguration)base.Configuration; 17 | } 18 | set 19 | { 20 | base.Configuration = value; 21 | } 22 | } 23 | 24 | public ConcatenateDuplicatedKeysIniDataParser() 25 | :this(new ConcatenateDuplicatedKeysIniParserConfiguration()) 26 | {} 27 | 28 | public ConcatenateDuplicatedKeysIniDataParser(ConcatenateDuplicatedKeysIniParserConfiguration parserConfiguration) 29 | :base(parserConfiguration) 30 | {} 31 | 32 | protected override void HandleDuplicatedKeyInCollection(string key, string value, KeyDataCollection keyDataCollection, string sectionName) 33 | { 34 | keyDataCollection[key] += Configuration.ConcatenateSeparator + value; 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/StreamIniDataParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using IniParser.Model; 4 | using IniParser.Parser; 5 | using IniParser.Model.Formatting; 6 | 7 | namespace IniParser 8 | { 9 | 10 | /// 11 | /// Represents an INI data parser for streams. 12 | /// 13 | public class StreamIniDataParser 14 | { 15 | /// 16 | /// This instance will handle ini data parsing and writing 17 | /// 18 | public IniDataParser Parser { get; protected set; } 19 | 20 | /// 21 | /// Ctor 22 | /// 23 | public StreamIniDataParser() : this (new IniDataParser()) {} 24 | 25 | /// 26 | /// Ctor 27 | /// 28 | /// 29 | public StreamIniDataParser(IniDataParser parser) 30 | { 31 | Parser = parser; 32 | } 33 | #region Public Methods 34 | 35 | /// 36 | /// Reads data in INI format from a stream. 37 | /// 38 | /// Reader stream. 39 | /// 40 | /// And instance with the readed ini data parsed. 41 | /// 42 | /// 43 | /// Thrown if is null. 44 | /// 45 | public IniData ReadData(StreamReader reader) 46 | { 47 | if (reader == null) 48 | throw new ArgumentNullException("reader"); 49 | 50 | return Parser.Parse(reader.ReadToEnd()); 51 | } 52 | 53 | /// 54 | /// Writes the ini data to a stream. 55 | /// 56 | /// A write stream where the ini data will be stored 57 | /// An instance. 58 | /// 59 | /// Thrown if is null. 60 | /// 61 | public void WriteData(StreamWriter writer, IniData iniData) 62 | { 63 | if (iniData == null) 64 | throw new ArgumentNullException("iniData"); 65 | if (writer == null) 66 | throw new ArgumentNullException("writer"); 67 | 68 | writer.Write(iniData.ToString()); 69 | } 70 | 71 | 72 | /// 73 | /// Writes the ini data to a stream. 74 | /// 75 | /// A write stream where the ini data will be stored 76 | /// An instance. 77 | /// Formaterr instance that controls how the ini data is transformed to a string 78 | /// 79 | /// Thrown if is null. 80 | /// 81 | public void WriteData(StreamWriter writer, IniData iniData, IIniDataFormatter formatter) 82 | { 83 | if (formatter == null) 84 | throw new ArgumentNullException("formatter"); 85 | if (iniData == null) 86 | throw new ArgumentNullException("iniData"); 87 | if (writer == null) 88 | throw new ArgumentNullException("writer"); 89 | 90 | writer.Write(iniData.ToString(formatter)); 91 | } 92 | 93 | #endregion 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /v2tap/3rd/IniParser/StringIniParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IniParser.Model; 3 | using IniParser.Parser; 4 | 5 | namespace IniParser 6 | { 7 | /// 8 | /// Represents an INI data parser for strings. 9 | /// 10 | /// 11 | /// 12 | /// This class is deprecated and kept for backwards compatibility. 13 | /// It's just a wrapper around class. 14 | /// Please, replace your code. 15 | /// 16 | [Obsolete("Use class IniDataParser instead. See remarks comments in this class.")] 17 | public class StringIniParser 18 | { 19 | /// 20 | /// This instance will handle ini data parsing and writing 21 | /// 22 | public IniDataParser Parser { get; protected set; } 23 | 24 | /// 25 | /// Ctor 26 | /// 27 | public StringIniParser() : this (new IniDataParser()) {} 28 | 29 | /// 30 | /// Ctor 31 | /// 32 | /// 33 | public StringIniParser(IniDataParser parser) 34 | { 35 | Parser = parser; 36 | } 37 | 38 | /// 39 | /// Parses a string containing data formatted as an INI file. 40 | /// 41 | /// The string containing the data. 42 | /// 43 | /// A new instance with the data parsed from the string. 44 | /// 45 | public IniData ParseString(string dataStr) 46 | { 47 | return Parser.Parse(dataStr); 48 | } 49 | 50 | /// 51 | /// Creates a string from the INI data. 52 | /// 53 | /// An instance. 54 | /// 55 | /// A formatted string with the contents of the 56 | /// instance object. 57 | /// 58 | public string WriteString(IniData iniData) 59 | { 60 | return iniData.ToString(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /v2tap/3rd/v2ray/Stats/CommandGrpc.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: test.proto 4 | // 5 | #pragma warning disable 0414, 1591 6 | #region Designer generated code 7 | 8 | using grpc = global::Grpc.Core; 9 | 10 | namespace v2ray.Core.App.Stats.Command { 11 | public static partial class StatsService 12 | { 13 | static readonly string __ServiceName = "v2ray.core.app.stats.command.StatsService"; 14 | 15 | static readonly grpc::Marshaller __Marshaller_v2ray_core_app_stats_command_GetStatsRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::v2ray.Core.App.Stats.Command.GetStatsRequest.Parser.ParseFrom); 16 | static readonly grpc::Marshaller __Marshaller_v2ray_core_app_stats_command_GetStatsResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::v2ray.Core.App.Stats.Command.GetStatsResponse.Parser.ParseFrom); 17 | static readonly grpc::Marshaller __Marshaller_v2ray_core_app_stats_command_QueryStatsRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::v2ray.Core.App.Stats.Command.QueryStatsRequest.Parser.ParseFrom); 18 | static readonly grpc::Marshaller __Marshaller_v2ray_core_app_stats_command_QueryStatsResponse = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::v2ray.Core.App.Stats.Command.QueryStatsResponse.Parser.ParseFrom); 19 | 20 | static readonly grpc::Method __Method_GetStats = new grpc::Method( 21 | grpc::MethodType.Unary, 22 | __ServiceName, 23 | "GetStats", 24 | __Marshaller_v2ray_core_app_stats_command_GetStatsRequest, 25 | __Marshaller_v2ray_core_app_stats_command_GetStatsResponse); 26 | 27 | static readonly grpc::Method __Method_QueryStats = new grpc::Method( 28 | grpc::MethodType.Unary, 29 | __ServiceName, 30 | "QueryStats", 31 | __Marshaller_v2ray_core_app_stats_command_QueryStatsRequest, 32 | __Marshaller_v2ray_core_app_stats_command_QueryStatsResponse); 33 | 34 | /// Service descriptor 35 | public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor 36 | { 37 | get { return global::v2ray.Core.App.Stats.Command.TestReflection.Descriptor.Services[0]; } 38 | } 39 | 40 | /// Base class for server-side implementations of StatsService 41 | public abstract partial class StatsServiceBase 42 | { 43 | public virtual global::System.Threading.Tasks.Task GetStats(global::v2ray.Core.App.Stats.Command.GetStatsRequest request, grpc::ServerCallContext context) 44 | { 45 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); 46 | } 47 | 48 | public virtual global::System.Threading.Tasks.Task QueryStats(global::v2ray.Core.App.Stats.Command.QueryStatsRequest request, grpc::ServerCallContext context) 49 | { 50 | throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); 51 | } 52 | 53 | } 54 | 55 | /// Client for StatsService 56 | public partial class StatsServiceClient : grpc::ClientBase 57 | { 58 | /// Creates a new client for StatsService 59 | /// The channel to use to make remote calls. 60 | public StatsServiceClient(grpc::Channel channel) : base(channel) 61 | { 62 | } 63 | /// Creates a new client for StatsService that uses a custom CallInvoker. 64 | /// The callInvoker to use to make remote calls. 65 | public StatsServiceClient(grpc::CallInvoker callInvoker) : base(callInvoker) 66 | { 67 | } 68 | /// Protected parameterless constructor to allow creation of test doubles. 69 | protected StatsServiceClient() : base() 70 | { 71 | } 72 | /// Protected constructor to allow creation of configured clients. 73 | /// The client configuration. 74 | protected StatsServiceClient(ClientBaseConfiguration configuration) : base(configuration) 75 | { 76 | } 77 | 78 | public virtual global::v2ray.Core.App.Stats.Command.GetStatsResponse GetStats(global::v2ray.Core.App.Stats.Command.GetStatsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) 79 | { 80 | return GetStats(request, new grpc::CallOptions(headers, deadline, cancellationToken)); 81 | } 82 | public virtual global::v2ray.Core.App.Stats.Command.GetStatsResponse GetStats(global::v2ray.Core.App.Stats.Command.GetStatsRequest request, grpc::CallOptions options) 83 | { 84 | return CallInvoker.BlockingUnaryCall(__Method_GetStats, null, options, request); 85 | } 86 | public virtual grpc::AsyncUnaryCall GetStatsAsync(global::v2ray.Core.App.Stats.Command.GetStatsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) 87 | { 88 | return GetStatsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); 89 | } 90 | public virtual grpc::AsyncUnaryCall GetStatsAsync(global::v2ray.Core.App.Stats.Command.GetStatsRequest request, grpc::CallOptions options) 91 | { 92 | return CallInvoker.AsyncUnaryCall(__Method_GetStats, null, options, request); 93 | } 94 | public virtual global::v2ray.Core.App.Stats.Command.QueryStatsResponse QueryStats(global::v2ray.Core.App.Stats.Command.QueryStatsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) 95 | { 96 | return QueryStats(request, new grpc::CallOptions(headers, deadline, cancellationToken)); 97 | } 98 | public virtual global::v2ray.Core.App.Stats.Command.QueryStatsResponse QueryStats(global::v2ray.Core.App.Stats.Command.QueryStatsRequest request, grpc::CallOptions options) 99 | { 100 | return CallInvoker.BlockingUnaryCall(__Method_QueryStats, null, options, request); 101 | } 102 | public virtual grpc::AsyncUnaryCall QueryStatsAsync(global::v2ray.Core.App.Stats.Command.QueryStatsRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) 103 | { 104 | return QueryStatsAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); 105 | } 106 | public virtual grpc::AsyncUnaryCall QueryStatsAsync(global::v2ray.Core.App.Stats.Command.QueryStatsRequest request, grpc::CallOptions options) 107 | { 108 | return CallInvoker.AsyncUnaryCall(__Method_QueryStats, null, options, request); 109 | } 110 | /// Creates a new instance of client from given ClientBaseConfiguration. 111 | protected override StatsServiceClient NewInstance(ClientBaseConfiguration configuration) 112 | { 113 | return new StatsServiceClient(configuration); 114 | } 115 | } 116 | 117 | /// Creates service definition that can be registered with a server 118 | /// An object implementing the server-side handling logic. 119 | public static grpc::ServerServiceDefinition BindService(StatsServiceBase serviceImpl) 120 | { 121 | return grpc::ServerServiceDefinition.CreateBuilder() 122 | .AddMethod(__Method_GetStats, serviceImpl.GetStats) 123 | .AddMethod(__Method_QueryStats, serviceImpl.QueryStats).Build(); 124 | } 125 | 126 | /// Register service method implementations with a service binder. Useful when customizing the service binding logic. 127 | /// Note: this method is part of an experimental API that can change or be removed without any prior notice. 128 | /// Service methods will be bound by calling AddMethod on this object. 129 | /// An object implementing the server-side handling logic. 130 | public static void BindService(grpc::ServiceBinderBase serviceBinder, StatsServiceBase serviceImpl) 131 | { 132 | serviceBinder.AddMethod(__Method_GetStats, serviceImpl.GetStats); 133 | serviceBinder.AddMethod(__Method_QueryStats, serviceImpl.QueryStats); 134 | } 135 | 136 | } 137 | } 138 | #endregion 139 | -------------------------------------------------------------------------------- /v2tap/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /v2tap/Forms/AdvancedForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.IO; 4 | using System.Net; 5 | using System.Net.NetworkInformation; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | 10 | namespace v2tap.Forms 11 | { 12 | public partial class AdvancedForm : Form 13 | { 14 | public AdvancedForm() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | private void AdvancedForm_Load(object sender, EventArgs e) 20 | { 21 | Init(); 22 | } 23 | 24 | private void AdvancedForm_FormClosing(object sender, FormClosingEventArgs e) 25 | { 26 | Global.Form.MainForm.Show(); 27 | } 28 | 29 | private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) 30 | { 31 | var cbx = sender as ComboBox; 32 | if (cbx != null) 33 | { 34 | e.DrawBackground(); 35 | 36 | if (e.Index >= 0) 37 | { 38 | var sf = new StringFormat(); 39 | sf.LineAlignment = StringAlignment.Center; 40 | sf.Alignment = StringAlignment.Center; 41 | 42 | var brush = new SolidBrush(cbx.ForeColor); 43 | 44 | if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) 45 | { 46 | brush = SystemBrushes.HighlightText as SolidBrush; 47 | } 48 | 49 | e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf); 50 | } 51 | } 52 | } 53 | 54 | private void SaveButton_Click(object sender, EventArgs e) 55 | { 56 | Global.Configs.TUNTAPAddress = TUNTAPAddressTextBox.Text; 57 | Global.Configs.TUNTAPGateway = TUNTAPGatewayTextBox.Text; 58 | Global.Configs.TUNTAPNetmask = TUNTAPNetmaskTextBox.Text; 59 | Global.Configs.TUNTAPDNS = TUNTAPDNSTextBox.Text; 60 | Global.Configs.TUNTAPMetric = int.Parse(TUNTAPMetricTextBox.Text); 61 | Global.Configs.AutoAdapterMetric = AutoAdapterMetricCheckBox.Checked; 62 | Global.Configs.AutoCheckAdapter = AutoCheckAdapterCheckBox.Checked; 63 | 64 | if (v2rayLoggingLevelComboBox.Text.Contains("DEBUG")) Global.Configs.v2rayLoggingLevel = "DEBUG"; 65 | if (v2rayLoggingLevelComboBox.Text.Contains("INFO")) Global.Configs.v2rayLoggingLevel = "INFO"; 66 | if (v2rayLoggingLevelComboBox.Text.Contains("WARNING")) Global.Configs.v2rayLoggingLevel = "WARNING"; 67 | if (v2rayLoggingLevelComboBox.Text.Contains("ERROR")) Global.Configs.v2rayLoggingLevel = "ERROR"; 68 | if (v2rayLoggingLevelComboBox.Text.Contains("NONE")) Global.Configs.v2rayLoggingLevel = "NONE"; 69 | 70 | Utils.Util.SaveConfigsToFile(); 71 | MessageBox.Show("保存成功", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information); 72 | } 73 | 74 | private void ResetButton_Click(object sender, EventArgs e) 75 | { 76 | File.WriteAllText("v2tap.ini", Encoding.UTF8.GetString(Properties.Resources.defaultConfig)); 77 | 78 | Utils.Util.InitConfigsFromFile(); 79 | Init(); 80 | MessageBox.Show("重置成功", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information); 81 | } 82 | 83 | private void Init() 84 | { 85 | TUNTAPAddressTextBox.Text = Global.Configs.TUNTAPAddress; 86 | TUNTAPGatewayTextBox.Text = Global.Configs.TUNTAPGateway; 87 | TUNTAPNetmaskTextBox.Text = Global.Configs.TUNTAPNetmask; 88 | TUNTAPDNSTextBox.Text = Global.Configs.TUNTAPDNS; 89 | TUNTAPMetricTextBox.Text = Global.Configs.TUNTAPMetric.ToString(); 90 | AutoAdapterMetricCheckBox.Checked = Global.Configs.AutoAdapterMetric; 91 | AutoCheckAdapterCheckBox.Checked = Global.Configs.AutoCheckAdapter; 92 | 93 | foreach (var item in Global.Configs.AdapterAddress) 94 | { 95 | AdapterAddressComboBox.Items.Add(item); 96 | } 97 | 98 | AdapterAddressComboBox.SelectedIndex = Global.Configs.AdapterAddressIndex; 99 | 100 | foreach (var item in Global.Configs.AdapterGateway) 101 | { 102 | AdapterGatewayComboBox.Items.Add(item); 103 | } 104 | 105 | AdapterGatewayComboBox.SelectedIndex = Global.Configs.AdapterGatewayIndex; 106 | 107 | switch (Global.Configs.v2rayLoggingLevel) 108 | { 109 | case "DEBUG": 110 | v2rayLoggingLevelComboBox.SelectedIndex = 0; 111 | break; 112 | case "INFO": 113 | v2rayLoggingLevelComboBox.SelectedIndex = 1; 114 | break; 115 | case "WARNING": 116 | v2rayLoggingLevelComboBox.SelectedIndex = 2; 117 | break; 118 | case "ERROR": 119 | v2rayLoggingLevelComboBox.SelectedIndex = 3; 120 | break; 121 | case "NONE": 122 | v2rayLoggingLevelComboBox.SelectedIndex = 4; 123 | break; 124 | default: 125 | v2rayLoggingLevelComboBox.SelectedIndex = 0; 126 | break; 127 | } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /v2tap/Forms/AdvancedForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /v2tap/Forms/EditForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Windows.Forms; 4 | 5 | namespace v2tap.Forms 6 | { 7 | public partial class EditForm : Form 8 | { 9 | /// 10 | /// 窗体模式 11 | /// 12 | public string Mode; 13 | 14 | /// 15 | /// 当工作于编辑模式下时指定配置索引号 16 | /// 17 | public int Index; 18 | 19 | /// 20 | /// 默认配置 21 | /// 22 | public Objects.Server Server; 23 | 24 | public EditForm() 25 | { 26 | InitializeComponent(); 27 | } 28 | 29 | private void EditForm_Load(object sender, EventArgs e) 30 | { 31 | if (Mode == "Add") 32 | { 33 | Text = "添加 - v2tap"; 34 | TransferMethodComboBox.SelectedIndex = 0; 35 | FakeComboBox.SelectedIndex = 0; 36 | } 37 | else if (Mode == "Edit") 38 | { 39 | Text = "编辑 - v2tap"; 40 | RemarkTextBox.Text = Global.Proxies[Index].Remark; 41 | ServerAddressTextBox.Text = Global.Proxies[Index].Address; 42 | ServerPortTextBox.Text = Global.Proxies[Index].Port.ToString(); 43 | UserIDTextBox.Text = Global.Proxies[Index].UserID; 44 | AlterIDTextBox.Text = Global.Proxies[Index].AlterID.ToString(); 45 | PathTextBox.Text = Global.Proxies[Index].Path; 46 | 47 | switch (Global.Proxies[Index].TransferMethod) 48 | { 49 | case "TCP": 50 | TransferMethodComboBox.SelectedIndex = 0; 51 | break; 52 | case "mKCP": 53 | TransferMethodComboBox.SelectedIndex = 1; 54 | break; 55 | case "WebSockets": 56 | TransferMethodComboBox.SelectedIndex = 2; 57 | break; 58 | case "HTTP/2": 59 | TransferMethodComboBox.SelectedIndex = 3; 60 | break; 61 | case "QUIC": 62 | TransferMethodComboBox.SelectedIndex = 4; 63 | break; 64 | default: 65 | TransferMethodComboBox.SelectedIndex = 0; 66 | break; 67 | } 68 | 69 | switch (Global.Proxies[Index].FakeType) 70 | { 71 | case "None": 72 | FakeComboBox.SelectedIndex = 0; 73 | break; 74 | case "HTTP": 75 | FakeComboBox.SelectedIndex = 1; 76 | break; 77 | case "SRTP": 78 | FakeComboBox.SelectedIndex = 2; 79 | break; 80 | case "UTP": 81 | FakeComboBox.SelectedIndex = 3; 82 | break; 83 | case "DTLS": 84 | FakeComboBox.SelectedIndex = 4; 85 | break; 86 | case "WireGuard": 87 | FakeComboBox.SelectedIndex = 5; 88 | break; 89 | case "WeChat": 90 | FakeComboBox.SelectedIndex = 6; 91 | break; 92 | default: 93 | FakeComboBox.SelectedIndex = 0; 94 | break; 95 | } 96 | 97 | TLSSecureCheckBox.Checked = Global.Proxies[Index].TLSSecure; 98 | } 99 | } 100 | 101 | private void EditForm_FormClosing(object sender, FormClosingEventArgs e) 102 | { 103 | Global.Form.MainForm.Show(); 104 | } 105 | 106 | private void InputTextBox_KeyPress(object sender, KeyPressEventArgs e) 107 | { 108 | if ((e.KeyChar >= '0' && e.KeyChar <= '9') || e.KeyChar == 8) 109 | { 110 | e.Handled = false; 111 | } 112 | else 113 | { 114 | e.Handled = true; 115 | } 116 | } 117 | 118 | private void ComboBox_DrawItem(object sender, DrawItemEventArgs e) 119 | { 120 | var cbx = sender as ComboBox; 121 | if (cbx != null) 122 | { 123 | e.DrawBackground(); 124 | 125 | if (e.Index >= 0) 126 | { 127 | var sf = new StringFormat(); 128 | sf.LineAlignment = StringAlignment.Center; 129 | sf.Alignment = StringAlignment.Center; 130 | 131 | var brush = new SolidBrush(cbx.ForeColor); 132 | 133 | if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) 134 | { 135 | brush = SystemBrushes.HighlightText as SolidBrush; 136 | } 137 | 138 | e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf); 139 | } 140 | } 141 | } 142 | 143 | private void ControlButton_Click(object sender, EventArgs e) 144 | { 145 | if (Mode == "Add") 146 | { 147 | try 148 | { 149 | var server = new Objects.Server() 150 | { 151 | ID = Guid.NewGuid().ToString(), 152 | Remark = RemarkTextBox.Text, 153 | Address = ServerAddressTextBox.Text, 154 | Port = int.Parse(ServerPortTextBox.Text), 155 | UserID = UserIDTextBox.Text, 156 | AlterID = int.Parse(AlterIDTextBox.Text), 157 | TransferMethod = TransferMethodComboBox.Text, 158 | Path = PathTextBox.Text, 159 | TLSSecure = TLSSecureCheckBox.Checked 160 | }; 161 | Global.Proxies.Add(server); 162 | } 163 | catch (Exception ex) 164 | { 165 | MessageBox.Show("发生错误:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 166 | return; 167 | } 168 | 169 | Global.Form.MainForm.InitProxies(); 170 | Utils.Util.SaveServersToFile(); 171 | 172 | MessageBox.Show("保存成功", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information); 173 | } 174 | else if (Mode == "Edit") 175 | { 176 | Global.Proxies[Index].Remark = RemarkTextBox.Text; 177 | Global.Proxies[Index].Address = ServerAddressTextBox.Text; 178 | Global.Proxies[Index].Port = int.Parse(ServerPortTextBox.Text); 179 | Global.Proxies[Index].UserID = UserIDTextBox.Text; 180 | Global.Proxies[Index].AlterID = int.Parse(AlterIDTextBox.Text); 181 | Global.Proxies[Index].TransferMethod = TransferMethodComboBox.Text; 182 | Global.Proxies[Index].Path = PathTextBox.Text; 183 | Global.Proxies[Index].FakeType = FakeComboBox.Text; 184 | Global.Proxies[Index].TLSSecure = TLSSecureCheckBox.Checked; 185 | 186 | Global.Form.MainForm.InitProxies(); 187 | Utils.Util.SaveServersToFile(); 188 | 189 | MessageBox.Show("保存成功", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information); 190 | } 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /v2tap/Forms/EditForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /v2tap/Forms/ImportForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace v2tap.Forms 2 | { 3 | partial class ImportForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.ImportFromSubscriptionURLGroupBox = new System.Windows.Forms.GroupBox(); 32 | this.SubscriptionImportButton = new System.Windows.Forms.Button(); 33 | this.SubscriptionURLTextBox = new System.Windows.Forms.TextBox(); 34 | this.SubscriptionURLLabel = new System.Windows.Forms.Label(); 35 | this.ImportFromTextBoxGroupBox = new System.Windows.Forms.GroupBox(); 36 | this.MyButton = new System.Windows.Forms.Button(); 37 | this.MyTextBox = new System.Windows.Forms.TextBox(); 38 | this.ImportFromSubscriptionURLGroupBox.SuspendLayout(); 39 | this.ImportFromTextBoxGroupBox.SuspendLayout(); 40 | this.SuspendLayout(); 41 | // 42 | // ImportFromSubscriptionURLGroupBox 43 | // 44 | this.ImportFromSubscriptionURLGroupBox.Controls.Add(this.SubscriptionImportButton); 45 | this.ImportFromSubscriptionURLGroupBox.Controls.Add(this.SubscriptionURLTextBox); 46 | this.ImportFromSubscriptionURLGroupBox.Controls.Add(this.SubscriptionURLLabel); 47 | this.ImportFromSubscriptionURLGroupBox.Location = new System.Drawing.Point(14, 17); 48 | this.ImportFromSubscriptionURLGroupBox.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); 49 | this.ImportFromSubscriptionURLGroupBox.Name = "ImportFromSubscriptionURLGroupBox"; 50 | this.ImportFromSubscriptionURLGroupBox.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); 51 | this.ImportFromSubscriptionURLGroupBox.Size = new System.Drawing.Size(559, 78); 52 | this.ImportFromSubscriptionURLGroupBox.TabIndex = 0; 53 | this.ImportFromSubscriptionURLGroupBox.TabStop = false; 54 | this.ImportFromSubscriptionURLGroupBox.Text = "从订阅链接导入"; 55 | // 56 | // SubscriptionImportButton 57 | // 58 | this.SubscriptionImportButton.Location = new System.Drawing.Point(478, 49); 59 | this.SubscriptionImportButton.Name = "SubscriptionImportButton"; 60 | this.SubscriptionImportButton.Size = new System.Drawing.Size(75, 23); 61 | this.SubscriptionImportButton.TabIndex = 2; 62 | this.SubscriptionImportButton.Text = "导入"; 63 | this.SubscriptionImportButton.UseVisualStyleBackColor = true; 64 | this.SubscriptionImportButton.Click += new System.EventHandler(this.SubscriptionImportButton_Click); 65 | // 66 | // SubscriptionURLTextBox 67 | // 68 | this.SubscriptionURLTextBox.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 69 | this.SubscriptionURLTextBox.Location = new System.Drawing.Point(44, 20); 70 | this.SubscriptionURLTextBox.Name = "SubscriptionURLTextBox"; 71 | this.SubscriptionURLTextBox.Size = new System.Drawing.Size(509, 22); 72 | this.SubscriptionURLTextBox.TabIndex = 1; 73 | // 74 | // SubscriptionURLLabel 75 | // 76 | this.SubscriptionURLLabel.AutoSize = true; 77 | this.SubscriptionURLLabel.Location = new System.Drawing.Point(8, 23); 78 | this.SubscriptionURLLabel.Name = "SubscriptionURLLabel"; 79 | this.SubscriptionURLLabel.Size = new System.Drawing.Size(44, 17); 80 | this.SubscriptionURLLabel.TabIndex = 0; 81 | this.SubscriptionURLLabel.Text = "链接:"; 82 | // 83 | // ImportFromTextBoxGroupBox 84 | // 85 | this.ImportFromTextBoxGroupBox.Controls.Add(this.MyButton); 86 | this.ImportFromTextBoxGroupBox.Controls.Add(this.MyTextBox); 87 | this.ImportFromTextBoxGroupBox.Location = new System.Drawing.Point(12, 102); 88 | this.ImportFromTextBoxGroupBox.Name = "ImportFromTextBoxGroupBox"; 89 | this.ImportFromTextBoxGroupBox.Size = new System.Drawing.Size(561, 260); 90 | this.ImportFromTextBoxGroupBox.TabIndex = 1; 91 | this.ImportFromTextBoxGroupBox.TabStop = false; 92 | this.ImportFromTextBoxGroupBox.Text = "从文本框中导入"; 93 | // 94 | // MyButton 95 | // 96 | this.MyButton.Location = new System.Drawing.Point(480, 231); 97 | this.MyButton.Name = "MyButton"; 98 | this.MyButton.Size = new System.Drawing.Size(75, 23); 99 | this.MyButton.TabIndex = 1; 100 | this.MyButton.Text = "导入"; 101 | this.MyButton.UseVisualStyleBackColor = true; 102 | this.MyButton.Click += new System.EventHandler(this.MyButton_Click); 103 | // 104 | // MyTextBox 105 | // 106 | this.MyTextBox.Font = new System.Drawing.Font("Consolas", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 107 | this.MyTextBox.Location = new System.Drawing.Point(13, 22); 108 | this.MyTextBox.Multiline = true; 109 | this.MyTextBox.Name = "MyTextBox"; 110 | this.MyTextBox.Size = new System.Drawing.Size(542, 203); 111 | this.MyTextBox.TabIndex = 0; 112 | // 113 | // ImportForm 114 | // 115 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); 116 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 117 | this.ClientSize = new System.Drawing.Size(585, 375); 118 | this.Controls.Add(this.ImportFromTextBoxGroupBox); 119 | this.Controls.Add(this.ImportFromSubscriptionURLGroupBox); 120 | this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); 121 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 122 | this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); 123 | this.MaximizeBox = false; 124 | this.Name = "ImportForm"; 125 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 126 | this.Text = "导入 - v2tap"; 127 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ImportForm_FormClosing); 128 | this.Load += new System.EventHandler(this.ImportForm_Load); 129 | this.ImportFromSubscriptionURLGroupBox.ResumeLayout(false); 130 | this.ImportFromSubscriptionURLGroupBox.PerformLayout(); 131 | this.ImportFromTextBoxGroupBox.ResumeLayout(false); 132 | this.ImportFromTextBoxGroupBox.PerformLayout(); 133 | this.ResumeLayout(false); 134 | 135 | } 136 | 137 | #endregion 138 | 139 | private System.Windows.Forms.GroupBox ImportFromSubscriptionURLGroupBox; 140 | private System.Windows.Forms.Button SubscriptionImportButton; 141 | private System.Windows.Forms.TextBox SubscriptionURLTextBox; 142 | private System.Windows.Forms.Label SubscriptionURLLabel; 143 | private System.Windows.Forms.GroupBox ImportFromTextBoxGroupBox; 144 | private System.Windows.Forms.TextBox MyTextBox; 145 | private System.Windows.Forms.Button MyButton; 146 | } 147 | } -------------------------------------------------------------------------------- /v2tap/Forms/ImportForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using System.Windows.Forms; 5 | 6 | namespace v2tap.Forms 7 | { 8 | public partial class ImportForm : Form 9 | { 10 | public ImportForm() 11 | { 12 | InitializeComponent(); 13 | } 14 | 15 | private void ImportForm_Load(object sender, EventArgs e) 16 | { 17 | // 读取订阅链接 18 | if (File.Exists("lastSubscriptionURL.txt")) SubscriptionURLTextBox.Text = File.ReadAllText("lastSubscriptionURL.txt"); 19 | } 20 | 21 | private void ImportForm_FormClosing(object sender, FormClosingEventArgs e) 22 | { 23 | Global.Form.MainForm.Show(); 24 | } 25 | 26 | private void SubscriptionImportButton_Click(object sender, EventArgs e) 27 | { 28 | try 29 | { 30 | var client = Override.WebClient.GetClient(); 31 | var data = client.DownloadString(SubscriptionURLTextBox.Text); 32 | 33 | if (data != "") 34 | { 35 | var next = false; 36 | for (int i = 0; i < 4; i++) 37 | { 38 | try 39 | { 40 | data = Encoding.UTF8.GetString(Convert.FromBase64String(data)); 41 | } 42 | catch (FormatException) 43 | { 44 | data += "="; 45 | continue; 46 | } 47 | 48 | next = true; 49 | break; 50 | } 51 | 52 | if (next) 53 | { 54 | Global.Proxies.Clear(); 55 | using (StringReader sr = new StringReader(data)) 56 | { 57 | string text; 58 | 59 | while ((text = sr.ReadLine()) != null) 60 | { 61 | var server = ParseServer(text); 62 | 63 | Global.Proxies.Add(server); 64 | } 65 | } 66 | 67 | Global.Form.MainForm.InitProxies(); 68 | File.WriteAllText("lastSubscriptionURL.txt", SubscriptionURLTextBox.Text); // 保存订阅链接 69 | MessageBox.Show("订阅已成功导入", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information); 70 | } 71 | else 72 | { 73 | MessageBox.Show("Base64 解码失败", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 74 | } 75 | } 76 | else 77 | { 78 | MessageBox.Show("返回数据为空", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 79 | } 80 | } 81 | catch (Exception ex) 82 | { 83 | MessageBox.Show("发生错误:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 84 | } 85 | } 86 | 87 | private void MyButton_Click(object sender, EventArgs e) 88 | { 89 | if (MyTextBox.Text == "") 90 | { 91 | MessageBox.Show("文本框为空", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 92 | return; 93 | } 94 | 95 | try 96 | { 97 | Global.Proxies.Clear(); 98 | using (StringReader sr = new StringReader(MyTextBox.Text)) 99 | { 100 | string text; 101 | 102 | while ((text = sr.ReadLine()) != null) 103 | { 104 | var server = ParseServer(text); 105 | 106 | Global.Proxies.Add(server); 107 | } 108 | } 109 | 110 | Global.Form.MainForm.InitProxies(); 111 | MessageBox.Show("订阅已成功导入", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information); 112 | } 113 | catch (Exception ex) 114 | { 115 | MessageBox.Show("发生错误:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 116 | } 117 | } 118 | 119 | public Objects.Server ParseServer(string text) 120 | { 121 | var json = SimpleJSON.JSON.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(text.Replace("vmess://", "")))); 122 | var server = new Objects.Server() 123 | { 124 | ID = Guid.NewGuid().ToString(), 125 | Remark = json["ps"].Value, 126 | Address = json["add"].Value, 127 | Port = json["port"].AsInt, 128 | UserID = json["id"].Value, 129 | AlterID = json["aid"].AsInt, 130 | Path = (json["path"].Value == "") ? "/" : json["path"].Value, 131 | TLSSecure = (json["tls"].Value == "") ? false : true 132 | }; 133 | 134 | switch (json["net"].Value) 135 | { 136 | case "tcp": 137 | server.TransferMethod = "TCP"; 138 | break; 139 | case "kcp": 140 | server.TransferMethod = "mKCP"; 141 | break; 142 | case "ws": 143 | server.TransferMethod = "WebSockets"; 144 | break; 145 | case "h2": 146 | server.TransferMethod = "HTTP/2"; 147 | break; 148 | case "quic": 149 | server.TransferMethod = "QUIC"; 150 | break; 151 | default: 152 | server.TransferMethod = "TCP"; 153 | break; 154 | } 155 | 156 | switch (json["type"].Value) 157 | { 158 | case "none": 159 | server.FakeType = "None"; 160 | break; 161 | case "http": 162 | server.FakeType = "HTTP"; 163 | break; 164 | case "srtp": 165 | server.FakeType = "SRTP"; 166 | break; 167 | case "utp": 168 | server.FakeType = "UTP"; 169 | break; 170 | case "dtls": 171 | server.FakeType = "DTLS"; 172 | break; 173 | case "wireguard": 174 | server.FakeType = "WireGuard"; 175 | break; 176 | case "wechat-video": 177 | server.FakeType = "WeChat"; 178 | break; 179 | default: 180 | server.FakeType = "None"; 181 | break; 182 | } 183 | 184 | return server; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /v2tap/Forms/ImportForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /v2tap/Forms/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace v2tap.Forms 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.v2rayGroupBox = new System.Windows.Forms.GroupBox(); 32 | this.v2rayEditButton = new System.Windows.Forms.Button(); 33 | this.v2rayImportButton = new System.Windows.Forms.Button(); 34 | this.v2rayDeleteButton = new System.Windows.Forms.Button(); 35 | this.v2rayAddButton = new System.Windows.Forms.Button(); 36 | this.v2rayModeComboBox = new System.Windows.Forms.ComboBox(); 37 | this.v2rayModeLabel = new System.Windows.Forms.Label(); 38 | this.v2rayProxyComboBox = new System.Windows.Forms.ComboBox(); 39 | this.v2rayProxyLabel = new System.Windows.Forms.Label(); 40 | this.AdvancedButton = new System.Windows.Forms.Button(); 41 | this.ControlButton = new System.Windows.Forms.Button(); 42 | this.StatusLabel = new System.Windows.Forms.Label(); 43 | this.StatusStrip = new System.Windows.Forms.StatusStrip(); 44 | this.UplinkLabel = new System.Windows.Forms.ToolStripStatusLabel(); 45 | this.DownlinkLabel = new System.Windows.Forms.ToolStripStatusLabel(); 46 | this.BandwidthLabel = new System.Windows.Forms.ToolStripStatusLabel(); 47 | this.v2rayGroupBox.SuspendLayout(); 48 | this.StatusStrip.SuspendLayout(); 49 | this.SuspendLayout(); 50 | // 51 | // v2rayGroupBox 52 | // 53 | this.v2rayGroupBox.Controls.Add(this.v2rayEditButton); 54 | this.v2rayGroupBox.Controls.Add(this.v2rayImportButton); 55 | this.v2rayGroupBox.Controls.Add(this.v2rayDeleteButton); 56 | this.v2rayGroupBox.Controls.Add(this.v2rayAddButton); 57 | this.v2rayGroupBox.Controls.Add(this.v2rayModeComboBox); 58 | this.v2rayGroupBox.Controls.Add(this.v2rayModeLabel); 59 | this.v2rayGroupBox.Controls.Add(this.v2rayProxyComboBox); 60 | this.v2rayGroupBox.Controls.Add(this.v2rayProxyLabel); 61 | this.v2rayGroupBox.Location = new System.Drawing.Point(14, 17); 62 | this.v2rayGroupBox.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); 63 | this.v2rayGroupBox.Name = "v2rayGroupBox"; 64 | this.v2rayGroupBox.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4); 65 | this.v2rayGroupBox.Size = new System.Drawing.Size(430, 111); 66 | this.v2rayGroupBox.TabIndex = 0; 67 | this.v2rayGroupBox.TabStop = false; 68 | this.v2rayGroupBox.Text = "v2ray 配置"; 69 | // 70 | // v2rayEditButton 71 | // 72 | this.v2rayEditButton.Location = new System.Drawing.Point(268, 82); 73 | this.v2rayEditButton.Name = "v2rayEditButton"; 74 | this.v2rayEditButton.Size = new System.Drawing.Size(75, 23); 75 | this.v2rayEditButton.TabIndex = 7; 76 | this.v2rayEditButton.Text = "编辑"; 77 | this.v2rayEditButton.UseVisualStyleBackColor = true; 78 | this.v2rayEditButton.Click += new System.EventHandler(this.v2rayEditButton_Click); 79 | // 80 | // v2rayImportButton 81 | // 82 | this.v2rayImportButton.Location = new System.Drawing.Point(349, 82); 83 | this.v2rayImportButton.Name = "v2rayImportButton"; 84 | this.v2rayImportButton.Size = new System.Drawing.Size(75, 23); 85 | this.v2rayImportButton.TabIndex = 6; 86 | this.v2rayImportButton.Text = "导入"; 87 | this.v2rayImportButton.UseVisualStyleBackColor = true; 88 | this.v2rayImportButton.Click += new System.EventHandler(this.v2rayImportButton_Click); 89 | // 90 | // v2rayDeleteButton 91 | // 92 | this.v2rayDeleteButton.Location = new System.Drawing.Point(187, 82); 93 | this.v2rayDeleteButton.Name = "v2rayDeleteButton"; 94 | this.v2rayDeleteButton.Size = new System.Drawing.Size(75, 23); 95 | this.v2rayDeleteButton.TabIndex = 5; 96 | this.v2rayDeleteButton.Text = "删除"; 97 | this.v2rayDeleteButton.UseVisualStyleBackColor = true; 98 | this.v2rayDeleteButton.Click += new System.EventHandler(this.v2rayDeleteButton_Click); 99 | // 100 | // v2rayAddButton 101 | // 102 | this.v2rayAddButton.Location = new System.Drawing.Point(106, 82); 103 | this.v2rayAddButton.Name = "v2rayAddButton"; 104 | this.v2rayAddButton.Size = new System.Drawing.Size(75, 23); 105 | this.v2rayAddButton.TabIndex = 4; 106 | this.v2rayAddButton.Text = "添加"; 107 | this.v2rayAddButton.UseVisualStyleBackColor = true; 108 | this.v2rayAddButton.Click += new System.EventHandler(this.v2rayAddButton_Click); 109 | // 110 | // v2rayModeComboBox 111 | // 112 | this.v2rayModeComboBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; 113 | this.v2rayModeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 114 | this.v2rayModeComboBox.FormattingEnabled = true; 115 | this.v2rayModeComboBox.Items.AddRange(new object[] { 116 | "[内部规则] 绕过局域网", 117 | "[内部规则] 绕过局域网和中国"}); 118 | this.v2rayModeComboBox.Location = new System.Drawing.Point(44, 51); 119 | this.v2rayModeComboBox.Name = "v2rayModeComboBox"; 120 | this.v2rayModeComboBox.Size = new System.Drawing.Size(380, 24); 121 | this.v2rayModeComboBox.TabIndex = 3; 122 | this.v2rayModeComboBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ComboBox_DrawItem); 123 | // 124 | // v2rayModeLabel 125 | // 126 | this.v2rayModeLabel.AutoSize = true; 127 | this.v2rayModeLabel.Location = new System.Drawing.Point(4, 55); 128 | this.v2rayModeLabel.Name = "v2rayModeLabel"; 129 | this.v2rayModeLabel.Size = new System.Drawing.Size(44, 17); 130 | this.v2rayModeLabel.TabIndex = 2; 131 | this.v2rayModeLabel.Text = "模式:"; 132 | // 133 | // v2rayProxyComboBox 134 | // 135 | this.v2rayProxyComboBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; 136 | this.v2rayProxyComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 137 | this.v2rayProxyComboBox.FormattingEnabled = true; 138 | this.v2rayProxyComboBox.Location = new System.Drawing.Point(44, 20); 139 | this.v2rayProxyComboBox.Name = "v2rayProxyComboBox"; 140 | this.v2rayProxyComboBox.Size = new System.Drawing.Size(380, 24); 141 | this.v2rayProxyComboBox.TabIndex = 1; 142 | this.v2rayProxyComboBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.ComboBox_DrawItem); 143 | // 144 | // v2rayProxyLabel 145 | // 146 | this.v2rayProxyLabel.AutoSize = true; 147 | this.v2rayProxyLabel.Location = new System.Drawing.Point(4, 24); 148 | this.v2rayProxyLabel.Name = "v2rayProxyLabel"; 149 | this.v2rayProxyLabel.Size = new System.Drawing.Size(44, 17); 150 | this.v2rayProxyLabel.TabIndex = 0; 151 | this.v2rayProxyLabel.Text = "代理:"; 152 | // 153 | // AdvancedButton 154 | // 155 | this.AdvancedButton.Location = new System.Drawing.Point(14, 135); 156 | this.AdvancedButton.Name = "AdvancedButton"; 157 | this.AdvancedButton.Size = new System.Drawing.Size(75, 23); 158 | this.AdvancedButton.TabIndex = 1; 159 | this.AdvancedButton.Text = "高级设置"; 160 | this.AdvancedButton.UseVisualStyleBackColor = true; 161 | this.AdvancedButton.Click += new System.EventHandler(this.AdvancedButton_Click); 162 | // 163 | // ControlButton 164 | // 165 | this.ControlButton.Location = new System.Drawing.Point(369, 135); 166 | this.ControlButton.Name = "ControlButton"; 167 | this.ControlButton.Size = new System.Drawing.Size(75, 23); 168 | this.ControlButton.TabIndex = 2; 169 | this.ControlButton.Text = "启动"; 170 | this.ControlButton.UseVisualStyleBackColor = true; 171 | this.ControlButton.Click += new System.EventHandler(this.ControlButton_Click); 172 | // 173 | // StatusLabel 174 | // 175 | this.StatusLabel.AutoSize = true; 176 | this.StatusLabel.Location = new System.Drawing.Point(95, 138); 177 | this.StatusLabel.Name = "StatusLabel"; 178 | this.StatusLabel.Size = new System.Drawing.Size(128, 17); 179 | this.StatusLabel.TabIndex = 3; 180 | this.StatusLabel.Text = "当前状态:等待指令中"; 181 | // 182 | // StatusStrip 183 | // 184 | this.StatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 185 | this.UplinkLabel, 186 | this.DownlinkLabel, 187 | this.BandwidthLabel}); 188 | this.StatusStrip.Location = new System.Drawing.Point(0, 163); 189 | this.StatusStrip.Name = "StatusStrip"; 190 | this.StatusStrip.Size = new System.Drawing.Size(456, 22); 191 | this.StatusStrip.SizingGrip = false; 192 | this.StatusStrip.TabIndex = 4; 193 | // 194 | // UplinkLabel 195 | // 196 | this.UplinkLabel.Name = "UplinkLabel"; 197 | this.UplinkLabel.Size = new System.Drawing.Size(60, 17); 198 | this.UplinkLabel.Text = "↑:0KB/s"; 199 | // 200 | // DownlinkLabel 201 | // 202 | this.DownlinkLabel.Name = "DownlinkLabel"; 203 | this.DownlinkLabel.Size = new System.Drawing.Size(60, 17); 204 | this.DownlinkLabel.Text = "↓:0KB/s"; 205 | // 206 | // BandwidthLabel 207 | // 208 | this.BandwidthLabel.Name = "BandwidthLabel"; 209 | this.BandwidthLabel.Size = new System.Drawing.Size(83, 17); 210 | this.BandwidthLabel.Text = "总流量:0 KB"; 211 | // 212 | // MainForm 213 | // 214 | this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F); 215 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 216 | this.ClientSize = new System.Drawing.Size(456, 185); 217 | this.Controls.Add(this.StatusStrip); 218 | this.Controls.Add(this.StatusLabel); 219 | this.Controls.Add(this.ControlButton); 220 | this.Controls.Add(this.AdvancedButton); 221 | this.Controls.Add(this.v2rayGroupBox); 222 | this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); 223 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 224 | this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); 225 | this.MaximizeBox = false; 226 | this.Name = "MainForm"; 227 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 228 | this.Text = "v2tap"; 229 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); 230 | this.Load += new System.EventHandler(this.MainForm_Load); 231 | this.v2rayGroupBox.ResumeLayout(false); 232 | this.v2rayGroupBox.PerformLayout(); 233 | this.StatusStrip.ResumeLayout(false); 234 | this.StatusStrip.PerformLayout(); 235 | this.ResumeLayout(false); 236 | this.PerformLayout(); 237 | 238 | } 239 | 240 | #endregion 241 | public System.Windows.Forms.GroupBox v2rayGroupBox; 242 | public System.Windows.Forms.Label v2rayProxyLabel; 243 | public System.Windows.Forms.ComboBox v2rayProxyComboBox; 244 | public System.Windows.Forms.Button v2rayAddButton; 245 | public System.Windows.Forms.ComboBox v2rayModeComboBox; 246 | public System.Windows.Forms.Label v2rayModeLabel; 247 | public System.Windows.Forms.Button v2rayDeleteButton; 248 | public System.Windows.Forms.Button v2rayImportButton; 249 | private System.Windows.Forms.Button AdvancedButton; 250 | public System.Windows.Forms.Button v2rayEditButton; 251 | public System.Windows.Forms.Button ControlButton; 252 | private System.Windows.Forms.Label StatusLabel; 253 | private System.Windows.Forms.StatusStrip StatusStrip; 254 | private System.Windows.Forms.ToolStripStatusLabel UplinkLabel; 255 | private System.Windows.Forms.ToolStripStatusLabel DownlinkLabel; 256 | private System.Windows.Forms.ToolStripStatusLabel BandwidthLabel; 257 | } 258 | } -------------------------------------------------------------------------------- /v2tap/Forms/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /v2tap/Global.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace v2tap 8 | { 9 | /// 10 | /// 全局变量 11 | /// 12 | public static class Global 13 | { 14 | /// 15 | /// 路径 16 | /// 17 | public static class Path 18 | { 19 | /// 20 | /// 日志目录 21 | /// 22 | public static string LoggingDirectory = "logging"; 23 | 24 | /// 25 | /// v2tap 日志 26 | /// 27 | public static string v2tapLogging = "v2tap.txt"; 28 | 29 | /// 30 | /// v2ray 日志 31 | /// 32 | public static string v2rayLogging = "v2ray.txt"; 33 | 34 | /// 35 | /// tun2socks 日志 36 | /// 37 | public static string tun2socksLogging = "tun2socks.txt"; 38 | 39 | /// 40 | /// 模式目录 41 | /// 42 | public static string ModeDirectory = "mode"; 43 | } 44 | 45 | /// 46 | /// 日志等级 47 | /// 48 | public enum Level 49 | { 50 | /// 51 | /// 调试 52 | /// 53 | DEBUG, 54 | 55 | /// 56 | /// 信息 57 | /// 58 | INFO, 59 | 60 | /// 61 | /// 警告 62 | /// 63 | WARNING, 64 | 65 | /// 66 | /// 错误 67 | /// 68 | ERROR 69 | } 70 | 71 | /// 72 | /// 窗体 73 | /// 74 | public static class Form 75 | { 76 | /// 77 | /// 主窗体 78 | /// 79 | public static Forms.MainForm MainForm; 80 | 81 | /// 82 | /// 编辑 83 | /// 84 | public static Forms.EditForm EditForm; 85 | 86 | /// 87 | /// 导入 88 | /// 89 | public static Forms.ImportForm ImportForm; 90 | 91 | /// 92 | /// 高级设置 93 | /// 94 | public static Forms.AdvancedForm AdvancedForm; 95 | } 96 | 97 | /// 98 | /// 配置信息 99 | /// 100 | public static class Configs 101 | { 102 | /// 103 | /// TUN/TAP 地址 104 | /// 105 | public static string TUNTAPAddress; 106 | 107 | /// 108 | /// TUN/TAP 网关 109 | /// 110 | public static string TUNTAPGateway; 111 | 112 | /// 113 | /// TUN/TAP 掩码 114 | /// 115 | public static string TUNTAPNetmask; 116 | 117 | /// 118 | /// TUN/TAP DNS 119 | /// 120 | public static string TUNTAPDNS; 121 | 122 | /// 123 | /// TUN/TAP 跃点数 124 | /// 125 | public static int TUNTAPMetric; 126 | 127 | /// 128 | /// 自动降低适配器跃点数 129 | /// 130 | public static bool AutoAdapterMetric; 131 | 132 | /// 133 | /// 适配器地址 134 | /// 135 | public static List AdapterAddress = new List(); 136 | 137 | /// 138 | /// 适配器地址索引 139 | /// 140 | public static int AdapterAddressIndex; 141 | 142 | /// 143 | /// 适配器网关 144 | /// 145 | public static List AdapterGateway = new List(); 146 | 147 | /// 148 | /// 适配器网关索引 149 | /// 150 | public static int AdapterGatewayIndex; 151 | 152 | /// 153 | /// 自动检测出网适配器 154 | /// 155 | public static bool AutoCheckAdapter; 156 | 157 | /// 158 | /// v2ray 日志等级 159 | /// 160 | public static string v2rayLoggingLevel; 161 | } 162 | 163 | /// 164 | /// 代理信息 165 | /// 166 | public static List Proxies = new List(); 167 | 168 | /// 169 | /// 模式信息 170 | /// 171 | public static List Modes = new List(); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /v2tap/Objects/Mode.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace v2tap.Objects 4 | { 5 | public class Mode 6 | { 7 | /// 8 | /// 名称 9 | /// 10 | public string Name; 11 | 12 | /// 13 | /// 规则 14 | /// 15 | public List> Rule = new List>(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /v2tap/Objects/Server.cs: -------------------------------------------------------------------------------- 1 | namespace v2tap.Objects 2 | { 3 | public class Server 4 | { 5 | /// 6 | /// 唯一 ID 7 | /// 8 | public string ID; 9 | 10 | /// 11 | /// 备注 12 | /// 13 | public string Remark; 14 | 15 | /// 16 | /// 地址 17 | /// 18 | public string Address; 19 | 20 | /// 21 | /// 端口 22 | /// 23 | public int Port; 24 | 25 | /// 26 | /// 用户 ID 27 | /// 28 | public string UserID; 29 | 30 | /// 31 | /// 额外 ID 32 | /// 33 | public int AlterID; 34 | 35 | /// 36 | /// 传输方式 37 | /// 38 | public string TransferMethod; 39 | 40 | /// 41 | /// 路径 42 | /// 43 | public string Path; 44 | 45 | /// 46 | /// 伪装类型 47 | /// 48 | public string FakeType; 49 | 50 | /// 51 | /// TLS 底层传输安全 52 | /// 53 | public bool TLSSecure; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /v2tap/Override/WebClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | 4 | namespace v2tap.Override 5 | { 6 | public class WebClient : System.Net.WebClient 7 | { 8 | /// 9 | /// 超时 10 | /// 11 | public int Timeout = 4000; 12 | 13 | protected override WebRequest GetWebRequest(Uri address) 14 | { 15 | var request = base.GetWebRequest(address); 16 | request.Timeout = Timeout; 17 | ((HttpWebRequest)request).ReadWriteTimeout = Timeout; 18 | 19 | return request; 20 | } 21 | 22 | public static WebClient GetClient() 23 | { 24 | return new WebClient(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /v2tap/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // 有关程序集的一般信息由以下 6 | // 控制。更改这些特性值可修改 7 | // 与程序集关联的信息。 8 | [assembly: AssemblyTitle("v2tap")] 9 | [assembly: AssemblyDescription("将 tun2socks 和 v2ray 搭配实现的 VPN 工具,跟 SSTap 类似")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("v2tap")] 13 | [assembly: AssemblyCopyright("Copyright © 2018 - 2019 Holli_Freed")] 14 | [assembly: AssemblyTrademark("Holli_Freed")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // 将 ComVisible 设置为 false 会使此程序集中的类型 18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 19 | //请将此类型的 ComVisible 特性设置为 true。 20 | [assembly: ComVisible(false)] 21 | 22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID 23 | [assembly: Guid("53132dc3-8a46-4558-978c-605a643d1300")] 24 | 25 | // 程序集的版本信息由下列四个值组成: 26 | // 27 | // 主版本 28 | // 次版本 29 | // 生成号 30 | // 修订号 31 | // 32 | // 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 33 | // 方法是按如下所示使用“*”: : 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.1.1.3")] 36 | [assembly: AssemblyFileVersion("0.1.1.3")] 37 | -------------------------------------------------------------------------------- /v2tap/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace v2tap.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("v2tap.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性 51 | /// 重写当前线程的 CurrentUICulture 属性。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找 System.Byte[] 类型的本地化资源。 65 | /// 66 | internal static byte[] defaultConfig { 67 | get { 68 | object obj = ResourceManager.GetObject("defaultConfig", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// 查找 System.Byte[] 类型的本地化资源。 75 | /// 76 | internal static byte[] defaultServerConfig { 77 | get { 78 | object obj = ResourceManager.GetObject("defaultServerConfig", resourceCulture); 79 | return ((byte[])(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// 查找 System.Byte[] 类型的本地化资源。 85 | /// 86 | internal static byte[] v2ray { 87 | get { 88 | object obj = ResourceManager.GetObject("v2ray", resourceCulture); 89 | return ((byte[])(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// 查找 System.Byte[] 类型的本地化资源。 95 | /// 96 | internal static byte[] v2rayNotBypassChina { 97 | get { 98 | object obj = ResourceManager.GetObject("v2rayNotBypassChina", resourceCulture); 99 | return ((byte[])(obj)); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /v2tap/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\defaultConfig.ini;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | 125 | ..\Resources\defaultServerConfig.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | 128 | ..\Resources\v2ray.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | ..\Resources\v2rayNotBypassChina.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 132 | 133 | -------------------------------------------------------------------------------- /v2tap/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace v2tap.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /v2tap/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /v2tap/Resources/defaultConfig.ini: -------------------------------------------------------------------------------- 1 | [v2tap] 2 | TUNTAPAddress = 10.0.100.10 3 | TUNTAPGateway = 10.0.100.1 4 | TUNTAPNetmask = 255.255.255.0 5 | TUNTAPDNS = 114.114.114.114,114.114.115.115 6 | TUNTAPMetric = 100 7 | AutoAdapterMetric = True 8 | AutoCheckAdapter = True 9 | v2rayLoggingLevel = ERROR 10 | -------------------------------------------------------------------------------- /v2tap/Resources/defaultServerConfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ID": "918170c7-b3cc-4fa4-aac6-c763886ffed1", 4 | "Remark": "HK - BandwagonHost - 1Gbps", 5 | "Address": "www.baidu.com", 6 | "Port": 443, 7 | "UserID": "e02d1b2d-7a22-453f-adb7-4576016df5c6", 8 | "AlterId": 0, 9 | "TransferMethod": "WebSockets", 10 | "Path": "/", 11 | "FakeType": "None", 12 | "TLSSecure": true 13 | } 14 | ] -------------------------------------------------------------------------------- /v2tap/Resources/v2ray.json: -------------------------------------------------------------------------------- 1 | { 2 | "stats": {}, 3 | "log": { 4 | "access": "logging\\v2ray-access.log", 5 | "error": "logging\\v2ray-error.log", 6 | "loglevel": "v2rayLoggingLevel" 7 | }, 8 | "api": { 9 | "services": [ 10 | "StatsService" 11 | ], 12 | "tag": "api" 13 | }, 14 | "policy": { 15 | "system": { 16 | "statsInboundUplink": true, 17 | "statsInboundDownlink": true 18 | } 19 | }, 20 | "dns": { 21 | "clientIP": "AdapterAddress", 22 | "hosts": { 23 | "localhost": "127.0.0.1", 24 | "domain:lan": "127.0.0.1", 25 | "domain:arpa": "127.0.0.1", 26 | "domain:local": "127.0.0.1" 27 | }, 28 | "servers": [ 29 | "8.8.8.8", 30 | { 31 | "address": "114.114.114.114", 32 | "port": 53, 33 | "domains": [ 34 | "geosite:cn" 35 | ] 36 | } 37 | ] 38 | }, 39 | "routing": { 40 | "strategy": "rules", 41 | "settings": { 42 | "domainStrategy": "IPIfNonMatch", 43 | "rules": [ 44 | { 45 | "type": "field", 46 | "inboundTag": [ 47 | "api" 48 | ], 49 | "outboundTag": "api" 50 | }, 51 | { 52 | "type": "field", 53 | "domain": [ 54 | "geosite:cn" 55 | ], 56 | "outboundTag": "directOutbound" 57 | }, 58 | { 59 | "type": "field", 60 | "ip": [ 61 | "geoip:cn", 62 | "geoip:private" 63 | ], 64 | "outboundTag": "directOutbound" 65 | } 66 | ] 67 | } 68 | }, 69 | "inbounds": [ 70 | { 71 | "listen": "127.0.0.1", 72 | "port": 1099, 73 | "protocol": "socks", 74 | "settings": { 75 | "udp": true 76 | }, 77 | "sniffing": { 78 | "enabled": true, 79 | "destOverride": [ 80 | "http", 81 | "tls" 82 | ] 83 | }, 84 | "tag": "defaultInbound" 85 | }, 86 | { 87 | "listen": "127.0.0.1", 88 | "port": 1020, 89 | "protocol": "dokodemo-door", 90 | "settings": { 91 | "address": "127.0.0.1" 92 | }, 93 | "tag": "api" 94 | } 95 | ], 96 | "outbounds": [ 97 | { 98 | "sendThrough": "AdapterAddress", 99 | "protocol": "vmess", 100 | "settings": { 101 | "vnext": [ 102 | { 103 | "address": "v2rayServerAddress", 104 | "port": v2rayServerPort, 105 | "users": [ 106 | { 107 | "id": "v2rayUserID", 108 | "alterId": v2rayAlterID, 109 | "security": "auto" 110 | } 111 | ] 112 | } 113 | ] 114 | }, 115 | "streamSettings": { 116 | "network": "v2rayTransferMethod", 117 | "security": "v2rayTLSSecure", 118 | "tcpSettings": { 119 | "header": { 120 | "type": "v2rayFakeType", 121 | "request": {}, 122 | "response": {} 123 | } 124 | }, 125 | "kcpSettings": { 126 | "header": { 127 | "type": "v2rayFakeType" 128 | } 129 | }, 130 | "wsSettings": { 131 | "path": "v2rayPath" 132 | }, 133 | "httpSettings": { 134 | "path": "v2rayPath" 135 | }, 136 | "quicSettings": { 137 | "header": { 138 | "type": "v2rayFakeType" 139 | } 140 | } 141 | }, 142 | "tag": "defaultOutbound" 143 | }, 144 | { 145 | "sendThrough": "AdapterAddress", 146 | "protocol": "freedom", 147 | "settings": {}, 148 | "tag": "directOutbound" 149 | } 150 | ] 151 | } -------------------------------------------------------------------------------- /v2tap/Resources/v2rayNotBypassChina.json: -------------------------------------------------------------------------------- 1 | { 2 | "stats": {}, 3 | "log": { 4 | "access": "logging\\v2ray-access.log", 5 | "error": "logging\\v2ray-error.log", 6 | "loglevel": "v2rayLoggingLevel" 7 | }, 8 | "api": { 9 | "services": [ 10 | "StatsService" 11 | ], 12 | "tag": "api" 13 | }, 14 | "policy": { 15 | "system": { 16 | "statsInboundUplink": true, 17 | "statsInboundDownlink": true 18 | } 19 | }, 20 | "dns": { 21 | "clientIP": "AdapterAddress", 22 | "hosts": { 23 | "localhost": "127.0.0.1", 24 | "domain:lan": "127.0.0.1", 25 | "domain:arpa": "127.0.0.1", 26 | "domain:local": "127.0.0.1" 27 | }, 28 | "servers": [ 29 | "8.8.8.8", 30 | { 31 | "address": "114.114.114.114", 32 | "port": 53, 33 | "domains": [ 34 | "geosite:cn" 35 | ] 36 | } 37 | ] 38 | }, 39 | "routing": { 40 | "strategy": "rules", 41 | "settings": { 42 | "domainStrategy": "IPIfNonMatch", 43 | "rules": [ 44 | { 45 | "type": "field", 46 | "inboundTag": [ 47 | "api" 48 | ], 49 | "outboundTag": "api" 50 | }, 51 | { 52 | "type": "field", 53 | "ip": [ 54 | "geoip:private" 55 | ], 56 | "outboundTag": "directOutbound" 57 | } 58 | ] 59 | } 60 | }, 61 | "inbounds": [ 62 | { 63 | "listen": "127.0.0.1", 64 | "port": 1099, 65 | "protocol": "socks", 66 | "settings": { 67 | "udp": true 68 | }, 69 | "sniffing": { 70 | "enabled": true, 71 | "destOverride": [ 72 | "http", 73 | "tls" 74 | ] 75 | }, 76 | "tag": "defaultInbound" 77 | }, 78 | { 79 | "listen": "127.0.0.1", 80 | "port": 1020, 81 | "protocol": "dokodemo-door", 82 | "settings": { 83 | "address": "127.0.0.1" 84 | }, 85 | "tag": "api" 86 | } 87 | ], 88 | "outbounds": [ 89 | { 90 | "sendThrough": "AdapterAddress", 91 | "protocol": "vmess", 92 | "settings": { 93 | "vnext": [ 94 | { 95 | "address": "v2rayServerAddress", 96 | "port": v2rayServerPort, 97 | "users": [ 98 | { 99 | "id": "v2rayUserID", 100 | "alterId": v2rayAlterID, 101 | "security": "auto" 102 | } 103 | ] 104 | } 105 | ] 106 | }, 107 | "streamSettings": { 108 | "network": "v2rayTransferMethod", 109 | "security": "v2rayTLSSecure", 110 | "tcpSettings": { 111 | "header": { 112 | "type": "v2rayFakeType", 113 | "request": {}, 114 | "response": {} 115 | } 116 | }, 117 | "kcpSettings": { 118 | "header": { 119 | "type": "v2rayFakeType" 120 | } 121 | }, 122 | "wsSettings": { 123 | "path": "v2rayPath" 124 | }, 125 | "httpSettings": { 126 | "path": "v2rayPath" 127 | }, 128 | "quicSettings": { 129 | "header": { 130 | "type": "v2rayFakeType" 131 | } 132 | } 133 | }, 134 | "tag": "defaultOutbound" 135 | }, 136 | { 137 | "sendThrough": "AdapterAddress", 138 | "protocol": "freedom", 139 | "settings": {}, 140 | "tag": "directOutbound" 141 | } 142 | ] 143 | } -------------------------------------------------------------------------------- /v2tap/Utils/Util.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Net; 6 | using System.Net.NetworkInformation; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | 10 | namespace v2tap.Utils 11 | { 12 | public static class Util 13 | { 14 | /// 15 | /// 写日志 16 | /// 17 | /// 日志内容 18 | public static void WriteLine(string content, Global.Level level) 19 | { 20 | var path = String.Format("{0}\\{1}", Global.Path.LoggingDirectory, Global.Path.v2tapLogging); 21 | var info = String.Format("[{0}][{1}] {2}\n", DateTime.Now.ToString(), "{0}", content); 22 | 23 | switch (level) 24 | { 25 | case Global.Level.DEBUG: 26 | File.AppendAllText(path, String.Format(info, "DBUG")); 27 | break; 28 | case Global.Level.INFO: 29 | File.AppendAllText(path, String.Format(info, "INFO")); 30 | break; 31 | case Global.Level.WARNING: 32 | File.AppendAllText(path, String.Format(info, "WARN")); 33 | break; 34 | case Global.Level.ERROR: 35 | File.AppendAllText(path, String.Format(info, "EROR")); 36 | break; 37 | default: 38 | break; 39 | } 40 | } 41 | 42 | /// 43 | /// 执行命令行命令 44 | /// 45 | /// 命令内容 46 | public static void ExecuteCommand(string content) 47 | { 48 | var p = new Process(); 49 | p.StartInfo.FileName = "cmd.exe"; 50 | p.StartInfo.Arguments = "/c " + content; 51 | p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; 52 | p.Start(); 53 | } 54 | 55 | /// 56 | /// 将 CIDR /xx 翻译为掩码 57 | /// 58 | /// CIDR 59 | /// 掩码 60 | public static string TranslateCIDRToNetmask(string CIDR) 61 | { 62 | var dict = new Dictionary() 63 | { 64 | { "1", "128.0.0.0" }, 65 | { "2", "192.0.0.0" }, 66 | { "3", "224.0.0.0" }, 67 | { "4", "240.0.0.0" }, 68 | { "5", "248.0.0.0" }, 69 | { "6", "252.0.0.0" }, 70 | { "7", "254.0.0.0" }, 71 | { "8", "255.0.0.0" }, 72 | { "9", "255.128.0.0" }, 73 | { "10", "255.192.0.0" }, 74 | { "11", "255.224.0.0" }, 75 | { "12", "255.240.0.0" }, 76 | { "13", "255.248.0.0" }, 77 | { "14", "255.252.0.0" }, 78 | { "15", "255.254.0.0" }, 79 | { "16", "255.255.0.0" }, 80 | { "17", "255.255.128.0" }, 81 | { "18", "255.255.192.0" }, 82 | { "19", "255.255.224.0" }, 83 | { "20", "255.255.240.0" }, 84 | { "21", "255.255.248.0" }, 85 | { "22", "255.255.252.0" }, 86 | { "23", "255.255.254.0" }, 87 | { "24", "255.255.255.0" }, 88 | { "25", "255.255.255.128" }, 89 | { "26", "255.255.255.192" }, 90 | { "27", "255.255.255.224" }, 91 | { "28", "255.255.255.240" }, 92 | { "29", "255.255.255.248" }, 93 | { "30", "255.255.255.252" }, 94 | { "31", "255.255.255.254" }, 95 | { "32", "255.255.255.255" } 96 | }; 97 | 98 | if (dict.ContainsKey(CIDR)) 99 | { 100 | return dict[CIDR]; 101 | } 102 | else 103 | { 104 | return "255.255.255.255"; 105 | } 106 | } 107 | 108 | /// 109 | /// 从文件中加载配置信息 110 | /// 111 | public static void InitConfigsFromFile() 112 | { 113 | var data = new IniParser.FileIniDataParser().ReadFile("v2tap.ini"); 114 | 115 | Global.Configs.TUNTAPAddress = data["v2tap"]["TUNTAPAddress"]; 116 | Global.Configs.TUNTAPGateway = data["v2tap"]["TUNTAPGateway"]; 117 | Global.Configs.TUNTAPNetmask = data["v2tap"]["TUNTAPNetmask"]; 118 | Global.Configs.TUNTAPDNS = data["v2tap"]["TUNTAPDNS"]; 119 | Global.Configs.TUNTAPMetric = int.Parse(data["v2tap"]["TUNTAPMetric"]); 120 | Global.Configs.AutoAdapterMetric = Boolean.Parse(data["v2tap"]["AutoAdapterMetric"]); 121 | Global.Configs.AutoCheckAdapter = Boolean.Parse(data["v2tap"]["AutoCheckAdapter"]); 122 | Global.Configs.v2rayLoggingLevel = data["v2tap"]["v2rayLoggingLevel"]; 123 | } 124 | 125 | /// 126 | /// 将配置信息保存到文件中 127 | /// 128 | public static void SaveConfigsToFile() 129 | { 130 | var data = new IniParser.FileIniDataParser().ReadFile("v2tap.ini"); 131 | 132 | data["v2tap"]["TUNTAPAddress"] = Global.Configs.TUNTAPAddress; 133 | data["v2tap"]["TUNTAPGateway"] = Global.Configs.TUNTAPGateway; 134 | data["v2tap"]["TUNTAPNetmask"] = Global.Configs.TUNTAPNetmask; 135 | data["v2tap"]["TUNTAPDNS"] = Global.Configs.TUNTAPDNS; 136 | data["v2tap"]["TUNTAPMetric"] = Global.Configs.TUNTAPMetric.ToString(); 137 | data["v2tap"]["AutoAdapterMetric"] = Global.Configs.AutoAdapterMetric.ToString(); 138 | data["v2tap"]["AutoCheckAdapter"] = Global.Configs.AutoCheckAdapter.ToString(); 139 | data["v2tap"]["v2rayLoggingLevel"] = Global.Configs.v2rayLoggingLevel; 140 | 141 | File.WriteAllText("v2tap.ini", data.ToString()); 142 | } 143 | 144 | /// 145 | /// 从文件中加载服务器配置信息 146 | /// 147 | public static void InitServersFromFile() 148 | { 149 | Global.Proxies = Newtonsoft.Json.JsonConvert.DeserializeObject>(File.ReadAllText("v2tap.json")); 150 | } 151 | 152 | /// 153 | /// 将服务器配置信息保存到文件中 154 | /// 155 | public static void SaveServersToFile() 156 | { 157 | File.WriteAllText("v2tap.json", Newtonsoft.Json.JsonConvert.SerializeObject(Global.Proxies)); 158 | } 159 | 160 | /// 161 | /// 从文件中加载模式配置信息 162 | /// 163 | public static void InitModesFromFile() 164 | { 165 | foreach (var filename in Directory.GetFiles(Global.Path.ModeDirectory, "*.txt")) 166 | { 167 | var mode = new Objects.Mode(); 168 | mode.Name = filename 169 | .Replace(Global.Path.ModeDirectory + "\\", "") 170 | .Replace(".txt", ""); 171 | 172 | using (var sr = new StringReader(File.ReadAllText(filename))) 173 | { 174 | string text; 175 | 176 | while ((text = sr.ReadLine()) != null) 177 | { 178 | var splited = text.Split('/'); 179 | mode.Rule.Add(new KeyValuePair(splited[0], TranslateCIDRToNetmask(splited[1]))); 180 | } 181 | } 182 | 183 | Global.Modes.Add(mode); 184 | } 185 | } 186 | 187 | /// 188 | /// 加载适配器信息 189 | /// 190 | public static void InitAdapter() 191 | { 192 | if (Global.Configs.AutoAdapterMetric) 193 | { 194 | using (var client = new UdpClient("114.114.114.114", 53)) 195 | { 196 | var address = ((IPEndPoint)client.Client.LocalEndPoint).Address; 197 | 198 | int addressCount = 0; 199 | int gatewayCount = 0; 200 | bool addressGeted = false; 201 | 202 | var adapters = NetworkInterface.GetAllNetworkInterfaces(); 203 | foreach (var adapter in adapters) 204 | { 205 | var properties = adapter.GetIPProperties(); 206 | 207 | foreach (var information in properties.UnicastAddresses) 208 | { 209 | if (information.Address.AddressFamily == AddressFamily.InterNetwork) 210 | { 211 | var ip = information.Address.ToString(); 212 | 213 | if (ip.StartsWith("10.") || ip.StartsWith("172.") || ip.StartsWith("192.")) 214 | { 215 | if (Equals(information.Address, address)) 216 | { 217 | addressGeted = true; 218 | } 219 | else 220 | { 221 | if (!addressGeted) addressCount++; 222 | } 223 | 224 | Global.Configs.AdapterAddress.Add(ip); 225 | } 226 | } 227 | } 228 | 229 | foreach (var information in properties.GatewayAddresses) 230 | { 231 | if (information.Address.AddressFamily == AddressFamily.InterNetwork) 232 | { 233 | string IP = information.Address.ToString(); 234 | 235 | if (IP.StartsWith("10.") || IP.StartsWith("172.") || IP.StartsWith("192.")) 236 | { 237 | if (!addressGeted) 238 | { 239 | gatewayCount++; 240 | } 241 | 242 | Global.Configs.AdapterGateway.Add(IP); 243 | } 244 | } 245 | } 246 | } 247 | 248 | Global.Configs.AdapterAddressIndex = addressCount; 249 | Global.Configs.AdapterGatewayIndex = gatewayCount; 250 | } 251 | } 252 | } 253 | 254 | /// 255 | /// 处理流量信息 256 | /// 257 | /// 流量信息 258 | /// 处理好的信息 259 | public static string ProcessBandwidth(long bandwidth) 260 | { 261 | var result = ((double)bandwidth) / 1024; 262 | 263 | if (result < 1024) 264 | { 265 | return Math.Round(result, 2).ToString() + " KB"; 266 | } 267 | 268 | result = result / 1024; 269 | if (result < 1024) 270 | { 271 | return Math.Round(result, 2).ToString() + " MB"; 272 | } 273 | 274 | result = result / 1024; 275 | if (result < 1024) 276 | { 277 | return Math.Round(result, 2).ToString() + " GB"; 278 | } 279 | 280 | result = result / 1024; 281 | return Math.Round(result, 2).ToString() + " TB"; 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /v2tap/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /v2tap/v2tap.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using System.Windows.Forms; 5 | 6 | namespace v2tap 7 | { 8 | public static class v2tap 9 | { 10 | public static String[] RequiredFile = new String[] 11 | { 12 | "tun2socks.exe", 13 | "wv2ray.exe", 14 | "v2ray.exe", 15 | "v2ctl.exe", 16 | "geoip.dat", 17 | "geosite.dat" 18 | }; 19 | 20 | /// 21 | /// 应用程序的主入口点 22 | /// 23 | [STAThread] 24 | public static void Main() 25 | { 26 | try 27 | { 28 | #if !DEBUG 29 | // 检查文件 30 | foreach (var file in RequiredFile) 31 | { 32 | if (!File.Exists(file)) 33 | { 34 | MessageBox.Show($"缺失重要文件:{file}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 35 | return; 36 | } 37 | } 38 | #endif 39 | 40 | // 日志目录 41 | if (!Directory.Exists(Global.Path.LoggingDirectory)) Directory.CreateDirectory(Global.Path.LoggingDirectory); 42 | 43 | // 模式目录 44 | if (!Directory.Exists(Global.Path.ModeDirectory)) Directory.CreateDirectory(Global.Path.ModeDirectory); 45 | 46 | // 默认配置 47 | if (!File.Exists("v2tap.ini")) File.WriteAllText("v2tap.ini", Encoding.UTF8.GetString(Properties.Resources.defaultConfig)); 48 | if (!File.Exists("v2tap.json")) File.WriteAllText("v2tap.json", Encoding.UTF8.GetString(Properties.Resources.defaultServerConfig)); 49 | 50 | // 加载配置 51 | Utils.Util.InitConfigsFromFile(); 52 | Utils.Util.InitServersFromFile(); 53 | Utils.Util.InitModesFromFile(); 54 | 55 | // 初始化适配器 56 | Utils.Util.InitAdapter(); 57 | } 58 | catch (Exception ex) 59 | { 60 | MessageBox.Show("在初始化配置时发生错误:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); 61 | return; 62 | } 63 | 64 | Application.EnableVisualStyles(); 65 | Application.SetCompatibleTextRenderingDefault(false); 66 | Application.Run(Global.Form.MainForm = new Forms.MainForm()); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /v2tap/v2tap.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | Debug 8 | AnyCPU 9 | {53132DC3-8A46-4558-978C-605A643D1300} 10 | WinExe 11 | v2tap 12 | v2tap 13 | v4.7.2 14 | 512 15 | true 16 | true 17 | 18 | 19 | false 20 | publish\ 21 | true 22 | Disk 23 | false 24 | Foreground 25 | 7 26 | Days 27 | false 28 | false 29 | true 30 | 0 31 | 1.0.0.%2a 32 | false 33 | true 34 | 35 | 36 | x64 37 | true 38 | full 39 | false 40 | bin\Debug\ 41 | DEBUG;TRACE 42 | prompt 43 | 4 44 | CS0618 45 | 46 | 47 | 48 | v2tap.manifest 49 | 50 | 51 | v2tap.v2tap 52 | 53 | 54 | bin\Release_x64\ 55 | TRACE 56 | true 57 | CS0618 58 | pdbonly 59 | x64 60 | prompt 61 | MinimumRecommendedRules.ruleset 62 | true 63 | 64 | 65 | bin\Release_x86\ 66 | TRACE 67 | true 68 | CS0618 69 | pdbonly 70 | x86 71 | prompt 72 | MinimumRecommendedRules.ruleset 73 | true 74 | 75 | 76 | 77 | ..\packages\Google.Protobuf.3.6.1\lib\net45\Google.Protobuf.dll 78 | 79 | 80 | ..\packages\Grpc.Core.1.18.0\lib\net45\Grpc.Core.dll 81 | 82 | 83 | ..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll 84 | True 85 | 86 | 87 | 88 | 89 | ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | Form 124 | 125 | 126 | AdvancedForm.cs 127 | 128 | 129 | Form 130 | 131 | 132 | EditForm.cs 133 | 134 | 135 | Form 136 | 137 | 138 | ImportForm.cs 139 | 140 | 141 | Form 142 | 143 | 144 | MainForm.cs 145 | 146 | 147 | 148 | 149 | 150 | Component 151 | 152 | 153 | 154 | 155 | 156 | AdvancedForm.cs 157 | 158 | 159 | EditForm.cs 160 | 161 | 162 | ImportForm.cs 163 | 164 | 165 | MainForm.cs 166 | 167 | 168 | ResXFileCodeGenerator 169 | Resources.Designer.cs 170 | Designer 171 | 172 | 173 | True 174 | Resources.resx 175 | True 176 | 177 | 178 | SettingsSingleFileGenerator 179 | Settings.Designer.cs 180 | 181 | 182 | True 183 | Settings.settings 184 | True 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | False 195 | Microsoft .NET Framework 4.7.2 %28x86 和 x64%29 196 | true 197 | 198 | 199 | False 200 | .NET Framework 3.5 SP1 201 | false 202 | 203 | 204 | 205 | 206 | 207 | 208 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | @echo off 217 | 218 | cd /d $(TargetDir) 219 | if "$(ConfigurationName)"=="Release x64" goto do64 220 | if "$(ConfigurationName)"=="Release x86" goto do86 221 | goto doNone 222 | 223 | :do64 224 | mkdir v2tap_x64 > nul 2>&1 225 | copy /y Google.Protobuf.dll v2tap_x64 > nul 2>&1 226 | copy /y Grpc.Core.dll v2tap_x64 > nul 2>&1 227 | copy /y grpc_csharp_ext.x64.dll v2tap_x64 > nul 2>&1 228 | copy /y Newtonsoft.Json.dll v2tap_x64 > nul 2>&1 229 | copy /y System.Interactive.Async.dll v2tap_x64 > nul 2>&1 230 | copy /y v2tap.exe v2tap_x64 > nul 2>&1 231 | copy /y ..\..\..\binaries\tap-windows-latest-stable.exe v2tap_x64 > nul 2>&1 232 | copy /y ..\..\..\binaries\tun2socks_x64.exe v2tap_x64\tun2socks.exe > nul 2>&1 233 | copy /y ..\..\..\binaries\v2ray\x64\v2ray.exe v2tap_x64 > nul 2>&1 234 | copy /y ..\..\..\binaries\v2ray\x64\wv2ray.exe v2tap_x64 > nul 2>&1 235 | copy /y ..\..\..\binaries\v2ray\x64\v2ctl.exe v2tap_x64 > nul 2>&1 236 | copy /y ..\..\..\binaries\v2ray\x64\geosite.dat v2tap_x64 > nul 2>&1 237 | copy /y ..\..\..\binaries\v2ray\x64\geoip.dat v2tap_x64 > nul 2>&1 238 | mkdir v2tap_x64\mode > nul 2>&1 239 | copy /y ..\..\..\modes\* v2tap_x64\mode > nul 2>&1 240 | bc c -fmt:7z -r v2tap_x64\v2tap_x64.7z v2tap_x64\* > nul 2>&1 241 | goto doNone 242 | 243 | :do86 244 | mkdir v2tap_x86 > nul 2>&1 245 | copy /y Google.Protobuf.dll v2tap_x86 > nul 2>&1 246 | copy /y Grpc.Core.dll v2tap_x86 > nul 2>&1 247 | copy /y grpc_csharp_ext.x86.dll v2tap_x86 > nul 2>&1 248 | copy /y Newtonsoft.Json.dll v2tap_x86 > nul 2>&1 249 | copy /y System.Interactive.Async.dll v2tap_x86 > nul 2>&1 250 | copy /y v2tap.exe v2tap_x86 > nul 2>&1 251 | copy /y ..\..\..\binaries\tap-windows-latest-stable.exe v2tap_x86 > nul 2>&1 252 | copy /y ..\..\..\binaries\tun2socks_x86.exe v2tap_x86\tun2socks.exe > nul 2>&1 253 | copy /y ..\..\..\binaries\v2ray\x86\v2ray.exe v2tap_x86 > nul 2>&1 254 | copy /y ..\..\..\binaries\v2ray\x86\wv2ray.exe v2tap_x86 > nul 2>&1 255 | copy /y ..\..\..\binaries\v2ray\x86\v2ctl.exe v2tap_x86 > nul 2>&1 256 | copy /y ..\..\..\binaries\v2ray\x86\geosite.dat v2tap_x86 > nul 2>&1 257 | copy /y ..\..\..\binaries\v2ray\x86\geoip.dat v2tap_x86 > nul 2>&1 258 | mkdir v2tap_x86\mode > nul 2>&1 259 | copy /y ..\..\..\modes\* v2tap_x86\mode > nul 2>&1 260 | bc c -fmt:7z -r v2tap_x86\v2tap_x86.7z v2tap_x86\* > nul 2>&1 261 | goto doNone 262 | 263 | :doNone 264 | exit 265 | 266 | 267 | @echo off 268 | 269 | cd /d $(TargetDir) 270 | if "$(ConfigurationName)"=="Release x64" goto do64 271 | if "$(ConfigurationName)"=="Release x86" goto do86 272 | goto doNone 273 | 274 | :do64 275 | rd /s /q v2tap_x64 > nul 2>&1 276 | goto doNone 277 | 278 | :do86 279 | rd /s /q v2tap_x86 > nul 2>&1 280 | goto doNone 281 | 282 | :doNone 283 | exit 284 | 285 | -------------------------------------------------------------------------------- /v2tap/v2tap.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------