mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-05-07 07:55:33 +02:00
- moved all files to a "source" subdirectory to tidy up the GitHub project page
- started to write a readme.md
This commit is contained in:
43
source/ChanSort.Api/Utils/BrowserHelper.cs
Normal file
43
source/ChanSort.Api/Utils/BrowserHelper.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.IO;
|
||||
|
||||
namespace ChanSort
|
||||
{
|
||||
public static class BrowserHelper
|
||||
{
|
||||
public static void OpenUrl(string url)
|
||||
{
|
||||
OpenHtml(@"
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv='Refresh' content='0;" + url + @"'/>
|
||||
</head>
|
||||
</html>");
|
||||
}
|
||||
|
||||
public static void OpenMail(string url)
|
||||
{
|
||||
OpenHtml(@"
|
||||
<html>
|
||||
<head>
|
||||
<script language=""javascript"">
|
||||
window.open(""" + url + @""");
|
||||
window.close();
|
||||
</script>
|
||||
</head>
|
||||
</html>");
|
||||
}
|
||||
|
||||
public static void OpenHtml(string html)
|
||||
{
|
||||
try
|
||||
{
|
||||
string fileName = Path.GetTempFileName() + ".html";
|
||||
File.WriteAllText(fileName, html);
|
||||
System.Diagnostics.Process.Start(fileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
151
source/ChanSort.Api/Utils/ChannelMappingBase.cs
Normal file
151
source/ChanSort.Api/Utils/ChannelMappingBase.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public unsafe class ChannelMappingBase : DataMapping
|
||||
{
|
||||
protected const string offInUse = "offInUse";
|
||||
protected const string maskInUse = "maskInUse";
|
||||
protected const string offProgramNr = "offProgramNr";
|
||||
protected const string offName = "offName";
|
||||
protected const string offNameLength = "offNameLength";
|
||||
protected const string lenName = "lenName";
|
||||
protected const string offSkip = "offSkip";
|
||||
protected const string maskSkip = "maskSkip";
|
||||
protected const string offLock = "offLock";
|
||||
protected const string maskLock = "maskLock";
|
||||
protected const string offLockSkipHide = "offHide";
|
||||
protected const string maskHide = "maskHide";
|
||||
protected const string offFavorites = "offFavorites";
|
||||
private const string offDeleted = "offDeleted";
|
||||
private const string maskDeleted = "maskDeleted";
|
||||
|
||||
#region ctor()
|
||||
public ChannelMappingBase(IniFile.Section settings, int length, Encoding stringEncoding) :
|
||||
base(settings, length, stringEncoding)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region InUse
|
||||
public virtual bool InUse
|
||||
{
|
||||
get
|
||||
{
|
||||
var val = this.GetOffsets(offInUse);
|
||||
return val.Length == 0 || this.GetFlag(offInUse, maskInUse);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ProgramNr
|
||||
public virtual ushort ProgramNr
|
||||
{
|
||||
get { return this.GetWord(offProgramNr); }
|
||||
set { this.SetWord(offProgramNr, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NameLength
|
||||
public virtual int NameLength
|
||||
{
|
||||
get
|
||||
{
|
||||
var off = this.GetOffsets(offNameLength);
|
||||
if (off.Length > 0)
|
||||
return this.GetWord(off[0]);
|
||||
return MaxNameLength;
|
||||
}
|
||||
set { this.SetByte(offNameLength, (byte) value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MaxNameLength
|
||||
public virtual int MaxNameLength
|
||||
{
|
||||
get
|
||||
{
|
||||
var off = this.GetOffsets(lenName); // not an offset!
|
||||
return off.Length > 0 ? off[0] : 0;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Name
|
||||
public virtual string Name
|
||||
{
|
||||
get { return this.GetString(offName, this.NameLength); }
|
||||
// ReSharper disable ValueParameterNotUsed
|
||||
set { }
|
||||
// ReSharper restore ValueParameterNotUsed
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region NamePtr
|
||||
|
||||
public virtual byte* NamePtr
|
||||
{
|
||||
get { return this.DataPtr + this.GetOffsets(offName)[0]; }
|
||||
set
|
||||
{
|
||||
int maxLen = this.MaxNameLength - 1;
|
||||
if (maxLen == 0)
|
||||
maxLen = this.NameLength;
|
||||
foreach (int off in this.GetOffsets(offName))
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < maxLen && value[i] != 0; i++)
|
||||
this.DataPtr[off + i] = value[i];
|
||||
for (; i <= maxLen; i++)
|
||||
this.DataPtr[off + i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ShortName
|
||||
public virtual string ShortName { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Skip
|
||||
public virtual bool Skip
|
||||
{
|
||||
get { return this.GetFlag(offSkip, maskSkip); }
|
||||
set { this.SetFlag(offSkip, maskSkip, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Lock
|
||||
public virtual bool Lock
|
||||
{
|
||||
get { return this.GetFlag(offLock, maskLock); }
|
||||
set { this.SetFlag(offLock, maskLock, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Hide
|
||||
public virtual bool Hide
|
||||
{
|
||||
get { return this.GetFlag(offLockSkipHide, maskHide); }
|
||||
set { this.SetFlag(offLockSkipHide, maskHide, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Favorites
|
||||
public virtual Favorites Favorites
|
||||
{
|
||||
get { return (Favorites) this.GetByte(offFavorites); }
|
||||
set { this.SetByte(offFavorites, (byte) value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IsDeleted
|
||||
public virtual bool IsDeleted
|
||||
{
|
||||
get { return this.GetFlag(offDeleted, maskDeleted); }
|
||||
set { this.SetFlag(offDeleted, maskDeleted, value); }
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
62
source/ChanSort.Api/Utils/Crc32.cs
Normal file
62
source/ChanSort.Api/Utils/Crc32.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public static class Crc32
|
||||
{
|
||||
private const uint CrcMask = 0xFFFFFFFF;
|
||||
private const uint CrcPoly = 0xEDB88320;
|
||||
|
||||
private static readonly uint[] crc32Table;
|
||||
|
||||
static Crc32()
|
||||
{
|
||||
crc32Table = InitCrc32Table();
|
||||
}
|
||||
|
||||
#region InitCrc32Table()
|
||||
|
||||
private static uint[] InitCrc32Table()
|
||||
{
|
||||
var crcTable = new uint[256];
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (uint j = 8; j > 0; j--)
|
||||
{
|
||||
if ((r & 1) == 1)
|
||||
r = ((r >> 1) ^ CrcPoly);
|
||||
else
|
||||
r >>= 1;
|
||||
}
|
||||
crcTable[i] = r;
|
||||
}
|
||||
return crcTable;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CalcCrc32()
|
||||
public static uint CalcCrc32(byte[] block, int start, int length)
|
||||
{
|
||||
uint crc32 = CrcMask;
|
||||
for (int i = 0; i < length; i++)
|
||||
crc32 = crc32Table[(crc32 & 0xff) ^ block[start + i]] ^ (crc32 >> 8);
|
||||
return crc32;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Crack()
|
||||
#if false
|
||||
public static unsafe int Crack(byte* block, int maxLen, uint checksum)
|
||||
{
|
||||
uint crc32 = CrcMask;
|
||||
for (int i = 0; i < maxLen; i++)
|
||||
{
|
||||
if (crc32 == checksum)
|
||||
return i;
|
||||
crc32 = crc32Table[(crc32 & 0xff) ^ block[i]] ^ (crc32 >> 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
45
source/ChanSort.Api/Utils/CsvFile.cs
Normal file
45
source/ChanSort.Api/Utils/CsvFile.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public static class CsvFile
|
||||
{
|
||||
public static IList<string> Parse(string line, char separator)
|
||||
{
|
||||
if (line.EndsWith("\n")) line = line.Substring(0, line.Length - 1);
|
||||
if (line.EndsWith("\r")) line = line.Substring(0, line.Length - 1);
|
||||
|
||||
List<string> tokens = new List<string>();
|
||||
if (line.Length == 0)
|
||||
return tokens;
|
||||
|
||||
bool inQuote = false;
|
||||
StringBuilder token = new StringBuilder();
|
||||
for(int i = 0, len=line.Length; i<len; i++)
|
||||
{
|
||||
char ch = line[i];
|
||||
if (ch == separator && !inQuote)
|
||||
{
|
||||
tokens.Add(token.ToString());
|
||||
token.Remove(0, token.Length);
|
||||
continue;
|
||||
}
|
||||
if (ch == '"')
|
||||
{
|
||||
if (inQuote && i+1 < len && line[i+1] == '"')
|
||||
{
|
||||
token.Append('"');
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
inQuote = !inQuote;
|
||||
continue;
|
||||
}
|
||||
token.Append(ch);
|
||||
}
|
||||
tokens.Add(token.ToString());
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
}
|
||||
197
source/ChanSort.Api/Utils/DataMapping.cs
Normal file
197
source/ChanSort.Api/Utils/DataMapping.cs
Normal file
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public class DataMapping
|
||||
{
|
||||
protected readonly IniFile.Section settings;
|
||||
private int baseOffset;
|
||||
private byte[] data { get; set; }
|
||||
public Encoding DefaultEncoding { get; set; }
|
||||
|
||||
#region ctor()
|
||||
public DataMapping(IniFile.Section settings)
|
||||
{
|
||||
this.settings = settings;
|
||||
this.DefaultEncoding = Encoding.Default;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetDataPtr(), Data, BaseOffset
|
||||
public void SetDataPtr(byte[] data, int baseOffset)
|
||||
{
|
||||
this.data = data;
|
||||
this.baseOffset = baseOffset;
|
||||
}
|
||||
|
||||
public byte[] Data { get { return this.data; } }
|
||||
public int BaseOffset { get { return this.baseOffset; } set { this.baseOffset = value; } }
|
||||
#endregion
|
||||
|
||||
|
||||
#region GetOffsets()
|
||||
public int[] GetOffsets(string key)
|
||||
{
|
||||
return settings.GetIntList(key);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public IniFile.Section Settings { get { return this.settings; } }
|
||||
|
||||
|
||||
#region Byte
|
||||
public byte GetByte(string key)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
if (offsets.Length==0) return 0;
|
||||
return this.data[baseOffset + offsets[0]];
|
||||
}
|
||||
|
||||
public void SetByte(string key, int value)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
foreach (int offset in offsets)
|
||||
this.data[baseOffset + offset] = (byte)value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Word
|
||||
public ushort GetWord(string key)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
if (offsets.Length == 0) return 0;
|
||||
return BitConverter.ToUInt16(this.data, baseOffset + offsets[0]);
|
||||
}
|
||||
|
||||
public void SetWord(string key, int value)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
foreach (int offset in offsets)
|
||||
{
|
||||
this.data[baseOffset + offset + 0] = (byte)value;
|
||||
this.data[baseOffset + offset + 1] = (byte)(value>>8);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DWord
|
||||
public long GetDword(string key)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
if (offsets.Length == 0) return 0;
|
||||
return BitConverter.ToUInt32(this.data, baseOffset + offsets[0]);
|
||||
}
|
||||
|
||||
public void SetDword(string key, long value)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
foreach (int offset in offsets)
|
||||
{
|
||||
this.data[baseOffset + offset + 0] = (byte)value;
|
||||
this.data[baseOffset + offset + 1] = (byte)(value >> 8);
|
||||
this.data[baseOffset + offset + 2] = (byte)(value >> 16);
|
||||
this.data[baseOffset + offset + 3] = (byte)(value >> 24);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Float
|
||||
public float GetFloat(string key)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
if (offsets.Length == 0) return 0;
|
||||
return BitConverter.ToSingle(this.data, baseOffset + offsets[0]);
|
||||
}
|
||||
|
||||
public void SetFloat(string key, float value)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
var bytes = BitConverter.GetBytes(value);
|
||||
foreach (int offset in offsets)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
this.data[baseOffset + offset + i] = bytes[i];
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetFlag
|
||||
|
||||
public bool GetFlag(string key, bool defaultValue = false)
|
||||
{
|
||||
return GetFlag("off" + key, "mask" + key, defaultValue);
|
||||
}
|
||||
|
||||
public bool GetFlag(string valueKey, string maskKey, bool defaultValue = false)
|
||||
{
|
||||
int mask = settings.GetInt(maskKey);
|
||||
return GetFlag(valueKey, mask, defaultValue);
|
||||
}
|
||||
|
||||
public bool GetFlag(string valueKey, int mask, bool defaultValue = false)
|
||||
{
|
||||
if (mask == 0) return defaultValue;
|
||||
var offsets = settings.GetIntList(valueKey);
|
||||
if (offsets.Length == 0) return defaultValue;
|
||||
return (this.data[baseOffset + offsets[0]] & mask) == mask;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetFlag()
|
||||
public void SetFlag(string key, bool value)
|
||||
{
|
||||
this.SetFlag("off" + key, "mask" + key, value);
|
||||
}
|
||||
|
||||
public void SetFlag(string valueKey, string maskKey, bool value)
|
||||
{
|
||||
int mask = settings.GetInt(maskKey);
|
||||
SetFlag(valueKey, mask, value);
|
||||
}
|
||||
|
||||
public void SetFlag(string valueKey, int mask, bool value)
|
||||
{
|
||||
if (mask == 0) return;
|
||||
var offsets = settings.GetIntList(valueKey);
|
||||
foreach (var offset in offsets)
|
||||
{
|
||||
if (value)
|
||||
this.data[baseOffset + offset] |= (byte)mask;
|
||||
else
|
||||
this.data[baseOffset + offset] &= (byte)~mask;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region GetString()
|
||||
public string GetString(string key, int maxLen)
|
||||
{
|
||||
var offsets = settings.GetIntList(key);
|
||||
if (offsets.Length == 0) return null;
|
||||
int length = this.GetByte(key + "Length");
|
||||
if (length == 0)
|
||||
length = maxLen;
|
||||
var encoding = this.DefaultEncoding;
|
||||
return encoding.GetString(this.data, baseOffset + offsets[0], length).TrimEnd('\0');
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetString()
|
||||
public int SetString(string key, string text, int maxLen)
|
||||
{
|
||||
var bytes = this.DefaultEncoding.GetBytes(text);
|
||||
int len = Math.Min(bytes.Length, maxLen);
|
||||
foreach (var offset in settings.GetIntList(key))
|
||||
{
|
||||
Array.Copy(bytes, 0, this.data, baseOffset + offset, len);
|
||||
for (int i = len; i < maxLen; i++)
|
||||
this.data[baseOffset + offset + i] = 0;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
21
source/ChanSort.Api/Utils/DependencyChecker.cs
Normal file
21
source/ChanSort.Api/Utils/DependencyChecker.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public static class DepencencyChecker
|
||||
{
|
||||
public static bool IsVc2010RedistPackageX86Installed()
|
||||
{
|
||||
object value = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0\VC\VCRedist\x86",
|
||||
"Installed", null);
|
||||
return value != null && Convert.ToInt32(value) == 1;
|
||||
}
|
||||
|
||||
public static void AssertVc2010RedistPackageX86Installed()
|
||||
{
|
||||
if (!IsVc2010RedistPackageX86Installed())
|
||||
throw new FileLoadException("Please download and install the Microsoft Visual C++ 2010 Redistributable Package (x86)");
|
||||
}
|
||||
}
|
||||
}
|
||||
237
source/ChanSort.Api/Utils/DvbStringDecoder.cs
Normal file
237
source/ChanSort.Api/Utils/DvbStringDecoder.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
#region Documentation
|
||||
/*
|
||||
ETSI EN 300 468
|
||||
|
||||
For one-byte character tables, the codes in the range 0x80 to 0x9F are assigned to control functions
|
||||
as shown in Table A.1: Single byte control codes
|
||||
|
||||
Control code - Control code Description
|
||||
0x80 to 0x85 reserved for future use
|
||||
0x86 character emphasis on
|
||||
0x87 character emphasis off
|
||||
0x88 to 0x89 reserved for future use
|
||||
0x8A CR/LF
|
||||
0x8B to 0x9F user defined
|
||||
|
||||
A.2 Selection of character table
|
||||
First byte value - Character code table - Table description - Reproduced in figure
|
||||
0x01 ISO/IEC 8859-5 [27] Latin/Cyrillic alphabet A.2
|
||||
0x02 ISO/IEC 8859-6 [28] Latin/Arabic alphabet A.3
|
||||
0x03 ISO/IEC 8859-7 [29] Latin/Greek alphabet A.4
|
||||
0x04 ISO/IEC 8859-8 [30] Latin/Hebrew alphabet A.5
|
||||
0x05 ISO/IEC 8859-9 [31] Latin alphabet No. 5 A.6
|
||||
0x06 ISO/IEC 8859-10 [32] Latin alphabet No. 6 A.7
|
||||
0x07 ISO/IEC 8859-11 [33] Latin/Thai (draft only) A.8
|
||||
0x08 reserved for future use (see note)
|
||||
0x09 ISO/IEC 8859-13 [34] Latin alphabet No. 7 A.9
|
||||
0x0A ISO/IEC 8859-14 [35] Latin alphabet No. 8 (Celtic) A.10
|
||||
0x0B ISO/IEC 8859-15 [36] Latin alphabet No. 9 A.11
|
||||
0x0C to 0x0F reserved for future use
|
||||
0x10 ISO/IEC 8859 See table A.4
|
||||
0x11 ISO/IEC 10646 [16] Basic Multilingual Plane (BMP)
|
||||
0x12 KSX1001-2004 [44] Korean Character Set
|
||||
0x13 GB-2312-1980 Simplified Chinese Character
|
||||
0x14 Big5 subset of ISO/IEC 10646 [16] Traditional Chinese
|
||||
0x15 UTF-8 encoding of ISO/IEC 10646 [16] Basic Multilingual Plane (BMP)
|
||||
0x16 to 0x1E reserved for future use
|
||||
0x1F Described by encoding_type_id Described by 8 bit
|
||||
|
||||
Table A.4: Character Coding Tables for first byte 0x10
|
||||
First byte value - Second byte value - Third Byte Value - Selected character code - table - Table Description
|
||||
0x10 0x00 0x00 reserved for future use
|
||||
0x10 0x00 0x01 ISO/IEC 8859-1 [23] West European
|
||||
0x10 0x00 0x02 ISO/IEC 8859-2 [24] East European
|
||||
0x10 0x00 0x03 ISO/IEC 8859-3 [25] South European
|
||||
0x10 0x00 0x04 ISO/IEC 8859-4 [26] North and North-East European
|
||||
0x10 0x00 0x05 ISO/IEC 8859-5 [27] Latin/Cyrillic A.2
|
||||
0x10 0x00 0x06 ISO/IEC 8859-6 [28] Latin/Arabic A.3
|
||||
0x10 0x00 0x07 ISO/IEC 8859-7 [29] Latin/Greek A.4
|
||||
0x10 0x00 0x08 ISO/IEC 8859-8 [30] Latin/Hebrew A.5
|
||||
0x10 0x00 0x09 ISO/IEC 8859-9 [31] West European & Turkish A.6
|
||||
0x10 0x00 0x0A ISO/IEC 8859-10 [32] North European A.7
|
||||
0x10 0x00 0x0B ISO/IEC 8859-11 [33] Thai A.8
|
||||
0x10 0x00 0x0C Reserved for future use
|
||||
0x10 0x00 0x0D ISO/IEC 8859-13 [34] Baltic A.9
|
||||
0x10 0x00 0x0E ISO/IEC 8859-14 [35] Celtic A.10
|
||||
0x10 0x00 0x0F ISO/IEC 8859-15 [36] West European A.11
|
||||
*/
|
||||
#endregion
|
||||
|
||||
public class DvbStringDecoder
|
||||
{
|
||||
static readonly string[] codePages1 =
|
||||
{
|
||||
null, "iso-8859-5", "iso-8859-6", "iso-8859-7", "iso-8859-8", "iso-8859-9", "iso-8859-10", "iso-8859-11",
|
||||
null, "iso-8859-13", "iso-8859-14", "iso-8859-15", null, null, null, null,
|
||||
null, // codePages2 prefix
|
||||
"utf-16", "x-cp20949", "x-cp20936", "utf-16", "utf-8", null, null, null,
|
||||
"utf-8", null, null, null, "utf-8"
|
||||
};
|
||||
|
||||
static readonly string[] codePages2 =
|
||||
{
|
||||
null, "iso-8859-1", "iso-8859-2", "iso-8859-3", "iso-8859-4", "iso-8859-5", "iso-8859-6", "iso-8859-7",
|
||||
"iso-8859-8", "iso-8859-9", "iso-8859-10", "iso-8859-11", null, "iso-8859-13", "iso-8859-14", "iso-8859-15"
|
||||
};
|
||||
|
||||
private readonly Dictionary<string, Decoder> decoderCache = new Dictionary<string, Decoder>();
|
||||
|
||||
public DvbStringDecoder(Encoding defaultEncoding)
|
||||
{
|
||||
this.DefaultEncoding = defaultEncoding;
|
||||
}
|
||||
|
||||
public Encoding DefaultEncoding { get; set; }
|
||||
|
||||
#region GetChannelNames()
|
||||
public void GetChannelNames(byte[] name, int off, int len, out string longName, out string shortName)
|
||||
{
|
||||
longName = "";
|
||||
shortName = "";
|
||||
if (len == 0)
|
||||
return;
|
||||
byte b = name[off];
|
||||
if (b == 0)
|
||||
return;
|
||||
|
||||
Decoder decoder = this.DefaultEncoding.GetDecoder();
|
||||
bool singleByteChar = true;
|
||||
if (b < 0x20)
|
||||
{
|
||||
if (b == 0x10) // prefix for 2-byte code page
|
||||
{
|
||||
int cpIndex = name[off + 1] * 256 + name[off + 2];
|
||||
off += 2;
|
||||
len -= 2;
|
||||
SetDecoder(codePages2, cpIndex, ref decoder);
|
||||
}
|
||||
if (b <= 0x1F)
|
||||
SetDecoder(codePages1, b, ref decoder);
|
||||
singleByteChar = b < 0x10;
|
||||
++off;
|
||||
--len;
|
||||
}
|
||||
if (!singleByteChar)
|
||||
{
|
||||
char[] buffer = new char[100];
|
||||
int l= decoder.GetChars(name, off, len, buffer, 0, false);
|
||||
longName = new string(buffer, 0, l);
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sbLong = new StringBuilder();
|
||||
StringBuilder sbShort = new StringBuilder();
|
||||
bool inShortMode = false;
|
||||
for (int c = 0; c < len; c++)
|
||||
{
|
||||
int i = off + c;
|
||||
b = name[i];
|
||||
if (b == 0x00)
|
||||
break;
|
||||
|
||||
char ch = '\0';
|
||||
switch (b)
|
||||
{
|
||||
case 0x86: inShortMode = true; continue;
|
||||
case 0x87: inShortMode = false; continue;
|
||||
case 0x8a: ch = '\n'; break;
|
||||
default:
|
||||
if (b >= 0x80 && b <= 0x9f) // DVB-S control characters
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (ch == '\0')
|
||||
{
|
||||
// read as many bytes as necessary to get a character
|
||||
char[] charArray = new char[1];
|
||||
for (int byteCnt = 1; decoder.GetChars(name, i, byteCnt, charArray, 0) == 0; byteCnt++)
|
||||
++i;
|
||||
ch = charArray[0];
|
||||
}
|
||||
if (ch == '\0')
|
||||
continue;
|
||||
|
||||
sbLong.Append(ch);
|
||||
if (inShortMode)
|
||||
sbShort.Append(ch);
|
||||
}
|
||||
longName = sbLong.ToString();
|
||||
shortName = sbShort.ToString();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetDecoder()
|
||||
private void SetDecoder(string[] codePages, int cpIndex, ref Decoder defaultDecoder)
|
||||
{
|
||||
if (cpIndex >= codePages.Length)
|
||||
return;
|
||||
Decoder decoder;
|
||||
|
||||
string cp = codePages[cpIndex];
|
||||
if (cp == null)
|
||||
return;
|
||||
|
||||
if (this.decoderCache.TryGetValue(cp, out decoder))
|
||||
{
|
||||
defaultDecoder = decoder;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var encoding = Encoding.GetEncoding(cp);
|
||||
defaultDecoder = encoding.GetDecoder();
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
}
|
||||
decoderCache[cp] = defaultDecoder;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetCodepageBytes()
|
||||
public static byte[] GetCodepageBytes(Encoding encoding)
|
||||
{
|
||||
var encName = encoding.WebName;
|
||||
for (int i = 0; i < codePages1.Length; i++)
|
||||
{
|
||||
if (codePages1[i] == encName)
|
||||
return new [] {(byte)i};
|
||||
}
|
||||
|
||||
for (int i = 0; i < codePages2.Length; i++)
|
||||
{
|
||||
if (codePages2[i] == encName)
|
||||
return new[] { (byte)0x10, (byte)i };
|
||||
}
|
||||
|
||||
return new byte[0];
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetEncoding()
|
||||
/// <summary>
|
||||
/// Pass in either a value <=0x1F excluding 0x10 or 0x10xxyy
|
||||
/// </summary>
|
||||
public static Encoding GetEncoding(int encodingMarker)
|
||||
{
|
||||
string enc = null;
|
||||
if (encodingMarker < 0x20)
|
||||
enc = codePages1[encodingMarker];
|
||||
else
|
||||
{
|
||||
encodingMarker &= 0xFFFF;
|
||||
if (encodingMarker < codePages2.Length)
|
||||
enc = codePages2[encodingMarker];
|
||||
}
|
||||
return enc == null ? null : Encoding.GetEncoding(enc);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
177
source/ChanSort.Api/Utils/IniFile.cs
Normal file
177
source/ChanSort.Api/Utils/IniFile.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public class IniFile
|
||||
{
|
||||
#region class Section
|
||||
|
||||
public class Section
|
||||
{
|
||||
private readonly Dictionary<string, string> data = new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
|
||||
|
||||
public Section(string name)
|
||||
{
|
||||
this.Name = name;
|
||||
}
|
||||
|
||||
#region Name
|
||||
public string Name { get; private set; }
|
||||
#endregion
|
||||
|
||||
#region Set()
|
||||
internal void Set(string key, string value)
|
||||
{
|
||||
data[key] = value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Keys
|
||||
public IEnumerable<string> Keys { get { return data.Keys; } }
|
||||
#endregion
|
||||
|
||||
#region GetString()
|
||||
|
||||
public string GetString(string key)
|
||||
{
|
||||
string value;
|
||||
if (!data.TryGetValue(key, out value))
|
||||
return null;
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetInt()
|
||||
|
||||
public int GetInt(string key, int defaultValue = 0)
|
||||
{
|
||||
string value;
|
||||
if (!data.TryGetValue(key, out value))
|
||||
return defaultValue;
|
||||
return this.ParseNumber(value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetBytes()
|
||||
|
||||
public byte[] GetBytes(string key)
|
||||
{
|
||||
string value;
|
||||
if (!data.TryGetValue(key, out value))
|
||||
return null;
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return new byte[0];
|
||||
|
||||
string[] parts = value.Split(',');
|
||||
byte[] bytes = new byte[parts.Length];
|
||||
int i = 0;
|
||||
foreach (var part in parts)
|
||||
bytes[i++] = (byte)this.ParseNumber(part);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetIntList()
|
||||
public int[] GetIntList(string key)
|
||||
{
|
||||
string value = this.GetString(key);
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return new int[0];
|
||||
string[] numbers = value.Split(',');
|
||||
int[] ret = new int[numbers.Length];
|
||||
for (int i = 0; i < numbers.Length; i++)
|
||||
ret[i] = this.ParseNumber(numbers[i]);
|
||||
return ret;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ParseNumber()
|
||||
private int ParseNumber(string value)
|
||||
{
|
||||
if (value.ToLower().StartsWith("0x"))
|
||||
{
|
||||
try { return Convert.ToInt32(value, 16); }
|
||||
catch { return 0; }
|
||||
}
|
||||
int intValue;
|
||||
int.TryParse(value, out intValue);
|
||||
return intValue;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
private readonly Dictionary<string, Section> sectionDict;
|
||||
private readonly List<Section> sectionList;
|
||||
|
||||
public IniFile(string fileName)
|
||||
{
|
||||
this.sectionDict = new Dictionary<string, Section>();
|
||||
this.sectionList = new List<Section>();
|
||||
this.ReadIniFile(fileName);
|
||||
}
|
||||
|
||||
public IEnumerable<Section> Sections
|
||||
{
|
||||
get { return this.sectionList; }
|
||||
}
|
||||
|
||||
public Section GetSection(string sectionName)
|
||||
{
|
||||
return sectionDict.TryGet(sectionName);
|
||||
}
|
||||
|
||||
#region ReadIniFile()
|
||||
private void ReadIniFile(string fileName)
|
||||
{
|
||||
using (StreamReader rdr = new StreamReader(fileName))
|
||||
{
|
||||
Section currentSection = null;
|
||||
string line;
|
||||
string key = null;
|
||||
string val = null;
|
||||
while ((line = rdr.ReadLine()) != null)
|
||||
{
|
||||
string trimmedLine = line.Trim();
|
||||
if (trimmedLine.StartsWith(";"))
|
||||
continue;
|
||||
if (trimmedLine.StartsWith("["))
|
||||
{
|
||||
string sectionName = trimmedLine.EndsWith("]")
|
||||
? trimmedLine.Substring(1, trimmedLine.Length - 2)
|
||||
: trimmedLine.Substring(1);
|
||||
currentSection = new Section(sectionName);
|
||||
this.sectionList.Add(currentSection);
|
||||
this.sectionDict[sectionName] = currentSection;
|
||||
continue;
|
||||
}
|
||||
if (currentSection == null)
|
||||
continue;
|
||||
if (val == null)
|
||||
{
|
||||
int idx = trimmedLine.IndexOf("=");
|
||||
if (idx < 0)
|
||||
continue;
|
||||
key = trimmedLine.Substring(0, idx).Trim();
|
||||
val = trimmedLine.Substring(idx + 1).Trim();
|
||||
}
|
||||
else
|
||||
val += line;
|
||||
if (val.EndsWith("\\"))
|
||||
val = val.Substring(val.Length - 1).Trim();
|
||||
else
|
||||
{
|
||||
currentSection.Set(key, val);
|
||||
val = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
47
source/ChanSort.Api/Utils/MappingPool.cs
Normal file
47
source/ChanSort.Api/Utils/MappingPool.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public class MappingPool<T> where T : DataMapping
|
||||
{
|
||||
private const string ERR_unknownACTChannelDataLength = "Configuration doesn't contain a {0} data mapping for length {1}";
|
||||
private readonly Dictionary<string, T> mappings = new Dictionary<string, T>();
|
||||
private readonly string caption;
|
||||
public System.Text.Encoding DefaultEncoding { get; set; }
|
||||
|
||||
public MappingPool(string caption)
|
||||
{
|
||||
this.caption = caption;
|
||||
}
|
||||
|
||||
public void AddMapping(int dataLength, T mapping)
|
||||
{
|
||||
this.AddMapping(dataLength.ToString(), mapping);
|
||||
}
|
||||
|
||||
public void AddMapping(string id, T mapping)
|
||||
{
|
||||
this.mappings.Add(id, mapping);
|
||||
}
|
||||
|
||||
public T GetMapping(int dataLength, bool throwException = true)
|
||||
{
|
||||
return this.GetMapping(dataLength.ToString(), throwException);
|
||||
}
|
||||
|
||||
public T GetMapping(string id, bool throwException = true)
|
||||
{
|
||||
if (id == "0" || string.IsNullOrEmpty(id))
|
||||
return null;
|
||||
|
||||
T mapping;
|
||||
if (!mappings.TryGetValue(id, out mapping) && throwException)
|
||||
throw new FileLoadException(string.Format(ERR_unknownACTChannelDataLength, this.caption, id));
|
||||
|
||||
if (mapping != null && this.DefaultEncoding != null)
|
||||
mapping.DefaultEncoding = this.DefaultEncoding;
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
}
|
||||
122
source/ChanSort.Api/Utils/Tools.cs
Normal file
122
source/ChanSort.Api/Utils/Tools.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ChanSort.Api
|
||||
{
|
||||
public static class Tools
|
||||
{
|
||||
public static V TryGet<K, V>(this IDictionary<K, V> dict, K key)
|
||||
{
|
||||
V val;
|
||||
dict.TryGetValue(key, out val);
|
||||
return val;
|
||||
}
|
||||
|
||||
#region GetAnalogChannelNumber()
|
||||
public static string GetAnalogChannelNumber(int freq)
|
||||
{
|
||||
if (freq < 41) return "";
|
||||
if (freq <= 68) return ((freq - 41)/7 + 1).ToString("d2"); // Band I (01-04)
|
||||
if (freq < 105) return "";
|
||||
if (freq <= 174) return "S" + ((freq - 105)/7 + 1).ToString("d2"); // Midband (S01-S10)
|
||||
if (freq <= 230) return ((freq - 175)/7 + 5).ToString("d2"); // Band III (05-12)
|
||||
if (freq <= 300) return "S" + ((freq - 231)/7 + 11); // Superband (S11-S20)
|
||||
if (freq <= 469) return "S" + ((freq - 303)/8 + 21); // Hyperband (S21-S41)
|
||||
if (freq <= 1000) return ((freq - 471)/8 + 21).ToString("d2"); // Band IV, V
|
||||
return "";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetInt16/32()
|
||||
|
||||
public static int GetInt16(byte[] data, int offset, bool littleEndian)
|
||||
{
|
||||
return littleEndian ? BitConverter.ToInt16(data, offset) : (data[offset] << 8) + data[offset + 1];
|
||||
}
|
||||
|
||||
public static int GetInt32(byte[] data, int offset, bool littleEndian)
|
||||
{
|
||||
return littleEndian ? BitConverter.ToInt32(data, offset) :
|
||||
(data[offset] << 24) + (data[offset + 1] << 16) + (data[offset + 2] << 8) + data[offset + 3];
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetInt16/32()
|
||||
|
||||
public static void SetInt16(byte[] data, int offset, int value, bool littleEndian = true)
|
||||
{
|
||||
if (littleEndian)
|
||||
{
|
||||
data[offset + 0] = (byte) value;
|
||||
data[offset + 1] = (byte) (value >> 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
data[offset + 0] = (byte)(value >> 8);
|
||||
data[offset + 1] = (byte) value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetInt32(byte[] data, int offset, int value, bool littleEndian = true)
|
||||
{
|
||||
if (littleEndian)
|
||||
{
|
||||
data[offset + 0] = (byte) value;
|
||||
data[offset + 1] = (byte) (value >> 8);
|
||||
data[offset + 2] = (byte) (value >> 16);
|
||||
data[offset + 3] = (byte) (value >> 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
data[offset + 0] = (byte)(value >> 24);
|
||||
data[offset + 1] = (byte)(value >> 16);
|
||||
data[offset + 2] = (byte)(value >> 8);
|
||||
data[offset + 3] = (byte)value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MemCopy(), MemSet()
|
||||
|
||||
public static void MemCopy(byte[] source, int sourceIndex, byte[] dest, int destIndex, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
dest[destIndex + i] = source[sourceIndex + i];
|
||||
}
|
||||
|
||||
public static void MemSet(byte[] data, int offset, byte value, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
data[offset++] = value;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReverseByteOrder()
|
||||
public static ushort ReverseByteOrder(ushort input)
|
||||
{
|
||||
return (ushort)(((input & 0x00FF) << 8) | (input >> 8));
|
||||
}
|
||||
|
||||
public static uint ReverseByteOrder(uint input)
|
||||
{
|
||||
return ((input & 0x000000FF) << 24) | ((input & 0x0000FF00) << 8) | ((input & 0x00FF0000) >> 8) | ((input & 0xFF000000) >> 24);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region HexDecode()
|
||||
public static byte[] HexDecode(string input)
|
||||
{
|
||||
var bytes = new byte[input.Length/2];
|
||||
for (int i = 0, c = input.Length/2; i < c; i++)
|
||||
{
|
||||
char ch = Char.ToUpper(input[i*2]);
|
||||
var high = Char.IsDigit(ch) ? ch - '0' : ch - 'A' + 10;
|
||||
ch = Char.ToUpper(input[i*2 + 1]);
|
||||
var low = Char.IsDigit(ch) ? ch - '0' : ch - 'A' + 10;
|
||||
bytes[i] = (byte)((high << 4) | low);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user