- function to remove backup files (so that a new backup will be generated)

- remember last directory in FileOpenDialog, even when opening the file failed
- HDD Hex Editor Neo file structure definition
- improvements for Panasonic LS/LX serializer
This commit is contained in:
Horst Beham
2022-10-05 18:03:12 +02:00
parent 391a9f3872
commit e582cb95b7
6 changed files with 202 additions and 65 deletions

View File

@@ -4,6 +4,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using ChanSort.Api;
using Microsoft.Data.Sqlite;
@@ -39,29 +40,35 @@ internal class IdtvChannelSerializer : SerializerBase
Encrypted = 0x0002,
IsFavorite = 0x0080,
Deleted = 0x0100,
Hidden = 0x0400
Skip = 0x0400,
CustomProgNr = 0x1000
}
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential,Pack=1)]
unsafe struct IdtvChannel
{
public short U0; // always 1
public short RecordLength; // 60 + length of channel name
public short U4; // always 6
public fixed byte U6[10]; // all 00
public fixed byte U6[3]; // all 00
public ushort U9; // 0 = sat, 18 = cable ?
public fixed byte U11[5]; // all 00
public uint Freq; // Hz for DVB-C/T, kHz for DVB-S
public uint SymRate; // in Sym/s, like 22000000
public short U24; // always 100
public short U26; // always 0
public short U28; // always 0
public short ProgNr;
public fixed byte U32[4]; // e.g. 0a 01 00 00
public short Lcn; // maybe?
public fixed byte U32[2]; // e.g. 0a 01 00 00
public Flags Flags;
public fixed byte U38[4]; // 12 07 01 02
public short Tsid;
public short Onid;
public short Sid;
public fixed byte U48[16];
public fixed byte U48[4];
public uint InternalProviderFlag2; // seems like all sat channels are in the 20000-29999 range, dvb-c in 30000-39999
public fixed byte U56[8];
//public fixed byte ChannelName[RecordLength - 60]; // pseudo-C# description of variable length channel name UTF8 data at end of structure
}
@@ -70,18 +77,21 @@ internal class IdtvChannelSerializer : SerializerBase
private readonly string dbFile;
private readonly string binFile;
private Dictionary<int, ChannelInfo> channelDict = new(); // maps record-index of .bin file to Channel object created from .db file
private byte[] binFileData;
private List<int> binFileRecordOffsets = new();
private readonly StringBuilder log = new();
#region ctor()
public IdtvChannelSerializer(string inputFile) : base(inputFile)
public IdtvChannelSerializer(string hotelBin) : base(hotelBin)
{
dbFile = inputFile;
binFile = Path.Combine(Path.GetDirectoryName(dbFile), "channel", "idtvChannel.bin");
var dir = Path.Combine(Path.GetDirectoryName(hotelBin), "mnt/vendor/tvdata/database");
dbFile = Path.Combine(dir, "tv.db");
binFile = Path.Combine(dir, "channel", "idtvChannel.bin");
this.Features.CanSaveAs = false;
this.Features.FavoritesMode = FavoritesMode.Flags;
this.Features.DeleteMode = DeleteMode.FlagWithPrNr;
this.DataRoot.AddChannelList(new ChannelList(SignalSource.Antenna | SignalSource.MaskTvRadioData, "Antenna"));
this.DataRoot.AddChannelList(new ChannelList(SignalSource.Cable | SignalSource.MaskTvRadioData, "Cable"));
@@ -89,6 +99,7 @@ internal class IdtvChannelSerializer : SerializerBase
foreach (var list in this.DataRoot.ChannelLists)
{
var names = list.VisibleColumnFieldNames;
names.Remove(nameof(ChannelInfo.Hidden)); // the TV's "hide" function actually works like "skip", only removing it from zapping, but allowing direct number input
names.Remove(nameof(ChannelInfo.ShortName));
names.Remove(nameof(ChannelInfo.Satellite));
names.Remove(nameof(ChannelInfo.PcrPid));
@@ -178,8 +189,8 @@ internal class IdtvChannelSerializer : SerializerBase
ch.Hidden = !r.GetBoolean(cols["searchable"]);
ch.Encrypted = r.GetBoolean(cols["scrambled"]);
ch.OriginalNetworkId = r.GetInt16(cols["original_network_id"]);
ch.TransportStreamId = r.GetInt16(cols["transport_stream_id"]);
ch.OriginalNetworkId = r.GetInt32(cols["original_network_id"]);
ch.TransportStreamId = r.GetInt32(cols["transport_stream_id"]);
ch.ServiceId = r.GetInt32(cols["service_id"]);
ch.FreqInMhz = r.GetInt64(cols["internal_provider_flag1"]) / 1000; // for DVB-S it is in MHz, for DVB-C/T it is in kHz
if (ch.FreqInMhz >= 13000)
@@ -197,6 +208,9 @@ internal class IdtvChannelSerializer : SerializerBase
var list = this.DataRoot.GetChannelList(signalSource);
this.DataRoot.AddChannel(list, ch);
if (channelDict.TryGetValue(ch.RecordOrder, out var otherChannel))
throw new FileLoadException($"tv.db channel _ids {otherChannel.RecordIndex} ({otherChannel.Name}) and {ch.RecordIndex} ({ch.Name}) both reference same idtvChannel.bin record {ch.RecordOrder}\n"+
"Please make sure to search satellite channels first and cable/antenna afterwards.");
channelDict.Add(ch.RecordOrder, ch);
}
}
@@ -205,19 +219,19 @@ internal class IdtvChannelSerializer : SerializerBase
#region ReadIdtvChannelsBin()
private void ReadIdtvChannelsBin()
{
this.binFileData = File.ReadAllBytes(this.binFile);
// verify MD5 checksum
var data = File.ReadAllBytes(this.binFile);
var md5 = MD5.Create();
var hash = md5.ComputeHash(data, 24, data.Length - 24);
var hash = md5.ComputeHash(binFileData, 24, binFileData.Length - 24);
int i;
for (i = 0; i < 16; i++)
{
if (data[8 + i] != hash[i])
if (binFileData[8 + i] != hash[i])
throw new FileLoadException("Invalid MD5 checksum in " + binFile);
}
using var strm = new MemoryStream(data);
using var strm = new MemoryStream(binFileData);
using var r = new BinaryReader(strm);
r.ReadBytes(2 + 2); // 00 00, 4b 09
@@ -226,8 +240,10 @@ internal class IdtvChannelSerializer : SerializerBase
r.ReadBytes(16); // md5
i = 0;
log.AppendLine($"#\tname\tprogNr\tonid-tsid-sid\tflags\tlcn\tipf2");
var structSize = Marshal.SizeOf<IdtvChannel>();
while (strm.Position + structSize <= data.Length)
while (strm.Position + structSize <= binFileData.Length)
{
var off = strm.Position;
binFileRecordOffsets.Add((int)off);
@@ -245,7 +261,7 @@ internal class IdtvChannelSerializer : SerializerBase
var progNr = chan.ProgNr;
var name = Encoding.UTF8.GetString(r.ReadBytes(chan.RecordLength - 60));
log.AppendLine($"{i}\t{name}\t{progNr}\t{chan.Onid}-{chan.Tsid}-{chan.Sid}\t{(ushort)chan.Flags:X4}");
log.AppendLine($"{i}\t{name}\t{progNr}\t{chan.Onid}-{chan.Tsid}-{chan.Sid}\t{(ushort)chan.Flags:X4}\t{chan.Lcn}\t{chan.InternalProviderFlag2}");
if (channelDict.TryGetValue(i, out var ch))
{
@@ -260,8 +276,8 @@ internal class IdtvChannelSerializer : SerializerBase
if (ch.Encrypted != ((chan.Flags & Flags.Encrypted) != 0))
throw new FileLoadException($"mismatching crypt-flag between tv.db _id {ch.RecordIndex} ({ch.Encrypted}) and idtvChannel.bin record {i}");
if (ch.Hidden != ((chan.Flags & Flags.Hidden) != 0))
throw new FileLoadException($"mismatching hide-flag between tv.db _id {ch.RecordIndex} ({ch.Hidden}) and idtvChannel.bin record {i}");
if (ch.Skip != ((chan.Flags & Flags.Skip) != 0))
throw new FileLoadException($"mismatching browsable-flag between tv.db _id {ch.RecordIndex} ({ch.Skip}) and idtvChannel.bin record {i}");
if ((ch.Favorites == 0) != ((chan.Flags & Flags.IsFavorite) == 0))
throw new FileLoadException($"mismatching favorites-info between tv.db _id {ch.RecordIndex} ({ch.Favorites}) and idtvChannel.bin record {i}");
@@ -292,9 +308,9 @@ internal class IdtvChannelSerializer : SerializerBase
public override void Save(string tvOutputFile)
{
// saving the list requires to:
// - physically reorder the .bin file and update fields inside the data records
// - update fields inside the data records and physically reorder the records
// - updating records in the .db file
// - updating this loaders internal data in channelDict, binFileRecordOffsets and channelInfo.RecordOrder for consecutive save operations to work
// - updating all channel record indexes in this loader's internal data in channelDict, binFileRecordOffsets and channelInfo.RecordOrder for consecutive save operations to work
GetNewIdtvChannelBinRecordOrder(out var newToOld, out var oldToNew);
@@ -310,8 +326,17 @@ internal class IdtvChannelSerializer : SerializerBase
newToOld = new List<int>(binFileRecordOffsets.Count);
for (int i = 0, c=this.binFileRecordOffsets.Count; i<c; i++)
newToOld.Add(i);
var offFreq = (int)Marshal.OffsetOf<IdtvChannel>(nameof(IdtvChannel.Freq));
newToOld.Sort((a, b) =>
{
// all sat channels must come first before cable/antenna channels
var freq1 = BitConverter.ToUInt32(this.binFileData, binFileRecordOffsets[a] + offFreq);
var freq2 = BitConverter.ToUInt32(this.binFileData, binFileRecordOffsets[b] + offFreq);
var c = (freq1 < 14000000 ? 0 : 1).CompareTo(freq2 < 14000000 ? 0 : 1); // hack: Sat has values below 14 000 000 (in kHz), Cable/antenna above (in Hz)
if (c != 0)
return c;
this.channelDict.TryGetValue(a, out var ch1);
this.channelDict.TryGetValue(b, out var ch2);
if (ch1 == null && ch2 == null)
@@ -321,7 +346,7 @@ internal class IdtvChannelSerializer : SerializerBase
if (ch1 == null)
return +1;
var c = ch1.SignalSource.CompareTo(ch2.SignalSource); // group by DVB-C/T/S and TV/Radio/Data
c = ((int)ch1.SignalSource).CompareTo((int)ch2.SignalSource); // group TV/Radio/Data
if (c != 0)
return c;
c = ch1.NewProgramNr.CompareTo(ch2.NewProgramNr);
@@ -341,64 +366,70 @@ internal class IdtvChannelSerializer : SerializerBase
#region SaveIdtvChannelBin()
private void SaveIdtvChannelBin(IList<int> newToOld)
{
var data = UpdateIdtvChannelBinRecords();
data = ReorderBinFileRecords(data, newToOld);
UpdateIdtvChannelBinRecords();
ReorderBinFileRecords(newToOld);
// update MD5 checksum
var md5 = MD5.Create();
var checksum = md5.ComputeHash(data, 8 + 16, data.Length - 8 - 16);
Array.Copy(checksum, 0, data, 8, 16);
var checksum = md5.ComputeHash(binFileData, 8 + 16, binFileData.Length - 8 - 16);
Array.Copy(checksum, 0, binFileData, 8, 16);
File.WriteAllBytes(binFile, data);
File.WriteAllBytes(binFile, binFileData);
}
#endregion
#region UpdateIdtvChannelBinRecords()
private byte[] UpdateIdtvChannelBinRecords()
private void UpdateIdtvChannelBinRecords()
{
// in-place update of the old .bin file data
var offProgNr = (int)Marshal.OffsetOf<IdtvChannel>(nameof(IdtvChannel.ProgNr));
var offFlags = (int)Marshal.OffsetOf<IdtvChannel>(nameof(IdtvChannel.Flags));
var data = File.ReadAllBytes(this.binFile);
var w = new BinaryWriter(new MemoryStream(data));
var w = new BinaryWriter(new MemoryStream(this.binFileData));
foreach (var list in this.DataRoot.ChannelLists)
{
foreach (var ch in list.Channels)
{
if (ch.IsProxy)
continue;
var filePosition = this.binFileRecordOffsets[ch.RecordOrder];
w.Seek(filePosition + offProgNr, SeekOrigin.Begin);
w.Write((ushort)ch.NewProgramNr);
//w.Write(ch.NewProgramNr > 0 ? (ushort)ch.NewProgramNr : (ushort)0xFFFE); // deleted channels have -2 / 0xFFFE
w.Write(ch.NewProgramNr);
// update flags
var off = filePosition + offFlags;
var flags = BitConverter.ToUInt16(data, off);
var flags = BitConverter.ToUInt16(this.binFileData, off);
if (ch.Favorites == 0)
flags = (ushort)(flags & ~(ushort)Flags.IsFavorite);
else
flags = (ushort)(flags | (ushort)Flags.IsFavorite);
if (ch.Hidden)
flags = (ushort)(flags | (ushort)Flags.Hidden);
if (ch.Skip)
flags = (ushort)(flags | (ushort)Flags.Skip);
else
flags = (ushort)(flags & ~(ushort)Flags.Hidden);
flags = (ushort)(flags & ~(ushort)Flags.Skip);
if (ch.IsDeleted)
flags |= (ushort)Flags.Deleted;
flags |= (ushort)Flags.CustomProgNr;
w.Seek(filePosition + offFlags, SeekOrigin.Begin);
w.Write(flags);
}
}
w.Flush();
return data;
}
#endregion
#region ReorderBinFileRecords()
private byte[] ReorderBinFileRecords(byte[] binFileData, IList<int> newToOld)
private void ReorderBinFileRecords(IList<int> newToOld)
{
using var mem = new MemoryStream(binFileData.Length);
using var mem = new MemoryStream(this.binFileData.Length);
mem.Write(binFileData, 0, 8 + 16); // copy header
var newOffsets = new List<int>(newToOld.Count);
@@ -416,7 +447,6 @@ internal class IdtvChannelSerializer : SerializerBase
binFileData = new byte[mem.Length];
Array.Copy(mem.GetBuffer(), 0, binFileData, 0, mem.Length);
return binFileData;
}
#endregion
@@ -430,11 +460,11 @@ internal class IdtvChannelSerializer : SerializerBase
using var trans = db.BeginTransaction();
using var upd = db.CreateCommand();
upd.CommandText = "update channels set display_number=@progNr, browsable=@browseable, searchable=@searchable, locked=@locked, favorite=@fav, channel_index=@recIdx where _id=@id";
upd.CommandText = "update channels set display_number=@progNr, browsable=@browseable, locked=@locked, favorite=@fav, channel_index=@recIdx where _id=@id"; // searchable=@searchable,
upd.Parameters.Add("@id", SqliteType.Integer);
upd.Parameters.Add("@progNr", SqliteType.Text);
upd.Parameters.Add("@browseable", SqliteType.Integer);
upd.Parameters.Add("@searchable", SqliteType.Integer);
//upd.Parameters.Add("@searchable", SqliteType.Integer);
upd.Parameters.Add("@locked", SqliteType.Integer);
upd.Parameters.Add("@fav", SqliteType.Integer);
upd.Parameters.Add("@recIdx", SqliteType.Integer);
@@ -464,7 +494,7 @@ internal class IdtvChannelSerializer : SerializerBase
upd.Parameters["@id"].Value = ch.RecordIndex;
upd.Parameters["@progNr"].Value = ch.NewProgramNr;
upd.Parameters["@browseable"].Value = !ch.Skip;
upd.Parameters["@searchable"].Value = !ch.Hidden;
//upd.Parameters["@searchable"].Value = !ch.Hidden;
upd.Parameters["@locked"].Value = ch.Lock;
upd.Parameters["@fav"].Value = (int)ch.Favorites;
upd.Parameters["@recIdx"].Value = newRecordIndex;

View File

@@ -15,13 +15,14 @@ namespace ChanSort.Loader.Panasonic
// check for files in the 2022 /mnt/vendor/tvdata/database/channel/ directory structure file format with tv.db and idtvChannel.bin
var name = Path.GetFileName(inputFile).ToLowerInvariant();
var baseDir = Path.GetDirectoryName(inputFile);
if (name == "hotel.bin")
baseDir = Path.Combine(baseDir, "mnt", "vendor", "tvdata", "database");
if (name == "idtvChannel.bin")
baseDir = Path.GetDirectoryName(baseDir);
var tvDb = Path.Combine(baseDir, "tv.db");
if (File.Exists(tvDb) && File.Exists(Path.Combine(baseDir, "channel", "idtvChannel.bin")))
return new IdtvChannelSerializer(tvDb);
if (name == "idtvchannel.bin")
baseDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(baseDir))))); // go down channel/database/tvdata/vendor/mnt
else if (name == "tv.db")
baseDir = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(baseDir)))); // go down database/tvdata/vendor/mnt
var hotelBin = Path.Combine(baseDir, "hotel.bin");
if (File.Exists(hotelBin) && File.Exists(Path.Combine(baseDir, "mnt/vendor/tvdata/database", "tv.db")) && File.Exists(Path.Combine(baseDir, "mnt/vendor/tvdata/database/channel", "idtvChannel.bin")))
return new IdtvChannelSerializer(hotelBin);
// Android based models use an .xml format. Unfortunately that format is utter garbage and not really useful
var ext = Path.GetExtension(inputFile).ToLowerInvariant();

