diff --git a/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs b/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs index 382cd40..305df18 100644 --- a/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs +++ b/source/ChanSort.Loader.LG/GlobalClone/GcJsonSerializer.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.IO; using System.Text; using ChanSort.Api; @@ -43,7 +44,7 @@ namespace ChanSort.Loader.GlobalClone this.DataRoot.AddChannelList(new ChannelList(SignalSource.DvbS | SignalSource.Radio, "DVB-S Radio")); } - + #region Load() public override void Load() { var startTag = ""; @@ -57,6 +58,7 @@ namespace ChanSort.Loader.GlobalClone if (end >= 0) { json = content.Substring(start + startTag.Length, end - start - startTag.Length); + json = UnescapeXml(json); this.xmlSuffix = content.Substring(end); } } @@ -90,6 +92,63 @@ namespace ChanSort.Loader.GlobalClone } } } + #endregion + + #region UnescapeXml() + private string UnescapeXml(string json) + { + var sb = new StringBuilder(json.Length); + int i=0,j=0; + for (i = json.IndexOf('&', j); i != -1; i = json.IndexOf('&', j)) + { + sb.Append(json, j, i - j); + j = json.IndexOf(';', i); + var entity = json.Substring(i + 1, j - i - 1); + switch (entity) + { + case "amp": sb.Append("&"); break; + case "lt": sb.Append("<"); break; + case "gt": sb.Append(">"); break; + default: + if (entity.StartsWith("#x")) + sb.Append((char) int.Parse("0x" + entity.Substring(2), NumberStyles.AllowHexSpecifier)); + else if (entity.StartsWith("#")) + sb.Append((char) int.Parse(entity.Substring(1))); + else + sb.Append("&").Append(entity).Append(";"); + break; + } + + ++j; + } + + sb.Append(json, j, json.Length - j); + return sb.ToString(); + } + #endregion + + #region EscapeXml() + private string EscapeXml(string json) + { + var sb = new StringBuilder(json.Length); + foreach (var c in json) + { + switch (c) + { + case '&': sb.Append("&"); break; + case '<': sb.Append("<"); break; + case '>': sb.Append(">"); break; + default: + if (c < 32 && !char.IsWhiteSpace(c)) + sb.Append($"&#x{(int) c:x4}"); + else + sb.Append(c); + break; + } + } + return sb.ToString(); + } + #endregion #region LoadSatellites() private void LoadSatellites() @@ -193,9 +252,9 @@ namespace ChanSort.Loader.GlobalClone ch.Transponder = this.DataRoot.Transponder.TryGet((int.Parse(tpId.Substring(0, 4)) << 16) + int.Parse(tpId.Substring(4))); // satId + freq, e.g. 0192126041 ch.IsDeleted = (bool) node["deleted"]; - ch.PcrPid = (int) node["pcrPid"]; - ch.AudioPid = (int) node["audioPid"]; - ch.VideoPid = (int) node["videoPid"]; + ch.PcrPid = (int) node["pcrPid"] & 0x3FF; + ch.AudioPid = (int) node["audioPid"] & 0x3FF; + ch.VideoPid = (int) node["videoPid"] & 0x3FF; ch.ServiceId = (int) node["SVCID"]; if (ch.ServiceId == 0) ch.ServiceId = (int) node["programNum"]; @@ -229,14 +288,18 @@ namespace ChanSort.Loader.GlobalClone { this.UpdateJsonDoc(); + var sb = new StringBuilder(); + sb.Append(xmlPrefix); + using var sw = new StringWriter(); - sw.Write(xmlPrefix); var jw = new JsonTextWriter(sw); { doc.WriteTo(jw); } - sw.Write(xmlSuffix); - File.WriteAllText(tvOutputFile, sw.ToString()); + var json = EscapeXml(sw.ToString()); + sb.Append(json); + sb.Append(xmlSuffix); + File.WriteAllText(tvOutputFile, sb.ToString()); this.FileName = tvOutputFile; } #endregion diff --git a/source/changelog.md b/source/changelog.md index 4c3de09..32fc73c 100644 --- a/source/changelog.md +++ b/source/changelog.md @@ -1,6 +1,11 @@ ChanSort Change Log =================== +2021-03-27_2005 +- LG webOS 5: fixed handling of channels with an ampersand (&) character showing as "&" and not matching + a text-only reference list. + + 2021-03-27 - SatcoDX (.sdx): fixed handling of format version 105, which contains trailing data after the last channel - SatcoDX: changing the character set in the menu now instantly corrects channel names with non-ASCII characters