Преглед на файлове

Add 'stbcheck': the STB File Multilanguage Full-Mesh Consistency Checker

Daiyuu Nobori преди 7 години
родител
ревизия
a6c4d2a2bc

+ 180 - 0
.gitignore

@@ -1,3 +1,4 @@
+# Global
 .cproject
 .project
 .settings/
@@ -10,3 +11,182 @@ tmp/
 .gitconfig
 CMakeCache.txt
 CMakeFiles/
+
+
+# Applied for 'developer_tools/stbchecker/'
+# Copied from by https://www.gitignore.io/api/visualstudio
+developer_tools/stbchecker/**/*.suo
+developer_tools/stbchecker/**/*.user
+developer_tools/stbchecker/**/*.userosscache
+developer_tools/stbchecker/**/*.sln.docstates
+developer_tools/stbchecker/**/*.userprefs
+developer_tools/stbchecker/**/[Dd]ebug/
+developer_tools/stbchecker/**/[Dd]ebugPublic/
+developer_tools/stbchecker/**/[Rr]elease/
+developer_tools/stbchecker/**/[Rr]eleases/
+developer_tools/stbchecker/**/x64/
+developer_tools/stbchecker/**/x86/
+developer_tools/stbchecker/**/bld/
+developer_tools/stbchecker/**/[Bb]in/
+developer_tools/stbchecker/**/[Oo]bj/
+developer_tools/stbchecker/**/[Ll]og/
+developer_tools/stbchecker/**/.vs/
+developer_tools/stbchecker/**/Generated\ Files/
+developer_tools/stbchecker/**/s
+developer_tools/stbchecker/**/[Tt]est[Rr]esult*/
+developer_tools/stbchecker/**/[Bb]uild[Ll]og.*
+developer_tools/stbchecker/**/*.VisualState.xml
+developer_tools/stbchecker/**/TestResult.xml
+developer_tools/stbchecker/**/[Dd]ebugPS/
+developer_tools/stbchecker/**/[Rr]eleasePS/
+developer_tools/stbchecker/**/dlldata.c
+developer_tools/stbchecker/**/BenchmarkDotNet.Artifacts/
+developer_tools/stbchecker/**/project.lock.json
+developer_tools/stbchecker/**/project.fragment.lock.json
+developer_tools/stbchecker/**/artifacts/
+developer_tools/stbchecker/**/StyleCopReport.xml
+developer_tools/stbchecker/**/*_i.c
+developer_tools/stbchecker/**/*_p.c
+developer_tools/stbchecker/**/*_i.h
+developer_tools/stbchecker/**/*.ilk
+developer_tools/stbchecker/**/*.meta
+developer_tools/stbchecker/**/*.obj
+developer_tools/stbchecker/**/*.iobj
+developer_tools/stbchecker/**/*.pch
+developer_tools/stbchecker/**/*.pdb
+developer_tools/stbchecker/**/*.ipdb
+developer_tools/stbchecker/**/*.pgc
+developer_tools/stbchecker/**/*.pgd
+developer_tools/stbchecker/**/*.rsp
+developer_tools/stbchecker/**/*.sbr
+developer_tools/stbchecker/**/*.tlb
+developer_tools/stbchecker/**/*.tli
+developer_tools/stbchecker/**/*.tlh
+developer_tools/stbchecker/**/*.tmp
+developer_tools/stbchecker/**/*.tmp_proj
+developer_tools/stbchecker/**/*.log
+developer_tools/stbchecker/**/*.vspscc
+developer_tools/stbchecker/**/*.vssscc
+developer_tools/stbchecker/**/.builds
+developer_tools/stbchecker/**/*.pidb
+developer_tools/stbchecker/**/*.svclog
+developer_tools/stbchecker/**/*.scc
+developer_tools/stbchecker/**/_Chutzpah*
+developer_tools/stbchecker/**/ipch/
+developer_tools/stbchecker/**/*.aps
+developer_tools/stbchecker/**/*.ncb
+developer_tools/stbchecker/**/*.opendb
+developer_tools/stbchecker/**/*.opensdf
+developer_tools/stbchecker/**/*.sdf
+developer_tools/stbchecker/**/*.cachefile
+developer_tools/stbchecker/**/*.VC.db
+developer_tools/stbchecker/**/*.VC.VC.opendb
+developer_tools/stbchecker/**/*.psess
+developer_tools/stbchecker/**/*.vsp
+developer_tools/stbchecker/**/*.vspx
+developer_tools/stbchecker/**/*.sap
+developer_tools/stbchecker/**/*.e2e
+developer_tools/stbchecker/**/$tf/
+developer_tools/stbchecker/**/*.gpState
+developer_tools/stbchecker/**/_ReSharper*/
+developer_tools/stbchecker/**/*.[Rr]e[Ss]harper
+developer_tools/stbchecker/**/*.DotSettings.user
+developer_tools/stbchecker/**/.JustCode
+developer_tools/stbchecker/**/_TeamCity*
+developer_tools/stbchecker/**/*.dotCover
+developer_tools/stbchecker/**/.axoCover/*
+developer_tools/stbchecker/**/!.axoCover/settings.json
+developer_tools/stbchecker/**/*.coverage
+developer_tools/stbchecker/**/*.coveragexml
+developer_tools/stbchecker/**/_NCrunch_*
+developer_tools/stbchecker/**/.*crunch*.local.xml
+developer_tools/stbchecker/**/nCrunchTemp_*
+developer_tools/stbchecker/**/*.mm.*
+developer_tools/stbchecker/**/AutoTest.Net/
+developer_tools/stbchecker/**/.sass-cache/
+developer_tools/stbchecker/**/[Ee]xpress/
+developer_tools/stbchecker/**/DocProject/buildhelp/
+developer_tools/stbchecker/**/DocProject/Help/*.HxT
+developer_tools/stbchecker/**/DocProject/Help/*.HxC
+developer_tools/stbchecker/**/DocProject/Help/*.hhc
+developer_tools/stbchecker/**/DocProject/Help/*.hhk
+developer_tools/stbchecker/**/DocProject/Help/*.hhp
+developer_tools/stbchecker/**/DocProject/Help/Html2
+developer_tools/stbchecker/**/DocProject/Help/html
+developer_tools/stbchecker/**/publish/
+developer_tools/stbchecker/**/*.[Pp]ublish.xml
+developer_tools/stbchecker/**/*.azurePubxml
+developer_tools/stbchecker/**/*.pubxml
+developer_tools/stbchecker/**/*.publishproj
+developer_tools/stbchecker/**/PublishScripts/
+developer_tools/stbchecker/**/*.nupkg
+developer_tools/stbchecker/**/**/[Pp]ackages/*
+developer_tools/stbchecker/**/!**/[Pp]ackages/build/
+developer_tools/stbchecker/**/*.nuget.props
+developer_tools/stbchecker/**/*.nuget.targets
+developer_tools/stbchecker/**/csx/
+developer_tools/stbchecker/**/*.build.csdef
+developer_tools/stbchecker/**/ecf/
+developer_tools/stbchecker/**/rcf/
+developer_tools/stbchecker/**/AppPackages/
+developer_tools/stbchecker/**/BundleArtifacts/
+developer_tools/stbchecker/**/Package.StoreAssociation.xml
+developer_tools/stbchecker/**/_pkginfo.txt
+developer_tools/stbchecker/**/*.appx
+developer_tools/stbchecker/**/*.[Cc]ache
+developer_tools/stbchecker/**/!*.[Cc]ache/
+developer_tools/stbchecker/**/ClientBin/
+developer_tools/stbchecker/**/~$*
+developer_tools/stbchecker/**/*~
+developer_tools/stbchecker/**/*.dbmdl
+developer_tools/stbchecker/**/*.dbproj.schemaview
+developer_tools/stbchecker/**/*.jfm
+developer_tools/stbchecker/**/*.pfx
+developer_tools/stbchecker/**/*.publishsettings
+developer_tools/stbchecker/**/orleans.codegen.cs
+developer_tools/stbchecker/**/Generated_Code/
+developer_tools/stbchecker/**/_UpgradeReport_Files/
+developer_tools/stbchecker/**/Backup*/
+developer_tools/stbchecker/**/UpgradeLog*.XML
+developer_tools/stbchecker/**/UpgradeLog*.htm
+developer_tools/stbchecker/**/ServiceFabricBackup/
+developer_tools/stbchecker/**/*.rptproj.bak
+developer_tools/stbchecker/**/*.mdf
+developer_tools/stbchecker/**/*.ldf
+developer_tools/stbchecker/**/*.ndf
+developer_tools/stbchecker/**/*.rdl.data
+developer_tools/stbchecker/**/*.bim.layout
+developer_tools/stbchecker/**/*.bim_*.settings
+developer_tools/stbchecker/**/*.rptproj.rsuser
+developer_tools/stbchecker/**/FakesAssemblies/
+developer_tools/stbchecker/**/*.GhostDoc.xml
+developer_tools/stbchecker/**/.ntvs_analysis.dat
+developer_tools/stbchecker/**/node_modules/
+developer_tools/stbchecker/**/*.plg
+developer_tools/stbchecker/**/*.opt
+developer_tools/stbchecker/**/*.vbw
+developer_tools/stbchecker/**/*.HTMLClient/GeneratedArtifacts
+developer_tools/stbchecker/**/*.DesktopClient/GeneratedArtifacts
+developer_tools/stbchecker/**/*.DesktopClient/ModelManifest.xml
+developer_tools/stbchecker/**/*.Server/GeneratedArtifacts
+developer_tools/stbchecker/**/*.Server/ModelManifest.xml
+developer_tools/stbchecker/**/_Pvt_Extensions
+developer_tools/stbchecker/**/.paket/paket.exe
+developer_tools/stbchecker/**/paket-files/
+developer_tools/stbchecker/**/.fake/
+developer_tools/stbchecker/**/.idea/
+developer_tools/stbchecker/**/*.sln.iml
+developer_tools/stbchecker/**/.cr/
+developer_tools/stbchecker/**/__pycache__/
+developer_tools/stbchecker/**/*.pyc
+developer_tools/stbchecker/**/*.tss
+developer_tools/stbchecker/**/*.jmconfig
+developer_tools/stbchecker/**/*.btp.cs
+developer_tools/stbchecker/**/*.btm.cs
+developer_tools/stbchecker/**/*.odx.cs
+developer_tools/stbchecker/**/*.xsd.cs
+developer_tools/stbchecker/**/OpenCover/
+developer_tools/stbchecker/**/ASALocalRun/
+developer_tools/stbchecker/**/*.binlog
+developer_tools/stbchecker/**/*.nvuser
+developer_tools/stbchecker/**/.mfractor/

