286 lines
9.4 KiB
C#
286 lines
9.4 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace PlaneGcsSdk.Contract.EhNetUWP
|
||
{
|
||
/// <summary>
|
||
/// 在UWP平台下支持GB2312、Big5编码的字符编码类。
|
||
/// </summary>
|
||
public sealed class DBCSEncoding : Encoding
|
||
{
|
||
private const char LEAD_BYTE_CHAR = '\uFFFE';
|
||
private char[] _dbcsToUnicode = null;
|
||
private ushort[] _unicodeToDbcs = null;
|
||
private string _webName = null;
|
||
private static Dictionary<string, Tuple<char[], ushort[]>> _cache = null;
|
||
|
||
static DBCSEncoding()
|
||
{
|
||
if (!BitConverter.IsLittleEndian)
|
||
throw new PlatformNotSupportedException("Not supported big endian platform.");
|
||
|
||
_cache = new Dictionary<string, Tuple<char[], ushort[]>>();
|
||
}
|
||
|
||
private DBCSEncoding() { }
|
||
|
||
/// <summary>
|
||
/// 支持GB2312和Big5编码
|
||
/// </summary>
|
||
/// <param name="name">“gb2312”或“big5”</param>
|
||
/// <returns></returns>
|
||
public static async Task<DBCSEncoding> GetDBCSEncoding(string name)
|
||
{
|
||
name = name.ToLower();
|
||
DBCSEncoding encoding = new DBCSEncoding();
|
||
encoding._webName = name;
|
||
if (_cache.ContainsKey(name))
|
||
{
|
||
var tuple = _cache[name];
|
||
encoding._dbcsToUnicode = tuple.Item1;
|
||
encoding._unicodeToDbcs = tuple.Item2;
|
||
return encoding;
|
||
}
|
||
|
||
var dbcsToUnicode = new char[0x10000];
|
||
var unicodeToDbcs = new ushort[0x10000];
|
||
|
||
/*
|
||
* According to many feedbacks, add this automatic function for finding resource in revision 1.0.0.1.
|
||
* We suggest that use the old method as below if you understand how to embed the resource.
|
||
* Please make sure the *.bin file was correctly embedded if throw an exception at here.
|
||
*/
|
||
//using (Stream stream = typeof(DBCSEncoding).Assembly.GetManifestResourceStream(typeof(DBCSEncoding).Namespace + "." + name + ".bin"))
|
||
//using (Stream stream = typeof(DBCSEncoding).Assembly.GetManifestResourceStream(typeof(DBCSEncoding).Assembly.GetManifestResourceNames().Single(s => s.EndsWith("." + name + ".bin"))))
|
||
using (Stream stream = await GetInstall(name))
|
||
using (BinaryReader reader = new BinaryReader(stream))
|
||
{
|
||
for (int i = 0; i < 0xffff; i++)
|
||
{
|
||
ushort u = reader.ReadUInt16();
|
||
unicodeToDbcs[i] = u;
|
||
}
|
||
for (int i = 0; i < 0xffff; i++)
|
||
{
|
||
ushort u = reader.ReadUInt16();
|
||
dbcsToUnicode[i] = (char)u;
|
||
}
|
||
}
|
||
|
||
_cache[name] = new Tuple<char[], ushort[]>(dbcsToUnicode, unicodeToDbcs);
|
||
encoding._dbcsToUnicode = dbcsToUnicode;
|
||
encoding._unicodeToDbcs = unicodeToDbcs;
|
||
return encoding;
|
||
}
|
||
|
||
public override int GetByteCount(char[] chars, int index, int count)
|
||
{
|
||
int byteCount = 0;
|
||
ushort u;
|
||
char c;
|
||
|
||
for (int i = 0; i < count; index++, byteCount++, i++)
|
||
{
|
||
c = chars[index];
|
||
u = _unicodeToDbcs[c];
|
||
if (u > 0xff)
|
||
byteCount++;
|
||
}
|
||
|
||
return byteCount;
|
||
}
|
||
|
||
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
|
||
{
|
||
int byteCount = 0;
|
||
ushort u;
|
||
char c;
|
||
|
||
for (int i = 0; i < charCount; charIndex++, byteIndex++, byteCount++, i++)
|
||
{
|
||
c = chars[charIndex];
|
||
u = _unicodeToDbcs[c];
|
||
if (u == 0 && c != 0)
|
||
{
|
||
bytes[byteIndex] = 0x3f; // 0x3f == '?'
|
||
}
|
||
else if (u < 0x100)
|
||
{
|
||
bytes[byteIndex] = (byte)u;
|
||
}
|
||
else
|
||
{
|
||
bytes[byteIndex] = (byte)((u >> 8) & 0xff);
|
||
byteIndex++;
|
||
byteCount++;
|
||
bytes[byteIndex] = (byte)(u & 0xff);
|
||
}
|
||
}
|
||
|
||
return byteCount;
|
||
}
|
||
|
||
public override int GetCharCount(byte[] bytes, int index, int count)
|
||
{
|
||
return GetCharCount(bytes, index, count, null);
|
||
}
|
||
|
||
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
|
||
{
|
||
return GetChars(bytes, byteIndex, byteCount, chars, charIndex, null);
|
||
}
|
||
|
||
public override int GetMaxByteCount(int charCount)
|
||
{
|
||
if (charCount < 0)
|
||
throw new ArgumentOutOfRangeException("charCount");
|
||
long count = charCount + 1;
|
||
count *= 2;
|
||
if (count > int.MaxValue)
|
||
throw new ArgumentOutOfRangeException("charCount");
|
||
return (int)count;
|
||
|
||
}
|
||
|
||
public override int GetMaxCharCount(int byteCount)
|
||
{
|
||
if (byteCount < 0)
|
||
throw new ArgumentOutOfRangeException("byteCount");
|
||
long count = byteCount + 3;
|
||
if (count > int.MaxValue)
|
||
throw new ArgumentOutOfRangeException("byteCount");
|
||
return (int)count;
|
||
}
|
||
|
||
public override Decoder GetDecoder()
|
||
{
|
||
return new DBCSDecoder(this);
|
||
}
|
||
|
||
public override string WebName
|
||
{
|
||
get
|
||
{
|
||
return _webName;
|
||
}
|
||
}
|
||
|
||
|
||
private int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex, DBCSDecoder decoder)
|
||
{
|
||
int charCount = 0;
|
||
ushort u;
|
||
char c;
|
||
|
||
for (int i = 0; i < byteCount; byteIndex++, charIndex++, charCount++, i++)
|
||
{
|
||
u = 0;
|
||
if (decoder != null && decoder.pendingByte != 0)
|
||
{
|
||
u = decoder.pendingByte;
|
||
decoder.pendingByte = 0;
|
||
}
|
||
|
||
u = (ushort)(u << 8 | bytes[byteIndex]);
|
||
c = _dbcsToUnicode[u];
|
||
if (c == LEAD_BYTE_CHAR)
|
||
{
|
||
if (i < byteCount - 1)
|
||
{
|
||
byteIndex++;
|
||
i++;
|
||
u = (ushort)(u << 8 | bytes[byteIndex]);
|
||
c = _dbcsToUnicode[u];
|
||
}
|
||
else if (decoder == null)
|
||
{
|
||
c = '\0';
|
||
}
|
||
else
|
||
{
|
||
decoder.pendingByte = bytes[byteIndex];
|
||
return charCount;
|
||
}
|
||
}
|
||
if (c == 0 && u != 0)
|
||
chars[charIndex] = '?';
|
||
else
|
||
chars[charIndex] = c;
|
||
}
|
||
|
||
return charCount;
|
||
}
|
||
|
||
private int GetCharCount(byte[] bytes, int index, int count, DBCSDecoder decoder)
|
||
{
|
||
int charCount = 0;
|
||
ushort u;
|
||
char c;
|
||
|
||
for (int i = 0; i < count; index++, charCount++, i++)
|
||
{
|
||
u = 0;
|
||
if (decoder != null && decoder.pendingByte != 0)
|
||
{
|
||
u = decoder.pendingByte;
|
||
decoder.pendingByte = 0;
|
||
}
|
||
|
||
u = (ushort)(u << 8 | bytes[index]);
|
||
c = _dbcsToUnicode[u];
|
||
if (c == LEAD_BYTE_CHAR)
|
||
{
|
||
if (i < count - 1)
|
||
{
|
||
index++;
|
||
i++;
|
||
}
|
||
else if (decoder != null)
|
||
{
|
||
decoder.pendingByte = bytes[index];
|
||
return charCount;
|
||
}
|
||
}
|
||
}
|
||
|
||
return charCount;
|
||
}
|
||
|
||
private async static Task<Stream> GetInstall(string name)
|
||
{
|
||
//此处只是简单的获取到gb2312.bin文件
|
||
//name = "gb2312";
|
||
var folderInstall = Windows.ApplicationModel.Package.Current.InstalledLocation;//获取安装包的位置
|
||
var folder = await folderInstall.GetFolderAsync("EncodingBins");
|
||
var file = await folder.GetFileAsync(name + ".bin"); //获取gb2312.bin
|
||
Stream stream = await file.OpenStreamForReadAsync(); //获取文件流
|
||
return stream;
|
||
}
|
||
|
||
private sealed class DBCSDecoder : Decoder
|
||
{
|
||
private DBCSEncoding _encoding = null;
|
||
|
||
public DBCSDecoder(DBCSEncoding encoding)
|
||
{
|
||
_encoding = encoding;
|
||
}
|
||
|
||
public override int GetCharCount(byte[] bytes, int index, int count)
|
||
{
|
||
return _encoding.GetCharCount(bytes, index, count, this);
|
||
}
|
||
|
||
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
|
||
{
|
||
return _encoding.GetChars(bytes, byteIndex, byteCount, chars, charIndex, this);
|
||
}
|
||
|
||
public byte pendingByte;
|
||
}
|
||
}
|
||
}
|