diff --git a/source/ChanSort.Loader.Toshiba/ChanSort.Loader.Toshiba.csproj b/source/ChanSort.Loader.Toshiba/ChanSort.Loader.Toshiba.csproj
index f85cdb2..4c337bc 100644
--- a/source/ChanSort.Loader.Toshiba/ChanSort.Loader.Toshiba.csproj
+++ b/source/ChanSort.Loader.Toshiba/ChanSort.Loader.Toshiba.csproj
@@ -25,6 +25,7 @@
4
x86
false
+ latest
pdbonly
@@ -34,6 +35,7 @@
prompt
4
false
+ latest
true
@@ -45,6 +47,7 @@
false
false
false
+ latest
..\Release\
@@ -56,6 +59,7 @@
false
false
false
+ latest
@@ -72,9 +76,10 @@
+
-
-
+
+
diff --git a/source/ChanSort.Loader.Toshiba/DbSerializer.cs b/source/ChanSort.Loader.Toshiba/ChmgtDbSerializer.cs
similarity index 98%
rename from source/ChanSort.Loader.Toshiba/DbSerializer.cs
rename to source/ChanSort.Loader.Toshiba/ChmgtDbSerializer.cs
index 053549c..4225fd7 100644
--- a/source/ChanSort.Loader.Toshiba/DbSerializer.cs
+++ b/source/ChanSort.Loader.Toshiba/ChmgtDbSerializer.cs
@@ -5,7 +5,7 @@ using ChanSort.Api;
namespace ChanSort.Loader.Toshiba
{
- class DbSerializer : SerializerBase
+ class ChmgtDbSerializer : SerializerBase
{
private const string FILE_chmgt_db = "\\chmgt_type001\\chmgt.db";
private const string FILE_dvbSysData_db = "\\dvb_type001\\dvbSysData.db";
@@ -19,7 +19,7 @@ namespace ChanSort.Loader.Toshiba
private readonly Dictionary channelInfoByUid = new Dictionary();
#region ctor()
- public DbSerializer(string inputFile) : base(inputFile)
+ public ChmgtDbSerializer(string inputFile) : base(inputFile)
{
DepencencyChecker.AssertVc2010RedistPackageX86Installed();
diff --git a/source/ChanSort.Loader.Toshiba/DbSerializerPlugin.cs b/source/ChanSort.Loader.Toshiba/DbSerializerPlugin.cs
deleted file mode 100644
index 7eaf51e..0000000
--- a/source/ChanSort.Loader.Toshiba/DbSerializerPlugin.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using ChanSort.Api;
-
-namespace ChanSort.Loader.Toshiba
-{
- public class DbSerializerPlugin : ISerializerPlugin
- {
- public string DllName { get; set; }
- public string PluginName => "Toshiba";
- public string FileFilter => "*.zip";
-
- public SerializerBase CreateSerializer(string inputFile)
- {
- return new DbSerializer(inputFile);
- }
- }
-}
diff --git a/source/ChanSort.Loader.Toshiba/SettingsDbSerializer.cs b/source/ChanSort.Loader.Toshiba/SettingsDbSerializer.cs
new file mode 100644
index 0000000..c9d6993
--- /dev/null
+++ b/source/ChanSort.Loader.Toshiba/SettingsDbSerializer.cs
@@ -0,0 +1,252 @@
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.SQLite;
+using System.IO;
+using ChanSort.Api;
+
+namespace ChanSort.Loader.Toshiba
+{
+ /*
+ * This class loads Toshiba files stores as CLONE00001\settingsDB.db along with settingsDBBackup.db
+ * Currently only channel renaming, reordering and deletion is supported.
+ * We don't know yet how/where information about favorites and skip/lock/hide is stored.
+ *
+ * Also, there are SatTable and SatTxTable for satellites and transponders in the file, but it's unknown
+ * how these tables are linked with EASISerTable / DVBSerTable / ...
+ */
+ class SettingsDbSerializer : SerializerBase
+ {
+ private readonly ChannelList channels = new ChannelList(SignalSource.All, "All");
+
+ #region ctor()
+ public SettingsDbSerializer(string inputFile) : base(inputFile)
+ {
+ DepencencyChecker.AssertVc2010RedistPackageX86Installed();
+
+ this.Features.ChannelNameEdit = ChannelNameEditMode.All;
+ this.Features.DeleteMode = DeleteMode.Physically;
+ this.Features.CanSkipChannels = false;
+ this.Features.CanLockChannels = false;
+ this.Features.CanHideChannels = false;
+ this.Features.SupportedFavorites = 0;
+
+ this.DataRoot.AddChannelList(this.channels);
+ }
+ #endregion
+
+ #region GetDataFilePaths()
+ public override IEnumerable GetDataFilePaths()
+ {
+ var list = new List();
+ list.Add(this.FileName);
+ var backupFile = GetBackupFilePath();
+ if (File.Exists(backupFile))
+ list.Add(backupFile);
+ return list;
+ }
+
+ private string GetBackupFilePath()
+ {
+ var dir = Path.GetDirectoryName(this.FileName);
+ var name = Path.GetFileNameWithoutExtension(this.FileName);
+ var ext = Path.GetExtension(this.FileName);
+ var backupFile = Path.Combine(dir, name + "Backup" + ext);
+ return backupFile;
+ }
+
+ #endregion
+
+ #region Load()
+ public override void Load()
+ {
+ string sysDataConnString = "Data Source=" + this.FileName;
+ using var conn = new SQLiteConnection(sysDataConnString);
+ conn.Open();
+ using var cmd = conn.CreateCommand();
+
+ this.RepairCorruptedDatabaseImage(cmd);
+
+ cmd.CommandText = "SELECT count(1) FROM sqlite_master WHERE type = 'table' and name='EASISerTable'";
+ if (Convert.ToInt32(cmd.ExecuteScalar()) != 1)
+ throw new FileLoadException("File doesn't contain the expected tables");
+
+ this.ReadSatellites(cmd);
+ this.ReadTransponders(cmd);
+ this.ReadChannels(cmd);
+ }
+ #endregion
+
+ #region RepairCorruptedDatabaseImage()
+ private void RepairCorruptedDatabaseImage(SQLiteCommand cmd)
+ {
+ cmd.CommandText = "REINDEX";
+ cmd.ExecuteNonQuery();
+ }
+ #endregion
+
+ #region ReadSatellites()
+ private void ReadSatellites(SQLiteCommand cmd)
+ {
+ cmd.CommandText = "select m_id, m_name_serialized, m_orbital_position from SatTable";
+ using var r = cmd.ExecuteReader();
+ while (r.Read())
+ {
+ Satellite sat = new Satellite(r.GetInt32(0));
+ string eastWest = "E";
+ int pos = r.GetInt32(2);
+ if (pos < 0)
+ {
+ pos = -pos;
+ eastWest = "W";
+ }
+ sat.OrbitalPosition = $"{pos / 10}.{pos % 10}{eastWest}";
+ sat.Name = r.GetString(1);
+ this.DataRoot.AddSatellite(sat);
+ }
+ }
+ #endregion
+
+ #region ReadTransponders()
+ private void ReadTransponders(SQLiteCommand cmd)
+ {
+ cmd.CommandText = "select m_id, m_satellite_id, m_frequency, m_polarisation, m_symbol_rate from SatTxTable";
+ using var r = cmd.ExecuteReader();
+ while (r.Read())
+ {
+ int id = r.GetInt32(0);
+ int satId = r.GetInt32(1);
+ int freq = r.GetInt32(2);
+
+ if (this.DataRoot.Transponder.TryGet(id) != null)
+ continue;
+ Transponder tp = new Transponder(id);
+ tp.FrequencyInMhz = (decimal)freq;
+ tp.Polarity = r.GetInt32(3) == 0 ? 'H' : 'V';
+ tp.Satellite = this.DataRoot.Satellites.TryGet(satId);
+ tp.SymbolRate = r.GetInt32(4);
+ this.DataRoot.AddTransponder(tp.Satellite, tp);
+ }
+ }
+ #endregion
+
+ #region ReadChannels()
+ private void ReadChannels(SQLiteCommand cmd)
+ {
+ int ixE = 0;
+ int ixD = 3;
+ int ixA = 8;
+ int ixT = 9;
+ int ixDC = 10;
+
+ cmd.CommandText = @"
+select
+ e.m_handle, e.m_rsn, e.m_name_serialized,
+ d.m_onid, d.m_tsid, d.m_id, d.m_type, d.m_name_serialized,
+ a.m_name_serialized,
+ t.frequency_in_multiples_of_10Hz,
+ dc.frequency
+from EASISerTable e
+left outer join DVBSerTable d on d.m_handle=e.m_handle
+left outer join AnalogSerTable a on a.m_handle=e.m_handle
+left outer join ChanDataTable dc on dc.handle=d.m_channel_no
+left outer join ChanDataTable ac on ac.handle=a.m_channel_no
+left outer join TADTunerDataTable t on t.channel=ac.channel_no";
+ using var r = cmd.ExecuteReader();
+ while (r.Read())
+ {
+ var handle = r.GetInt32(ixE + 0);
+ var oldProgNr = r.GetInt32(ixE + 1);
+ var name = r.GetString(ixE + 2);
+ ChannelInfo channel = new ChannelInfo(0, handle, oldProgNr, name);
+
+ // DVB
+ if (!r.IsDBNull(ixD + 0))
+ {
+ channel.OriginalNetworkId = r.GetInt32(ixD + 0) & 0x1FFF;
+ channel.TransportStreamId = r.GetInt32(ixD + 1) & 0x1FFF;
+ channel.ServiceId = r.GetInt32(ixD + 2) & 0x1FFF;
+ channel.ServiceType = r.GetInt32(ixD + 3);
+ channel.FreqInMhz = (decimal) r.GetInt32(ixDC + 0) / 1000;
+ }
+
+ // analog
+ if (!r.IsDBNull(ixA + 0))
+ {
+ channel.FreqInMhz = (decimal) r.GetInt32(ixT + 0) / 100000;
+ }
+
+ if (!channel.IsDeleted)
+ this.DataRoot.AddChannel(this.channels, channel);
+ }
+ }
+ #endregion
+
+
+ #region Save()
+ public override void Save(string tvOutputFile)
+ {
+ if (tvOutputFile != this.FileName)
+ {
+ File.Copy(this.FileName, tvOutputFile, true);
+ this.FileName = tvOutputFile;
+ }
+
+ string channelConnString = "Data Source=" + this.FileName;
+ using var conn = new SQLiteConnection(channelConnString);
+ conn.Open();
+ using var cmd = conn.CreateCommand();
+ using var cmd2 = conn.CreateCommand();
+ using var trans = conn.BeginTransaction();
+
+ this.WriteChannels(cmd, cmd2, this.channels);
+ trans.Commit();
+
+ this.RepairCorruptedDatabaseImage(cmd);
+ conn.Close();
+
+ // copy settingsDB.db to settingsDBBackup.db
+ var backupFile = GetBackupFilePath();
+ File.Copy(this.FileName, backupFile, true);
+ }
+ #endregion
+
+ #region WriteChannels()
+ private void WriteChannels(SQLiteCommand cmd, SQLiteCommand cmdDelete, ChannelList channelList)
+ {
+ cmd.CommandText = "update EASISerTable set m_rsn=@nr, m_name_serialized=@name where m_handle=@handle";
+ cmd.Parameters.Add(new SQLiteParameter("@handle", DbType.Int32));
+ cmd.Parameters.Add(new SQLiteParameter("@nr", DbType.Int32));
+ cmd.Parameters.Add(new SQLiteParameter("@name", DbType.String));
+ cmd.Prepare();
+
+ cmdDelete.CommandText = @"
+delete from EASISerTable where m_handle=@handle;
+delete from DVBSerTable where m_handle=@handle;
+delete from AnalogSerTable where m_handle=@handle;
+";
+ cmdDelete.Parameters.Add(new SQLiteParameter("@handle", DbType.Int32));
+
+ foreach (ChannelInfo channel in channelList.Channels)
+ {
+ if (channel.IsProxy) // ignore reference list proxy channels
+ continue;
+
+ if (channel.IsDeleted)
+ {
+ cmdDelete.Parameters["@handle"].Value = channel.RecordIndex;
+ cmdDelete.ExecuteNonQuery();
+ }
+ else
+ {
+ channel.UpdateRawData();
+ cmd.Parameters["@handle"].Value = channel.RecordIndex;
+ cmd.Parameters["@nr"].Value = channel.NewProgramNr;
+ cmd.Parameters["@name"].Value = channel.Name;
+ cmd.ExecuteNonQuery();
+ }
+ }
+ }
+ #endregion
+ }
+}
diff --git a/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs b/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs
new file mode 100644
index 0000000..b2262e7
--- /dev/null
+++ b/source/ChanSort.Loader.Toshiba/ToshibaPlugin.cs
@@ -0,0 +1,20 @@
+using System.IO;
+using ChanSort.Api;
+
+namespace ChanSort.Loader.Toshiba
+{
+ public class ToshibaPlugin : ISerializerPlugin
+ {
+ public string DllName { get; set; }
+ public string PluginName => "Toshiba";
+ public string FileFilter => "*.zip;*.db";
+
+ public SerializerBase CreateSerializer(string inputFile)
+ {
+ if (Path.GetExtension(inputFile).ToLower() == ".db")
+ return new SettingsDbSerializer(inputFile);
+ else
+ return new ChmgtDbSerializer(inputFile);
+ }
+ }
+}
diff --git a/source/ChanSort/MainForm.cs b/source/ChanSort/MainForm.cs
index d1aa2d3..9a15266 100644
--- a/source/ChanSort/MainForm.cs
+++ b/source/ChanSort/MainForm.cs
@@ -534,7 +534,8 @@ namespace ChanSort.Ui
catch (Exception ex)
{
serializer?.Dispose();
- errorMsgs.AppendLine($"{plugin.DllName} ({plugin.PluginName}): {ex}\n\n");
+ var errMsg = ex is FileLoadException ? ex.Message : ex.ToString(); // FileLoadExceptions are normal when a Loader does not support a file. No stack trace needed
+ errorMsgs.AppendLine($"{plugin.DllName} ({plugin.PluginName}): {errMsg}\n\n");
if (ex is ArgumentException)
{
var msg = ex.ToString();
diff --git a/source/Test.Loader.Toshiba/ToshibaChmgtDbTest.cs b/source/Test.Loader.Toshiba/ToshibaChmgtDbTest.cs
index 38161b6..32a008b 100644
--- a/source/Test.Loader.Toshiba/ToshibaChmgtDbTest.cs
+++ b/source/Test.Loader.Toshiba/ToshibaChmgtDbTest.cs
@@ -34,7 +34,7 @@ namespace Test.Loader.Toshiba
private void TestChannelsAddedToCorrectLists(string fileName, SignalSource signalSource, int expectedTv, int expectedRadio, int dataProgramSid = 0, string dataProgramName = null)
{
var tempFile = TestUtils.DeploymentItem("Test.Loader.Toshiba\\TestFiles\\" + fileName);
- var plugin = new DbSerializerPlugin();
+ var plugin = new ToshibaPlugin();
var ser = plugin.CreateSerializer(tempFile);
ser.Load();
@@ -72,7 +72,7 @@ namespace Test.Loader.Toshiba
public void TestDeletingChannel()
{
var tempFile = TestUtils.DeploymentItem("Test.Loader.Toshiba\\TestFiles\\Toshiba-SL863G.zip");
- var plugin = new DbSerializerPlugin();
+ var plugin = new ToshibaPlugin();
var ser = plugin.CreateSerializer(tempFile);
ser.Load();
var data = ser.DataRoot;
diff --git a/source/changelog.md b/source/changelog.md
index df2e7bf..a3f0b59 100644
--- a/source/changelog.md
+++ b/source/changelog.md
@@ -1,6 +1,9 @@
ChanSort Change Log
===================
+2021-01-23
+- Toshiba: added support for settingsDB.db lists
+
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)