diff --git a/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.csproj b/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.csproj new file mode 100644 index 0000000..0fb28d5 --- /dev/null +++ b/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.csproj @@ -0,0 +1,27 @@ + + + + net48 + latest + + + ..\Debug\ + MinimumRecommendedRules.ruleset + + + ..\Release\ + MinimumRecommendedRules.ruleset + + + + + + + + + PreserveNewest + + + + + diff --git a/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini b/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini new file mode 100644 index 0000000..1095e1d --- /dev/null +++ b/source/ChanSort.Loader.DBM/ChanSort.Loader.DBM.ini @@ -0,0 +1,33 @@ +[dbm:163772] +isDvbS=false +offChecksum=0x0000 +offDataLength=0x0002 +offData=0x0006 + +offTransponderBitmap=0x0006 +lenTransponderBitmap=16 +offTransponderData=0x0016 +numTransponder=100 +lenTransponderData=36 + +offChannelBitmap=0x0E3C +lenChannelBitmap=126 +offChannelData=0x0EBA +numChannel=1000 +lenChannelData=160 + +[transponder:163772] +offFreq=0 +offSymRate=8 + +[channel:163772] +offName=0 +lenName=64 +offProgNr=64 +offLcn=66 +offTransponderIndex=70 +offTsid=96 +offOnid=98 +offSid=100 +offPcrPid=104 +offVideoPid=106 diff --git a/source/ChanSort.Loader.DBM/DbmPlugin.cs b/source/ChanSort.Loader.DBM/DbmPlugin.cs new file mode 100644 index 0000000..cf3a7b5 --- /dev/null +++ b/source/ChanSort.Loader.DBM/DbmPlugin.cs @@ -0,0 +1,22 @@ +using ChanSort.Api; + +namespace ChanSort.Loader.DBM +{ + public class DbmPlugin : ISerializerPlugin + { + /* + * Various brands use variations of an underlying .DBM binary file format for DVB-C and DVB-S tuners. + * + * Known models include Xoro, TechniSat, ... + */ + + public string DllName { get; set; } + public string PluginName => "DBM (Xoro, TechniSat, ...)"; + public string FileFilter => "*.dbm"; + + public SerializerBase CreateSerializer(string inputFile) + { + return new DbmSerializer(inputFile); + } + } +} diff --git a/source/ChanSort.Loader.DBM/DbmSerializer.cs b/source/ChanSort.Loader.DBM/DbmSerializer.cs new file mode 100644 index 0000000..bf0744f --- /dev/null +++ b/source/ChanSort.Loader.DBM/DbmSerializer.cs @@ -0,0 +1,217 @@ +using System; +using System.IO; +using System.Reflection; +using System.Text; +using ChanSort.Api; + +namespace ChanSort.Loader.DBM +{ + /* + + + */ + public class DbmSerializer : SerializerBase + { + private readonly IniFile ini; + private IniFile.Section sec; + private DataMapping mapping; + private readonly ChannelList allChannels = new ChannelList(SignalSource.All, "All"); + + private byte[] data; + private int fileSize; + + private readonly StringBuilder logMessages = new StringBuilder(); + + + #region ctor() + public DbmSerializer(string inputFile) : base(inputFile) + { + this.Features.ChannelNameEdit = ChannelNameEditMode.None; + this.Features.CanSkipChannels = false; + this.Features.CanLockChannels = false; + this.Features.CanHideChannels = false; + this.Features.DeleteMode = DeleteMode.NotSupported; + this.Features.CanHaveGaps = false; + this.Features.FavoritesMode = FavoritesMode.None; + this.Features.MaxFavoriteLists = 0; + this.Features.AllowGapsInFavNumbers = false; + this.Features.CanEditFavListNames = false; + + this.DataRoot.AddChannelList(this.allChannels); + + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ChannelOrTransponder)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Provider)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Encrypted)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ServiceType)); + list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.ServiceTypeName)); + } + + string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini"); + this.ini = new IniFile(iniFile); + } + #endregion + + // loading + + #region Load + public override void Load() + { + var info = new FileInfo(this.FileName); + this.fileSize = (int)info.Length; + + this.sec = ini.GetSection("dbm:" + this.fileSize); + if (sec == null) + throw LoaderException.Fail($"No configuration for .DBM files with size {info.Length} in .ini file"); + + if (!sec.GetBool("isDvbS")) + allChannels.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Satellite)); + + this.data = File.ReadAllBytes(this.FileName); + this.mapping = new DataMapping(sec); + this.mapping.SetDataPtr(data, 0); + + ValidateChecksum(data, sec); + + LoadTransponder(sec, data); + LoadChannels(sec, data); + } + #endregion + + #region ValidateChecksum() + private void ValidateChecksum(byte[] data, IniFile.Section sec) + { + var expectedChecksum = BitConverter.ToUInt16(data, 0); + var calculatedChecksum = CalcChecksum(data, sec.GetInt("offData"), (int)mapping.GetDword("offDataLength")); + if (expectedChecksum != calculatedChecksum) + { + var msg = $"Invalid checksum. Expected {expectedChecksum:x4} but calculated {calculatedChecksum:x4}"; + throw LoaderException.Fail(msg); + } + } + + #endregion + + #region LoadTransponder() + + private void LoadTransponder(IniFile.Section sec, byte[] data) + { + var num = sec.GetInt("numTransponder"); + var offBitmap = sec.GetInt("offTransponderBitmap"); + + var map = new DataMapping(ini.GetSection("transponder:" + this.fileSize)); + map.SetDataPtr(data, sec.GetInt("offTransponderData")); + var recordSize = sec.GetInt("lenTransponderData"); + + for (int i = 0; i < num; i++) + { + if ((data[offBitmap + i / 8] & (1 << (i & 0x07))) != 0) + { + var t = new Transponder(i); + t.FrequencyInMhz = (decimal)map.GetDword("offFreq") / 1000; + t.SymbolRate = (int)map.GetDword("offSymRate"); + this.DataRoot.AddTransponder(null, t); + } + + map.BaseOffset += recordSize; + } + } + #endregion + + #region LoadChannels() + + private void LoadChannels(IniFile.Section sec, byte[] data) + { + var num = sec.GetInt("numChannel"); + var offBitmap = sec.GetInt("offChannelBitmap"); + + var sec2 = ini.GetSection("channel:" + this.fileSize); + var map = new DataMapping(sec2); + map.SetDataPtr(data, sec.GetInt("offChannelData")); + var recordSize = sec.GetInt("lenChannelData"); + + var dec = new DvbStringDecoder(this.DefaultEncoding); + + for (int i = 0; i < num; i++) + { + if ((data[offBitmap + i / 8] & (1 << (i & 0x07))) != 0) + { + var c = new ChannelInfo(SignalSource.Any, i, -1, null); + dec.GetChannelNames(data, map.BaseOffset + sec2.GetInt("offName"), sec2.GetInt("lenName"), out var longName, out var shortName); + c.Name = longName; + c.ShortName = shortName; + c.OldProgramNr = map.GetWord("offProgNr") + 1; + c.OriginalNetworkId = map.GetWord("offOnid"); + c.TransportStreamId = map.GetWord("offTsid"); + c.ServiceId = map.GetWord("offSid"); + c.PcrPid = map.GetWord("offPcrPid"); + c.VideoPid = map.GetWord("offVideoPid"); + + var transpIdx = map.GetByte("offTransponderIndex"); + var tp = this.DataRoot.Transponder.TryGet(transpIdx); + if (tp != null) + { + c.FreqInMhz = tp.FrequencyInMhz; + c.SymbolRate = tp.SymbolRate; + } + + this.DataRoot.AddChannel(this.allChannels, c); + } + + map.BaseOffset += recordSize; + } + } + #endregion + + // saving + + #region Save() + public override void Save() + { + var sec2 = ini.GetSection("channel:" + this.fileSize); + var map = new DataMapping(sec2); + var baseOffset = sec.GetInt("offChannelData"); + map.SetDataPtr(data, baseOffset); + var recordSize = sec.GetInt("lenChannelData"); + + foreach (var chan in this.allChannels.Channels) + { + if (chan.IsProxy) continue; + map.BaseOffset = baseOffset + (int)chan.RecordIndex * recordSize; + map.SetWord("offProgNr", chan.NewProgramNr - 1); + } + + var calculatedChecksum = CalcChecksum(data, sec.GetInt("offData"), (int)mapping.GetDword("offDataLength")); + mapping.SetWord("offChecksum", calculatedChecksum); + File.WriteAllBytes(this.FileName, this.data); + } + #endregion + + // common + + #region CalcChecksum + /// + /// The checksum is the byte sum over the data bytes (offset 6 to end-2) plus 0x55 added to it + /// + public ushort CalcChecksum(byte[] bytes, int start, int count) + { + var sum = 0x55u; + while (count-- > 0) + sum += bytes[start++]; + return (ushort)sum; + } + #endregion + + + // framework support methods + + #region GetFileInformation + public override string GetFileInformation() + { + return base.GetFileInformation() + this.logMessages.Replace("\n", "\r\n"); + } + #endregion + } +} diff --git a/source/ChanSort.sln b/source/ChanSort.sln index ef21989..8a0bd0c 100644 --- a/source/ChanSort.sln +++ b/source/ChanSort.sln @@ -33,7 +33,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Solution.props = Solution.props EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Loader", "Test.Loader\Test.Loader.csproj", "{68CFCB2F-B52A-43A1-AA5C-5D64A1D655D2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Loader", "Test.Loader\Test.Loader.csproj", "{68CFCB2F-B52A-43A1-AA5C-5D64A1D655D2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.Samsung", "ChanSort.Loader.Samsung\ChanSort.Loader.Samsung.csproj", "{A1C9A98D-368A-44E8-9B7F-7EACA46C9EC5}" EndProject @@ -101,7 +101,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.Loader.CmdbBin", "Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.Unsupported", "ChanSort.Loader.Unsupported\ChanSort.Loader.Unsupported.csproj", "{D7C32DAE-5D77-46A0-BC16-C95D9C7EFDD5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.TCL", "ChanSort.Loader.TCL\ChanSort.Loader.TCL.csproj", "{460D9527-F7EF-4277-9382-FB609A44D66A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.TCL", "ChanSort.Loader.TCL\ChanSort.Loader.TCL.csproj", "{460D9527-F7EF-4277-9382-FB609A44D66A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.DBM", "ChanSort.Loader.DBM\ChanSort.Loader.DBM.csproj", "{C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1260,6 +1262,36 @@ Global {460D9527-F7EF-4277-9382-FB609A44D66A}.Release|Mixed Platforms.Build.0 = Release|Any CPU {460D9527-F7EF-4277-9382-FB609A44D66A}.Release|x86.ActiveCfg = Release|Any CPU {460D9527-F7EF-4277-9382-FB609A44D66A}.Release|x86.Build.0 = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Debug|Any CPU.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Debug|x86.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Debug|x86.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Release|Any CPU.ActiveCfg = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Release|Any CPU.Build.0 = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Release|Mixed Platforms.Build.0 = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Release|x86.ActiveCfg = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.All_Release|x86.Build.0 = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Debug|x86.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Debug|x86.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.NoDevExpress_Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.NoDevExpress_Debug|Any CPU.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.NoDevExpress_Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.NoDevExpress_Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.NoDevExpress_Debug|x86.ActiveCfg = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.NoDevExpress_Debug|x86.Build.0 = Debug|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|Any CPU.Build.0 = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|x86.ActiveCfg = Release|Any CPU + {C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/ChanSort/ChanSort.csproj b/source/ChanSort/ChanSort.csproj index 43f05fb..36b044a 100644 --- a/source/ChanSort/ChanSort.csproj +++ b/source/ChanSort/ChanSort.csproj @@ -129,6 +129,7 @@ + diff --git a/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-163772-dvbc.h b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-163772-dvbc.h new file mode 100644 index 0000000..5d62919 --- /dev/null +++ b/source/Information/FileStructures_for_HHD_Hex_Editor_Neo/dbm-163772-dvbc.h @@ -0,0 +1,52 @@ +#include "chansort.h" + +struct s_Transponder +{ + var off0 = current_offset; + dword Freq; + byte unk1[4]; + dword SymRate; + var off1 = current_offset; + + byte unk[36 - (off1 - off0)]; +}; + +struct s_Channel +{ + var off0 = current_offset; + byte Name[64]; + word progNrMinus1; + word lcn; + byte u3[2]; + byte transponderIndex; + byte u4[25]; + word tsid; + word onid; + word sid; + + byte u5[2]; + word pcrPidMaybe; + word vpidMaybe; + + var off1 = current_offset; + byte unk[160 - (off1-off0)]; +}; + + +public struct DBM_163772_DvbC +{ + word BytesumPlus0x55; + dword DataLengthForBytesum; + + byte TransponderBitmap[16]; + s_Transponder TransponderData[100]; + + var off0 = current_offset; + byte unk1[0x0E3C - off0]; + + byte ChannelBitmap[126]; + s_Channel ChannelData[1000]; + + byte Extra[*]; +}; +