From 077d08a3439a2f111479505a69c52ef6f7dc8149 Mon Sep 17 00:00:00 2001 From: hbeham Date: Mon, 15 Jul 2019 14:01:01 +0200 Subject: [PATCH] - added support for DVB-T, DVB-C and predefined DVB-S lists (all still read-only) --- source/ChanSort.Loader.Sony/Serializer.cs | 206 +++++++++++++--------- 1 file changed, 125 insertions(+), 81 deletions(-) diff --git a/source/ChanSort.Loader.Sony/Serializer.cs b/source/ChanSort.Loader.Sony/Serializer.cs index 5d04875..65b1da5 100644 --- a/source/ChanSort.Loader.Sony/Serializer.cs +++ b/source/ChanSort.Loader.Sony/Serializer.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Reflection; using System.Text; using System.Xml; using System.Xml.Schema; @@ -12,11 +11,24 @@ namespace ChanSort.Loader.Sony { class Serializer : SerializerBase { - private readonly ChannelList satChannels = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "Sat"); + /* + * At the time of this writing, there seem to be 4 different versions of this format. + * One defines an element with a typo: 1.1.0, which has different XML elements and checksum calculation than all other versions. + * This format is identified as "e1.1.0" here, with the leading "e". + * The other formats define ... with versions 1.0.0, 1.1.0 and 1.2.0, which are otherwise identical. + * + * NOTE: Even within the same version, there are some files using CRLF and some using LF for newlines. + */ + + private readonly ChannelList terrChannels = new ChannelList(SignalSource.DvbC | SignalSource.Tv | SignalSource.Radio, "DVB-T"); + private readonly ChannelList cableChannels = new ChannelList(SignalSource.DvbC | SignalSource.Tv | SignalSource.Radio, "DVB-C"); + private readonly ChannelList satChannels = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S"); + private readonly ChannelList satChannelsP = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S Preset"); + private readonly ChannelList satChannelsCi = new ChannelList(SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S Ci"); + private XmlDocument doc; private byte[] content; private string textContent; - private XmlNode sdbXml; private string format; #region Crc32Table @@ -48,14 +60,21 @@ namespace ChanSort.Loader.Sony this.Features.ChannelNameEdit = ChannelNameEditMode.All; this.Features.CanDeleteChannels = true; - satChannels.VisibleColumnFieldNames.Remove("PcrPid"); - satChannels.VisibleColumnFieldNames.Remove("VideoPid"); - satChannels.VisibleColumnFieldNames.Remove("AudioPid"); - satChannels.VisibleColumnFieldNames.Remove("Lock"); - satChannels.VisibleColumnFieldNames.Remove("Skip"); - satChannels.VisibleColumnFieldNames.Remove("Provider"); - + this.DataRoot.AddChannelList(this.terrChannels); + this.DataRoot.AddChannelList(this.cableChannels); this.DataRoot.AddChannelList(this.satChannels); + this.DataRoot.AddChannelList(this.satChannelsP); + + foreach (var list in this.DataRoot.ChannelLists) + { + list.VisibleColumnFieldNames.Remove("PcrPid"); + list.VisibleColumnFieldNames.Remove("VideoPid"); + list.VisibleColumnFieldNames.Remove("AudioPid"); + list.VisibleColumnFieldNames.Remove("Lock"); + list.VisibleColumnFieldNames.Remove("Skip"); + list.VisibleColumnFieldNames.Remove("ShortName"); + list.VisibleColumnFieldNames.Remove("Provider"); + } } #endregion @@ -75,9 +94,11 @@ namespace ChanSort.Loader.Sony this.doc = new XmlDocument(); this.content = File.ReadAllBytes(this.FileName); this.textContent = Encoding.UTF8.GetString(this.content); - var tc2 = ReplaceInvalidXmlCharacters(textContent); - if (tc2 != this.textContent) - this.textContent = tc2; + + //var tc2 = ReplaceInvalidXmlCharacters(textContent); + //if (tc2 != this.textContent) + // this.textContent = tc2; + var settings = new XmlReaderSettings { CheckCharacters = false, @@ -114,8 +135,7 @@ namespace ChanSort.Loader.Sony } } - this.Features.ChannelNameEdit = ChannelNameEditMode.All; - if (this.format != "1.1.0e") + if (this.format.StartsWith("e")) { satChannels.VisibleColumnFieldNames.Remove("Hidden"); satChannels.VisibleColumnFieldNames.Remove("Satellite"); @@ -126,43 +146,50 @@ namespace ChanSort.Loader.Sony #region ReadSdbXml() private void ReadSdbXml(XmlNode node) { - this.sdbXml = node; - - this.format = null; + this.format = ""; var formatNode = node["FormatVer"]; if (formatNode != null) this.format = formatNode.InnerText; else if ((formatNode = node["FormateVer"]) != null) - this.format = formatNode.InnerText + "e"; + this.format = "e" + formatNode.InnerText; - if (" 1.0.0 1.1.0e 1.1.0 1.2.0 ".IndexOf(" " + this.format + " ") < 0) + if (" e1.1.0 1.0.0 1.1.0 1.2.0 ".IndexOf(" " + this.format + " ") < 0) throw new FileLoadException("Unsupported file format version: " + this.format); foreach(XmlNode child in node.ChildNodes) { var name = child.LocalName.ToLowerInvariant(); - if (name == "sdbgs") - ReadSdb(child); + if (name == "sdbt") + ReadSdb(child, this.terrChannels, 0, "DvbT"); + else if (name == "sdbc") + ReadSdb(child, this.cableChannels, 0x10000, "DvbC"); + else if (name == "sdbgs") + ReadSdb(child, this.satChannels, 0x20000, "DvbS"); + else if (name == "sdbps") + ReadSdb(child, this.satChannelsP, 0x30000, "DvbS"); + else if (name == "sdbcis") + ReadSdb(child, this.satChannelsCi, 0x40000, "DvbS"); } } #endregion - #region ReadSdb - private void ReadSdb(XmlNode node) + #region ReadSdb() + private void ReadSdb(XmlNode node, ChannelList list, int idAdjustment, string dvbSystem) { - this.satChannels.ReadOnly = node["Editable"].InnerText != "T"; + list.ReadOnly = node["Editable"].InnerText != "T"; - this.ReadSatellites(node); - this.ReadTransponder(node); - if (this.format == "1.1.0e") - this.ReadServices110e(node); + this.ReadSatellites(node, idAdjustment); + this.ReadTransponder(node, idAdjustment, dvbSystem); + + if (this.format.StartsWith("e")) + this.ReadServicesE110(node, list, idAdjustment); else - this.ReadServices(node); + this.ReadServices(node, list, idAdjustment); } #endregion - #region ReadSatellites - private void ReadSatellites(XmlNode node) + #region ReadSatellites() + private void ReadSatellites(XmlNode node, int satIdAdjustment) { var satlRec = node["SATL_REC"]; if (satlRec == null) @@ -171,7 +198,7 @@ namespace ChanSort.Loader.Sony var ids = data["ui2_satl_rec_id"]; for (int i = 0, c = ids.Length; i < c; i++) { - var sat = new Satellite(int.Parse(ids[i])); + var sat = new Satellite(int.Parse(ids[i]) + satIdAdjustment); sat.Name = data["ac_sat_name"][i]; var pos = int.Parse(data["i2_orb_pos"][i]); sat.OrbitalPosition = Math.Abs((decimal) pos / 10) + (pos < 0 ? "W" : "E"); @@ -180,23 +207,24 @@ namespace ChanSort.Loader.Sony } #endregion - #region ReadTransponder - private void ReadTransponder(XmlNode node) + #region ReadTransponder() + private void ReadTransponder(XmlNode node, int idAdjustment, string dvbSystem) { var mux = node["Multiplex"] ?? throw new FileLoadException("Missing Multiplex XML element"); var muxData = SplitLines(mux); - var muxIds = this.format == "1.1.0e" ? muxData["MuxID"] : muxData["MuxRowId"]; - var rfParmData = this.format != "1.1.0e" ? SplitLines(mux["RfParam"]) : null; - var dvbsData = rfParmData != null ? SplitLines(mux["RfParam"]["DvbS"]) : null; - + var isEFormat = this.format.StartsWith("e"); + var muxIds = isEFormat ? muxData["MuxID"] : muxData["MuxRowId"]; + var rfParmData = isEFormat ? null : SplitLines(mux["RfParam"]); + var dvbsData = isEFormat ? null : SplitLines(mux["RfParam"][dvbSystem]); + var polarity = dvbsData?.ContainsKey("Pola") ?? false ? dvbsData["Pola"] : null; for (int i = 0, c = muxIds.Length; i < c; i++) { Satellite sat = null; - var transp = new Transponder(int.Parse(muxIds[i])); - if (this.format == "1.1.0e") + var transp = new Transponder(int.Parse(muxIds[i]) + idAdjustment); + if (isEFormat) { - var satId = int.Parse(muxData["ui2_satl_rec_id"][i]); + var satId = int.Parse(muxData["ui2_satl_rec_id"][i]) + idAdjustment; transp.FrequencyInMhz = int.Parse(muxData["SysFreq"][i]); transp.SymbolRate = int.Parse(muxData["ui4_sym_rate"][i]); transp.Polarity = muxData["e_pol"][i] == "1" ? 'H' : 'V'; @@ -204,10 +232,10 @@ namespace ChanSort.Loader.Sony } else { - transp.OriginalNetworkId = intParse(muxData["Onid"][i]); - transp.TransportStreamId = intParse(muxData["Tsid"][i]); + transp.OriginalNetworkId = this.ParseInt(muxData["Onid"][i]); + transp.TransportStreamId = this.ParseInt(muxData["Tsid"][i]); transp.FrequencyInMhz = int.Parse(rfParmData["Freq"][i]) / 1000; - transp.Polarity = dvbsData["Pola"][i] == "H_L" ? 'H' : 'V'; + transp.Polarity = polarity == null ? ' ' : polarity[i] == "H_L" ? 'H' : 'V'; transp.SymbolRate = int.Parse(dvbsData["SymbolRate"][i]) / 1000; } @@ -216,8 +244,8 @@ namespace ChanSort.Loader.Sony } #endregion - #region ReadServices110e - private void ReadServices110e(XmlNode node) + #region ReadServicesE110() + private void ReadServicesE110(XmlNode node, ChannelList list, int idAdjustment) { var tsDescrNode = node["TS_Descr"] ?? throw new FileLoadException("Missing TS_Descr XML element"); var tsData = SplitLines(tsDescrNode); @@ -238,7 +266,7 @@ namespace ChanSort.Loader.Sony chan.Favorites = (Favorites) ((nwMask & 0xF0) >> 4); chan.ServiceId = int.Parse(svcData["ui2_prog_id"][i]); chan.Name = svcData["Name"][i]; - var muxId = int.Parse(svcData["MuxID"][i]); + var muxId = int.Parse(svcData["MuxID"][i]) + idAdjustment; var transp = this.DataRoot.Transponder[muxId]; chan.Transponder = transp; if (transp != null) @@ -248,6 +276,11 @@ namespace ChanSort.Loader.Sony chan.Polarity = transp.Polarity; chan.Satellite = transp.Satellite?.Name; chan.SatPosition = transp.Satellite?.OrbitalPosition; + + if ((list.SignalSource & SignalSource.Cable) != 0) + chan.ChannelOrTransponder = LookupData.Instance.GetDvbcChannelName(chan.FreqInMhz); + if ((list.SignalSource & SignalSource.Cable) != 0) + chan.ChannelOrTransponder = LookupData.Instance.GetDvbtTransponder(chan.FreqInMhz).ToString(); } var tsIdx = int.Parse(svcData["ui2_tsl_rec_id"][i]) - 1; @@ -257,13 +290,13 @@ namespace ChanSort.Loader.Sony chan.ServiceType = int.Parse(dvbData["ui1_sdt_service_type"][i]); chan.SignalSource |= LookupData.Instance.IsRadioOrTv(chan.ServiceType); - this.DataRoot.AddChannel(this.satChannels, chan); + this.DataRoot.AddChannel(list, chan); } } #endregion - #region ReadServices - private void ReadServices(XmlNode node) + #region ReadServices() + private void ReadServices(XmlNode node, ChannelList list, int idAdjustment) { var serviceNode = node["Service"] ?? throw new FileLoadException("Missing Service XML element"); var svcData = SplitLines(serviceNode); @@ -280,11 +313,11 @@ namespace ChanSort.Loader.Sony chan.OldProgramNr = -1; chan.IsDeleted = true; chan.ServiceType = int.Parse(svcData["Type"][i]); - chan.OriginalNetworkId = intParse(svcData["Onid"][i]); - chan.TransportStreamId = intParse(svcData["Tsid"][i]); - chan.ServiceId = intParse(svcData["Sid"][i]); + chan.OriginalNetworkId = this.ParseInt(svcData["Onid"][i]); + chan.TransportStreamId = this.ParseInt(svcData["Tsid"][i]); + chan.ServiceId = this.ParseInt(svcData["Sid"][i]); chan.Name = svcData["Name"][i]; - var muxId = int.Parse(svcData["MuxRowId"][i]); + var muxId = int.Parse(svcData["MuxRowId"][i]) + idAdjustment; var transp = this.DataRoot.Transponder[muxId]; chan.Transponder = transp; if (transp != null) @@ -292,11 +325,16 @@ namespace ChanSort.Loader.Sony chan.FreqInMhz = transp.FrequencyInMhz; chan.SymbolRate = transp.SymbolRate; chan.Polarity = transp.Polarity; + if ((list.SignalSource & SignalSource.Cable) != 0) + chan.ChannelOrTransponder = LookupData.Instance.GetDvbcChannelName(chan.FreqInMhz); + if ((list.SignalSource & SignalSource.Cable) != 0) + chan.ChannelOrTransponder = LookupData.Instance.GetDvbtTransponder(chan.FreqInMhz).ToString(); } + chan.SignalSource |= LookupData.Instance.IsRadioOrTv(chan.ServiceType); - var att = intParse(svcData["Attribute"][i]); + var att = this.ParseInt(svcData["Attribute"][i]); chan.Encrypted = (att & 8) != 0; - this.DataRoot.AddChannel(this.satChannels, chan); + this.DataRoot.AddChannel(list, chan); } for (int i = 0, c = progData["ServiceRowId"].Length; i < c; i++) @@ -313,8 +351,7 @@ namespace ChanSort.Loader.Sony } #endregion - - #region SplitLines + #region SplitLines() private Dictionary SplitLines(XmlNode parent) { var dict = new Dictionary(); @@ -339,19 +376,22 @@ namespace ChanSort.Loader.Sony int end; uint expectedCrc; - if (this.format == "1.1.0e") + if (this.format.StartsWith("e")) { - // files with the typo-element "1.1.0" differ in several ways from all other files (including 1.1.0): - // "\n" after the closing Tag is included in the checksum, the checksum has no 0x prefix and the bytes are used as-is for the calculation, without any XML cleanup + // files with the typo-element "1.1.0" differ from other formats: + // - "\n" after the closing Tag is included in the checksum, + // - the value in the element has no "0x" prefix + // - the file's bytes are used as-is for the calculation, without any prior XML cleanup data = this.content; - start = this.IndexOf(""); - end = this.IndexOf("") + 10; // including the \n at the end - expectedCrc = uint.Parse(node.InnerText, NumberStyles.HexNumber); // no 0x prefix + start = this.FindMarker(this.content, ""); + end = this.FindMarker(this.content, "") + 10; // including the \n at the end + expectedCrc = uint.Parse(node.InnerText, NumberStyles.HexNumber); } else { start = this.textContent.IndexOf(""); end = this.textContent.IndexOf("") + 9; + // the TV calculates the checksum and then does some XML manipulation afterwards. So we have to undo the manipulations first var text = this.textContent.Substring(start, end - start); text = text.Replace("\r\n", "\n"); text = text.Replace(" />", "/>"); @@ -378,15 +418,17 @@ namespace ChanSort.Loader.Sony if (crc != expectedCrc) throw new FileLoadException($"Invalid checksum: expected 0x{expectedCrc:x8}, calculated 0x{crc:x8}"); } + #endregion - private int IndexOf(string marker) + #region FindMarker() + private int FindMarker(byte[] data, string marker) { var bytes = Encoding.ASCII.GetBytes(marker); var len = bytes.Length; - int i = -1, c = this.content.Length - len; - for (; ; ) + int i = -1; + for (;;) { - i = Array.IndexOf(this.content, bytes[0], i + 1); + i = Array.IndexOf(data, bytes[0], i + 1); if (i < 0) return -1; @@ -399,10 +441,24 @@ namespace ChanSort.Loader.Sony if (j == len) return i; + + i += j - 1; } } #endregion + #region ParseInt() + private int ParseInt(string input) + { + if (string.IsNullOrWhiteSpace(input)) + return 0; + if (input.Length > 2 && input[0] == '0' && char.ToLower(input[1]) == 'x') + return int.Parse(input.Substring(2), NumberStyles.HexNumber); + if (int.TryParse(input, out var value)) + return value; + return 0; + } + #endregion @@ -505,18 +561,6 @@ namespace ChanSort.Loader.Sony #endregion - #region intParse - private int intParse(string input) - { - if (string.IsNullOrWhiteSpace(input)) - return 0; - if (input.StartsWith("0x")) - return int.Parse(input.Substring(2), NumberStyles.HexNumber); - if (int.TryParse(input, out var value)) - return value; - return 0; - } - #endregion #region ReplaceInvalidXmlCharacters() private string ReplaceInvalidXmlCharacters(string input)