+ 59 - 0
developer_tools/stbchecker/Program.cs

@@ -0,0 +1,59 @@
+using System;
+using System.IO;
+
+public class Program
+{
+	static int Main(string[] args)
+	{
+		Console.WriteLine("SoftEther VPN Project");
+		Console.WriteLine("STB File Multilanguage Full-Mesh Consistency Checker");
+		Console.WriteLine("");
+
+		if (args.Length != 1)
+		{
+			Console.WriteLine("Usage: dotnet run [hamcore_dir]");
+			return -1;
+		}
+		else
+		{
+			string hamcore_dir = args[0];
+
+			string[] stb_files = Directory.GetFiles(hamcore_dir, "*.stb", SearchOption.TopDirectoryOnly);
+
+			if (stb_files.Length == 0)
+			{
+				Console.WriteLine("Error: There are no .stb files in the directory '" + hamcore_dir + "'.");
+				return -1;
+			}
+
+			int total_num = 0;
+
+			for (int i = 0; i < stb_files.Length; i++)
+			{
+				for (int j = 0; j < stb_files.Length; j++)
+				{
+					if (i != j)
+					{
+						Console.WriteLine("---\nComparing '{1}' to '{0}'...", Path.GetFileName(stb_files[i]), Path.GetFileName(stb_files[j]));
+
+						total_num += Stb.Compare(stb_files[i], stb_files[j]);
+					}
+				}
+			}
+
+			Console.WriteLine("--- Results ---");
+			if (total_num == 0)
+			{
+				Console.WriteLine("OK: Excellent! There are no errors between multilanguage stb files.");
+				Console.WriteLine();
+				Console.WriteLine("   - In Jurassic Park: \"It's a UNIX system! I know this!\"");
+				return 0;
+			}
+			else
+			{
+				Console.WriteLine($"ERROR: There are {total_num} errors on multilanguage stb files. Please kindly correct them before submitting us Pull Requests.");
+				return -3;
+			}
+		}
+	}
+}

