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;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|