View File

@@ -220,6 +220,7 @@
this.popupInputSource = new DevExpress.XtraBars.PopupMenu(this.components);
this.popupFavList = new DevExpress.XtraBars.PopupMenu(this.components);
this.timerSelectFocusedRow = new System.Windows.Forms.Timer(this.components);
this.miDeleteBackup = new DevExpress.XtraBars.BarButtonItem();
((System.ComponentModel.ISupportInitialize)(this.splitContainerControl1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.splitContainerControl1.Panel1)).BeginInit();
this.splitContainerControl1.Panel1.SuspendLayout();
@@ -235,7 +236,6 @@
((System.ComponentModel.ISupportInitialize)(this.repositoryItemTextEdit1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pnlEditControls)).BeginInit();
this.pnlEditControls.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.globalImageCollection1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.grpInputList)).BeginInit();
this.grpInputList.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.gridRight)).BeginInit();
@@ -494,10 +494,6 @@
this.btnSearchLeft.Name = "btnSearchLeft";
this.btnSearchLeft.Click += new System.EventHandler(this.btnSearch_Click);
//
// globalImageCollection1
//
this.globalImageCollection1.ParentControl = this;
//
// btnToggleFavH
//
resources.ApplyResources(this.btnToggleFavH, "btnToggleFavH");
@@ -1129,9 +1125,10 @@
this.miSplitView,
this.miTheme,
this.miAutoHideColumns,
this.miLoadListAfterStart});
this.miLoadListAfterStart,
this.miDeleteBackup});
this.barManager1.MainMenu = this.bar1;
this.barManager1.MaxItemId = 117;
this.barManager1.MaxItemId = 118;
this.barManager1.ShowFullMenus = true;
this.barManager1.ShortcutItemClick += new DevExpress.XtraBars.ShortcutItemClickEventHandler(this.barManager1_ShortcutItemClick);
//
@@ -1182,6 +1179,7 @@
new DevExpress.XtraBars.LinkPersistInfo(this.miOpen),
new DevExpress.XtraBars.LinkPersistInfo(this.miReload),
new DevExpress.XtraBars.LinkPersistInfo(this.miRestoreOriginal),
new DevExpress.XtraBars.LinkPersistInfo(this.miDeleteBackup),
new DevExpress.XtraBars.LinkPersistInfo(this.miFileInformation),
new DevExpress.XtraBars.LinkPersistInfo(this.miSave, true),
new DevExpress.XtraBars.LinkPersistInfo(this.miSaveAs),
@@ -2224,6 +2222,13 @@
//
this.timerSelectFocusedRow.Tick += new System.EventHandler(this.timerSelectFocusedRow_Tick);
//
// miDeleteBackup
//
resources.ApplyResources(this.miDeleteBackup, "miDeleteBackup");
this.miDeleteBackup.Id = 117;
this.miDeleteBackup.Name = "miDeleteBackup";
this.miDeleteBackup.ItemClick += new DevExpress.XtraBars.ItemClickEventHandler(this.miDeleteBackup_ItemClick);
//
// MainForm
//
this.AllowDrop = true;
@@ -2256,7 +2261,6 @@
((System.ComponentModel.ISupportInitialize)(this.repositoryItemTextEdit1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pnlEditControls)).EndInit();
this.pnlEditControls.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.globalImageCollection1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.grpInputList)).EndInit();
this.grpInputList.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.gridRight)).EndInit();
@@ -2480,6 +2484,7 @@
private System.Windows.Forms.Timer timerSelectFocusedRow;
private DevExpress.XtraBars.BarButtonItem miAutoHideColumns;
private DevExpress.XtraBars.BarButtonItem miLoadListAfterStart;
}
private DevExpress.XtraBars.BarButtonItem miDeleteBackup;
}
}