+ 60 - 0
developer_tools/stbchecker/README.md

@@ -0,0 +1,60 @@
+# STB File Multilanguage Full-Mesh Consistency Checker
+
+September 20, 2018 By Daiyuu Nobori
+
+## Overview
+stbchecker is a utility to check the consistency between existing `*.stb` files (string resources) in the specified directory.
+
+- Works on Windows, Linux, macOS with .NET Core 2.1.
+- Written in C#.
+- Easy to use.
+
+
+When modifying or adding any stb files, you have to check the consistency between all existing `*.stb` files. If there are any error, the SoftEther VPN programs may fail or crash on runtime.
+
+
+You must not publish any build which has failed to pass stbchecker.
+
+
+## Usage
+### 1. Install .NET Core 2.1
+https://www.microsoft.com/net/download/dotnet-core/2.1
+
+
+#### Option: Use Visual Studio 2017 on Windows
+If you are using Visual Studio 2017 on Windows, you can open the `stbchecker.sln` file instead. With Visual Studio 2017 you do not need using .NET Core 2.1 command-line utility.
+
+### 2. Go to the `developer_tools/stbchcker` directory
+```
+$ cd developer_tools/stbchcker/
+```
+
+### 3. Run stbchecker
+```
+$ dotnet run [hamcore_dir]
+```
+You need to specify the `src/bin/hamcore` directory of the SoftEther VPN repository. The `hamcore` directory has multiple `*.stb` files.
+
+
+### 4. Show the result
+#### In error cases
+Errors as following will be displayed, and the program returns `non-zero` values as the exit code.
+
+```
+Comparing 'strtable_ko.stb' to 'strtable_cn.stb'...
+File2: Error: Missing 'HUB_AO_DenyAllRadiusLoginWithNoVlanAssign'
+File2: Error: Missing 'HUB_AO_UseHubNameAsDhcpUserClassOption'
+File2: Error: Missing 'HUB_AO_UseHubNameAsRadiusNasId'
+File2: Error: Missing 'CM_VLAN_REINSTALL_MSG'
+--- Results ---
+ERROR: There are 123 errors on multilanguage stb files. Please kindly correct them before submitting us Pull Requests.
+```
+
+
+#### In successful cases
+The following message will be displayed, and the program returns `0` as the exit code.
+
+
+```
+OK: Excellent! There are no errors between multilanguage stb files.
+```

+ 375 - 0
developer_tools/stbchecker/Stb.cs

