diff --git a/source/ChanSort.Api/Utils/DvbStringDecoder.cs b/source/ChanSort.Api/Utils/DvbStringDecoder.cs index 1267956..1f9610f 100644 --- a/source/ChanSort.Api/Utils/DvbStringDecoder.cs +++ b/source/ChanSort.Api/Utils/DvbStringDecoder.cs @@ -90,7 +90,15 @@ namespace ChanSort.Api public Encoding DefaultEncoding { get; set; } #region GetChannelNames() + public void GetChannelNames(byte[] name, int off, int len, out string longName, out string shortName) + { + this.GetChannelNamesCore(name, off, len, out longName, out shortName); + longName = longName.TrimGarbage(); + shortName = shortName.TrimGarbage(); + } + + private void GetChannelNamesCore(byte[] name, int off, int len, out string longName, out string shortName) { longName = ""; shortName = ""; diff --git a/source/ChanSort.Api/Utils/Tools.cs b/source/ChanSort.Api/Utils/Tools.cs index 4c85962..fc71736 100644 --- a/source/ChanSort.Api/Utils/Tools.cs +++ b/source/ChanSort.Api/Utils/Tools.cs @@ -215,5 +215,14 @@ namespace ChanSort.Api } #endregion + public static string TrimGarbage(this string input) + { + if (input == null) return null; + var i = input.IndexOf('\0'); + if (i >= 0) + return input.Substring(0, i); + return input; + } + } } diff --git a/source/ChanSort.Loader.Philips/BinarySerializer.cs b/source/ChanSort.Loader.Philips/BinarySerializer.cs index 5f001b3..77be72d 100644 --- a/source/ChanSort.Loader.Philips/BinarySerializer.cs +++ b/source/ChanSort.Loader.Philips/BinarySerializer.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Data; +using System.Data.SQLite; using System.IO; using System.Linq; using System.Reflection; @@ -9,6 +11,9 @@ using ChanSort.Api; namespace ChanSort.Loader.Philips { /* + + This loader handles the file format versions 1.x (*Table and *.dat files) and version 25.x-45.x (*Db.bin files) + channellib\CableDigSrvTable: =========================== Channels in this file are not physically ordered by the program number and there is no linked list with prev/next indexes. @@ -92,37 +97,42 @@ namespace ChanSort.Loader.Philips #region Load() public override void Load() { - if (!SetFileNameToChanLstBin()) - throw new FileLoadException("Unsupported folder structure. Required files are:\n" - + "ChannelList\\chanLst.bin\n" - + "ChannelList\\channellib\\CableDigSrvTable\n" - + "ChannelList\\s2channellib\\service.dat"); - this.chanLstBin = new ChanLstBin(); this.chanLstBin.Load(this.FileName, msg => this.logMessages.AppendLine(msg)); + this.dataFilePaths.Add(this.FileName); + + if (chanLstBin.VersionMajor >= 25 && chanLstBin.VersionMajor <= 45) // need VC2010 Redist for the SQLite library + DepencencyChecker.AssertVc2010RedistPackageX86Installed(); var dir = Path.GetDirectoryName(this.FileName) ?? ""; var channellib = Path.Combine(dir, "channellib"); var s2channellib = Path.Combine(dir, "s2channellib"); - // channellib files for DVB-C/T in version 1.1 and 1.2 - LoadDvbCT(dvbtChannels, Path.Combine(channellib, "AntennaDigSrvTable"), "CableDigSrvTable_entry"); - LoadDvbCTPresets(dvbtChannels, Path.Combine(channellib, "AntennaPresetTable")); - LoadDvbCT(dvbcChannels, Path.Combine(channellib, "CableDigSrvTable"), "CableDigSrvTable_entry"); - LoadDvbCTPresets(dvbcChannels, Path.Combine(channellib, "CablePresetTable")); + if (chanLstBin.VersionMajor <= 11) + { + LoadDvbCT(dvbtChannels, Path.Combine(channellib, "AntennaDigSrvTable"), "CableDigSrvTable_entry"); + LoadDvbCTPresets(dvbtChannels, Path.Combine(channellib, "AntennaPresetTable")); + LoadDvbCT(dvbcChannels, Path.Combine(channellib, "CableDigSrvTable"), "CableDigSrvTable_entry"); + LoadDvbCTPresets(dvbcChannels, Path.Combine(channellib, "CablePresetTable")); - // s2channellib files for DVB-S in version 1.1 and 1.2 - LoadDvbsSatellites(Path.Combine(s2channellib, "satellite.dat")); - LoadDvbsTransponders(Path.Combine(s2channellib, "tuneinfo.dat")); - LoadDvbS(satChannels, Path.Combine(s2channellib, "service.dat"), "service.dat_entry"); - LoadDvbsFavorites(Path.Combine(s2channellib, "favorite.dat")); - var db_file_info = Path.Combine(s2channellib, "db_file_info.dat"); - if (File.Exists(db_file_info)) - this.dataFilePaths.Add(db_file_info); - - // version 45 - if (chanLstBin.VersionMajor == 45) - LoadDvbS(satChannels, Path.Combine(s2channellib, "SatelliteDb.bin"), "Map45_SatelliteDb_entry"); + LoadDvbsSatellites(Path.Combine(s2channellib, "satellite.dat")); + LoadDvbsTransponders(Path.Combine(s2channellib, "tuneinfo.dat")); + LoadDvbS(satChannels, Path.Combine(s2channellib, "service.dat"), "service.dat_entry"); + LoadDvbsFavorites(Path.Combine(s2channellib, "favorite.dat")); + var db_file_info = Path.Combine(s2channellib, "db_file_info.dat"); + if (File.Exists(db_file_info)) + this.dataFilePaths.Add(db_file_info); + } + else if (chanLstBin.VersionMajor >= 25 && chanLstBin.VersionMajor <= 45) + { + // version 25-45 + LoadDvbCT(dvbtChannels, Path.Combine(channellib, "TerrestrialDb.bin"), "Map45_CableDb.bin_entry"); + LoadDvbCT(dvbcChannels, Path.Combine(channellib, "CableDb.bin"), "Map45_CableDb.bin_entry"); + LoadDvbS(satChannels, Path.Combine(s2channellib, "SatelliteDb.bin"), "Map45_SatelliteDb.bin_entry"); + var tvDbFile = Path.Combine(dir, "tv.db"); + if (File.Exists(tvDbFile)) + this.dataFilePaths.Add(tvDbFile); + } // for a proper ChanSort backup/restore with .bak files, the Philips _backup.dat files must also be included foreach (var file in this.dataFilePaths.ToList()) @@ -131,36 +141,8 @@ namespace ChanSort.Loader.Philips this.dataFilePaths.Add(file.Replace(".dat", "_backup.dat")); } } - #endregion - #region SetFileNameToChanLstBin() - private bool SetFileNameToChanLstBin() - { - var dir = Path.GetDirectoryName(this.FileName) ?? ""; - var dirName = Path.GetFileName(dir); - if (StringComparer.InvariantCultureIgnoreCase.Compare(dirName, "channellib") == 0 || StringComparer.InvariantCultureIgnoreCase.Compare(dirName, "s2channellib") == 0) - { - dir = Path.GetDirectoryName(dir) ?? ""; - dirName = Path.GetFileName(dir); - } - - if (StringComparer.InvariantCultureIgnoreCase.Compare(dirName, "ChannelList") != 0) - return false; - - var chanLstBin = Path.Combine(dir, "chanLst.bin"); - if (!File.Exists(chanLstBin)) - return false; - - if (!File.Exists(Path.Combine(dir, "channellib", "CableDigSrvTable"))) - return false; - if (!File.Exists(Path.Combine(dir, "s2channellib", "service.dat"))) - return false; - - this.FileName = chanLstBin; // this file is used as a fixed reference point for the whole directory structure - return true; - } - #endregion #region LoadDvbCT private void LoadDvbCT(ChannelList list, string path, string mappingName) @@ -169,7 +151,7 @@ namespace ChanSort.Loader.Philips return; var mapping = new DataMapping(this.ini.GetSection(mappingName)); - mapping.SetDataPtr(data, 20); + mapping.SetDataPtr(data, chanLstBin.VersionMajor <= 11 ? 20 : 12); for (int i = 0; i < recordCount; i++, mapping.BaseOffset += recordSize) { @@ -187,13 +169,17 @@ namespace ChanSort.Loader.Philips } string channelName = Encoding.Unicode.GetString(data, offChannelName, lenName); - var checksum = mapping.GetDword("offChecksum"); - mapping.SetDword("offChecksum", 0); - var crc = FaultyCrc32(data, mapping.BaseOffset + mapping.GetConst("offChecksum", 0), recordSize); - if (crc != checksum) - throw new FileLoadException($"Invalid CRC in record {i} in {path}"); + if (chanLstBin.VersionMajor <= 11) + { + var checksum = mapping.GetDword("offChecksum"); + mapping.SetDword("offChecksum", 0); + var crc = FaultyCrc32(data, mapping.BaseOffset + mapping.GetConst("offChecksum", 0), recordSize); + if (crc != checksum) + throw new FileLoadException($"Invalid CRC in record {i} in {path}"); + } var ch = new Channel(list.SignalSource, i, progNr, channelName); + ch.Id = mapping.GetWord("offId"); // only relevant for ChannelMap45 ch.FreqInMhz = (decimal) mapping.GetWord("offFreqTimes16") / 16; ch.OriginalNetworkId = mapping.GetWord("offOnid"); ch.TransportStreamId = mapping.GetWord("offTsid"); @@ -254,13 +240,27 @@ namespace ChanSort.Loader.Philips return false; data = File.ReadAllBytes(path); - if (data.Length < 20) - return false; + if (chanLstBin.VersionMajor <= 11) + { + if (data.Length < 20) + return false; + + recordSize = BitConverter.ToInt32(data, 8); + recordCount = BitConverter.ToInt32(data, 12); + if (data.Length != 20 + recordCount * recordSize) + throw new FileLoadException("Unsupported file content: " + path); + } + else + { + if (data.Length < 12) + return false; + + recordSize = 156; // Map45 + recordCount = BitConverter.ToInt32(data, 8); + if (data.Length != 12 + recordCount * recordSize) + throw new FileLoadException("Unsupported file content: " + path); + } - recordSize = BitConverter.ToInt32(data, 8); - recordCount = BitConverter.ToInt32(data, 12); - if (data.Length != 20 + recordCount * recordSize) - throw new FileLoadException("Unsupported file content: " + path); this.dataFilePaths.Add(path); return true; @@ -296,7 +296,8 @@ namespace ChanSort.Loader.Philips var s = new Satellite(i); var pos = (sbyte)data[baseOffset + 8]; s.OrbitalPosition = pos < 0 ? -pos + "W" : pos + "E"; - s.Name = this.DefaultEncoding.GetString(data, baseOffset + 16, 16).TrimEnd('\0'); + s.Name = this.DefaultEncoding.GetString(data, baseOffset + 16, 16).TrimGarbage(); + this.DataRoot.AddSatellite(s); } } @@ -350,10 +351,12 @@ namespace ChanSort.Loader.Philips return; var data = File.ReadAllBytes(path); - if (data.Length < 4) + if (data.Length < 12) return; - if (chanLstBin.VersionMajor == 1) + var version = chanLstBin.VersionMajor; + + if (version <= 11) { var checksum = BitConverter.ToUInt32(data, data.Length - 4); @@ -366,8 +369,10 @@ namespace ChanSort.Loader.Philips int recordSize = BitConverter.ToInt32(data, 4); int recordCount = BitConverter.ToInt32(data, 8); + if (recordSize == 0 && version != 1) + recordSize = recordCount == 0 ? 0 : (data.Length - 12) / recordCount; - if (chanLstBin.VersionMajor == 1) + if (chanLstBin.VersionMajor <= 11) { // 12 bytes header, then a "next/prev" table, then the service records, then a CRC32 // the "next/prev" table is a ring-list, every entry consists of 2 ushorts with the next and previous channel, wrapping around on the ends @@ -380,7 +385,7 @@ namespace ChanSort.Loader.Philips var dvbStringDecoder = new DvbStringDecoder(this.DefaultEncoding); var mapping = new DataMapping(this.ini.GetSection(mappingName)); - mapping.SetDataPtr(data, 12 + recordCount * 4); + mapping.SetDataPtr(data, 12 + (chanLstBin.VersionMajor <= 11 ? recordCount * 4 : 0)); for (int i = 0; i < recordCount; i++, mapping.BaseOffset += recordSize) { var ch = LoadDvbsChannel(list, mapping, i, dvbStringDecoder); @@ -394,7 +399,7 @@ namespace ChanSort.Loader.Philips { var transponderId = mapping.GetWord("offTransponderIndex"); var progNr = mapping.GetWord("offProgNr"); - var ch = new ChannelInfo(list.SignalSource, recordIndex, progNr, null); + var ch = new Channel(list.SignalSource, recordIndex, progNr, ""); // deleted channels must be kept in the list because their records must also be physically reordered when saving the list if (progNr == 0xFFFF || transponderId == 0xFFFF) @@ -413,14 +418,24 @@ namespace ChanSort.Loader.Philips ch.VideoPid = mapping.GetWord("offVpid") & mapping.GetMask("maskVpid"); ch.Favorites = mapping.GetFlag("IsFav") ? Favorites.A : 0; ch.OldProgramNr = progNr; + ch.Id = mapping.GetWord("offId"); // relevant for ChannelMap45 - // the 0x1F as the first byte of the channel name is likely the DVB encoding indicator for UTF-8. So we use the DvbStringDecoder here - dvbStringDecoder.GetChannelNames(mapping.Data, mapping.BaseOffset + mapping.GetConst("offName", 0), mapping.GetConst("lenName", 0), out var longName, out var shortName); - ch.Name = longName.TrimEnd('\0'); - ch.ShortName = shortName.TrimEnd('\0'); + if (chanLstBin.VersionMajor <= 11) + { + // the 0x1F as the first byte of the channel name is likely the DVB encoding indicator for UTF-8. So we use the DvbStringDecoder here + dvbStringDecoder.GetChannelNames(mapping.Data, mapping.BaseOffset + mapping.GetConst("offName", 0), mapping.GetConst("lenName", 0), out var longName, out var shortName); + ch.Name = longName; + ch.ShortName = shortName; + } + else + { + ch.Name = Encoding.Unicode.GetString(mapping.Data, mapping.BaseOffset + mapping.GetConst("offName", 0), mapping.GetConst("lenName", 0)).TrimEnd('\0'); + ch.FreqInMhz = mapping.GetWord("offFreq"); + ch.SymbolRate = (int)(mapping.GetDword("offSymbolRate") / 1000); + } dvbStringDecoder.GetChannelNames(mapping.Data, mapping.BaseOffset + mapping.GetConst("offProvider", 0), mapping.GetConst("lenProvider", 0), out var provider, out _); - ch.Provider = provider.TrimEnd('\0'); + ch.Provider = provider; // copy values from the satellite/transponder tables to the channel if (this.DataRoot.Transponder.TryGetValue(transponderId, out var t)) @@ -495,14 +510,25 @@ namespace ChanSort.Loader.Philips var channellib = Path.Combine(dir, "channellib"); var s2channellib = Path.Combine(dir, "s2channellib"); - SaveDvbCTChannels(this.dvbtChannels, Path.Combine(channellib, "AntennaDigSrvTable")); - SaveDvbCTPresets(this.dvbtChannels, Path.Combine(channellib, "AntennaPresetTable")); - SaveDvbCTChannels(this.dvbcChannels, Path.Combine(channellib, "CableDigSrvTable")); - SaveDvbCTPresets(this.dvbcChannels, Path.Combine(channellib, "CablePresetTable")); + if (chanLstBin.VersionMajor <= 11) + { + SaveDvbCTChannels(this.dvbtChannels, Path.Combine(channellib, "AntennaDigSrvTable")); + SaveDvbCTPresets(this.dvbtChannels, Path.Combine(channellib, "AntennaPresetTable")); + SaveDvbCTChannels(this.dvbcChannels, Path.Combine(channellib, "CableDigSrvTable")); + SaveDvbCTPresets(this.dvbcChannels, Path.Combine(channellib, "CablePresetTable")); - SaveDvbsChannels(Path.Combine(s2channellib, "service.dat")); - SaveDvbsFavorites(Path.Combine(s2channellib, "favorite.dat")); - SaveDvbsDbFileInfo(Path.Combine(s2channellib, "db_file_info.dat")); + SaveDvbsChannels(Path.Combine(s2channellib, "service.dat")); + SaveDvbsFavorites(Path.Combine(s2channellib, "favorite.dat")); + SaveDvbsDbFileInfo(Path.Combine(s2channellib, "db_file_info.dat")); + } + else if (chanLstBin.VersionMajor >= 25 && chanLstBin.VersionMajor <= 45) + { + SaveDvbCTChannels(this.dvbtChannels, Path.Combine(channellib, "TerrestrialDb.bin")); + SaveDvbCTChannels(this.dvbcChannels, Path.Combine(channellib, "CableDb.bin")); + SaveDvbsChannels(Path.Combine(s2channellib, "SatelliteDb.bin")); + + UpdateChannelMap45TvDb(); + } this.chanLstBin.Save(this.FileName); } @@ -515,18 +541,38 @@ namespace ChanSort.Loader.Philips if (!ReadAndValidateChannellibFile(path, out var data, out var recordSize, out _)) return; - var mapping = new DataMapping(this.ini.GetSection("CableDigSrvTable_entry")); - mapping.SetDataPtr(data, 20); + int baseOffset; + DataMapping mapping; + + if (chanLstBin.VersionMajor <= 11) + { + mapping = new DataMapping(this.ini.GetSection("CableDigSrvTable_entry")); + baseOffset = 20; + } + else + { + mapping = new DataMapping(this.ini.GetSection("Map45_CableDb.bin_entry")); + baseOffset = 12; + } + mapping.SetDataPtr(data, baseOffset); foreach (var ch in list.Channels) { - mapping.BaseOffset = 20 + (int)ch.RecordIndex * recordSize; + if (ch.IsProxy) continue; + mapping.BaseOffset = baseOffset + (int)ch.RecordIndex * recordSize; mapping.SetWord("offProgNr", ch.NewProgramNr); mapping.SetByte("offLocked", ch.Lock ? 1 : 0); mapping.SetByte("offIsFav", ch.Favorites == 0 ? 0 : 1); - mapping.SetDword("offChecksum", 0); - var crc = FaultyCrc32(data, mapping.BaseOffset, recordSize); - mapping.SetDword("offChecksum", crc); + if (chanLstBin.VersionMajor <= 11) + { + mapping.SetDword("offChecksum", 0); + var crc = FaultyCrc32(data, mapping.BaseOffset, recordSize); + mapping.SetDword("offChecksum", crc); + } + else if (chanLstBin.VersionMajor >= 25 && chanLstBin.VersionMajor <= 45) + { + mapping.SetWord("offServiceEdit", 1); + } } File.WriteAllBytes(path, data); @@ -564,16 +610,32 @@ namespace ChanSort.Loader.Philips private void SaveDvbsChannels(string path) { var orig = File.ReadAllBytes(path); - int recordSize = BitConverter.ToInt32(orig, 4); - int recordCount = BitConverter.ToInt32(orig, 8); - + // create a new array for the modified data, copying the header and next/prev table var data = new byte[orig.Length]; - Array.Copy(orig, data, 12 + recordCount * 4); - var baseOffset = 12 + recordCount * 4; + int recordCount = BitConverter.ToInt32(orig, 8); + int recordSize; + int baseOffset; + DataMapping mapping; - var mapping = new DataMapping(this.ini.GetSection("service.dat_entry")); + if (chanLstBin.VersionMajor <= 11) + { + recordSize = BitConverter.ToInt32(orig, 4); + baseOffset = 12 + recordCount * 4; + mapping = new DataMapping(this.ini.GetSection("service.dat_entry")); + } + else + { + recordSize = recordCount == 0 ? 0 : (orig.Length - 12) / recordCount; + baseOffset = 12; + mapping = new DataMapping(this.ini.GetSection("Map45_SatelliteDb.bin_entry")); + } + + if (recordCount == 0) + return; + + Array.Copy(orig, data, baseOffset); mapping.SetDataPtr(data, baseOffset); // copy physical records to bring them in the new order and update fields like progNr @@ -594,18 +656,22 @@ namespace ChanSort.Loader.Philips mapping.SetWord("offProgNr", ch.NewProgramNr); mapping.SetFlag("IsFav", ch.Favorites != 0); mapping.SetFlag("Locked", ch.Lock); + mapping.SetWord("offServiceEdit", 1); } ch.RecordIndex = i++; // required so that subsequent saves don't reshuffle the records } + if (chanLstBin.VersionMajor <= 11) + { + var crc32 = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4); + data.SetInt32(data.Length - 4, (int) crc32); + + var backupFile = path.Replace(".dat", "_backup.dat"); + File.WriteAllBytes(backupFile, data); + } - var crc32 = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4); - data.SetInt32(data.Length-4, (int)crc32); File.WriteAllBytes(path, data); - - var backupFile = path.Replace(".dat", "_backup.dat"); - File.WriteAllBytes(backupFile, data); } #endregion @@ -667,6 +733,47 @@ namespace ChanSort.Loader.Philips } #endregion + #region UpdateChannelMap45TvDb() + private void UpdateChannelMap45TvDb() + { + var tvDb = Path.Combine(Path.GetDirectoryName(this.FileName) ?? "", "tv.db"); + if (!File.Exists(tvDb)) + return; + + using var conn = new SQLiteConnection($"Data Source={tvDb}"); + conn.Open(); + using var trans = conn.BeginTransaction(); + using var cmd = conn.CreateCommand(); + cmd.CommandText = "update channels set display_number=@prNum, display_name=@name, browsable=@browsable, locked=@locked where _id=@id"; + cmd.Parameters.Clear(); + cmd.Parameters.Add(new SQLiteParameter("@id", DbType.Int32)); + cmd.Parameters.Add(new SQLiteParameter("@prNum", DbType.Int32)); + cmd.Parameters.Add(new SQLiteParameter("@name", DbType.String)); + cmd.Parameters.Add(new SQLiteParameter("@browsable", DbType.Int32)); + cmd.Parameters.Add(new SQLiteParameter("@locked", DbType.Int32)); + cmd.Prepare(); + foreach (var list in this.DataRoot.ChannelLists) + { + foreach (var chan in list.Channels) + { + if (!(chan is Channel ch)) + continue; + cmd.Parameters["@id"].Value = ch.Id; + cmd.Parameters["@prNum"].Value = ch.NewProgramNr; + cmd.Parameters["@name"].Value = ch.Name; + cmd.Parameters["@browsable"].Value = ch.Skip ? 0 : 1; + cmd.Parameters["@locked"].Value = ch.Lock ? 1 : 0; + + var res = cmd.ExecuteNonQuery(); + if (res == 0) + this.logMessages.AppendFormat($"Could not update record with id {ch.Id} in tv.db service table"); + } + } + trans.Commit(); + conn.Close(); + } + #endregion + #region FaultyCrc32 public static uint FaultyCrc32(byte[] bytes, int start, int count) diff --git a/source/ChanSort.Loader.Philips/ChanLstBin.cs b/source/ChanSort.Loader.Philips/ChanLstBin.cs index f71816d..95d70d1 100644 --- a/source/ChanSort.Loader.Philips/ChanLstBin.cs +++ b/source/ChanSort.Loader.Philips/ChanLstBin.cs @@ -54,7 +54,7 @@ namespace ChanSort.Loader.Philips var modelNameLen = BitConverter.ToInt32(content, off); off += 4 + modelNameLen; - var baseDir = Path.GetDirectoryName(path); + var baseDir = Path.GetDirectoryName(path) ?? ""; var relPath = "/channellib/"; while (off < content.Length) { @@ -67,6 +67,7 @@ namespace ChanSort.Loader.Philips else { // normally all files after the /s2channellib/ entry are inside that folder, but "Favorite.xml" is in the main folder + // in ChannelMap45 there is also tv.db and list.db in the main folder var newPath = relPath + fileName; if (!File.Exists(Path.Combine(baseDir, newPath)) && File.Exists(Path.Combine(baseDir, fileName))) newPath = "/" + fileName; @@ -92,9 +93,18 @@ namespace ChanSort.Loader.Philips var filePath = baseDir + entry.Key; if (!File.Exists(filePath)) + { + errors += $"\nchanLst.bin: file not found in directory structure: {entry.Key}"; continue; + } + var data = File.ReadAllBytes(filePath); - var length = Math.Min(data.Length, VersionMajor <= 12 ? 0x6000 : 0x145A00); + var length = data.Length; + if (VersionMajor < 12 && length > 0x6000) + length = 0x6000; // there might be another cap at 0x013FA000 + 0x6000 in some versions + //if (length > 0x0140000) + // length = 0x0140000; + var actualCrc = Crc16.Calc(data, 0, length); if (actualCrc != expectedCrc) { @@ -104,10 +114,7 @@ namespace ChanSort.Loader.Philips } if (errors != "") - { - this.log.Invoke(errors); - //throw new FileLoadException(errors); - } + this.log?.Invoke(errors); } public void Save(string chanLstBinPath) @@ -117,7 +124,9 @@ namespace ChanSort.Loader.Philips { var path = baseDir + entry.Key; var data = File.ReadAllBytes(path); - var length = Math.Min(data.Length, VersionMajor <= 12 ? 0x6000 : 0x145A00); + var length = data.Length; + if (VersionMajor < 12 && length > 0x6000) + length = 0x6000; // there might be another cap at 0x013FA000 + 0x6000 in some versions var crc = Crc16.Calc(data, 0, length); var off = entry.Value; content[off] = (byte) crc; diff --git a/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.csproj b/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.csproj index 3684e8e..6dd8bb9 100644 --- a/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.csproj +++ b/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.csproj @@ -56,11 +56,13 @@ + + ..\DLL\System.Data.SQLite.dll + - @@ -79,9 +81,9 @@ - + Always - + \ No newline at end of file diff --git a/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.ini b/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.ini index 26977ef..3b8e074 100644 --- a/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.ini +++ b/source/ChanSort.Loader.Philips/ChanSort.Loader.Philips.ini @@ -47,7 +47,7 @@ offFreq=18 # ChannelMap_45 format -[Map45_SatelliteDbBin_entry] +[Map45_CableDb.bin_entry] offId=0 offFreq=4 offProgNr=8 @@ -61,7 +61,26 @@ offScrambleStat=36 offLocked=40 offModulateion=44 offServiceType=52 +offServiceEdit=58 +offName=88 +lenName=64 + +[Map45_SatelliteDb.bin_entry] +offId=0 +offFreq=4 +offProgNr=8 +offAnalogUid=12 +offOnid=16 +offTsid=20 +offSid=24 +offSymbolRate=28 +offLogoNr=32 +offScrambleStat=36 +offLocked=40 +offModulateion=44 +offServiceType=52 +offServiceEdit=58 offName=80 lenName=64 offSatName=146 -lenSatName=64 \ No newline at end of file +lenSatName=64 diff --git a/source/ChanSort.Loader.Philips/Channel.cs b/source/ChanSort.Loader.Philips/Channel.cs index 70ef0b1..c2d9ac5 100644 --- a/source/ChanSort.Loader.Philips/Channel.cs +++ b/source/ChanSort.Loader.Philips/Channel.cs @@ -7,6 +7,7 @@ namespace ChanSort.Loader.Philips { public Channel(SignalSource source, long index, int oldProgNr, string name) : base(source, index, oldProgNr, name) { + this.RecordOrder = (int)index; } internal Channel(SignalSource source, int order, int rowId, XmlNode setupNode) @@ -27,6 +28,7 @@ namespace ChanSort.Loader.Philips public string RawName; public string RawSatellite; public int Format; + public int Id; // links entries in the ChannelMap45/*Db.bin files with the entries in the tv.db channels table } } diff --git a/source/ChanSort.Loader.Philips/PhilipsLoader.cs b/source/ChanSort.Loader.Philips/PhilipsLoader.cs index 00e3fbd..2eecd01 100644 --- a/source/ChanSort.Loader.Philips/PhilipsLoader.cs +++ b/source/ChanSort.Loader.Philips/PhilipsLoader.cs @@ -29,7 +29,7 @@ namespace ChanSort.Loader.Philips * e.g. 32PFL5806K/02, 42PFL7656K/02 * * version 1.2 - * same as version 1.1 + * same as version 1.1 for most parts, but different tuneinfo.dat format * e.g. 32PFL5507K/12, 42PFL4317K/12, 32PFL5507K/12 * * version 11.1 @@ -112,10 +112,10 @@ namespace ChanSort.Loader.Philips if (majorVersion == 0 || majorVersion >= 100 && majorVersion <= 110) return new XmlSerializer(inputFile); - if (majorVersion == 1) + if (majorVersion == 1 || majorVersion == 45) // || majorVersion == 11 // format version 11 is similar to 1.x, but not (yet) supported return new BinarySerializer(inputFile); - throw new FileLoadException($"Selected file must be either chanLst.bin or CM_*.xml/.bin"); + throw new FileLoadException($"Philips ChannelMap format version {majorVersion} is not supported."); } } } diff --git a/source/ChanSort.Loader.Philips/XmlSerializer.cs b/source/ChanSort.Loader.Philips/XmlSerializer.cs index 18e00de..a77fd74 100644 --- a/source/ChanSort.Loader.Philips/XmlSerializer.cs +++ b/source/ChanSort.Loader.Philips/XmlSerializer.cs @@ -245,6 +245,12 @@ namespace ChanSort.Loader.Philips medium = fname; bool hasEncrypt = false; + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove("ServiceType"); + list.VisibleColumnFieldNames.Add("ServiceTypeName"); + } + if (setupNode.HasAttribute("ChannelName")) { file.formatVersion = 1; @@ -271,7 +277,6 @@ namespace ChanSort.Loader.Philips list.VisibleColumnFieldNames.Remove("Favorites"); list.VisibleColumnFieldNames.Remove("Lock"); list.VisibleColumnFieldNames.Remove("Hidden"); - list.VisibleColumnFieldNames.Remove("ServiceType"); list.VisibleColumnFieldNames.Remove("ServiceTypeName"); list.VisibleColumnFieldNames.Remove("Encrypted"); } @@ -354,11 +359,9 @@ namespace ChanSort.Loader.Philips chan.TransportStreamId = ParseInt(data.TryGet("Tsid")); chan.ServiceId = ParseInt(data.TryGet("Sid")); chan.FreqInMhz = ParseInt(data.TryGet("Frequency")); ; - if (chan.FreqInMhz > 2000) + if (chan.FreqInMhz > 2000 && (chan.SignalSource & SignalSource.Sat) == 0) chan.FreqInMhz /= 1000; - if (chan.FreqInMhz > 2000) - chan.FreqInMhz /= 1000; - chan.ServiceType = ParseInt(data.TryGet("ServiceType")); + chan.ServiceTypeName = ParseInt(data.TryGet("ServiceType")) == 1 ? "TV" : "Radio"; var decoderType = data.TryGet("DecoderType"); if (decoderType == "1") chan.Source = "DVB-T"; @@ -366,6 +369,8 @@ namespace ChanSort.Loader.Philips chan.Source = "DVB-C"; chan.SignalSource |= LookupData.Instance.IsRadioTvOrData(chan.ServiceType); chan.SymbolRate = ParseInt(data.TryGet("SymbolRate")); + if (chan.SymbolRate > 100000) // DVB-S stores values in kSym, DVB-C stores it in Sym, DVB-T stores 0 + chan.SymbolRate /= 1000; if (data.TryGetValue("Polarization", out var pol)) chan.Polarity = pol == "0" ? 'H' : 'V'; chan.Hidden |= data.TryGet("SystemHidden") == "1"; @@ -382,9 +387,9 @@ namespace ChanSort.Loader.Philips chan.Name = data.TryGet("name"); chan.RawName = chan.Name; chan.FreqInMhz = ParseInt(data.TryGet("frequency")); - //if ((chan.SignalSource & SignalSource.Analog) != 0) + //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) + if (chan.FreqInMhz > 1200 && (chan.SignalSource & SignalSource.Sat) == 0) chan.FreqInMhz /= 1000; chan.ServiceId = ParseInt(data.TryGet("serviceID")); chan.OriginalNetworkId = ParseInt(data.TryGet("ONID")); @@ -444,42 +449,12 @@ namespace ChanSort.Loader.Philips foreach (var part in hexParts) { - if (part == "" || part == "0x00") + if (part == "") continue; buffer.WriteByte((byte)ParseInt(part)); } - return this.DefaultEncoding.GetString(buffer.GetBuffer(), 0, (int)buffer.Length); - } - #endregion - - #region DefaultEncoding - public override Encoding DefaultEncoding - { - get => base.DefaultEncoding; - set - { - if (value == this.DefaultEncoding) - return; - base.DefaultEncoding = value; - this.ChangeEncoding(); - } - } - #endregion - - #region ChangeEncoding - private void ChangeEncoding() - { - foreach (var list in this.DataRoot.ChannelLists) - { - foreach (var channel in list.Channels) - { - if (!(channel is Channel ch)) - continue; - ch.Name = this.DecodeName(ch.RawName); - ch.Satellite = this.DecodeName(ch.RawSatellite); - } - } + return Encoding.Unicode.GetString(buffer.GetBuffer(), 0, (int) buffer.Length).TrimEnd('\x0'); } #endregion @@ -518,7 +493,7 @@ namespace ChanSort.Loader.Philips { // by default .NET reformats the whole XML. These settings produce almost same format as the TV xml files use var xmlSettings = new XmlWriterSettings(); - xmlSettings.Encoding = this.DefaultEncoding; + xmlSettings.Encoding = new UTF8Encoding(false); xmlSettings.CheckCharacters = false; xmlSettings.Indent = true; xmlSettings.IndentChars = " "; @@ -616,10 +591,10 @@ namespace ChanSort.Loader.Philips #region EncodeName private string EncodeName(string name) { - var bytes = this.DefaultEncoding.GetBytes(name); + var bytes = Encoding.Unicode.GetBytes(name); var sb = new StringBuilder(); foreach (var b in bytes) - sb.Append($"0x{b:X2} 0x00 "); + sb.Append($"0x{b:X2} "); sb.Remove(sb.Length - 1, 1); return sb.ToString(); } diff --git a/source/ChanSort/ChanSort.csproj b/source/ChanSort/ChanSort.csproj index d0b732c..0cb4ade 100644 --- a/source/ChanSort/ChanSort.csproj +++ b/source/ChanSort/ChanSort.csproj @@ -506,7 +506,7 @@ {68da8072-3a29-4076-9f64-d66f38349585} ChanSort.Loader.Panasonic - + {1f52b5ec-a2f1-4e53-9e1a-4658296c5bb5} ChanSort.Loader.Philips @@ -568,6 +568,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -592,9 +595,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest diff --git a/source/ChanSort/ReferenceLists/it_hotbird130E_FTA.txt b/source/ChanSort/ReferenceLists/it_hotbird130E_FTA.txt deleted file mode 100644 index 959c63b..0000000 --- a/source/ChanSort/ReferenceLists/it_hotbird130E_FTA.txt +++ /dev/null @@ -1,41 +0,0 @@ -1;Horse TV HD;200-1800-3629 -2;Radio Radio TV;318-15700-1329 -3;Yes TV;318-15700-1312 -4;Italian Fishing TV;318-9300-1602 -5;MS MOTORTV;318-9300-1613 -6;MS CHANNEL;318-9300-1614 -7;Well TV;318-900-503 -8;PACI CONTEMPORARY CHANNEL;318-9000-9014 -9;Wine TV;318-9300-1603 -10;Class TvModa;200-1800-3630 -11;RTL 102.5 NEWS;318-15700-1323 -12;RADIONORBA TV;318-15700-1311 -13;RDS Relax;318-15800-16978 -14;Canale Italia 83;318-13300-4961 -15;TRM h24;318-15800-16922 -16;TG NORBA 24;200-1800-3628 -17;Radio Cusano Campus;318-13300-4958 -18;Rete Uno;318-1700-14031 -19;Rete Due;318-1700-14032 -20;Rete Tre;318-1700-14033 -21;R-BuonConsiglio;200-1800-3636 -22;InBlu;64511-6700-11131 -23;INBLU2000;64511-6700-11174 -24;Radio Vaticana Europa;64511-6900-11181 -25;DimSuono Soft MI;318-7000-766 -26;DimSuono Soft RM;318-7000-767 -27;R. Eurospin;318-7000-749 -28;Radio PadrePio;318-7000-744 -29;Radio RADICALE;318-7000-761 -30;Radio Iglesias;318-7200-3654 -31;SMTv San Marino Radio;318-7200-7255 -32;Canale Italia 84;318-13300-4962 -33;Canale Italia;318-13300-4959 -34;Canale Italia 2;318-13300-4960 -35;TLC Telecampione;318-13300-4970 -36;Arte Investimenti;318-13300-4993 -37;Tesory Channel;318-900-532 -38;Arte Atelier;318-15800-16964 -39;Antichita Chiossone;318-15800-16965 -40;Deluxe 139;318-9000-9008 -41;TV Art Live;318-9300-1617 diff --git a/source/ChanSort/ReferenceLists/it_tivusat_EasyHD.txt b/source/ChanSort/ReferenceLists/it_tivusat_EasyHD.txt deleted file mode 100644 index d836a70..0000000 --- a/source/ChanSort/ReferenceLists/it_tivusat_EasyHD.txt +++ /dev/null @@ -1,203 +0,0 @@ -1;Rai 1 HD;318-5200-3401 -2;Rai 2 HD;318-5200-3402 -3;Rai 3 HD;318-5200-3403 -4;Rete4 HD;272-1200-123 -5;Canale5 HD;272-1200-122 -6;Italia1 HD;272-1200-121 -7;LA7 HD;272-6000-79 -8;TV8 HD;64511-6800-7260 -9;Nove HD;318-1000-4323 -10;Rai 4 HD;318-5200-3405 -11;Iris;272-1200-124 -12;La 5;272-1200-127 -13;Rai 5 HD;318-12500-17716 -14;Rai Movie HD;318-5200-3406 -15;Rai Premium HD;318-12500-17717 -16;Mediaset ITALIA DUE;272-1200-130 -17;Mediaset EXTRA;272-1200-129 -18;TV2000 HD;64511-6900-11180 -19;cielo HD;64511-6800-4120 -20;20 MEDIASET HD;272-1200-120 -21;Rai Sport + HD;318-5200-3404 -22;VH1;200-1800-3625 -23;Rai Storia HD;318-12500-17714 -24;Rai News 24 HD;318-12500-17711 -25;TgCom24;272-1200-128 -26;Spike;200-1800-3624 -27;Paramount Network HD;318-15700-1324 -28;DMAX HD;64511-6900-14253 -29;LA7d;272-6000-73 -31;Real Time HD;64511-6900-11507 -32;QVC HD;318-15800-16979 -33;Rai Scuola HD;318-12500-17715 -34;Cine34;272-1200-111 -35;Radio Italia Tv HD;318-15800-16962 -36;RTL 102.5 HD;318-15700-1307 -37;HSE24;318-12100-1731 -38;Giallo HD;318-1000-4322 -39;Topcrime;272-1200-132 -40;Boing;272-1200-126 -41;Cartoonito;272-1200-133 -42;Rai Gulp HD;318-12500-17712 -43;Rai YoYo HD;318-12500-17713 -44;-frisbee-;64511-6900-11418 -46;K2;64511-6900-11466 -47;Super!;200-1800-3621 -48;Arte HD;319-15900-307 -49;MEZZO;318-15600-10725 -50;RDS Social TV;318-15800-16977 -51;UNIRESAT HD;318-15800-16963 -53;Food Network HD;64511-6900-11722 -56;MotorTrend HD;318-1000-4321 -59;Euronews Italian;318-8900-2017 -60;Focus;272-1200-134 -61;BFC;318-15800-16980 -63;Radio Italia Trend TV HD;318-15800-16966 -64;Radio Kiss Kiss Tv;318-15800-16976 -65;RADIO ZETA HD;318-15700-1321 -66;RADIOFRECCIA HD;318-15700-1308 -67;RADIO MONTE CARLO;272-1200-119 -69;France 24 HD (in English);318-15300-808 -70;BBC World News;318-9400-8204 -71;Al Jazeera English HD;318-13100-7306 -72;TRT World HD;318-15300-803 -73;NHK WORLD-JAPAN;318-900-533 -75;France 24 HD (en Francais);318-15300-807 -77;Al Jazeera HD;318-9300-1601 -78;AlAraby TV HD;318-9000-9006 -79;Sonlife;318-700-9 -80;Juwelo TV;318-13300-4910 -81;CNBC HD;64511-6700-7245 -82;Bloomberg European TV;318-13100-7302 -83;i24News HD English;318-15700-1310 -84;i24News HD French;318-15700-1309 -85;DW English HD;318-5000-13101 -86;Euronews English HD;318-15300-801 -87;CGTN;318-15400-872 -88;CGTN Documentary;318-15400-873 -89;Senato;318-12400-8520 -90;Camera Deputati;318-12400-8519 -91;KBS World HD;318-15700-1313 -92;CCTV 4E;318-15400-871 -93;SMTv San Marino HD;318-7200-7254 -100;tivùlink;318-12400-8517 -101;Rai 1;318-12400-8511 -102;Rai 2;318-12400-8512 -103;Rai 3;318-12400-8513 -104;Rete 4;272-6000-3 -105;Canale 5;272-6000-2 -106;Italia 1;272-6000-1 -107;LA7;272-6000-71 -110;Rai 4;318-12400-8514 -111;Iris provvisorio;272-6000-4 -112;La 5 provvisorio;272-6000-7 -113;Rai 5;318-12400-8515 -114;Rai Movie;318-12400-8502 -115;Rai Premium;318-12400-8522 -116;Mediaset ITALIA DUE provvisorio;272-6000-10 -117;Mediaset EXTRA provvisorio;272-6000-9 -120;20 Mediaset provvisorio;272-6000-15 -121;Rai Sport;318-12400-8523 -123;Rai Storia;318-12400-8518 -124;Rai News 24;318-12400-8516 -125;TgCom24 provvisorio;272-6000-8 -127;Paramount Network;200-1800-3627 -132;QVC Italia;318-7000-780 -133;Rai Scuola;318-12400-8521 -139;Topcrime provvisorio;272-6000-12 -140;Boing provvisorio;272-6000-6 -141;Cartoonito provvisorio;272-6000-13 -142;Rai Gulp;318-12400-8524 -143;Rai YoYo;318-12400-8525 -160;Focus provvisorio;272-6000-14 -171;Al Jazeera English;318-13100-7305 -177;Al Jazeera;318-7000-708 -187;CGTN;318-12600-1706 -192;CCTV-4;318-7200-7224 -200;HotBird 4K1;318-700-17 -210;Rai 4K;318-5200-3407 -211;Nasa TV UHD;318-11100-4602 -220;Museum 4K;318-11100-4604 -222;MyZen 4K;318-9100-1104 -225;TRAVELXP 4K;318-11100-4603 -289;FTV UHD;318-9100-1102 -301;Rai 3 TGR Valle d'Aosta;318-12500-17744 -302;Rai 3 TGR Piemonte;318-12500-17739 -303;Rai 3 TGR Liguria;318-12500-17735 -304;Rai 3 TGR Lombardia;318-12500-17740 -305;Rai 3 TGR Veneto;318-12500-17742 -306;Rai 3 TGR Trentino Alto Adige Bolzano;318-12500-17752 -307;Rai 3 TGR Trentino Alto Adige Trento;318-12500-17751 -308;Rai 3 TGR Tagesschau;318-12500-17743 -309;Rai 3 TGR Friuli Venezia Giulia;318-12500-17749 -310;Rai 3 TGR Furlanija Julijska Krajina;318-12500-17750 -311;Rai 3 TGR Emilia-Romagna;318-12500-17741 -312;Rai 3 TGR Toscana;318-12500-17736 -313;Rai 3 TGR Marche;318-12500-17738 -314;Rai 3 TGR Umbria;318-12500-17737 -315;Rai 3 TGR Lazio;318-12500-17753 -316;Rai 3 TGR Abruzzo;318-12500-17746 -317;Rai 3 TGR Molise;318-12500-17747 -318;Rai 3 TGR Campania;318-12500-17748 -319;Rai 3 TGR Puglia;318-12500-17731 -320;Rai 3 TGR Basilicata;318-12500-17732 -321;Rai 3 TGR Calabria;318-12500-17733 -322;Rai 3 TGR Sardegna;318-12500-17745 -323;Rai 3 TGR Sicilia;318-12500-17734 -420;People TV;318-15700-1328 -422;Telecupole;318-13300-4994 -445;Padre Pio Tv;318-15800-16952 -454;Parole di Vita;318-900-510 -518;Emilia Romagna 24;318-15800-16920 -601;Rai Radio 1;318-5200-3441 -602;Rai Radio 2;318-5200-3442 -603;Rai Radio 3;318-5200-3443 -604;Rai GR Parlamento;318-5200-3445 -605;Rai Radio3 Classica;318-5200-3444 -606;Rai Radio Kids;318-5200-3449 -607;Rai Radio Live;318-5200-3448 -608;RDS;318-7000-736 -609;DimSuono Roma;318-7000-737 -610;RTL 102.5;318-7200-3642 -611;RADIO ZETA;318-7200-3643 -612;RADIO FRECCIA;318-7200-3630 -615;Radio 105;272-6000-105 -616;Virgin radio;272-6000-104 -617;Radio R101;272-6000-101 -618;Radio Monte Carlo;272-6000-102 -619;RMC2;272-6000-103 -620;RADIO ITALIA s.m.i.;318-7200-3632 -621;M DUE O;318-7200-3653 -622;CAPITAL;318-7200-3652 -623;DEEJAY;318-7200-3651 -624;Radio 24;318-7200-3644 -625;Discoradio;318-7000-768 -626;R.ONDA D'URTO;318-7200-3645 -627;ANNI 60;318-7000-738 -630;Rai Radio Tutta Italiana;318-5200-3451 -631;Radio Number One;318-15800-16981 -632;Radio Radio;318-7200-3646 -633;Radio Maria;318-7000-732 -634;RADIO MATER;318-7200-7280 -635;popolare;318-7200-3656 -637;Radio Margherita;318-13300-4957 -639;Rai Radio Slovenia;318-5200-3454 -640;Rai Radio Techete';318-5200-3447 -641;Rai Radio1 Sport;318-5200-3453 -642;Rai Radio2 Indie;318-5200-3450 -643;Radio Kiss Kiss;318-7000-742 -644;Radio Sportiva;318-7200-3637 -656;RFI Francais;318-5000-13130 -661;Swiss Pop;318-1700-14035 -662;Swiss Jazz;318-1700-14036 -663;Swiss Classica;318-1700-14047 -667;DW-FM02;318-5000-13124 -669;DW08;318-5000-13121 -670;DW09;318-5000-13122 -699;Rai Isoradio;318-5200-3446 -701;UNINETTUNO UNIVERSITY TV;318-12500-17718 -805;Mediaset Play;272-1200-805 -815;TELEPACE HD;318-8900-2004 -819;VIDEOLINA;318-15800-16992 -832;TVA Vicenza;318-15800-16988 -899;Infinity;272-1200-899 \ No newline at end of file diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_SatelliteDb-bin.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_SatelliteDb-bin.h index aa26e28..d49b4ba 100644 --- a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_SatelliteDb-bin.h +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_SatelliteDb-bin.h @@ -3,6 +3,42 @@ /*********************************************************** * Philips ChannelMap_45 format ***********************************************************/ + +public struct Ph_ChannelMap45_CableDbBin +{ + dword majorVersion; + dword minorVersion; + dword recordCount; + struct + { + var off0 = current_offset; + dword id; + dword freq; + dword number; + dword analogUid; + dword onid; + dword tsid; + dword sid; + dword symRate; + dword logoNr; + dword scrambleStat; + dword locked; + dword modulation; + dword unk1; + dword serviceType; + dword systemHideMaybe; + dword isUserModifiedLogo; + dword serviceEdit; + dword streamPriorityMaybe; + dword unk2; + word unk3TransponderRelated; + word unk4TransponderRelated; + byte unk3[8]; + wchar_t name[32+1]; + + byte unk[156 - (current_offset - off0)]; + } Channels[recordCount]; +}; public struct Ph_ChannelMap45_SatelliteDbBin diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_dat.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_dat.h index 1a8d638..763a45a 100644 --- a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_dat.h +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/philips_dat.h @@ -45,7 +45,7 @@ public struct Ph_SatelliteDat dword crc32; }; -public struct Ph_TuneinfoDat +public struct Ph_TuneinfoDat_1_0 { word unk1; word unk2; @@ -66,7 +66,36 @@ public struct Ph_TuneinfoDat byte unk2[9]; word tsid; word onid; - word unk3; + byte unk3[2]; + char networkName[32]; + word unk4; + byte unk[recordSize - (current_offset - off0)]; + } Transponders[recordCount]; + dword crc32; +}; + +public struct Ph_TuneinfoDat_1_2 +{ + word unk1; + word unk2; + dword recordSize; + dword recordCount; + Ph_NextPrevTableEntry NextPrevTable[recordCount]; + struct + { + var off0 = current_offset; + word symbolRate; + word freqInMhz; + word unk1; + struct + { + byte unk : 4; + byte satIndex: 4; + } u1a; + byte unk2[9]; + word tsid; + word onid; + byte unk3[6]; char networkName[32]; word unk4; byte unk[recordSize - (current_offset - off0)]; @@ -138,6 +167,37 @@ public struct Ph_FavoriteDat dword crc32; }; +public struct Ph_SatelliteDigSrvTable_11 +{ + dword version; + dword unk2; + dword chRecordSize; + dword channelCount; + dword versionCode; + struct Ph_CableChannel + { + var off0 = current_offset; + dword checksum; + byte unk1[16]; + dword symbolRate; + byte unk2[16]; + dword freq; + word onid; + word sid; + word tsid; + byte unk3b[58]; + word progNrMostly; + byte unk4[6]; + word progNr; + byte unk5[22]; + byte locked; + byte isFav; + byte unk6[68]; + wchar_t channelName[32]; + byte unk4[chRecordSize - (current_offset - off0)]; + } Channels[channelCount]; +}; + /*********************************************************** * channellib / antenna and cable files ***********************************************************/ diff --git a/source/changelog.md b/source/changelog.md index 5ff8e75..df2e7bf 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,6 +1,12 @@ ChanSort Change Log =================== +2021-01-17 +- Philips: added support for ChannelMap_45 format +- Philips: fixed display of symbol rate and frequency (off by factor 1000 depending of list and DVB source) +- Philips: fixed special characters in channel names (e.g. german umlauts) +- Philips: "ServiceType" now only shows "TV" or "Radio". There is no information about HD/SD in the file. + 2021-01-02 - Grundig: added support for dvb*_config.xml channel lists