View File

@@ -57,6 +57,7 @@ namespace ChanSort.Ui
private bool splitView = true;
private int ignoreEvents;
private bool adjustWindowLocationOnScale = true;
private string lastOpenedFile;
#region ctor()
@@ -244,7 +245,8 @@ namespace ChanSort.Ui
var filter = GetTvDataFileFilter(out var supportedExtensions, out var numberOfFilters);
using var dlg = new OpenFileDialog();
dlg.InitialDirectory = this.mruFiles.Count > 0 ? Path.GetDirectoryName(this.mruFiles[0]) : Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
var lastFile = this.lastOpenedFile ?? (this.mruFiles.Count > 0 ? this.mruFiles[0] : null);
dlg.InitialDirectory = lastFile != null ? Path.GetDirectoryName(this.lastOpenedFile) : Environment.GetFolderPath(Environment.SpecialFolder.MyComputer);
dlg.AddExtension = true;
dlg.Filter = filter + string.Format(Resources.MainForm_FileDialog_OpenFileFilter, supportedExtensions);
dlg.FilterIndex = numberOfFilters + 1;
@@ -321,6 +323,7 @@ namespace ChanSort.Ui
private void LoadFiles(ISerializerPlugin plugin, string tvDataFile)
{
var dataUpdated = false;
this.lastOpenedFile = tvDataFile;
try
{
if (DetectCommonFileCorruptions(tvDataFile))
@@ -1761,6 +1764,7 @@ namespace ChanSort.Ui
this.miReload.Enabled = fileLoaded;
this.miFileInformation.Enabled = fileLoaded;
this.miRestoreOriginal.Enabled = fileLoaded && this.GetPathOfMissingBackupFile() == null;
this.miDeleteBackup.Enabled = fileLoaded;
this.miSave.Enabled = fileLoaded;
this.miSaveAs.Enabled = fileLoaded && this.currentTvSerializer.Features.CanSaveAs;
this.miOpenReferenceFile.Enabled = fileLoaded;
@@ -1884,6 +1888,32 @@ namespace ChanSort.Ui
}
#endregion
#region DeleteBackupFile()
private void DeleteBackupFile()
{
if (this.currentTvSerializer == null)
return;
var files = this.currentTvSerializer.GetDataFilePaths();
string lastError = null;
foreach (var file in files)
{
try
{
var bak = file + ".bak";
if (File.Exists(bak))
File.Delete(bak);
}
catch (Exception ex)
{
lastError = ex.Message;
}
}
if (lastError != null)
XtraMessageBox.Show(this, lastError);
}
#endregion
#region ShowFileInformation()
private void ShowFileInformation()
@@ -3159,6 +3189,11 @@ namespace ChanSort.Ui
TryExecute(this.RestoreBackupFile);
}
private void miDeleteBackup_ItemClick(object sender, ItemClickEventArgs e)
{
TryExecute(this.DeleteBackupFile);
}
private void miFileInformation_ItemClick(object sender, ItemClickEventArgs e)
{
TryExecute(this.ShowFileInformation);

View File

@@ -276,7 +276,7 @@
<value>gridLeft</value>
</data>
<data name="&gt;&gt;gridLeft.Type" xml:space="preserve">
<value>ChanSort.XGridControl, ChanSort, Version=1.0.8308.20323, Culture=neutral, PublicKeyToken=null</value>
<value>ChanSort.XGridControl, ChanSort, Version=1.0.8313.22695, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;gridLeft.Parent" xml:space="preserve">
<value>grpOutputList</value>
@@ -410,6 +410,9 @@
<data name="miRestoreOriginal.ImageOptions.ImageIndex" type="System.Int32, mscorlib">
<value>31</value>
</data>
<data name="miDeleteBackup.Caption" xml:space="preserve">
<value>Delete backup files</value>
</data>
<data name="miFileInformation.Caption" xml:space="preserve">
<value>File &amp;information...</value>
</data>
@@ -1237,7 +1240,7 @@
<value>gviewLeft</value>
</data>
<data name="&gt;&gt;gviewLeft.Type" xml:space="preserve">
<value>ChanSort.XGridView, ChanSort, Version=1.0.8308.20323, Culture=neutral, PublicKeyToken=null</value>
<value>ChanSort.XGridView, ChanSort, Version=1.0.8313.22695, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;colIndex1.Name" xml:space="preserve">
<value>colIndex1</value>
@@ -1321,13 +1324,13 @@
<value>globalImageCollection1</value>
</data>
<data name="&gt;&gt;globalImageCollection1.Type" xml:space="preserve">
<value>ChanSort.Ui.GlobalImageCollection, ChanSort, Version=1.0.8308.20323, Culture=neutral, PublicKeyToken=null</value>
<value>ChanSort.Ui.GlobalImageCollection, ChanSort, Version=1.0.8313.22695, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;gviewRight.Name" xml:space="preserve">
<value>gviewRight</value>
</data>
<data name="&gt;&gt;gviewRight.Type" xml:space="preserve">
<value>ChanSort.XGridView, ChanSort, Version=1.0.8308.20323, Culture=neutral, PublicKeyToken=null</value>
<value>ChanSort.XGridView, ChanSort, Version=1.0.8313.22695, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;colIndex.Name" xml:space="preserve">
<value>colIndex</value>
@@ -2091,12 +2094,24 @@
<data name="&gt;&gt;timerSelectFocusedRow.Type" xml:space="preserve">
<value>System.Windows.Forms.Timer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;miDeleteBackup.Name" xml:space="preserve">
<value>miDeleteBackup</value>
</data>
<data name="&gt;&gt;miDeleteBackup.Type" xml:space="preserve">
<value>DevExpress.XtraBars.BarButtonItem, DevExpress.XtraBars.v22.1, Version=22.1.5.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>MainForm</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>DevExpress.XtraEditors.XtraForm, DevExpress.Utils.v22.1, Version=22.1.5.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a</value>
</data>
<data name="SharedImageCollection.Timestamp" type="System.DateTime, mscorlib">
<value>10/05/2022 12:50:36</value>
</data>
<data name="SharedImageCollection.ImageSize" type="System.Drawing.Size, System.Drawing">
<value>16, 16</value>
</data>
<data name="btnSearchLeft.Location" type="System.Drawing.Point, System.Drawing">
<value>444, 5</value>
</data>
@@ -2982,7 +2997,7 @@
<value>gridRight</value>
</data>
<data name="&gt;&gt;gridRight.Type" xml:space="preserve">
<value>ChanSort.XGridControl, ChanSort, Version=1.0.8308.20323, Culture=neutral, PublicKeyToken=null</value>
<value>ChanSort.XGridControl, ChanSort, Version=1.0.8313.22695, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;gridRight.Parent" xml:space="preserve">
<value>grpInputList</value>

View File

@@ -0,0 +1,51 @@
#include "chansort.h"
/***********************************************************
* Panasonic LS/LX 2022 idtvChannel.bin
***********************************************************/
enum Flags : word
{
Encrypted = 0x0002,
IsFavorite = 0x0080,
Deleted = 0x0100,
Hidden = 0x0400,
CustomProgNr = 0x1000
};
struct Pa_idtvChannel_bin_FileEntry
{
word U0; // always 1
word RecordLength; // 60 + length of channel name
word U4; // always 6
byte U6[3]; // all 00
word U9; // 0 = Sat, 18 = Cable ?
byte U11[5]; // all 00
dword Freq; // Hz for DVB-C/T, kHz for DVB-S
dword SymRate; // in Sym/s, like 22000000
word U24; // always 100
word U26; // always 0
word U28; // always 0
word ProgNr;
word LcnMaybe;
byte U32[2]; // e.g. 0a 01 00 00
Flags Flags;
byte U38[4]; // 12 07 01 02
word Tsid;
word Onid;
word Sid;
byte U48[4];
dword ProviderFlag2;
byte U56[8];
byte ChannelName[RecordLength - 60];
};
public struct Pa_idtvChannel_bin
{
word u0;
word u2;
word numRecords;
word u6;
byte md5[16];
Pa_idtvChannel_bin_FileEntry fileEntries[numRecords];
};