From 1b250b2a18e121310f169786accfca0285d3d80c Mon Sep 17 00:00:00 2001 From: Horst Beham Date: Tue, 31 Aug 2021 22:13:28 +0200 Subject: [PATCH] - ChanSort didn't work properly for Turkish (and other system locales) that don't translate ".bin" to uppercase ".BIN" and ".BIN" to lowercase ".bin". - Philips: Removing a channel from a list is no longer possible (because it is not supported by the TV's import). When saving a file, all unsorted channels will be placed at the end of the list. - support for Philips Repair\mgr_chan_s_fta.db lists is now read-only. Files can be used as a reference list, but modifying them won't be possible. --- .../Controller/RefListSerializerPlugin.cs | 2 +- .../ChanSort.Api/Controller/SerializerBase.cs | 4 +- .../Controller/TxtRefListSerializer.cs | 2 +- source/ChanSort.Api/Model/ChannelList.cs | 4 +- source/ChanSort.Api/Model/LookupData.cs | 2 +- source/ChanSort.Api/Utils/IniFile.cs | 2 +- source/ChanSort.Api/Utils/Tools.cs | 4 +- .../ServicelistDb/ServicelistDbSerializer.cs | 4 +- .../Binary/TllFileSerializer.cs | 6 +- .../GlobalClone/GcJsonSerializer.cs | 2 +- .../GlobalClone/GcXmlSerializer.cs | 4 +- source/ChanSort.Loader.M3u/Serializer.cs | 2 +- .../ChanSort.Loader.Philips/DbSerializer.cs | 28 +++- .../ChanSort.Loader.Philips/PhilipsPlugin.cs | 4 +- .../ChanSort.Loader.Philips/XmlSerializer.cs | 122 ++++++++++-------- .../Zip/DbSerializer.cs | 2 +- .../ChanSort.Loader.Toshiba/ToshibaPlugin.cs | 2 +- source/ChanSort.Loader.VDR/Channels.cs | 2 +- source/ChanSort/MainForm.cs | 10 +- source/ChanSort/XGrid/XGridControl.cs | 2 +- .../get_doc_size.js | 9 ++ .../philips_mgr_chan_s_fta.db.h | 117 ++++++++++------- source/Test.Loader.Philips/PhilipsXmlTest.cs | 28 ++-- source/changelog.md | 9 +- 24 files changed, 225 insertions(+), 148 deletions(-) create mode 100644 source/Information/FileStructures_for_HHD_Hex_Editor_Neo/get_doc_size.js diff --git a/source/ChanSort.Api/Controller/RefListSerializerPlugin.cs b/source/ChanSort.Api/Controller/RefListSerializerPlugin.cs index a1ff1ca..066b07b 100644 --- a/source/ChanSort.Api/Controller/RefListSerializerPlugin.cs +++ b/source/ChanSort.Api/Controller/RefListSerializerPlugin.cs @@ -12,7 +12,7 @@ namespace ChanSort.Api public SerializerBase CreateSerializer(string inputFile) { - var ext = (Path.GetExtension(inputFile) ?? "").ToLower(); + var ext = (Path.GetExtension(inputFile) ?? "").ToLowerInvariant(); if (ext == ".csv") return new CsvRefListSerializer(inputFile); else diff --git a/source/ChanSort.Api/Controller/SerializerBase.cs b/source/ChanSort.Api/Controller/SerializerBase.cs index 7f3f1ec..da2e334 100644 --- a/source/ChanSort.Api/Controller/SerializerBase.cs +++ b/source/ChanSort.Api/Controller/SerializerBase.cs @@ -213,7 +213,7 @@ namespace ChanSort.Api { if (string.IsNullOrWhiteSpace(input)) return 0; - if (input.Length > 2 && input[0] == '0' && char.ToLower(input[1]) == 'x') + if (input.Length > 2 && input[0] == '0' && char.ToLowerInvariant(input[1]) == 'x') return int.Parse(input.Substring(2), NumberStyles.HexNumber); if (int.TryParse(input, out var value)) return value; @@ -226,7 +226,7 @@ namespace ChanSort.Api { if (string.IsNullOrWhiteSpace(input)) return 0; - if (input.Length > 2 && input[0] == '0' && char.ToLower(input[1]) == 'x') + if (input.Length > 2 && input[0] == '0' && char.ToLowerInvariant(input[1]) == 'x') return long.Parse(input.Substring(2), NumberStyles.HexNumber); if (long.TryParse(input, out var value)) return value; diff --git a/source/ChanSort.Api/Controller/TxtRefListSerializer.cs b/source/ChanSort.Api/Controller/TxtRefListSerializer.cs index cb94965..304a9e7 100644 --- a/source/ChanSort.Api/Controller/TxtRefListSerializer.cs +++ b/source/ChanSort.Api/Controller/TxtRefListSerializer.cs @@ -110,7 +110,7 @@ namespace ChanSort.Api public static void Save(string fileName, ChannelList list) { - var samToolBoxMode = (Path.GetExtension(fileName) ?? "").ToLower() == ".chl"; + var samToolBoxMode = (Path.GetExtension(fileName) ?? "").ToLowerInvariant() == ".chl"; using (var writer = new StreamWriter(fileName, false, Encoding.UTF8)) { diff --git a/source/ChanSort.Api/Model/ChannelList.cs b/source/ChanSort.Api/Model/ChannelList.cs index 6d9dc1d..a042aeb 100644 --- a/source/ChanSort.Api/Model/ChannelList.cs +++ b/source/ChanSort.Api/Model/ChannelList.cs @@ -102,7 +102,7 @@ namespace ChanSort.Api if (!isDupeProgNr) this.channelByProgNr[ci.OldProgramNr] = ci; - var lowerName = (ci.Name ?? "").ToLower().Trim(); + var lowerName = (ci.Name ?? "").ToLowerInvariant().Trim(); var byNameList = this.channelByName.TryGet(lowerName); if (byNameList == null) { @@ -138,7 +138,7 @@ namespace ChanSort.Api #region GetChannelByName() public IEnumerable GetChannelByName(string name) { - var hits = this.channelByName.TryGet(name.ToLower().Trim()); + var hits = this.channelByName.TryGet(name.ToLowerInvariant().Trim()); return hits ?? new List(); } #endregion diff --git a/source/ChanSort.Api/Model/LookupData.cs b/source/ChanSort.Api/Model/LookupData.cs index 2c41809..14ca6d9 100644 --- a/source/ChanSort.Api/Model/LookupData.cs +++ b/source/ChanSort.Api/Model/LookupData.cs @@ -73,7 +73,7 @@ namespace ChanSort.Api var fields = CsvFile.Parse(line, ';'); if (fields.Count == 0) continue; - switch (fields[0].ToLower()) + switch (fields[0].ToLowerInvariant()) { case "onid": this.ParseNetwork(fields); break; case "transp": this.ParseTransponder(fields); break; diff --git a/source/ChanSort.Api/Utils/IniFile.cs b/source/ChanSort.Api/Utils/IniFile.cs index f1bad61..6e282db 100644 --- a/source/ChanSort.Api/Utils/IniFile.cs +++ b/source/ChanSort.Api/Utils/IniFile.cs @@ -110,7 +110,7 @@ namespace ChanSort.Api int sig = value.StartsWith("-") ? -1 : 1; if (sig < 0) value = value.Substring(1).Trim(); - if (value.ToLower().StartsWith("0x")) + if (value.ToLowerInvariant().StartsWith("0x")) { try { return Convert.ToInt32(value, 16) * sig; } catch { return 0; } diff --git a/source/ChanSort.Api/Utils/Tools.cs b/source/ChanSort.Api/Utils/Tools.cs index fc71736..73dbf57 100644 --- a/source/ChanSort.Api/Utils/Tools.cs +++ b/source/ChanSort.Api/Utils/Tools.cs @@ -110,9 +110,9 @@ namespace ChanSort.Api 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]); + char ch = Char.ToUpperInvariant(input[i*2]); var high = Char.IsDigit(ch) ? ch - '0' : ch - 'A' + 10; - ch = Char.ToUpper(input[i*2 + 1]); + ch = Char.ToUpperInvariant(input[i*2 + 1]); var low = Char.IsDigit(ch) ? ch - '0' : ch - 'A' + 10; bytes[i] = (byte)((high << 4) | low); } diff --git a/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs b/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs index 71b8601..35832e7 100644 --- a/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs +++ b/source/ChanSort.Loader.Hisense/ServicelistDb/ServicelistDbSerializer.cs @@ -162,7 +162,7 @@ namespace ChanSort.Loader.Hisense.ServicelistDb cmd.CommandText = "SELECT name FROM sqlite_master WHERE type = 'table' order by name"; using var r = cmd.ExecuteReader(); while (r.Read()) - tableNames.Add(r.GetString(0).ToLower()); + tableNames.Add(r.GetString(0).ToLowerInvariant()); } #endregion @@ -298,7 +298,7 @@ namespace ChanSort.Loader.Hisense.ServicelistDb private void LoadTunerData2017(SqliteCommand cmd, string joinTable, string joinFields, Action enhanceTransponderInfo) { - if (!tableNames.Contains(joinTable.ToLower())) + if (!tableNames.Contains(joinTable.ToLowerInvariant())) return; cmd.CommandText = $"select tuner.tunerid, oid, tid, satellite {joinFields} " diff --git a/source/ChanSort.Loader.LG/Binary/TllFileSerializer.cs b/source/ChanSort.Loader.LG/Binary/TllFileSerializer.cs index f238c4d..5815f3c 100644 --- a/source/ChanSort.Loader.LG/Binary/TllFileSerializer.cs +++ b/source/ChanSort.Loader.LG/Binary/TllFileSerializer.cs @@ -113,7 +113,7 @@ namespace ChanSort.Loader.LG.Binary private void ReadConfigurationFromIniFile() { - string iniFile = this.GetType().Assembly.Location.ToLower().Replace(".dll", ".ini"); + string iniFile = this.GetType().Assembly.Location.ToLowerInvariant().Replace(".dll", ".ini"); IniFile ini = new IniFile(iniFile); foreach (var section in ini.Sections) { @@ -142,7 +142,7 @@ namespace ChanSort.Loader.LG.Binary { this.InitUiFactory(); - string basename = (Path.GetFileNameWithoutExtension(this.FileName) ?? "").ToUpper(); + string basename = (Path.GetFileNameWithoutExtension(this.FileName) ?? "").ToUpperInvariant(); if (basename.StartsWith("XXLH250")) this.specialModel = SpecialHandlingModels.LH250; else if (basename.StartsWith("XXLH3000")) @@ -1131,7 +1131,7 @@ Due to issues with most recent LG firmwares such lists can no longer be modified set { if (value.Length < 3 || this.settingsBlockOffset == 0 || this.settingsBlockSize < 8) return; - value = value.ToUpper(); + value = value.ToUpperInvariant(); int off = this.settingsBlockOffset + 4 + 4 + 2; for (int i = 0; i < 3; i++) this.fileContent[off--] = (byte)value[i]; diff --git a/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs b/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs index 37119db..e32d56b 100644 --- a/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs +++ b/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs @@ -183,7 +183,7 @@ namespace ChanSort.Loader.GlobalClone tp.FrequencyInMhz = (int) node["frequency"]; tp.Number = (int) node["channelIdx"]; - var pol = ((string) node["polarization"]).ToLower(); + var pol = ((string) node["polarization"]).ToLowerInvariant(); tp.Polarity = pol.StartsWith("h") ? 'H' : pol.StartsWith("V") ? 'V' : '\0'; tp.TransportStreamId = (int) node["TSID"]; tp.OriginalNetworkId = (int)node["ONID"]; diff --git a/source/ChanSort.Loader.LG/GlobalClone/GcXmlSerializer.cs b/source/ChanSort.Loader.LG/GlobalClone/GcXmlSerializer.cs index 5a1d597..b9441b2 100644 --- a/source/ChanSort.Loader.LG/GlobalClone/GcXmlSerializer.cs +++ b/source/ChanSort.Loader.LG/GlobalClone/GcXmlSerializer.cs @@ -115,7 +115,7 @@ namespace ChanSort.Loader.GlobalClone // ask whether binary TLL file should be deleted var dir = Path.GetDirectoryName(this.FileName) ?? "."; var binTlls = Directory.GetFiles(dir, "xx" + series + "*.tll"); - if (binTlls.Length > 0 && !(binTlls.Length == 1 && Path.GetFileName(binTlls[0]).ToLower() == Path.GetFileName(this.FileName).ToLower())) + if (binTlls.Length > 0 && !(binTlls.Length == 1 && Path.GetFileName(binTlls[0]).ToLowerInvariant() == Path.GetFileName(this.FileName).ToLowerInvariant())) { var txt = Resource.GcSerializer_ReadModelInfo_ModelWarning; if (Api.View.Default != null && Api.View.Default.MessageBox(txt, "LG GlobalClone", View.MessageBoxButtons.YesNo, View.MessageBoxIcon.Information) == View.DialogResult.Yes) @@ -585,7 +585,7 @@ namespace ChanSort.Loader.GlobalClone private int HexNibble(char hexDigit) { - return hexDigit >= '0' && hexDigit <= '9' ? hexDigit - '0' : (Char.ToUpper(hexDigit) - 'A') + 10; + return hexDigit >= '0' && hexDigit <= '9' ? hexDigit - '0' : (Char.ToUpperInvariant(hexDigit) - 'A') + 10; } #endregion } diff --git a/source/ChanSort.Loader.M3u/Serializer.cs b/source/ChanSort.Loader.M3u/Serializer.cs index e3362f3..4851a54 100644 --- a/source/ChanSort.Loader.M3u/Serializer.cs +++ b/source/ChanSort.Loader.M3u/Serializer.cs @@ -166,7 +166,7 @@ namespace ChanSort.Loader.M3u break; case "pol": if (val.Length == 1) - chan.Polarity = Char.ToUpper(val[0]); + chan.Polarity = Char.ToUpperInvariant(val[0]); break; case "sr": chan.SymbolRate = this.ParseInt(val); diff --git a/source/ChanSort.Loader.Philips/DbSerializer.cs b/source/ChanSort.Loader.Philips/DbSerializer.cs index 376d534..0ffcc4c 100644 --- a/source/ChanSort.Loader.Philips/DbSerializer.cs +++ b/source/ChanSort.Loader.Philips/DbSerializer.cs @@ -12,6 +12,9 @@ namespace ChanSort.Loader.Philips * This serializer is used for the channel list format with a Repair\ folder containing files like channel_db_ver.db, mgr_chan_s_fta.db, ... * The .db files are proprietary binary files, not SQLite databases. * So far only the mgr_chan_s_fta.db file holing DVB-S channels is reverse engineered, the offsets are defined in PChanSort.Loader.Philips.ini + * + * Unfortunately modifying the .db files does not seem to be enough. The TV also depends on channel data in the FLASH_* files, which I don't know how how to edit. + * Therefore lists of this format can be read as read-only reference lists, but modifications are disabled. */ class DbSerializer : SerializerBase { @@ -26,6 +29,7 @@ namespace ChanSort.Loader.Philips this.Features.MaxFavoriteLists = 1; this.Features.FavoritesMode = FavoritesMode.OrderedPerSource; this.Features.DeleteMode = DeleteMode.NotSupported; + this.Features.CanHaveGaps = false; string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini"); this.ini = new IniFile(iniFile); @@ -43,6 +47,7 @@ namespace ChanSort.Loader.Philips nameof(Channel.OriginalNetworkId), nameof(Channel.ServiceId) }; + dvbsChannels.ReadOnly = true; } #region Load() @@ -163,7 +168,7 @@ namespace ChanSort.Loader.Philips var offFooterChecksum = sec.GetInt("offFooterChecksum"); var mapping = new DataMapping(ini.GetSection("mgr_chan_s_fta.db_entry")); - +#if JUST_CHANGE_NUMBERS // update channel data foreach (var ch in dvbsChannels.Channels) { @@ -172,7 +177,28 @@ namespace ChanSort.Loader.Philips mapping.SetWord("offPrevProgNr", ch.NewProgramNr - 1); mapping.SetWord("offFav", Math.Max(0, ch.GetPosition(1))); } +#else + // physically reorder channels + var newData = new byte[data.Length]; + Array.Copy(data, newData, lenHeader); + var off = lenHeader + lenEntry * dvbsChannels.Channels.Count; + Array.Copy(data, off, newData, off, lenFooter); + int i = 0; + foreach (var ch in dvbsChannels.Channels.OrderBy(c => c.NewProgramNr)) + { + off = lenHeader + i * lenEntry; + Array.Copy(data, lenHeader + ch.RecordOrder * lenEntry, newData, off, lenEntry); + mapping.SetDataPtr(newData, off); + mapping.SetWord("offProgNr", ch.NewProgramNr); + mapping.SetWord("offPrevProgNr", ch.NewProgramNr - 1); + mapping.SetWord("offFav", Math.Max(0, ch.GetPosition(1))); + ch.RecordOrder = i; + ++i; + } + + data = newData; +#endif // update checksum var offChecksum = data.Length - lenFooter + offFooterChecksum; var checksum = CalcChecksum(data, 0, offChecksum); diff --git a/source/ChanSort.Loader.Philips/PhilipsPlugin.cs b/source/ChanSort.Loader.Philips/PhilipsPlugin.cs index 8af6fdc..440f72d 100644 --- a/source/ChanSort.Loader.Philips/PhilipsPlugin.cs +++ b/source/ChanSort.Loader.Philips/PhilipsPlugin.cs @@ -85,7 +85,7 @@ namespace ChanSort.Loader.Philips public SerializerBase CreateSerializer(string inputFile) { int majorVersion = int.MinValue; - var filename = Path.GetFileName(inputFile).ToLower(); + var filename = Path.GetFileName(inputFile).ToLowerInvariant(); if (Regex.IsMatch(filename, @"^CM_.*\.(?:bin|xml)$", RegexOptions.IgnoreCase)) majorVersion = 0; else @@ -111,7 +111,7 @@ namespace ChanSort.Loader.Philips break; } - var dirName = Path.GetFileName(dir).ToLower(); + var dirName = Path.GetFileName(dir).ToLowerInvariant(); if (dirName == "channellib" || dirName == "s2channellib") dir = Path.GetDirectoryName(dir); else if (Directory.Exists(Path.Combine(dir, "PhilipsChannelMaps"))) diff --git a/source/ChanSort.Loader.Philips/XmlSerializer.cs b/source/ChanSort.Loader.Philips/XmlSerializer.cs index d0e86ae..46c9f8f 100644 --- a/source/ChanSort.Loader.Philips/XmlSerializer.cs +++ b/source/ChanSort.Loader.Philips/XmlSerializer.cs @@ -14,11 +14,19 @@ namespace ChanSort.Loader.Philips This loader supports 2 different kinds of XML files from Philips, the first in a "Repair" folder, the others in a "ChannelMap_100" (or later) folder Example from Repair\CM_TPM1013E_LA_CK.xml: + This "Repair" format comes with a visible .BIN file and a .xml file that has file system attributes "hidden" and "system". + The TV seems to use the .BIN file as its primary source for setting up the internal list and then applies the .xml on top of it to reorder channels. + It uses the "oldpresetnumber" from the XML to lookup the channel from the .BIN file and then apply the new "presetnumber". + The .BIN file itself is compressed with some unknown cl_Zip compression / archive format and can't be edited with ChanSort. + Deleting a channel is not possible by modifiying the .xml file. Omitting a channel only results in duplicate numbers with the TV still showing the missing channels at their old numbers. + - + + + Newer channel lists from Philips contain multiple XML files with a different internal structure, which also varies based on the version number in the ChannelMap_xxx folder name: @@ -70,7 +78,7 @@ namespace ChanSort.Loader.Philips this.Features.CanSkipChannels = false; this.Features.CanLockChannels = true; this.Features.CanHideChannels = true; - this.Features.DeleteMode = DeleteMode.Physically; + this.Features.DeleteMode = DeleteMode.NotSupported; this.Features.CanSaveAs = false; this.Features.AllowGapsInFavNumbers = false; this.Features.CanEditFavListNames = true; @@ -132,7 +140,7 @@ namespace ChanSort.Loader.Philips // support for files in a ChannelMap_xxx directory structure bool isChannelMapFolderStructure = false; var dir = Path.GetDirectoryName(this.FileName); - var dirName = Path.GetFileName(dir).ToLower(); + var dirName = Path.GetFileName(dir).ToLowerInvariant(); if (dirName == "channellib" || dirName == "s2channellib") { dir = Path.GetDirectoryName(dir); @@ -147,7 +155,7 @@ namespace ChanSort.Loader.Philips this.chanLstBin = new ChanLstBin(); this.chanLstBin.Load(this.FileName, msg => this.logMessages.AppendLine(msg)); } - else if (Path.GetExtension(this.FileName).ToLower() == ".bin") + else if (Path.GetExtension(this.FileName).ToLowerInvariant() == ".bin") { // older Philips models export a visible file like Repair\CM_T911_LA_CK.BIN and an invisible (hidden+system) .xml file with the same name var xmlPath = Path.Combine(dir, Path.GetFileNameWithoutExtension(this.FileName) + ".xml"); @@ -264,7 +272,7 @@ namespace ChanSort.Loader.Philips var setupNode = node["Setup"] ?? throw new FileLoadException("Missing Setup XML element"); var bcastNode = node["Broadcast"] ?? throw new FileLoadException("Missing Broadcast XML element"); - var fname = Path.GetFileNameWithoutExtension(file.path).ToLower(); + var fname = Path.GetFileNameWithoutExtension(file.path).ToLowerInvariant(); var medium = bcastNode.GetAttribute("medium"); if (medium == "" && fname.Length >= 4 && fname.StartsWith("dvb")) medium = fname; @@ -276,9 +284,22 @@ namespace ChanSort.Loader.Philips list.VisibleColumnFieldNames.Add("ServiceTypeName"); } - if (setupNode.HasAttribute("ChannelName")) + if (setupNode.HasAttribute("name")) { file.formatVersion = 1; + this.Features.FavoritesMode = FavoritesMode.None; + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove("Favorites"); + list.VisibleColumnFieldNames.Remove("Lock"); + list.VisibleColumnFieldNames.Remove("Hidden"); + list.VisibleColumnFieldNames.Remove("ServiceTypeName"); + list.VisibleColumnFieldNames.Remove("Encrypted"); + } + } + else if (setupNode.HasAttribute("ChannelName")) + { + file.formatVersion = 2; this.Features.FavoritesMode = FavoritesMode.OrderedPerSource; this.Features.MaxFavoriteLists = 1; @@ -292,19 +313,6 @@ namespace ChanSort.Loader.Philips hasEncrypt = setupNode.HasAttribute("Scrambled"); } - else if (setupNode.HasAttribute("name")) - { - file.formatVersion = 2; - this.Features.FavoritesMode = FavoritesMode.None; - foreach (var list in this.DataRoot.ChannelLists) - { - list.VisibleColumnFieldNames.Remove("Favorites"); - list.VisibleColumnFieldNames.Remove("Lock"); - list.VisibleColumnFieldNames.Remove("Hidden"); - list.VisibleColumnFieldNames.Remove("ServiceTypeName"); - list.VisibleColumnFieldNames.Remove("Encrypted"); - } - } else throw new FileLoadException("Unknown data format"); @@ -353,9 +361,9 @@ namespace ChanSort.Loader.Philips chan.OldProgramNr = -1; chan.IsDeleted = false; if (file.formatVersion == 1) - this.ParseChannelFormat1(data, chan); + this.ParseRepairFormat(data, chan); else if (file.formatVersion == 2) - this.ParseChannelFormat2(data, chan); + this.ParseChannelMapFormat(data, chan); if ((chan.SignalSource & SignalSource.MaskAdInput) == SignalSource.DvbT) chan.ChannelOrTransponder = LookupData.Instance.GetDvbtTransponder(chan.FreqInMhz).ToString(); @@ -366,10 +374,30 @@ namespace ChanSort.Loader.Philips } #endregion - #region ParseChannelFormat1 - private void ParseChannelFormat1(Dictionary data, Channel chan) + #region ParseRepairFormat + private void ParseRepairFormat(Dictionary data, Channel chan) { chan.Format = 1; + chan.OldProgramNr = ParseInt(data.TryGet("presetnumber")); + chan.Name = data.TryGet("name"); + chan.RawName = chan.Name; + chan.FreqInMhz = ParseInt(data.TryGet("frequency")); + //if ((chan.SignalSource & SignalSource.Analog) != 0) // analog channels have some really strange values (e.g. 00080 - 60512) that I can't convert to a plausible freq range (48-856 MHz) + // chan.FreqInMhz /= 16; + if (chan.FreqInMhz > 1200 && (chan.SignalSource & SignalSource.Sat) == 0) + chan.FreqInMhz /= 1000; + chan.ServiceId = ParseInt(data.TryGet("serviceID")); + chan.OriginalNetworkId = ParseInt(data.TryGet("ONID")); + chan.TransportStreamId = ParseInt(data.TryGet("TSID")); + chan.ServiceType = ParseInt(data.TryGet("serviceType")); + chan.SymbolRate = ParseInt(data.TryGet("symbolrate")) / 1000; + } + #endregion + + #region ParseChannelMapFormat + private void ParseChannelMapFormat(Dictionary data, Channel chan) + { + chan.Format = 2; chan.RawSatellite = data.TryGet("SatelliteName"); chan.Satellite = DecodeName(chan.RawSatellite); chan.OldProgramNr = ParseInt(data.TryGet("ChannelNumber")); @@ -410,26 +438,6 @@ namespace ChanSort.Loader.Philips } #endregion - #region ParseChannelFormat2 - private void ParseChannelFormat2(Dictionary data, Channel chan) - { - chan.Format = 2; - chan.OldProgramNr = ParseInt(data.TryGet("presetnumber")); - chan.Name = data.TryGet("name"); - chan.RawName = chan.Name; - chan.FreqInMhz = ParseInt(data.TryGet("frequency")); - //if ((chan.SignalSource & SignalSource.Analog) != 0) // analog channels have some really strange values (e.g. 00080 - 60512) that I can't convert to a plausible freq range (48-856 MHz) - // chan.FreqInMhz /= 16; - if (chan.FreqInMhz > 1200 && (chan.SignalSource & SignalSource.Sat) == 0) - chan.FreqInMhz /= 1000; - chan.ServiceId = ParseInt(data.TryGet("serviceID")); - chan.OriginalNetworkId = ParseInt(data.TryGet("ONID")); - chan.TransportStreamId = ParseInt(data.TryGet("TSID")); - chan.ServiceType = ParseInt(data.TryGet("serviceType")); - chan.SymbolRate = ParseInt(data.TryGet("symbolrate")) / 1000; - } - #endregion - #region ReadFavList private void ReadFavList(XmlNode node) { @@ -542,15 +550,25 @@ namespace ChanSort.Loader.Philips } if (ch.Format == 1) - this.UpdateChannelFormat1(ch, setFavoriteNumber); + this.UpdateRepairFormat(ch); else if (ch.Format == 2) - this.UpdateChannelFormat2(ch); + this.UpdateChannelMapFormat(ch, setFavoriteNumber); } } #endregion - #region UpdateChannelFormat1 and 2 - private void UpdateChannelFormat1(Channel ch, bool setFavoriteNumber) + #region UpdateRepairFormat() + + private void UpdateRepairFormat(Channel ch) + { + ch.SetupNode.Attributes["presetnumber"].Value = ch.NewProgramNr.ToString(); + if (ch.IsNameModified) + ch.SetupNode.Attributes["name"].Value = ch.Name; + } + #endregion + + #region UpdateChannelMapFormat() + private void UpdateChannelMapFormat(Channel ch, bool setFavoriteNumber) { ch.SetupNode.Attributes["ChannelNumber"].Value = ch.NewProgramNr.ToString(); @@ -574,18 +592,12 @@ namespace ChanSort.Loader.Philips } } - private void UpdateChannelFormat2(Channel ch) - { - ch.SetupNode.Attributes["presetnumber"].Value = ch.NewProgramNr.ToString(); - if (ch.IsNameModified) - ch.SetupNode.Attributes["name"].Value = ch.Name; - } #endregion #region UpdateFavList private void UpdateFavList() { - var favFile = this.fileDataList.FirstOrDefault(fd => Path.GetFileName(fd.path).ToLower() == "favorite.xml"); + var favFile = this.fileDataList.FirstOrDefault(fd => Path.GetFileName(fd.path).ToLowerInvariant() == "favorite.xml"); if (favFile == null) return; @@ -644,7 +656,7 @@ namespace ChanSort.Loader.Philips #region ReorderNodes private void ReorderNodes(FileData file) { - if (file.formatVersion != 1) + if (file.formatVersion != 2) return; var nodes = file.doc.DocumentElement.GetElementsByTagName("Channel"); diff --git a/source/ChanSort.Loader.Samsung/Zip/DbSerializer.cs b/source/ChanSort.Loader.Samsung/Zip/DbSerializer.cs index 973b830..ed35995 100644 --- a/source/ChanSort.Loader.Samsung/Zip/DbSerializer.cs +++ b/source/ChanSort.Loader.Samsung/Zip/DbSerializer.cs @@ -120,7 +120,7 @@ namespace ChanSort.Loader.Samsung.Zip cmd.CommandText = "select name from sqlite_master where type='table'"; using var r = cmd.ExecuteReader(); while (r.Read()) - this.tableNames.Add(r.GetString(0).ToUpper()); + this.tableNames.Add(r.GetString(0).ToUpperInvariant()); if (tableNames.Contains("SAT") && tableNames.Contains("SAT_TP")) return FileType.SatDb; diff --git a/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs b/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs index f8e132b..2e0e1a4 100644 --- a/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs +++ b/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs @@ -11,7 +11,7 @@ namespace ChanSort.Loader.Toshiba public SerializerBase CreateSerializer(string inputFile) { - if (Path.GetExtension(inputFile).ToLower() == ".db") + if (Path.GetExtension(inputFile).ToLowerInvariant() == ".db") return new SettingsDbSerializer(inputFile); else return new ChmgtDbSerializer(inputFile); diff --git a/source/ChanSort.Loader.VDR/Channels.cs b/source/ChanSort.Loader.VDR/Channels.cs index 76826b6..7797737 100644 --- a/source/ChanSort.Loader.VDR/Channels.cs +++ b/source/ChanSort.Loader.VDR/Channels.cs @@ -214,7 +214,7 @@ namespace ChanSort.Loader.VDR #region ParseParams private void ParseParams(String Params) { - Params = Params.ToUpper(); + Params = Params.ToUpperInvariant(); for (int i = 0; i < Params.Length; i++) { switch (Params[i]) diff --git a/source/ChanSort/MainForm.cs b/source/ChanSort/MainForm.cs index 39f61a4..1788f3a 100644 --- a/source/ChanSort/MainForm.cs +++ b/source/ChanSort/MainForm.cs @@ -265,7 +265,7 @@ namespace ChanSort.Ui { filter.Append(plugin.PluginName).Append("|").Append(plugin.FileFilter); filter.Append("|"); - foreach (var ext in plugin.FileFilter.ToLower().Split(';')) + foreach (var ext in plugin.FileFilter.ToLowerInvariant().Split(';')) { if (!(";" + extension + ";").Contains(";" + ext + ";")) { @@ -533,10 +533,10 @@ namespace ChanSort.Ui candidates.Add(hint); else { - var upperFileName = (Path.GetFileName(inputFileName) ?? "").ToUpper(); + var upperFileName = (Path.GetFileName(inputFileName) ?? "").ToLowerInvariant(); foreach (var plugin in this.Plugins) { - foreach (var filter in plugin.FileFilter.ToUpper().Split(';')) + foreach (var filter in plugin.FileFilter.ToLowerInvariant().Split(';')) { var regex = filter.Replace(".", "\\.").Replace("*", ".*").Replace("?", "."); if (Regex.IsMatch(upperFileName, regex)) @@ -966,7 +966,7 @@ namespace ChanSort.Ui fileName = dlg.FileName; } - var ext = (Path.GetExtension(fileName) ?? "").ToLower(); + var ext = (Path.GetExtension(fileName) ?? "").ToLowerInvariant(); if (ext == ".csv") CsvRefListSerializer.Save(fileName, this.DataRoot); else if (ext == ".chl" || ext == ".txt") @@ -1652,7 +1652,7 @@ namespace ChanSort.Ui private void SetFavorite(string fav, bool set) { if (string.IsNullOrEmpty(fav) || !this.mnuFavSet.Enabled) return; - int idx = char.ToUpper(fav[0]) - 'A'; + int idx = char.ToUpperInvariant(fav[0]) - 'A'; if (idx < 0 || idx >= this.mnuFavSet.ItemLinks.Count || this.subListIndex == idx + 1) return; var list = this.GetSelectedChannels(this.lastFocusedGrid); if (list.Count == 0) return; diff --git a/source/ChanSort/XGrid/XGridControl.cs b/source/ChanSort/XGrid/XGridControl.cs index 7948366..e8aab8b 100644 --- a/source/ChanSort/XGrid/XGridControl.cs +++ b/source/ChanSort/XGrid/XGridControl.cs @@ -347,7 +347,7 @@ namespace ChanSort try { this.isExporting = true; - switch ((Path.GetExtension(dlg.FileName) ?? "").ToLower()) + switch ((Path.GetExtension(dlg.FileName) ?? "").ToLowerInvariant()) { case ".xlsx": this.ExportToXlsx(dlg.FileName); diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/get_doc_size.js b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/get_doc_size.js new file mode 100644 index 0000000..b807b4a --- /dev/null +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/get_doc_size.js @@ -0,0 +1,9 @@ +// Copyright (c) 2015 by HHD Software Ltd. +// This file is part of the HHD Software Hex Editor +// For usage and distribution policies, consult the license distributed with a product installation program + +// Get the current document size +function GetDocumentSize() +{ + return document.FileSize; +} diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_mgr_chan_s_fta.db.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_mgr_chan_s_fta.db.h index f3cdeb5..94ce687 100644 --- a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_mgr_chan_s_fta.db.h +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_mgr_chan_s_fta.db.h @@ -1,52 +1,77 @@ #include +struct SHeader +{ + uint32 blockId; + uint32 blockSize; + uint16 u1; + uint16 u2; + uint32 numTvChannels; + uint32 numRadioChannels; + uint32 u3; + uint32 channelBlockId; + uint32 channelBlockSize; +}; + +struct SChannel +{ + uint32 curProgNr; + uint32 u1; + uint8 u2[8]; + uint32 favNr; + union + { + char chName1[200]; +#pragma byte_order (BigEndian) + big_endian wchar_t chName2[100]; +#pragma byte_order () + struct + { + uint8 zero; + wchar_t chName3[99]; + uint8 zero2; + } chName4; + } chName; + uint16 u3; + uint8 u3b[208]; + uint8 u3c[2]; + uint16 u3d; + uint8 u4[10]; + uint16 freqInMhz1; + uint16 u5; + uint16 u6; + uint16 symRate; + uint32 curProgNr2; + uint32 prevProgNr; + uint16 tsid; + uint16 u7; + uint16 sid; + uint16 onid; + uint16 freqInMhz2; + uint16 u9; + uint32 u10; +}; + +struct SFooter +{ + uint32 numDataBlocks; + uint32 numDataBlockBytes; + uint16 bytesumFrom0; + uint16 u_zero; +}; + +#pragma script("get_doc_size.js") + public struct Philips_mgr_chan_s_fta { - uint8 header[64]; - struct - { - uint32 curProgNr; - uint32 u1; - uint8 u2[8]; - uint32 favNr; - union - { - char chName1[200]; -//#pragma byte_order(BigEndian) - big_endian wchar_t chName2[100]; - little_endian wchar_t chName3[100]; - struct - { - uint8 zero; - wchar_t chName3[99]; - uint8 zero2; - } chName4; -//#pragma byte_order(Default) - } chName; - uint16 u3; - uint8 u3b[208]; - uint8 u3c[2]; - uint16 u3d; - uint8 u4[10]; - uint16 freqInMhz1; - uint16 u5; - uint16 u6; - uint16 symRate; - uint32 curProgNr2; - uint32 prevProgNr; - uint16 tsid; - uint16 u7; - uint16 sid; - uint16 onid; - uint16 freqInMhz2; - uint16 u9; - uint32 u10; - } channels[1231]; - struct - { - uint8 u1[8]; - uint16 wordsum; - uint8 u2[2]; - } footer; + var docSize = GetDocumentSize(); + + char filename[32]; + SHeader header; + + var recordCount = header.channelBlockSize / sizeof(SChannel); + SChannel channels[recordCount]; + + SFooter footer; }; \ No newline at end of file diff --git a/source/Test.Loader.Philips/PhilipsXmlTest.cs b/source/Test.Loader.Philips/PhilipsXmlTest.cs index fa31496..f7e5cc9 100644 --- a/source/Test.Loader.Philips/PhilipsXmlTest.cs +++ b/source/Test.Loader.Philips/PhilipsXmlTest.cs @@ -8,34 +8,34 @@ namespace Test.Loader.Philips [TestClass] public class PhilipsXmlTest { - #region TestFormat1SatChannelsAddedToCorrectLists + #region TestRepairFormatCableChannelsAddedToCorrectLists [TestMethod] - public void TestFormat1SatChannelsAddedToCorrectLists() + public void TestRepairFormatCableChannelsAddedToCorrectLists() + { + // this file format doesn't provide any information whether a channel is TV/radio/data or analog/digital. It only contains the "medium" for antenna/cable/sat + var file = TestUtils.DeploymentItem("Test.Loader.Philips\\TestFiles") + "\\Repair\\CM_TPM1013E_LA_CK.xml"; + this.TestChannelsAddedToCorrectLists(file, SignalSource.DvbC, 483, 0, 0); + } + #endregion + + #region TestChannelMapFormatSatChannelsAddedToCorrectLists + [TestMethod] + public void TestChannelMapFormatSatChannelsAddedToCorrectLists() { var file = TestUtils.DeploymentItem("Test.Loader.Philips\\TestFiles") + "\\ChannelMap_100\\ChannelList\\chanLst.bin"; this.TestChannelsAddedToCorrectLists(file, SignalSource.DvbS, 502, 350, 152); } #endregion - #region TestFormat1CableChannelsAddedToCorrectLists + #region TestChannelMapFormatCableChannelsAddedToCorrectLists [TestMethod] - public void TestFormat1CableChannelsAddedToCorrectLists() + public void TestChannelMapFormatCableChannelsAddedToCorrectLists() { var file = TestUtils.DeploymentItem("Test.Loader.Philips\\TestFiles") + "\\ChannelMap_100\\ChannelList\\chanLst.bin"; this.TestChannelsAddedToCorrectLists(file, SignalSource.DvbC, 459, 358, 101); } #endregion - #region TestFormat2CableChannelsAddedToCorrectLists - [TestMethod] - public void TestFormat2CableChannelsAddedToCorrectLists() - { - // this file format doesn't provide any information whether a channel is TV/radio/data or analog/digital. It only contains the "medium" for antenna/cable/sat - var file = TestUtils.DeploymentItem("Test.Loader.Philips\\TestFiles") + "\\Repair\\CM_TPM1013E_LA_CK.xml"; - this.TestChannelsAddedToCorrectLists(file, SignalSource.DvbC, 483, 0, 0); - } - #endregion - #region TestChannelsAddedToCorrectList private void TestChannelsAddedToCorrectLists(string filePath, SignalSource signalSource, int expectedTotal, int expectedTv, int expectedRadio) diff --git a/source/changelog.md b/source/changelog.md index fe4ff6e..945c834 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,11 +1,16 @@ ChanSort Change Log =================== -TBD +2021-08-31 +- ChanSort didn't work properly for Turkish (and other system locales) that don't translate ".bin" to uppercase + ".BIN" and ".BIN" to lowercase ".bin". - Sony: Files with incorrect checksum are no longer rejected. Information about a bad checksum is visible unter File / File Information. (The TV seems to ignore bad checksums during the import and the official Sony PC Editor ignores bad checksums and write incorrect ones, depending on the file format version) -- Philips: experimental support for Repair\mgr_chan_s_fta.db file format (DVB-S only) +- Philips: Removing a channel from a list is no longer possible (because it is not supported by the TV's import). + When saving a file, all unsorted channels will be placed at the end of the list. +- Added read-only support for Philips Repair\\Mgr_chan_s_fta.db lists. Files can be used as a reference list, + but modifying them won't be possible. - Updated Hungarian translation. Thanks to efi99 on Github! 2021-07-27