Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/SoftEtherVPN/SoftEtherVPN_Stable.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mayaqua/Table.c')
-rw-r--r--src/Mayaqua/Table.c1473
1 files changed, 1473 insertions, 0 deletions
diff --git a/src/Mayaqua/Table.c b/src/Mayaqua/Table.c
new file mode 100644
index 00000000..6cc3282b
--- /dev/null
+++ b/src/Mayaqua/Table.c
@@ -0,0 +1,1473 @@
+// SoftEther VPN Source Code
+// Mayaqua Kernel
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Table.c
+// Read and management routines for string table
+
+#include <GlobalConst.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// List of TABLE
+static LIST *TableList = NULL;
+static wchar_t old_table_name[MAX_SIZE] = {0}; // Old table name
+static LANGLIST current_lang = {0};
+static LANGLIST current_os_lang = {0};
+
+// Initialization of string table routine
+void InitTable()
+{
+ LIST *o;
+ char tmp[MAX_SIZE];
+ LANGLIST *e = NULL;
+ LANGLIST *os_lang = NULL;
+ char table_name[MAX_SIZE];
+ if (MayaquaIsMinimalMode())
+ {
+ // Not to load in case of minimum mode
+ return;
+ }
+
+ o = LoadLangList();
+ if (o == NULL)
+ {
+LABEL_FATAL_ERROR:
+ Alert("Fatal Error: The file \"hamcore.se2\" is missing or broken.\r\nPlease check hamcore.se2.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)", NULL);
+ exit(-1);
+ return;
+ }
+
+ // Read the lang.config
+ if (LoadLangConfigCurrentDir(tmp, sizeof(tmp)))
+ {
+ e = GetBestLangByName(o, tmp);
+ }
+
+ os_lang = GetBestLangForCurrentEnvironment(o);
+
+ if (e == NULL)
+ {
+ e = os_lang;
+ }
+
+ if (e == NULL)
+ {
+ goto LABEL_FATAL_ERROR;
+ }
+
+ SaveLangConfigCurrentDir(e->Name);
+
+ Copy(&current_lang, e, sizeof(LANGLIST));
+ Copy(&current_os_lang, os_lang, sizeof(LANGLIST));
+
+ current_lang.LangList = current_lang.LcidList = NULL;
+ current_os_lang.LangList = current_os_lang.LcidList = NULL;
+
+ // Read the corresponding string table
+ Format(table_name, sizeof(table_name), "|strtable_%s.stb", current_lang.Name);
+ if (LoadTable(table_name) == false)
+ {
+ goto LABEL_FATAL_ERROR;
+ }
+
+ FreeLangList(o);
+}
+
+// Get the language of the current OS
+void GetCurrentOsLang(LANGLIST *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ Copy(e, &current_os_lang, sizeof(LANGLIST));
+}
+
+// Get the language ID of the current OS
+UINT GetCurrentOsLangId()
+{
+ LANGLIST e;
+
+ Zero(&e, sizeof(e));
+
+ GetCurrentOsLang(&e);
+
+ return e.Id;
+}
+
+// Get the current language
+void GetCurrentLang(LANGLIST *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ Copy(e, &current_lang, sizeof(LANGLIST));
+}
+
+// Get the current language ID
+UINT GetCurrentLangId()
+{
+ LANGLIST e;
+
+ Zero(&e, sizeof(e));
+
+ GetCurrentLang(&e);
+
+ return e.Id;
+}
+
+// Write to the lang.config file in the current directory
+bool SaveLangConfigCurrentDir(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ return SaveLangConfig(LANG_CONFIG_FILENAME, str);
+}
+
+// Write to the lang.config file
+bool SaveLangConfig(wchar_t *filename, char *str)
+{
+ BUF *b;
+ LIST *o;
+ UINT i;
+ bool ret;
+ // Validate arguments
+ if (filename == NULL)
+ {
+ return false;
+ }
+
+ // Read the template
+ b = ReadDump(LANG_CONFIG_TEMPLETE);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ SeekBuf(b, b->Size, 0);
+
+ o = LoadLangList();
+ if (o != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ AppendBufStr(b, "# Available Language IDs are:\r\n");
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+
+ UniFormat(tmp, sizeof(tmp), L"# %S: %s (%s)\r\n",
+ e->Name, e->TitleEnglish, e->TitleLocal);
+
+ AppendBufUtf8(b, tmp);
+ }
+
+ AppendBufStr(b, "\r\n\r\n# Specify a Language ID here.\r\n");
+ AppendBufStr(b, str);
+ AppendBufStr(b, "\r\n\r\n");
+
+ FreeLangList(o);
+ }
+
+ ret = DumpBufW(b, filename);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Read the lang.config file in the current directory
+bool LoadLangConfigCurrentDir(char *str, UINT str_size)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ return LoadLangConfig(LANG_CONFIG_FILENAME, str, str_size);
+}
+
+// Read the lang.config file
+bool LoadLangConfig(wchar_t *filename, char *str, UINT str_size)
+{
+ BUF *b;
+ bool ret = false;
+ // Validate arguments
+ if (filename == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDumpW(filename);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ while (true)
+ {
+ char *line = CfgReadNextLine(b);
+
+ if (line == NULL)
+ {
+ break;
+ }
+
+ Trim(line);
+
+ if (IsEmptyStr(line) == false)
+ {
+ if (StartWith(line, "#") == false && StartWith(line, "//") == false && StartWith(line, ";") == false &&
+ InStr(line, "#") == false)
+ {
+ StrCpy(str, str_size, line);
+ ret = true;
+ }
+ }
+
+ Free(line);
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Choose the language from the ID
+LANGLIST *GetLangById(LIST *o, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+
+ if (e->Id == id)
+ {
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+// Choice the best language for the current environment
+LANGLIST *GetBestLangForCurrentEnvironment(LIST *o)
+{
+ LANGLIST *ret = NULL;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+#ifdef OS_WIN32
+ ret = GetBestLangByLcid(o, MsGetUserLocaleId());
+#else // OS_WIN32
+ if (true)
+ {
+ char lang[MAX_SIZE];
+
+ if (GetEnv("LANG", lang, sizeof(lang)))
+ {
+ ret = GetBestLangByLangStr(o, lang);
+ }
+ else
+ {
+ ret = GetBestLangByLangStr(o, "C");
+ }
+ }
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Search for the best language from LANG string of UNIX
+LANGLIST *GetBestLangByLangStr(LIST *o, char *str)
+{
+ UINT i;
+ LANGLIST *ret;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+ UINT j;
+
+ for (j = 0;j < LIST_NUM(e->LangList);j++)
+ {
+ char *v = LIST_DATA(e->LangList, j);
+
+ if (StrCmpi(v, str) == 0)
+ {
+ return e;
+ }
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+ UINT j;
+
+ for (j = 0;j < LIST_NUM(e->LangList);j++)
+ {
+ char *v = LIST_DATA(e->LangList, j);
+
+ if (StartWith(str, v) || StartWith(v, str))
+ {
+ return e;
+ }
+ }
+ }
+
+ ret = GetBestLangByName(o, "en");
+
+ return ret;
+}
+
+// Search for the best language from LCID
+LANGLIST *GetBestLangByLcid(LIST *o, UINT lcid)
+{
+ LANGLIST *ret;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+
+ if (IsIntInList(e->LcidList, lcid))
+ {
+ return e;
+ }
+ }
+
+ ret = GetBestLangByName(o, "en");
+
+ return ret;
+}
+
+// Search for the best language from the name
+LANGLIST *GetBestLangByName(LIST *o, char *name)
+{
+ UINT i;
+ LANGLIST *ret = NULL;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+
+ if (StrCmpi(e->Name, name) == 0)
+ {
+ ret = e;
+ break;
+ }
+ }
+
+ if (ret != NULL)
+ {
+ return ret;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+
+ if (StartWith(e->Name, name) || StartWith(name, e->Name))
+ {
+ ret = e;
+ break;
+ }
+ }
+
+ if (ret != NULL)
+ {
+ return ret;
+ }
+
+ return ret;
+}
+
+// Release the language list
+void FreeLangList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *e = LIST_DATA(o, i);
+
+ FreeStrList(e->LangList);
+ ReleaseIntList(e->LcidList);
+
+ Free(e);
+ }
+
+ ReleaseList(o);
+}
+
+// Read the language list
+LIST *LoadLangList()
+{
+ LIST *o = NewListFast(NULL);
+ char *filename = LANGLIST_FILENAME;
+ BUF *b;
+
+ b = ReadDump(filename);
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ while (true)
+ {
+ char *line = CfgReadNextLine(b);
+
+ if (line == NULL)
+ {
+ break;
+ }
+
+ Trim(line);
+
+ if (IsEmptyStr(line) == false && StartWith(line, "#") == false)
+ {
+ TOKEN_LIST *t = ParseToken(line, "\t ");
+ if (t != NULL)
+ {
+ if (t->NumTokens == 6)
+ {
+ LANGLIST *e = ZeroMalloc(sizeof(LANGLIST));
+ TOKEN_LIST *t2;
+
+ e->Id = ToInt(t->Token[0]);
+ StrCpy(e->Name, sizeof(e->Name), t->Token[1]);
+ Utf8ToUni(e->TitleEnglish, sizeof(e->TitleEnglish), t->Token[2], StrLen(t->Token[2]));
+ Utf8ToUni(e->TitleLocal, sizeof(e->TitleLocal), t->Token[3], StrLen(t->Token[3]));
+
+ UniReplaceStrEx(e->TitleEnglish, sizeof(e->TitleEnglish), e->TitleEnglish,
+ L"_", L" ", true);
+
+ UniReplaceStrEx(e->TitleLocal, sizeof(e->TitleLocal), e->TitleLocal,
+ L"_", L" ", true);
+
+ e->LcidList = NewIntList(false);
+
+ t2 = ParseToken(t->Token[4], ",");
+ if (t2 != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < t2->NumTokens;i++)
+ {
+ UINT id = ToInt(t2->Token[i]);
+
+ AddIntDistinct(e->LcidList, id);
+ }
+
+ FreeToken(t2);
+ }
+
+ e->LangList = NewListFast(NULL);
+
+ t2 = ParseToken(t->Token[5], ",");
+ if (t2 != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < t2->NumTokens;i++)
+ {
+ Add(e->LangList, CopyStr(t2->Token[i]));
+ }
+
+ FreeToken(t2);
+ }
+
+ Add(o, e);
+ }
+
+ FreeToken(t);
+ }
+ }
+
+ Free(line);
+ }
+
+ FreeBuf(b);
+
+ return o;
+}
+
+// Get an error string in Unicode
+wchar_t *GetUniErrorStr(UINT err)
+{
+ wchar_t *ret;
+ char name[MAX_SIZE];
+ Format(name, sizeof(name), "ERR_%u", err);
+
+ ret = GetTableUniStr(name);
+ if (UniStrLen(ret) != 0)
+ {
+ return ret;
+ }
+ else
+ {
+ return _UU("ERR_UNKNOWN");
+ }
+}
+
+// Get an error string
+char *GetErrorStr(UINT err)
+{
+ char *ret;
+ char name[MAX_SIZE];
+ Format(name, sizeof(name), "ERR_%u", err);
+
+ ret = GetTableStr(name);
+ if (StrLen(ret) != 0)
+ {
+ return ret;
+ }
+ else
+ {
+ return _SS("ERR_UNKNOWN");
+ }
+}
+
+// Load the integer value from the table
+UINT GetTableInt(char *name)
+{
+ char *str;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return 0;
+ }
+
+ str = GetTableStr(name);
+ return ToInt(str);
+}
+
+// Load a Unicode string from the table
+wchar_t *GetTableUniStr(char *name)
+{
+ TABLE *t;
+ // Validate arguments
+ if (name == NULL)
+ {
+// Debug("%s: ************\n", name);
+ return L"";
+ }
+
+ // Search
+ t = FindTable(name);
+ if (t == NULL)
+ {
+ //Debug("%s: UNICODE STRING NOT FOUND\n", name);
+ return L"";
+ }
+
+ return t->unistr;
+}
+
+// Load the string from the table
+char *GetTableStr(char *name)
+{
+ TABLE *t;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return "";
+ }
+
+#ifdef OS_WIN32
+ if (StrCmpi(name, "DEFAULT_FONT") == 0)
+ {
+ if (_II("LANG") == 2)
+ {
+ UINT os_type = GetOsType();
+ if (OS_IS_WINDOWS_9X(os_type) ||
+ GET_KETA(os_type, 100) <= 4)
+ {
+ // Use the SimSun font in Windows 9x, Windows NT 4.0, Windows 2000, Windows XP, and Windows Server 2003
+ return "SimSun";
+ }
+ }
+ }
+#endif // OS_WIN32
+
+ // Search
+ t = FindTable(name);
+ if (t == NULL)
+ {
+ //Debug("%s: ANSI STRING NOT FOUND\n", name);
+ return "";
+ }
+
+ return t->str;
+}
+
+// Get the string name that begins with the specified name
+TOKEN_LIST *GetTableNameStartWith(char *str)
+{
+ UINT i;
+ UINT len;
+ LIST *o;
+ TOKEN_LIST *t;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NullToken();
+ }
+
+ StrCpy(tmp, sizeof(tmp), str);
+ StrUpper(tmp);
+
+ len = StrLen(tmp);
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(TableList);i++)
+ {
+ TABLE *t = LIST_DATA(TableList, i);
+ UINT len2 = StrLen(t->name);
+
+ if (len2 >= len)
+ {
+ if (Cmp(t->name, tmp, len) == 0)
+ {
+ Insert(o, CopyStr(t->name));
+ }
+ }
+ }
+
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+
+ ReleaseList(o);
+
+ return t;
+}
+
+// Search the table
+TABLE *FindTable(char *name)
+{
+ TABLE *t, tt;
+ // Validate arguments
+ if (name == NULL || TableList == NULL)
+ {
+ return NULL;
+ }
+
+ tt.name = CopyStr(name);
+ t = Search(TableList, &tt);
+ Free(tt.name);
+
+ return t;
+}
+
+// A function that compares the table name
+int CmpTableName(void *p1, void *p2)
+{
+ TABLE *t1, *t2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ t1 = *(TABLE **)p1;
+ t2 = *(TABLE **)p2;
+ if (t1 == NULL || t2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(t1->name, t2->name);
+}
+
+// Interpret a line
+TABLE *ParseTableLine(char *line, char *prefix, UINT prefix_size, LIST *replace_list)
+{
+ UINT i, len;
+ UINT len_name;
+ UINT string_start;
+ char *name;
+ char *name2;
+ UINT name2_size;
+ wchar_t *unistr;
+ char *str;
+ UINT unistr_size, str_size;
+ TABLE *t;
+ // Validate arguments
+ if (line == NULL || prefix == NULL)
+ {
+ return NULL;
+ }
+ TrimLeft(line);
+
+ // No line
+ len = StrLen(line);
+ if (len == 0)
+ {
+ return NULL;
+ }
+
+ // Comment
+ if (line[0] == '#' || (line[0] == '/' && line[1] == '/'))
+ {
+ return NULL;
+ }
+
+ // Search to the end position of the name
+ len_name = 0;
+ for (i = 0;;i++)
+ {
+ if (line[i] == 0)
+ {
+ // There is only one token
+ return NULL;
+ }
+ if (line[i] == ' ' || line[i] == '\t')
+ {
+ break;
+ }
+ len_name++;
+ }
+
+ name = Malloc(len_name + 1);
+ StrCpy(name, len_name + 1, line);
+
+ string_start = len_name;
+ for (i = len_name;i < len;i++)
+ {
+ if (line[i] != ' ' && line[i] != '\t')
+ {
+ break;
+ }
+ string_start++;
+ }
+ if (i == len)
+ {
+ Free(name);
+ return NULL;
+ }
+
+ // Unescape
+ UnescapeStr(&line[string_start]);
+
+ // Convert to Unicode
+ unistr_size = CalcUtf8ToUni(&line[string_start], StrLen(&line[string_start]));
+ if (unistr_size == 0)
+ {
+ Free(name);
+ return NULL;
+ }
+ unistr = Malloc(unistr_size);
+ Utf8ToUni(unistr, unistr_size, &line[string_start], StrLen(&line[string_start]));
+
+ if (UniInChar(unistr, L'$'))
+ {
+ // Replace the replacement string
+ wchar_t *tmp;
+ UINT tmp_size = (UniStrSize(unistr) + 1024) * 2;
+ UINT i;
+
+ tmp = Malloc(tmp_size);
+
+ UniStrCpy(tmp, tmp_size, unistr);
+
+ for (i = 0; i < LIST_NUM(replace_list);i++)
+ {
+ TABLE *r = LIST_DATA(replace_list, i);
+
+ UniReplaceStrEx(tmp, tmp_size, tmp, (wchar_t *)r->name, r->unistr, false);
+ }
+
+ unistr = CopyUniStr(tmp);
+
+ Free(tmp);
+ }
+
+ // Convert to ANSI
+ str_size = CalcUniToStr(unistr);
+ if (str_size == 0)
+ {
+ str_size = 1;
+ str = Malloc(1);
+ str[0] = 0;
+ }
+ else
+ {
+ str = Malloc(str_size);
+ UniToStr(str, str_size, unistr);
+ }
+
+ if (StrCmpi(name, "PREFIX") == 0)
+ {
+ // Prefix is specified
+ StrCpy(prefix, prefix_size, str);
+ Trim(prefix);
+
+ if (StrCmpi(prefix, "$") == 0 || StrCmpi(prefix, "NULL") == 0)
+ {
+ prefix[0] = 0;
+ }
+
+ Free(name);
+ Free(str);
+ Free(unistr);
+
+ return NULL;
+ }
+
+ name2_size = StrLen(name) + StrLen(prefix) + 2;
+ name2 = ZeroMalloc(name2_size);
+
+ if (prefix[0] != 0)
+ {
+ StrCat(name2, name2_size, prefix);
+ StrCat(name2, name2_size, "@");
+ }
+
+ StrCat(name2, name2_size, name);
+
+ Free(name);
+
+ // Create a TABLE
+ t = Malloc(sizeof(TABLE));
+ StrUpper(name2);
+ t->name = name2;
+ t->str = str;
+ t->unistr = unistr;
+
+ return t;
+}
+
+// Unescape the string
+void UnescapeStr(char *src)
+{
+ UINT i, len, wp;
+ char *tmp;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return;
+ }
+
+ len = StrLen(src);
+ tmp = Malloc(len + 1);
+ wp = 0;
+ for (i = 0;i < len;i++)
+ {
+ if (src[i] == '\\')
+ {
+ i++;
+ switch (src[i])
+ {
+ case 0:
+ goto FINISH;
+ case '\\':
+ tmp[wp++] = '\\';
+ break;
+ case ' ':
+ tmp[wp++] = ' ';
+ break;
+ case 'n':
+ case 'N':
+ tmp[wp++] = '\n';
+ break;
+ case 'r':
+ case 'R':
+ tmp[wp++] = '\r';
+ break;
+ case 't':
+ case 'T':
+ tmp[wp++] = '\t';
+ break;
+ }
+ }
+ else
+ {
+ tmp[wp++] = src[i];
+ }
+ }
+FINISH:
+ tmp[wp++] = 0;
+ StrCpy(src, 0, tmp);
+ Free(tmp);
+}
+
+// Release the table
+void FreeTable()
+{
+ UINT i, num;
+ TABLE **tables;
+ if (TableList == NULL)
+ {
+ return;
+ }
+
+ TrackingDisable();
+
+ num = LIST_NUM(TableList);
+ tables = ToArray(TableList);
+ for (i = 0;i < num;i++)
+ {
+ TABLE *t = tables[i];
+ Free(t->name);
+ Free(t->str);
+ Free(t->unistr);
+ Free(t);
+ }
+ ReleaseList(TableList);
+ TableList = NULL;
+ Free(tables);
+
+ Zero(old_table_name, sizeof(old_table_name));
+
+ TrackingEnable();
+}
+
+// Read a string table from the buffer
+bool LoadTableFromBuf(BUF *b)
+{
+ char *tmp;
+ char prefix[MAX_SIZE];
+ LIST *replace_list = NULL;
+ UINT i;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ // If the table already exists, delete it
+ FreeTable();
+
+ // Create a list
+ TableList = NewList(CmpTableName);
+
+ Zero(prefix, sizeof(prefix));
+
+ replace_list = NewListFast(NULL);
+
+ // Read the contents of the buffer line by line
+ while (true)
+ {
+ TABLE *t;
+ bool ok = true;
+
+ tmp = CfgReadNextLine(b);
+ if (tmp == NULL)
+ {
+ break;
+ }
+
+ if (tmp[0] == '$')
+ {
+ char key[128];
+ char value[MAX_SIZE];
+ if (GetKeyAndValue(tmp, key, sizeof(key), value, sizeof(value), " \t"))
+ {
+ if (StartWith(key, "$") && EndWith(key, "$") && StrLen(key) >= 3)
+ {
+ TABLE *t;
+ wchar_t univalue[MAX_SIZE];
+ wchar_t uniname[MAX_SIZE];
+
+ t = ZeroMalloc(sizeof(TABLE));
+
+ Zero(univalue, sizeof(univalue));
+ Utf8ToUni(univalue, sizeof(univalue), value, StrLen(value));
+
+ StrToUni(uniname, sizeof(uniname), key);
+
+ t->name = (char *)CopyUniStr(uniname);
+ t->unistr = CopyUniStr(univalue);
+
+ Add(replace_list, t);
+
+ // Found a replacement definition
+ ok = false;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ t = ParseTableLine(tmp, prefix, sizeof(prefix), replace_list);
+ if (t != NULL)
+ {
+ // Register
+ Insert(TableList, t);
+ }
+ }
+
+ Free(tmp);
+ }
+
+ for (i = 0;i < LIST_NUM(replace_list);i++)
+ {
+ TABLE *t = LIST_DATA(replace_list, i);
+
+ Free(t->name);
+ Free(t->str);
+ Free(t->unistr);
+
+ Free(t);
+ }
+
+ ReleaseList(replace_list);
+
+ return true;
+}
+
+// Generate the Unicode string cache file name
+void GenerateUnicodeCacheFileName(wchar_t *name, UINT size, wchar_t *strfilename, UINT strfilesize, UCHAR *filehash)
+{
+ wchar_t tmp[MAX_SIZE];
+ wchar_t hashstr[64];
+ wchar_t hashtemp[MAX_SIZE];
+ wchar_t exe[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (name == NULL || strfilename == NULL || filehash == NULL)
+ {
+ return;
+ }
+
+ GetExeDirW(exe, sizeof(exe));
+ UniStrCpy(hashtemp, sizeof(hashtemp), strfilename);
+ BinToStrW(tmp, sizeof(tmp), filehash, MD5_SIZE);
+ UniStrCat(hashtemp, sizeof(hashtemp), tmp);
+ UniStrCat(hashtemp, sizeof(hashtemp), exe);
+ UniStrLower(hashtemp);
+
+ Hash(hash, hashtemp, UniStrLen(hashtemp) * sizeof(wchar_t), true);
+ BinToStrW(hashstr, sizeof(hashstr), hash, 4);
+ UniFormat(tmp, sizeof(tmp), UNICODE_CACHE_FILE, hashstr);
+ UniStrLower(tmp);
+
+#ifndef OS_WIN32
+ UniStrCpy(exe, sizeof(exe), L"/tmp");
+#else // OS_WIN32
+ StrToUni(exe, sizeof(exe), MsGetTempDir());
+#endif // OS_WIN32
+
+ UniFormat(name, size, L"%s/%s", exe, tmp);
+ NormalizePathW(name, size, name);
+}
+
+// Save the Unicode cache
+void SaveUnicodeCache(wchar_t *strfilename, UINT strfilesize, UCHAR *hash)
+{
+ UNICODE_CACHE c;
+ BUF *b;
+ UINT i;
+ IO *io;
+ wchar_t name[MAX_PATH];
+ UCHAR binhash[MD5_SIZE];
+ // Validate arguments
+ if (strfilename == NULL || hash == NULL)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ UniToStr(c.StrFileName, sizeof(c.StrFileName), strfilename);
+ c.StrFileSize = strfilesize;
+ GetMachineName(c.MachineName, sizeof(c.MachineName));
+ c.OsType = GetOsInfo()->OsType;
+ Copy(c.hash, hash, MD5_SIZE);
+
+#ifdef OS_UNIX
+ GetCurrentCharSet(c.CharSet, sizeof(c.CharSet));
+#else // OS_UNIX
+ {
+ UINT id = MsGetThreadLocale();
+ Copy(c.CharSet, &id, sizeof(id));
+ }
+#endif // OS_UNIX
+
+ b = NewBuf();
+ WriteBuf(b, &c, sizeof(c));
+
+ WriteBufInt(b, LIST_NUM(TableList));
+ for (i = 0;i < LIST_NUM(TableList);i++)
+ {
+ TABLE *t = LIST_DATA(TableList, i);
+ WriteBufInt(b, StrLen(t->name));
+ WriteBuf(b, t->name, StrLen(t->name));
+ WriteBufInt(b, StrLen(t->str));
+ WriteBuf(b, t->str, StrLen(t->str));
+ WriteBufInt(b, UniStrLen(t->unistr));
+ WriteBuf(b, t->unistr, UniStrLen(t->unistr) * sizeof(wchar_t));
+ }
+
+ Hash(binhash, b->Buf, b->Size, false);
+ WriteBuf(b, binhash, MD5_SIZE);
+
+ GenerateUnicodeCacheFileName(name, sizeof(name), strfilename, strfilesize, hash);
+
+ io = FileCreateW(name);
+ if (io != NULL)
+ {
+ SeekBuf(b, 0, 0);
+ BufToFile(io, b);
+ FileClose(io);
+ }
+
+ FreeBuf(b);
+}
+
+// Reading the Unicode cache
+bool LoadUnicodeCache(wchar_t *strfilename, UINT strfilesize, UCHAR *hash)
+{
+ UNICODE_CACHE c, t;
+ BUF *b;
+ UINT i, num;
+ IO *io;
+ wchar_t name[MAX_PATH];
+ UCHAR binhash[MD5_SIZE];
+ UCHAR binhash_2[MD5_SIZE];
+ // Validate arguments
+ if (strfilename == NULL || hash == NULL)
+ {
+ return false;
+ }
+
+ GenerateUnicodeCacheFileName(name, sizeof(name), strfilename, strfilesize, hash);
+
+ io = FileOpenW(name, false);
+ if (io == NULL)
+ {
+ return false;
+ }
+
+ b = FileToBuf(io);
+ if (b == NULL)
+ {
+ FileClose(io);
+ return false;
+ }
+
+ SeekBuf(b, 0, 0);
+ FileClose(io);
+
+ Hash(binhash, b->Buf, b->Size >= MD5_SIZE ? (b->Size - MD5_SIZE) : 0, false);
+ Copy(binhash_2, ((UCHAR *)b->Buf) + (b->Size >= MD5_SIZE ? (b->Size - MD5_SIZE) : 0), MD5_SIZE);
+ if (Cmp(binhash, binhash_2, MD5_SIZE) != 0)
+ {
+ FreeBuf(b);
+ return false;
+ }
+
+ Zero(&c, sizeof(c));
+ UniToStr(c.StrFileName, sizeof(c.StrFileName), strfilename);
+ c.StrFileSize = strfilesize;
+ DisableNetworkNameCache();
+ GetMachineName(c.MachineName, sizeof(c.MachineName));
+ EnableNetworkNameCache();
+ c.OsType = GetOsInfo()->OsType;
+ Copy(c.hash, hash, MD5_SIZE);
+
+#ifdef OS_UNIX
+ GetCurrentCharSet(c.CharSet, sizeof(c.CharSet));
+#else // OS_UNIX
+ {
+ UINT id = MsGetThreadLocale();
+ Copy(c.CharSet, &id, sizeof(id));
+ }
+#endif // OS_UNIX
+
+ Zero(&t, sizeof(t));
+ ReadBuf(b, &t, sizeof(t));
+
+ if (Cmp(&c, &t, sizeof(UNICODE_CACHE)) != 0)
+ {
+ FreeBuf(b);
+ return false;
+ }
+
+ num = ReadBufInt(b);
+
+ FreeTable();
+ TableList = NewList(CmpTableName);
+
+ for (i = 0;i < num;i++)
+ {
+ UINT len;
+ TABLE *t = ZeroMalloc(sizeof(TABLE));
+
+ len = ReadBufInt(b);
+ t->name = ZeroMalloc(len + 1);
+ ReadBuf(b, t->name, len);
+
+ len = ReadBufInt(b);
+ t->str = ZeroMalloc(len + 1);
+ ReadBuf(b, t->str, len);
+
+ len = ReadBufInt(b);
+ t->unistr = ZeroMalloc((len + 1) * sizeof(wchar_t));
+ ReadBuf(b, t->unistr, len * sizeof(wchar_t));
+
+ Add(TableList, t);
+ }
+
+ FreeBuf(b);
+
+ Sort(TableList);
+
+ return true;
+}
+
+// Read the string table
+bool LoadTableMain(wchar_t *filename)
+{
+ BUF *b;
+ UINT64 t1, t2;
+ UCHAR hash[MD5_SIZE];
+ // Validate arguments
+ if (filename == NULL)
+ {
+ return false;
+ }
+
+ if (MayaquaIsMinimalMode())
+ {
+ return true;
+ }
+
+ if (UniStrCmpi(old_table_name, filename) == 0)
+ {
+ // Already loaded
+ return true;
+ }
+
+ t1 = Tick64();
+
+ // Open the file
+ b = ReadDumpW(filename);
+ if (b == NULL)
+ {
+ char tmp[MAX_SIZE];
+ StrCpy(tmp, sizeof(tmp), "Error: Can't read string tables (file not found).\r\nPlease check hamcore.se2.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)");
+ Alert(tmp, NULL);
+ exit(-1);
+ return false;
+ }
+
+ Hash(hash, b->Buf, b->Size, false);
+
+ if (LoadUnicodeCache(filename, b->Size, hash) == false)
+ {
+ if (LoadTableFromBuf(b) == false)
+ {
+ FreeBuf(b);
+ return false;
+ }
+
+ SaveUnicodeCache(filename, b->Size, hash);
+
+ Debug("Unicode Source: strtable.stb\n");
+ }
+ else
+ {
+ Debug("Unicode Source: unicode_cache\n");
+ }
+
+ FreeBuf(b);
+
+ SetLocale(_UU("DEFAULE_LOCALE"));
+
+ UniStrCpy(old_table_name, sizeof(old_table_name), filename);
+
+ t2 = Tick64();
+
+ if (StrCmpi(_SS("STRTABLE_ID"), STRTABLE_ID) != 0)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "Error: Can't read string tables (invalid version: '%s'!='%s').\r\nPlease check hamcore.se2.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)",
+ _SS("STRTABLE_ID"), STRTABLE_ID);
+ Alert(tmp, NULL);
+ exit(-1);
+ return false;
+ }
+
+ Debug("Unicode File Read Cost: %u (%u Lines)\n", (UINT)(t2 - t1), LIST_NUM(TableList));
+
+ return true;
+}
+bool LoadTable(char *filename)
+{
+ wchar_t *filename_a = CopyStrToUni(filename);
+ bool ret = LoadTableW(filename_a);
+
+ Free(filename_a);
+
+ return ret;
+}
+bool LoadTableW(wchar_t *filename)
+{
+ bool ret;
+ BUF *b;
+ wchar_t replace_name[MAX_PATH];
+
+ Zero(replace_name, sizeof(replace_name));
+
+ TrackingDisable();
+
+ b = ReadDump("@table_name.txt");
+ if (b != NULL)
+ {
+ char *s = CfgReadNextLine(b);
+ if (s != NULL)
+ {
+ if (IsEmptyStr(s) == false)
+ {
+ StrToUni(replace_name, sizeof(replace_name), s);
+ filename = replace_name;
+ }
+
+ Free(s);
+ }
+ FreeBuf(b);
+ }
+
+ ret = LoadTableMain(filename);
+
+ TrackingEnable();
+
+ return ret;
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/