179 lines
6.1 KiB
C#
179 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Text;
|
|
|
|
namespace Ra3.BattleNet.Database.Utils;
|
|
|
|
public static class ChineseEncoding
|
|
{
|
|
private const int EncodedChineseTotalLength = 120;
|
|
private const int EncodedChineseChecksumLength = 3;
|
|
private const int EncodedChineseContentLength = EncodedChineseTotalLength - EncodedChineseChecksumLength;
|
|
private const int ChineseCodeSize = 13;
|
|
private const int ChineseCodeMask = 0b1111111111111;
|
|
private const int AsciiSectionSize = 0x80;
|
|
private const int Gb2312EucOffset = 0xA0;
|
|
private const int Gb2312RowWidth = 94;
|
|
private const int Gb2312LastRow = 87;
|
|
private const int Gb2312FirstUnassignedSectionBegin = 10;
|
|
private const int Gb2312FirstUnassignedSectionSize = 6;
|
|
private const int Gb2312SecondUnassignedSectionBegin = 88;
|
|
private const int Base64CodeSize = 6;
|
|
private const int Base64CodeMask = 0b111111;
|
|
private const string Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
|
|
public static string DecodeChineseFromBase64(string original)
|
|
{
|
|
BigInteger bits = 0;
|
|
int index = 0;
|
|
foreach (var c in original)
|
|
{
|
|
BigInteger value = Base64Table.IndexOf(c);
|
|
if (value == -1)
|
|
{
|
|
throw new Exception("Invalid base64 string");
|
|
}
|
|
bits = bits | (value << index);
|
|
index += Base64CodeSize;
|
|
}
|
|
BigInteger checksum = 0;
|
|
var result = new List<byte>();
|
|
for (var bitIndex = 0; bitIndex < EncodedChineseContentLength; bitIndex += ChineseCodeSize)
|
|
{
|
|
int value = (int)((bits >> bitIndex) & ChineseCodeMask);
|
|
checksum += value;
|
|
if (value == 0)
|
|
{
|
|
break;
|
|
}
|
|
if (value < AsciiSectionSize)
|
|
{
|
|
if (value < 0x20 || value == 0x7F)
|
|
{
|
|
throw new Exception("Invalid ASCII");
|
|
}
|
|
result.Add((byte)value);
|
|
}
|
|
else
|
|
{
|
|
value -= AsciiSectionSize;
|
|
var index1 = value / Gb2312RowWidth + 1;
|
|
var index2 = value % Gb2312RowWidth + 1;
|
|
if (index1 >= Gb2312FirstUnassignedSectionBegin)
|
|
{
|
|
index1 += Gb2312FirstUnassignedSectionSize;
|
|
}
|
|
if (index1 >= Gb2312SecondUnassignedSectionBegin)
|
|
{
|
|
throw new Exception("Invalid first byte");
|
|
}
|
|
if (index2 > Gb2312RowWidth)
|
|
{
|
|
throw new Exception("Invalid second byte");
|
|
}
|
|
index1 += Gb2312EucOffset;
|
|
index2 += Gb2312EucOffset;
|
|
result.Add((byte)index1);
|
|
result.Add((byte)index2);
|
|
}
|
|
}
|
|
if ((bits >> EncodedChineseContentLength) != checksum % 8)
|
|
{
|
|
throw new Exception("Invalid checksum");
|
|
}
|
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
return Encoding.GetEncoding(936).GetString(result.ToArray());
|
|
}
|
|
|
|
public static string EncodeChineseToBase64(string original)
|
|
{
|
|
BigInteger bits = 0;
|
|
int index = 0;
|
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
|
var bytes = Encoding.GetEncoding(936).GetBytes(original);
|
|
BigInteger checksum = 0;
|
|
for (var i = 0; i < bytes.Length;)
|
|
{
|
|
BigInteger c = bytes[i];
|
|
if (c < AsciiSectionSize)
|
|
{
|
|
if (c < 0x20 || c == 0x7F)
|
|
{
|
|
throw new Exception("Invalid ASCII");
|
|
}
|
|
bits = bits | (c << index);
|
|
index += ChineseCodeSize;
|
|
checksum += c;
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
if (c <= Gb2312EucOffset || c > (Gb2312EucOffset + Gb2312LastRow))
|
|
{
|
|
throw new Exception("Invalid first byte");
|
|
}
|
|
BigInteger c2 = bytes[i + 1];
|
|
if (c2 <= Gb2312EucOffset || c2 > (Gb2312EucOffset + Gb2312RowWidth))
|
|
{
|
|
throw new Exception("Invalid second byte");
|
|
}
|
|
var index1 = c - Gb2312EucOffset;
|
|
if (index1 >= Gb2312FirstUnassignedSectionBegin)
|
|
{
|
|
var offset = index1 - Gb2312FirstUnassignedSectionBegin;
|
|
if (offset < Gb2312FirstUnassignedSectionSize)
|
|
{
|
|
throw new Exception("AA-AF user defined zone not supported");
|
|
}
|
|
index1 -= Gb2312FirstUnassignedSectionSize;
|
|
}
|
|
var index2 = c2 - Gb2312EucOffset;
|
|
if (index2 > Gb2312RowWidth)
|
|
{
|
|
throw new Exception("Invalid second byte");
|
|
}
|
|
var value = (index1 - 1) * Gb2312RowWidth + (index2 - 1);
|
|
value = AsciiSectionSize + value;
|
|
bits = bits | (value << index);
|
|
index += ChineseCodeSize;
|
|
checksum += value;
|
|
i += 2;
|
|
}
|
|
}
|
|
bits = bits | ((checksum % 8) << EncodedChineseContentLength);
|
|
var result = "";
|
|
var bitsIndex = 0;
|
|
while (bitsIndex < EncodedChineseTotalLength)
|
|
{
|
|
int v = (int)((bits >> bitsIndex) & Base64CodeMask);
|
|
result += Base64Table[v];
|
|
bitsIndex += Base64CodeSize;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public static string GetPrettyName(string name)
|
|
{
|
|
if (name.Length != 20)
|
|
{
|
|
return name;
|
|
}
|
|
foreach (var c in name)
|
|
{
|
|
if (!Base64Table.Contains(c))
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
try
|
|
{
|
|
return DecodeChineseFromBase64(name);
|
|
}
|
|
catch
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
} |