@@ -0,0 +1,375 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+public class StbTable
+{
+	List<string> tagList;
+	public string[] TagList
+	{
+		get
+		{
+			return tagList.ToArray();
+		}
+	}
+
+	string name;
+	public string Name
+	{
+		get { return name; }
+	}
+
+	string str;
+	public string String
+	{
+		get { return str; }
+	}
+
+	public StbTable(string name, string str)
+	{
+		this.name = name;
+		this.str = str;
+
+		tagList = ParseTagList(str);
+	}
+
+	public static string UnescapeStr(string str)
+	{
+		int i, len;
+		string tmp;
+
+		len = str.Length;
+		tmp = "";
+
+		for (i = 0; i < len; i++)
+		{
+			if (str[i] == '\\')
+			{
+				i++;
+				switch (str[i])
+				{
+					case '\\':
+						tmp += '\\';
+						break;
+
+					case ' ':
+						tmp += ' ';
+						break;
+
+					case 'n':
+					case 'N':
+						tmp += '\n';
+						break;
+
+					case 'r':
+					case 'R':
+						tmp += '\r';
+						break;
+
+					case 't':
+					case 'T':
+						tmp += '\t';
+						break;
+				}
+			}
+			else
+			{
+				tmp += str[i];
+			}
+		}
+
+		return tmp;
+	}
+
+	public static StbTable ParseTableLine(string line, ref string prefix)
+	{
+		int i, len;
+		int string_start;
+		int len_name;
+		string name, name2;
+
+		line = line.TrimStart(' ', '\t');
+		len = line.Length;
+		if (len == 0)
+		{
+			return null;
+		}
+
+		if (line[0] == '#' || (line[0] == '/' && line[1] == '/'))
+		{
+			return null;
+		}
+
+		bool b = false;
+		len_name = 0;
+		for (i = 0; i < line.Length; i++)
+		{
+			if (line[i] == ' ' || line[i] == '\t')
+			{
+				b = true;
+				break;
+			}
+			len_name++;
+		}
+
+		if (b == false)
+		{
+			return null;
+		}
+
+		name = line.Substring(0, len_name);
+
+		string_start = len_name;
+		for (i = len_name; i < len; i++)
+		{
+			if (line[i] != ' ' && line[i] != '\t')
+			{
+				break;
+			}
+			string_start++;
+		}
+		if (i == len)
+		{
+			return null;
+		}
+
+		string str = line.Substring(string_start);
+
+		str = UnescapeStr(str);
+
+		if (Str.StrCmpi(name, "PREFIX"))
+		{
+			prefix = str;
+			prefix = prefix.TrimStart();
+
+			if (Str.StrCmpi(prefix, "$") || Str.StrCmpi(prefix, "NULL"))
+			{
+				prefix = "";
+			}
+
+			return null;
+		}
+
+		name2 = "";
+
+		if (prefix != "")
+		{
+			name2 += prefix + "@";
+		}
+
+		name2 += name;
+
+		return new StbTable(name2, str);
+	}
+
+	public static bool CompareTagList(string[] list1, string[] list2)
+	{
+		if (list1.Length != list2.Length)
+		{
+			return false;
+		}
+
+		int i;
+		for (i = 0; i < list1.Length; i++)
+		{
+			if (list1[i] != list2[i])
+			{
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	public static List<string> ParseTagList(string str)
+	{
+		List<string> list = new List<string>();
+		int i, len;
+		int mode = 0;
+		string tmp = "";
+
+		str += "_";
+
+		len = str.Length;
+
+		for (i = 0; i < len; i++)
+		{
+			char c = str[i];
+
+			if (mode == 0)
+			{
+				switch (c)
+				{
+					case '%':
+						if (str[i + 1] == '%')
+						{
+							i++;
+							tmp += c;
+						}
+						else
+						{
+							mode = 1;
+							tmp = "" + c;
+						}
+						break;
+
+					default:
+						tmp = "" + c;
+						break;
+				}
+			}
+			else
+			{
+				string tag;
+
+				switch (c)
+				{
+					case 'c':
+					case 'C':
+					case 'd':
+					case 'i':
+					case 'o':
+					case 'u':
+					case 'x':
+					case 'X':
+					case 'e':
+					case 'E':
+					case 'f':
+					case 'g':
+					case 'G':
+					case 'n':
+					case 'N':
+					case 's':
+					case 'S':
+					case 'r':
+					case ' ':
+						tmp += c;
+						tag = tmp;
+						list.Add(tag);
+						mode = 0;
+						break;
+					default:
+						tmp += c;
+						break;
+				}
+			}
+		}
+
+		return list;
+	}
+}
+
+public class Stb
+{
+	Dictionary<string, StbTable> tableList;
+	string name;
+	public string Name
+	{
+		get { return name; }
+	}
+
+	public Stb(string fileName)
+	{
+		init(File.ReadAllBytes(fileName), fileName);
+	}
+
+	public Stb(string fileName, string name)
+	{
+		init(File.ReadAllBytes(fileName), name);
+	}
+
+	public Stb(byte[] data, string name)
+	{
+		init(data, name);
+	}
+
+	void init(byte[] data, string name)
+	{
+		if (data[0] == 0xef && data[1] == 0xbb && data[2] == 0xbf)
+		{
+			byte[] tmp = new byte[data.Length - 3];
+			Array.Copy(data, 3, tmp, 0, data.Length - 3);
+			data = tmp;
+		}
+
+		StringReader sr = new StringReader(Str.Utf8Encoding.GetString(data));
+		tableList = new Dictionary<string, StbTable>();
+
+		this.name = name;
+		string prefix = "";
+
+		while (true)
+		{
+			string tmp = sr.ReadLine();
+			if (tmp == null)
+			{
+				break;
+			}
+
+			StbTable t = StbTable.ParseTableLine(tmp, ref prefix);
+			if (t != null)
+			{
+				if (tableList.ContainsKey(t.Name.ToUpper()) == false)
+				{
+					tableList.Add(t.Name.ToUpper(), t);
+				}
+				else
+				{
+					ShowWarning(name, string.Format("Duplicated '{0}'", t.Name));
+				}
+			}
+		}
+	}
+
+	protected static void ShowWarning(string name, string str)
+	{
+		Console.WriteLine("{0}: Warning: {1}", name, str);
+	}
+
+	protected static void ShowError(string name, string str)
+	{
+		Console.WriteLine("{0}: Error: {1}", name, str);
+	}
+
+	public static int Compare(string file1, string file2)
+	{
+		Stb stb1 = new Stb(file1, "File1");
+		Stb stb2 = new Stb(file2, "File2");
+		int num = 0;
+
+		string file1_fn = Path.GetFileName(file1);
+		string file2_fn = Path.GetFileName(file2);
+
+		foreach (string name1 in stb1.tableList.Keys)
+		{
+			if (name1.Equals("DEFAULT_FONT_WIN7", StringComparison.InvariantCultureIgnoreCase) ||
+				name1.Equals("DEFAULT_FONT_HIGHDPI", StringComparison.InvariantCultureIgnoreCase))
+			{
+				continue;
+			}
+
+			StbTable t1 = stb1.tableList[name1];
+
+			if (stb2.tableList.ContainsKey(name1) == false)
+			{
+				ShowError(stb2.name, string.Format("Missing '{0}'", t1.Name));
+				num++;
+			}
+			else
+			{
+				StbTable t2 = stb2.tableList[name1];
+
+				if (StbTable.CompareTagList(t1.TagList, t2.TagList) == false)
+				{
+					ShowError(stb2.name, string.Format("Difference printf-style parameters '{0}'", t1.Name));
+					num++;
+				}
+			}
+		}
+
+		Console.WriteLine("\nThere are {0} errors.\n\n{1}\n", num,
+			(num == 0 ? "Good work! No problem!" : "You must correct them before sending us Pull Requests!"));
+
+		return num;
+	}
+}

+ 555 - 0
developer_tools/stbchecker/Str.cs

@@ -0,0 +1,555 @@
+using System;
+using System.Text;
+using System.Collections.Generic;
+using System.IO;
+
+public class Str
+{
+	static Encoding asciiEncoding = Encoding.ASCII;
+	public static Encoding AsciiEncoding
+	{
+		get { return Str.asciiEncoding; }
+	}
+
+	static Encoding utf8Encoding = Encoding.UTF8;
+	public static Encoding Utf8Encoding
+	{
+		get { return Str.utf8Encoding; }
+	}
+
+	static Encoding uniEncoding = Encoding.Unicode;
+	public static Encoding UniEncoding
+	{
+		get { return Str.uniEncoding; }
+	}
+
+	public static string ByteToHex3(byte[] data)
+	{
+		if (data.Length == 0)
+		{
+			return "";
+		}
+
+		return BitConverter.ToString(data) + "-";
+	}
+
+	public static string ByteToHex(byte[] data)
+	{
+		StringBuilder ret = new StringBuilder();
+		foreach (byte b in data)
+		{
+			string s = b.ToString("X");
+			if (s.Length == 1)
+			{
+				s = "0" + s;
+			}
+
+			ret.Append(s);
+		}
+
+		return ret.ToString();
+	}
+
+	public static byte[] HexToByte(string str)
+	{
+		try
+		{
+			List<byte> o = new List<byte>();
+			string tmp = "";
+			int i, len;
+
+			str = str.ToUpper().Trim();
+			len = str.Length;
+
+			for (i = 0; i < len; i++)
+			{
+				char c = str[i];
+				if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F'))
+				{
+					tmp += c;
+					if (tmp.Length == 2)
+					{
+						byte b = Convert.ToByte(tmp, 16);
+						o.Add(b);
+						tmp = "";
+					}
+				}
+				else if (c == ' ' || c == ',' || c == '-' || c == ';')
+				{
+				}
+				else
+				{
+					break;
+				}
+			}
+
+			return o.ToArray();
+		}
+		catch
+		{
+			return new byte[0];
+		}
+	}
+
+	public static string ByteToStr(byte[] data, Encoding enc)
+	{
+		try
+		{
+			return enc.GetString(data);
+		}
+		catch
+		{
+			return "";
+		}
+	}
+
+	public static byte[] StrToByte(string str, Encoding enc)
+	{
+		try
+		{
+			return enc.GetBytes(str);
+		}
+		catch
+		{
+			return new byte[0];
+		}
+	}
+
+	public static string[] GetLines(string str)
+	{
+		List<string> a = new List<string>();
+		StringReader sr = new StringReader(str);
+		while (true)
+		{
+			string s = sr.ReadLine();
+			if (s == null)
+			{
+				break;
+			}
+			a.Add(s);
+		}
+		return a.ToArray();
+	}
+
+	public static string LinesToStr(string[] lines)
+	{
+		StringWriter sw = new StringWriter();
+		foreach (string s in lines)
+		{
+			sw.WriteLine(s);
+		}
+		return sw.ToString();
+	}
+
+	public static bool IsEmptyStr(string str)
+	{
+		if (str == null || str.Trim().Length == 0)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	public static bool IsSplitChar(char c, string splitStr)
+	{
+		if (splitStr == null)
+		{
+			splitStr = StrToken.DefaultSplitStr;
+		}
+
+		foreach (char t in splitStr)
+		{
+			string a = "" + t;
+			string b = "" + c;
+			if (Util.StrCmpi(a, b))
+			{
+				return true;
+			}
+		}
+
+		return false;
+	}
+
+	public static bool GetKeyAndValue(string str, out string key, out string value)
+	{
+		return GetKeyAndValue(str, out key, out value, null);
+	}
+	public static bool GetKeyAndValue(string str, out string key, out string value, string splitStr)
+	{
+		uint mode = 0;
+		string keystr = "", valuestr = "";
+		if (splitStr == null)
+		{
+			splitStr = StrToken.DefaultSplitStr;
+		}
+
+		foreach (char c in str)
+		{
+			switch (mode)
+			{
+				case 0:
+					if (IsSplitChar(c, splitStr) == false)
+					{
+						mode = 1;
+						keystr += c;
+					}
+					break;
+
+				case 1:
+					if (IsSplitChar(c, splitStr) == false)
+					{
+						keystr += c;
+					}
+					else
+					{
+						mode = 2;
+					}
+					break;
+
+				case 2:
+					if (IsSplitChar(c, splitStr) == false)
+					{
+						mode = 3;
+						valuestr += c;
+					}
+					break;
+
+				case 3:
+					valuestr += c;
+					break;
+			}
+		}
+
+		if (mode == 0)
+		{
+			value = "";
+			key = "";
+			return false;
+		}
+		else
+		{
+			value = valuestr;
+			key = keystr;
+			return true;
+		}
+	}
+
+	public static int StrCmpRetInt(string s1, string s2)
+	{
+		return s1.CompareTo(s2);
+	}
+	public static bool StrCmp(string s1, string s2)
+	{
+		return StrCmpRetInt(s1, s2) == 0 ? true : false;
+	}
+	public static int StrCmpiRetInt(string s1, string s2)
+	{
+		s1 = s1.ToUpper();
+		s2 = s2.ToUpper();
+		return StrCmpRetInt(s1, s2);
+	}
+	public static bool StrCmpi(string s1, string s2)
+	{
+		return StrCmpiRetInt(s1, s2) == 0 ? true : false;
+	}
+
+	public static bool IsStrInList(string str, params string[] args)
+	{
+		return IsStrInList(str, true, args);
+	}
+	public static bool IsStrInList(string str, bool ignoreCase, params string[] args)
+	{
+		foreach (string s in args)
+		{
+			if (ignoreCase)
+			{
+				if (StrCmpi(str, s))
+				{
+					return true;
+				}
+			}
+			else
+			{
+				if (StrCmp(str, s))
+				{
+					return true;
+				}
+			}
+		}
+
+		return false;
+	}
+
+	public static bool IsNumber(string str)
+	{
+		str = str.Trim();
+
+		foreach (char c in str)
+		{
+			if (c >= '0' && c <= '9')
+			{
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	public static string DateToString(DateTime dt)
+	{
+		if (dt.Ticks != 0)
+		{
+			return dt.ToString("yyyyMMdd HHmmss").Substring(2);
+		}
+		else
+		{
+			return "000000_000000";
+		}
+	}
+
+	public static DateTime StringToDate(string str)
+	{
+		str = str.Replace("(JST)", "").Trim();
+
+		try
+		{
+			return DateTime.Parse(str);
+		}
+		catch
+		{
+			return new DateTime(0);
+		}
+	}
+
+	public static string ToSafeString(string str)
+	{
+		char[] chars =
+				{
+					';', '?', '=', '<', '>', ':', '@', '%', '$', '\\', '/', '|', '\"', '\r', '\n',
+				};
+
+		string ret = str;
+		foreach (char c in chars)
+		{
+			ret = ret.Replace(c, '_');
+		}
+
+		string ret2 = "";
+
+		foreach (char c in ret)
+		{
+			bool b = false;
+
+			if (c >= 0x00 && c <= 0x1f)
+			{
+				b = true;
+			}
+
+			if (c >= 0x7f && c <= 0xff)
+			{
+				b = true;
+			}
+
+			if (b == false)
+			{
+				ret2 += c;
+			}
+			else
+			{
+				ret2 += "_";
+			}
+		}
+
+		return ret2;
+	}
+
+	public static byte[] Base64Decode(string src)
+	{
+		try
+		{
+			return System.Convert.FromBase64String(src);
+		}
+		catch
+		{
+			return null;
+		}
+	}
+
+	public static string DecodeMime(string src)
+	{
+		string[] s = src.Split('?');
+		byte[] b;
+		if (s[2] == "B")
+		{
+			b = System.Convert.FromBase64String(s[3]);
+		}
+		else
+		{
+			throw new Exception("Bad Encode.");
+		}
+		string ret = System.Text.Encoding.GetEncoding(s[1]).GetString(b);
+
+		if (s.Length >= 4)
+		{
+			string tmp = s[s.Length - 1];
+
+			if (tmp.StartsWith("="))
+			{
+				ret += tmp.Substring(1);
+			}
+		}
+
+		return ret;
+	}
+
+	public static bool HasNullChar(string str)
+	{
+		if (str.IndexOf('\0') != -1)
+		{
+			return true;
+		}
+
+		return false;
+	}
+
+	public static bool IsMailHeaderStr(string str)
+	{
+		if (str == null)
+		{
+			return false;
+		}
+		if (HasNullChar(str))
+		{
+			return false;
+		}
+
+		string[] sep = { ": " };
+		string[] tokens = str.Split(sep, StringSplitOptions.RemoveEmptyEntries);
+
+		if (tokens.Length >= 2)
+		{
+			return true;
+		}
+
+		return false;
+	}
+
+	public static bool IsStrForBase64(string str)
+	{
+		string b64str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/+=";
+
+		foreach (char c in str)
+		{
+			bool b = false;
+
+			foreach (char c2 in b64str)
+			{
+				if (c == c2)
+				{
+					b = true;
+					break;
+				}
+			}
+
+			if (b == false)
+			{
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+}
+
+public class StrToken
+{
+	string[] tokens;
+
+	public string[] Tokens
+	{
+		get { return tokens; }
+	}
+
+	public string this[uint index]
+	{
+		get { return tokens[index]; }
+	}
+
+	public uint NumTokens
+	{
+		get
+		{
+			return (uint)Tokens.Length;
+		}
+	}
+
+	const string defaultSplitStr = " ,\t\r\n";
+
+	public static string DefaultSplitStr
+	{
+		get { return defaultSplitStr; }
+	}
+
+
+	public StrToken(string str)
+		: this(str, null)
+	{
+	}
+	public StrToken(string str, string splitStr)
+	{
+		if (splitStr == null)
+		{
+			splitStr = defaultSplitStr;
+		}
+		int i, len;
+		len = splitStr.Length;
+		char[] chars = new char[len];
+		for (i = 0; i < len; i++)
+		{
+			chars[i] = splitStr[i];
+		}
+		tokens = str.Split(chars, StringSplitOptions.RemoveEmptyEntries);
+	}
+}
+
+public class StrData
+{
+	string strValue;
+
+	public string StrValue
+	{
+		get { return strValue; }
+	}
+
+	public uint IntValue
+	{
+		get
+		{
+			return Util.StrToUInt(strValue);
+		}
+	}
+
+	public ulong Int64Value
+	{
+		get
+		{
+			return Util.StrToULong(strValue);
+		}
+	}
+
+	public StrData(string str)
+	{
+		if (str == null)
+		{
+			str = "";
+		}
+		strValue = str;
+	}
+}

+ 603 - 0
developer_tools/stbchecker/Util.cs

@@ -0,0 +1,603 @@
+using System;
+using System.Text;
+using System.Collections;
+using System.Security.Cryptography;
+using System.Web;
+using System.IO;
+using System.Drawing;
+
+public class Util
+{
+	public static string TruncStr(string str, int len)
+	{
+		if (str.Length <= len)
+		{
+			return str;
+		}
+		else
+		{
+			return str.Substring(len);
+		}
+	}
+
+	public static string GenRand()
+	{
+		return ByteToStr(Hash(Guid.NewGuid().ToByteArray()));
+	}
+
+	public static bool StrCmpi(string s1, string s2)
+	{
+		try
+		{
+			if (s1.ToUpper() == s2.ToUpper())
+			{
+				return true;
+			}
+
+			return false;
+		}
+		catch
+		{
+			return false;
+		}
+	}
+
+	public static bool StrCmp(string s1, string s2)
+	{
+		try
+		{
+			if (s1 == s2)
+			{
+				return true;
+			}
+
+			return false;
+		}
+		catch
+		{
+			return false;
+		}
+	}
+
+	public static Encoding UTF8()
+	{
+		return Encoding.UTF8;
+	}
+
+	public static Encoding EucJP()
+	{
+		return Encoding.GetEncoding("euc-jp");
+	}
+
+	public static Encoding ShiftJIS()
+	{
+		return Encoding.GetEncoding("shift_jis");
+	}
+
+	public static byte[] Hash(string str)
+	{
+		return Hash(Encoding.UTF8.GetBytes(str));
+	}
+
+	public static byte[] Hash(byte[] data)
+	{
+		SHA1 sha1 = SHA1.Create();
+		return sha1.ComputeHash(data);
+	}
+
+	public static string ByteToStr(byte[] data)
+	{
+		StringBuilder sb = new StringBuilder();
+		foreach (byte b in data)
+		{
+			sb.Append(b.ToString("X2"));
+		}
+
+		return sb.ToString();
+	}
+
+	public static string RandToStr6(string rand)
+	{
+		byte[] hash = Hash(rand + "packetix.net");
+		return ByteToStr(hash).Substring(0, 6);
+	}
+
+	public static bool CheckImageRand(string rand, string str)
+	{
+		string s = RandToStr6(rand);
+		string tmp = str.ToUpper();
+		tmp = tmp.Replace("O", "0").Replace("I", "1");
+		return StrCmpi(s, tmp);
+	}
+
+	public static bool IsAscii(char c)
+	{
+		if (c >= '0' && c <= '9')
+		{
+			return true;
+		}
+		if (c >= 'A' && c <= 'Z')
+		{
+			return true;
+		}
+		if (c >= 'a' && c <= 'z')
+		{
+			return true;
+		}
+		if (c == '!' || c == '\"' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' ||
+			c == '(' || c == ')' || c == '-' || c == ' ' || c == '=' || c == '~' || c == '^' || c == '_' ||
+			c == '\\' || c == '|' || c == '{' || c == '}' || c == '[' || c == ']' || c == '@' ||
+			c == '*' || c == '+' || c == '.' || c == '<' || c == '>' ||
+			c == ',' || c == '?' || c == '/')
+		{
+			return true;
+		}
+		return false;
+	}
+	public static bool IsAscii(string str)
+	{
+		foreach (char c in str)
+		{
+			if (IsAscii(c) == false)
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public static bool CheckMailAddress(string str)
+	{
+		str = str.Trim();
+		if (str.Length == 0)
+		{
+			return false;
+		}
+
+		string[] tokens = str.Split('@');
+
+		if (tokens.Length != 2)
+		{
+			return false;
+		}
+
+		string a = tokens[0];
+		string b = tokens[1];
+
+		if (a.Length == 0 || b.Length == 0)
+		{
+			return false;
+		}
+
+		if (b.IndexOf(".") == -1)
+		{
+			return false;
+		}
+
+		return IsAscii(str);
+	}
+
+	public static string GetFileSizeStr(int size)
+	{
+		if (size >= 1024 * 1024)
+		{
+			return ((double)(size) / 1024.0f / 1024.0f).ToString(".##") + " MB";
+		}
+		if (size >= 1024)
+		{
+			return ((double)(size) / 1024.0f).ToString(".##") + " KB";
+		}
+		return ((double)(size)).ToString() + " Bytes";
+	}
+
+
+	public static string IntToStr(int i)
+	{
+		return i.ToString();
+	}
+	public static string IntToStr(uint i)
+	{
+		return i.ToString();
+	}
+
+	public static string LongToStr(long i)
+	{
+		return i.ToString();
+	}
+	public static string LongToStr(ulong i)
+	{
+		return i.ToString();
+	}
+
+	public static int StrToInt(string str)
+	{
+		try
+		{
+			return int.Parse(str);
+		}
+		catch
+		{
+			try
+			{
+				return (int)double.Parse(str);
+			}
+			catch
+			{
+				return 0;
+			}
+		}
+	}
+	public static uint StrToUInt(string str)
+	{
+		try
+		{
+			return uint.Parse(str);
+		}
+		catch
+		{
+			return 0;
+		}
+	}
+
+	public static long StrToLong(string str)
+	{
+		try
+		{
+			return long.Parse(str);
+		}
+		catch
+		{
+			return 0;
+		}
+	}
+	public static ulong StrToULong(string str)
+	{
+		try
+		{
+			return ulong.Parse(str);
+		}
+		catch
+		{
+			return 0;
+		}
+	}
+
+	public static DateTime StrToDate(string str)
+	{
+		DateTime ret = new DateTime(0);
+		str = str.Trim();
+		if (str.Length == 8)
+		{
+			int year = StrToInt(str.Substring(0, 4));
+			int month = StrToInt(str.Substring(4, 2));
+			int day = StrToInt(str.Substring(6, 2));
+
+			ret = new DateTime(year, month, day);
+		}
+		return ret;
+	}
+
+	public static string SafeSql(string str)
+	{
+		return str.Replace("'", "");
+	}
+
+	public static bool IsFileExists(string name)
+	{
+		try
+		{
+			return File.Exists(name);
+		}
+		catch
+		{
+			return false;
+		}
+	}
+
+	public static string GetDefaultDocumentIfExists(string dir)
+	{
+		string[] targets =
+			{
+				"default.aspx",
+				"default.asp",
+				"default.html",
+				"default.htm",
+				"index.html",
+				"index.htm",
+			};
+
+		foreach (string s in targets)
+		{
+			string name = dir + s;
+
+			if (IsFileExists(name))
+			{
+				return name;
+			}
+		}
+
+		return null;
+	}
+
+	public static string ReadHtmlFile(string filename)
+	{
+		return File.ReadAllText(filename, Encoding.GetEncoding("shift_jis"));
+	}
+
+	public static string GetAlternativeTitleFromHtml(string src)
+	{
+		string tmp;
+		string upper;
+		int i;
+
+		upper = src.ToLower();
+		i = upper.IndexOf("</at>");
+		if (i == -1)
+		{
+			return null;
+		}
+
+		tmp = src.Substring(0, i);
+
+		i = tmp.IndexOf("<at>");
+		if (i == -1)
+		{
+			return null;
+		}
+
+		string ret = tmp.Substring(i + 4);
+
+		if (ret.Length == 0)
+		{
+			return null;
+		}
+		else
+		{
+			return ret;
+		}
+	}
+
+	public static string GetTitleFromHtml(string src)
+	{
+		string tmp;
+		string upper;
+		int i;
+
+		upper = src.ToLower();
+		i = upper.IndexOf("</title>");
+		if (i == -1)
+		{
+			return null;
+		}
+
+		tmp = src.Substring(0, i);
+
+		i = tmp.IndexOf("<title>");
+		if (i == -1)
+		{
+			return null;
+		}
+
+		return tmp.Substring(i + 7);
+	}
+
+	public static string GetTitleFromHtmlFile(string filename)
+	{
+		return GetTitleFromHtml(ReadHtmlFile(filename));
+	}
+	public static string GetAlternativeTitleFromHtmlFile(string filename)
+	{
+		return GetAlternativeTitleFromHtml(ReadHtmlFile(filename));
+	}
+
+	public static string GetUrlFileNameFromPath(string url)
+	{
+		string folder = GetUrlDirNameFromPath(url);
+
+		return url.Substring(folder.Length);
+	}
+
+	public static string GetUrlDirNameFromPath(string url)
+	{
+		string ret = "";
+		string[] strs = url.Split('/');
+		int i;
+		if (strs.Length >= 1)
+		{
+			for (i = 0; i < strs.Length - 1; i++)
+			{
+				ret += strs[i] + "/";
+			}
+		}
+		return ret;
+	}
+
+	public static string Encode64(string str)
+	{
+		return Convert.ToBase64String(Encoding.UTF8.GetBytes(str)).Replace("/", "(").Replace("+", ")");
+	}
+
+	public static string Decode64(string str)
+	{
+		return Encoding.UTF8.GetString(Convert.FromBase64String(str.Replace(")", "+").Replace("(", "/")));
+	}
+
+	public static string RemoveDefaultHtml(string url)
+	{
+		string tmp = url.ToLower();
+		if (tmp.EndsWith("/default.asp") || tmp.EndsWith("/default.aspx") || tmp.EndsWith("/default.htm") || tmp.EndsWith("/default.html"))
+		{
+			return GetUrlDirNameFromPath(url);
+		}
+		else
+		{
+			return url;
+		}
+	}
+
+	public static string RemovePortFromHostHeader(string str)
+	{
+		try
+		{
+			string[] ret = str.Split(':');
+
+			return ret[0];
+		}
+		catch
+		{
+			return str;
+		}
+	}
+
+	public static string ToStr3(ulong v)
+	{
+		string tmp = LongToStr(v);
+		int len, i;
+		string tmp2 = "";
+
+		len = tmp.Length;
+
+		for (i = len - 1; i >= 0; i--)
+		{
+			tmp2 += tmp[i];
+		}
+
+		tmp = "";
+
+		for (i = 0; i < len; i++)
+		{
+			if (i != 0 && (i % 3) == 0)
+			{
+				tmp += ",";
+			}
+			tmp += tmp2[i];
+		}
+
+		tmp2 = "";
+		len = tmp.Length;
+
+		for (i = len - 1; i >= 0; i--)
+		{
+			tmp2 += tmp[i];
+		}
+
+		return tmp2;
+	}
+
+	public static string DateTimeToStr(DateTime dt)
+	{
+		return DateTimeToStr(dt, false);
+	}
+	public static string DateTimeToStr(DateTime dt, bool toLocalTime)
+	{
+		if (toLocalTime)
+		{
+			dt = dt.ToLocalTime();
+		}
+
+		return dt.ToString("yyyy年M月d日(ddd) H時m分s秒");
+	}
+
+	public static byte[] IntToByte(uint value)
+	{
+		MemoryStream st = new MemoryStream();
+		BinaryWriter w = new BinaryWriter(st);
+		w.Write(value);
+		st.Seek(0, SeekOrigin.Begin);
+		return st.ToArray();
+	}
+
+	public static uint ByteToInt(byte[] b)
+	{
+		MemoryStream st = new MemoryStream();
+		st.Write(b, 0, b.Length);
+		st.Seek(0, SeekOrigin.Begin);
+		BinaryReader r = new BinaryReader(st);
+		return r.ReadUInt32();
+	}
+
+	public static byte[] ReverseByteArray(byte[] b)
+	{
+		int i, num, j;
+		num = b.Length;
+		byte[] ret = new byte[num];
+		j = 0;
+
+		for (i = num - 1; i >= 0; i--)
+		{
+			ret[j++] = b[i];
+		}
+
+		return ret;
+	}
+
+	public static uint ReverseEndian(uint value)
+	{
+		return ByteToInt(ReverseByteArray(IntToByte(value)));
+	}
+
+	public static string SafeDomainStr(string str)
+	{
+		string ret = str.Replace("(", "").Replace(")", "").Replace(" ", "").Replace("-", "").Replace("#", "")
+			.Replace("%", "").Replace("%", "").Replace("&", "").Replace(".", "");
+		if (ret == "")
+		{
+			ret = "host";
+		}
+
+		return ret;
+	}
+
+	public static bool CompareByte(byte[] b1, byte[] b2)
+	{
+		if (b1.Length != b2.Length)
+		{
+			return false;
+		}
+		int i, len;
+		len = b1.Length;
+		for (i = 0; i < len; i++)
+		{
+			if (b1[i] != b2[i])
+			{
+				return false;
+			}
+		}
+		return true;
+	}
+
+	public static int CompareByteRetInt(byte[] b1, byte[] b2)
+	{
+		int i;
+		for (i = 0; ; i++)
+		{
+			int a1 = -1, a2 = -1;
+			if (b1.Length < i)
+			{
+				a1 = (int)b1[i];
+			}
+			if (b2.Length < i)
+			{
+				a2 = (int)b2[i];
+			}
+
+			if (a1 > a2)
+			{
+				return 1;
+			}
+			else if (a1 < a2)
+			{
+				return -1;
+			}
+			if (a1 == -1 && a2 == -1)
+			{
+				return 0;
+			}
+		}
+	}
+
+	public static byte[] CloneByteArray(byte[] src)
+	{
+		return (byte[])src.Clone();
+	}
+}

+ 16 - 0
developer_tools/stbchecker/stbchecker.csproj

@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+
+</Project>

+ 24 - 0
developer_tools/stbchecker/stbchecker.sln

@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28010.2026
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "stbchecker", "stbchecker.csproj", "{BA902FC8-E936-44AA-9C88-57D358BBB700}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BA902FC8-E936-44AA-9C88-57D358BBB700}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BA902FC8-E936-44AA-9C88-57D358BBB700}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BA902FC8-E936-44AA-9C88-57D358BBB700}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BA902FC8-E936-44AA-9C88-57D358BBB700}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {AD05DECC-E457-42C1-B8AC-46F021023817}
+	EndGlobalSection
+EndGlobal