mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-05-06 22:46:20 +02:00
- Philips: added support for CM\_*.xml variant that uses a <ECSM> root element around the <ChannelMap>
- Philips: ability to read/write broken CM\_*.xml files that contain channel names with an unescaped & character - Philips: enabled write mode for Repair\\FLASH\_\*/\*.db file format (one variant was confirmed to work) Favorite lists for this format are disabled for now (TV ignored them). - Panasonic: importing a modified svl.bin file caused the TV to use case-sensitive sorting when using the function to list the names sorted alphabetically. This is now fixed.
This commit is contained in:
@@ -133,9 +133,6 @@ namespace ChanSort.Loader.Panasonic
|
||||
{
|
||||
byte[] buffer = new byte[100];
|
||||
int len = (int)r.GetBytes(field["sname"], 0, buffer, 0, buffer.Length);
|
||||
int end = Array.IndexOf<byte>(buffer, 0, 0, len);
|
||||
if (end >= 0)
|
||||
len = end;
|
||||
this.RawName = new byte[len];
|
||||
Array.Copy(buffer, 0, this.RawName, 0, len);
|
||||
this.ChangeEncoding(encoding);
|
||||
@@ -152,22 +149,25 @@ namespace ChanSort.Loader.Panasonic
|
||||
// it can be code page encoded without any clue to what the code page is
|
||||
// it can have DVB-control characters inside an UTF-8 stream
|
||||
|
||||
if (RawName.Length == 0)
|
||||
int len = Array.IndexOf<byte>(this.RawName, 0, 0, this.RawName.Length);
|
||||
if (len < 0)
|
||||
len = this.RawName.Length;
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
int startOffset;
|
||||
int bytesPerChar;
|
||||
if (!GetRecommendedEncoding(ref encoding, out startOffset, out bytesPerChar))
|
||||
if (!GetRecommendedEncoding(ref encoding, out var startOffset, out var bytesPerChar))
|
||||
return;
|
||||
|
||||
// single byte code pages might have UTF-8 code mixed in, so we have to parse it manually
|
||||
StringBuilder sb = new StringBuilder();
|
||||
this.NonAscii = false;
|
||||
this.ValidUtf8 = true;
|
||||
for (int i = startOffset; i < this.RawName.Length; i+=bytesPerChar)
|
||||
for (int i = startOffset; i < len; i+=bytesPerChar)
|
||||
{
|
||||
byte c = this.RawName[i];
|
||||
byte c2 = i + 1 < this.RawName.Length ? this.RawName[i + 1] : (byte)0;
|
||||
byte c2 = i + 1 < len ? this.RawName[i + 1] : (byte)0;
|
||||
byte c3 = i + 2 < len ? this.RawName[i + 2] : (byte)0;
|
||||
byte c4 = i + 4 < len ? this.RawName[i + 3] : (byte)0;
|
||||
if (c >= 0x80)
|
||||
NonAscii = true;
|
||||
|
||||
@@ -178,10 +178,28 @@ namespace ChanSort.Loader.Panasonic
|
||||
ValidUtf8 = false;
|
||||
sb.Append((char) c);
|
||||
}
|
||||
else if (bytesPerChar == 1 && c >= 0xC0 && c <= 0xDF && c2 >= 0x80 && c2 <= 0xBF) // 2 byte UTF-8
|
||||
else if (bytesPerChar == 1)
|
||||
{
|
||||
sb.Append((char)(((c & 0x1F) << 6) | (c2 & 0x3F)));
|
||||
++i;
|
||||
if (c >= 0xC0 && c <= 0xDF && c2 >= 0x80 && c2 <= 0xBF) // 2 byte UTF-8
|
||||
{
|
||||
sb.Append((char)(((c & 0x1F) << 6) | (c2 & 0x3F)));
|
||||
++i;
|
||||
}
|
||||
else if (c >= 0xE0 && c <= 0xEF && (c2 & 0xC0) == 0x80 && (c3 & 0xC0) == 0x80) // 3 byte UTF-8
|
||||
{
|
||||
sb.Append((char)(((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F)));
|
||||
i += 2;
|
||||
}
|
||||
else if (c >= 0xF0 && c <= 0xF7 && (c2 & 0xC0) == 0x80 && (c3 & 0xC0) == 0x80 && (c4 & 0xC0) == 0x80) // 4 byte UTF-8
|
||||
{
|
||||
sb.Append((char)(((c & 0x07) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F)));
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
ValidUtf8 = false;
|
||||
sb.Append(encoding.GetString(this.RawName, i, bytesPerChar));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -190,8 +208,7 @@ namespace ChanSort.Loader.Panasonic
|
||||
}
|
||||
}
|
||||
|
||||
string longName, shortName;
|
||||
this.GetChannelNames(sb.ToString(), out longName, out shortName);
|
||||
this.GetChannelNames(sb.ToString(), out var longName, out var shortName);
|
||||
this.Name = longName;
|
||||
this.ShortName = shortName;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace ChanSort.Loader.Panasonic
|
||||
|
||||
private string workFile;
|
||||
private CypherMode cypherMode;
|
||||
private byte[] fileHeader = new byte[0];
|
||||
private byte[] fileHeader = Array.Empty<byte>();
|
||||
private int dbSizeOffset;
|
||||
private bool littleEndianByteOrder;
|
||||
private string charEncoding;
|
||||
@@ -329,11 +329,14 @@ order by s.ntype,major_channel
|
||||
#region WriteChannels()
|
||||
private void WriteChannels(SqliteCommand cmd, ChannelList channelList)
|
||||
{
|
||||
if (channelList.Channels.Count == 0)
|
||||
return;
|
||||
|
||||
cmd.CommandText = "update SVL set major_channel=@progNr, sname=@sname, profile1index=@fav1, profile2index=@fav2, profile3index=@fav3, profile4index=@fav4, child_lock=@lock, skip=@skip where rowid=@rowid";
|
||||
cmd.Parameters.Clear();
|
||||
cmd.Parameters.Add("@rowid", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@progNr", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@sname", SqliteType.Blob);
|
||||
cmd.Parameters.Add("@sname", this.implicitUtf8 ? SqliteType.Text : SqliteType.Blob); // must use "TEXT" when possible to preserve collation / case-insensitive sorting for the TV
|
||||
cmd.Parameters.Add("@fav1", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@fav2", SqliteType.Integer);
|
||||
cmd.Parameters.Add("@fav3", SqliteType.Integer);
|
||||
@@ -351,7 +354,7 @@ order by s.ntype,major_channel
|
||||
channel.UpdateRawData(this.explicitUtf8, this.implicitUtf8);
|
||||
cmd.Parameters["@rowid"].Value = channel.RecordIndex;
|
||||
cmd.Parameters["@progNr"].Value = channel.NewProgramNr;
|
||||
cmd.Parameters["@sname"].Value = channel.RawName;
|
||||
cmd.Parameters["@sname"].Value = this.implicitUtf8 ? channel.Name : channel.RawName; // must use a string when possible to preserve collation / case-insensitive sorting for the TV
|
||||
for (int fav = 0; fav < 4; fav++)
|
||||
cmd.Parameters["@fav" + (fav + 1)].Value = Math.Max(0, channel.GetPosition(fav+1));
|
||||
cmd.Parameters["@lock"].Value = channel.Lock;
|
||||
|
||||
Reference in New Issue
Block a user