finished DVB-C and DVB-S2 implementation of Philips BIN format with Repair / channellib/*Table and s2channellib/*.dat format

This commit is contained in:
Horst Beham
2020-08-10 11:27:05 +02:00
parent bfc12eae66
commit df5d8770be
9 changed files with 444 additions and 137 deletions

View File

@@ -64,6 +64,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Channel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Serializer.cs" />
<Compile Include="SerializerPlugin.cs" />

View File

@@ -17,3 +17,28 @@ lenName=32
offProvider=60
lenProvider=32
[CableDigSrvTable_entry]
offChecksum=0
offSymbolRate=24
offFreqTimes16=48
offOnid=50
offSid=52
offTsid=54
offProgNr=122
offLocked=146
offIsFav=147
offName=216
lenName=64
[CablePresetTable_entry]
offChecksum=0
offFreqTimes16=4
offProgNr=8
offOnid=14
offTsid=16
offSid=18
[CableFrqMapTable_entry]
offChecksum=0
offSymbolRate=8
offFreq=18

View File

@@ -0,0 +1,16 @@
using ChanSort.Api;
namespace ChanSort.Loader.PhilipsBin
{
class Channel : ChannelInfo
{
public Channel(SignalSource source, long index, int oldProgNr, string name) : base(source, index, oldProgNr, name)
{
}
/// <summary>
/// index of the record in the AntennaPresetTable / CablePresetTable file for the channel, matched by (onid + tsid + sid)
/// </summary>
public int PresetTableIndex { get; set; } = -1;
}
}

View File

@@ -3,16 +3,19 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Schema;
using ChanSort.Api;
namespace ChanSort.Loader.PhilipsBin
{
/*
channellib\CableDigSrvTable:
===========================
Channels in this file are not phyiscally ordered by the program number and there is no linked list with prev/next indexes.
When editing a channel with the Philips Channel Editor, it only updates the progNr field (and overwrites all trailing bytes of the channel name with 0x00).
There is also the CablePresetTable file which is probably used for LCN. The Philips tool also updates the progNr in that file and uses it as is primary source
for the progNr. I don't know if there is a direct reference from the channel to the preset, hence this code uses the combination of ONID+TSID+SID to link the two.
s2channellib\service.dat:
========================
All observed files have a perfectly linear next/prev table. The Philips Channel Editor also keeps that list linear and physically reorders the channel records.
@@ -27,17 +30,20 @@ namespace ChanSort.Loader.PhilipsBin
When swapping satellite channels 1 and 2 with the Philips Channel Editor 6.62, it only updates a few fields and leaves the rest stale.
updated: SID, transponderIndex, channelName, providerName
This code here copyies the whole record before updating the fields
This code here copies the whole record before updating the fields.
The favorite.dat file stores favorites as linked list which may support independent ordering from the main channel list.
The Philips editor even saves non-linear lists, but not in any particular order.
*/
class Serializer : SerializerBase
{
private readonly IniFile ini;
private readonly List<string> dataFilePaths = new List<string>();
private readonly ChannelList dvbtChannels = new ChannelList(SignalSource.DvbCT, "DVB-T");
private readonly ChannelList dvbcChannels = new ChannelList(SignalSource.DvbCT, "DVB-C");
private readonly ChannelList dvbtChannels = new ChannelList(SignalSource.DvbT, "DVB-T");
private readonly ChannelList dvbcChannels = new ChannelList(SignalSource.DvbC, "DVB-C");
private readonly ChannelList satChannels = new ChannelList(SignalSource.DvbS, "DVB-S");
#region ctor()
public Serializer(string inputFile) : base(inputFile)
{
@@ -49,7 +55,7 @@ namespace ChanSort.Loader.PhilipsBin
this.Features.CanSaveAs = false;
this.Features.CanHaveGaps = false;
this.Features.SupportedFavorites = Favorites.A;
this.Features.SortedFavorites = true;
this.Features.SortedFavorites = false; // satellite favorites are stored in a separate file that may support independent sorting, but DVB C/T only have a flag
this.Features.AllowGapsInFavNumbers = false;
this.Features.CanEditFavListNames = false;
@@ -61,17 +67,20 @@ namespace ChanSort.Loader.PhilipsBin
{
list.VisibleColumnFieldNames.Remove("Skip");
list.VisibleColumnFieldNames.Remove("ShortName");
list.VisibleColumnFieldNames.Remove("ServiceTypeName");
list.VisibleColumnFieldNames.Remove("Hidden");
list.VisibleColumnFieldNames.Remove("AudioPid");
list.VisibleColumnFieldNames.Remove("Encrypted");
}
var supportedColumns = new[] {"OldPosition", "Position", "Name", "Lock"};
//this.satChannels.VisibleColumnFieldNames.Clear();
//foreach(var supportedColumn in supportedColumns)
// this.satChannels.VisibleColumnFieldNames.Add(supportedColumn);
this.satChannels.VisibleColumnFieldNames.Remove("AudioPid");
this.satChannels.VisibleColumnFieldNames.Remove("ServiceTypeName");
this.satChannels.VisibleColumnFieldNames.Remove("Encrypted");
this.satChannels.VisibleColumnFieldNames.Remove("Hidden");
foreach (var list in new[] {dvbcChannels, dvbtChannels})
{
list.VisibleColumnFieldNames.Remove("PcrPid");
list.VisibleColumnFieldNames.Remove("VideoPid");
list.VisibleColumnFieldNames.Remove("AudioPid");
list.VisibleColumnFieldNames.Remove("ChannelOrTransponder");
list.VisibleColumnFieldNames.Remove("Provider");
}
string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini");
this.ini = new IniFile(iniFile);
@@ -87,32 +96,43 @@ namespace ChanSort.Loader.PhilipsBin
+ "ChannelList\\channellib\\CableDigSrvTable\n"
+ "ChannelList\\s2channellib\\service.dat");
var dir = Path.GetDirectoryName(this.FileName);
LoadDvbCT(dvbtChannels, Path.Combine(dir, "channellib", "AntennaDigSrvTable"));
LoadDvbCT(dvbcChannels, Path.Combine(dir, "channellib", "CableDigSrvTable"));
var dir = Path.GetDirectoryName(this.FileName) ?? "";
var channellib = Path.Combine(dir, "channellib");
var s2channellib = Path.Combine(dir, "s2channellib");
LoadDvbsSatellites(Path.Combine(dir, "s2channellib", "satellite.dat"));
LoadDvbsTransponders(Path.Combine(dir, "s2channellib", "tuneinfo.dat"));
LoadDvbS(satChannels, Path.Combine(dir, "s2channellib", "service.dat"));
LoadDvbsFavorites(Path.Combine(dir, "s2channellib", "favorite.dat"));
var db_file_info = Path.Combine(dir, "s2channellib", "db_file_info.dat");
// channellib files for DVB-C/T
LoadDvbCT(dvbtChannels, Path.Combine(channellib, "AntennaDigSrvTable"));
LoadDvbCTPresets(dvbtChannels, Path.Combine(channellib, "AntennaPresetTable"));
LoadDvbCT(dvbcChannels, Path.Combine(channellib, "CableDigSrvTable"));
LoadDvbCTPresets(dvbcChannels, Path.Combine(channellib, "CablePresetTable"));
// s2channellib files for DVB-S
LoadDvbsSatellites(Path.Combine(s2channellib, "satellite.dat"));
LoadDvbsTransponders(Path.Combine(s2channellib, "tuneinfo.dat"));
LoadDvbS(satChannels, Path.Combine(s2channellib, "service.dat"));
LoadDvbsFavorites(Path.Combine(s2channellib, "favorite.dat"));
var db_file_info = Path.Combine(s2channellib, "db_file_info.dat");
if (File.Exists(db_file_info))
this.dataFilePaths.Add(db_file_info);
// for a proper ChanSort backup/restore with .bak files, the Philips _backup.dat files must also be included
foreach(var file in this.dataFilePaths.ToList())
this.dataFilePaths.Add(file.Replace(".dat", "_backup.dat"));
foreach (var file in this.dataFilePaths.ToList())
{
if (file.Contains(".dat"))
this.dataFilePaths.Add(file.Replace(".dat", "_backup.dat"));
}
}
#endregion
#region SetFileNameToChanLstBin()
private bool SetFileNameToChanLstBin()
{
var dir = Path.GetDirectoryName(this.FileName);
var dir = Path.GetDirectoryName(this.FileName) ?? "";
var dirName = Path.GetFileName(dir);
if (StringComparer.InvariantCultureIgnoreCase.Compare(dirName, "channellib") == 0 || StringComparer.InvariantCultureIgnoreCase.Compare(dirName, "s2channellib") == 0)
{
dir = Path.GetDirectoryName(dir);
dir = Path.GetDirectoryName(dir) ?? "";
dirName = Path.GetFileName(dir);
}
@@ -134,52 +154,110 @@ namespace ChanSort.Loader.PhilipsBin
#endregion
#region LoadDvbCT
private byte[] LoadDvbCT(ChannelList list, string path)
private void LoadDvbCT(ChannelList list, string path)
{
if (!ReadAndValidateChannellibFile(path, out var data, out var recordSize, out var recordCount))
return;
var mapping = new DataMapping(this.ini.GetSection("CableDigSrvTable_entry"));
mapping.SetDataPtr(data, 20);
for (int i = 0; i < recordCount; i++, mapping.BaseOffset += recordSize)
{
var progNr = mapping.GetWord("offProgNr");
var offChannelName = mapping.BaseOffset + mapping.GetConst("offName", 0);
var lenName = mapping.GetConst("lenName", 0);
for (int j = 0; j < lenName; j += 2)
{
if (data[offChannelName + j] == 0)
{
lenName = j;
break;
}
}
string channelName = Encoding.Unicode.GetString(data, offChannelName, lenName);
var checksum = mapping.GetDword("offChecksum");
mapping.SetDword("offChecksum", 0);
var crc = FaultyCrc32(data, mapping.BaseOffset + mapping.GetConst("offChecksum", 0), recordSize);
if (crc != checksum)
throw new FileLoadException($"Invalid CRC in record {i} in {path}");
var ch = new Channel(list.SignalSource, i, progNr, channelName);
ch.FreqInMhz = (decimal) mapping.GetWord("offFreqTimes16") / 16;
ch.OriginalNetworkId = mapping.GetWord("offOnid");
ch.TransportStreamId = mapping.GetWord("offTsid");
ch.ServiceId = mapping.GetWord("offSid");
ch.SymbolRate = (int)mapping.GetDword("offSymbolRate") / 1000;
ch.Lock = mapping.GetByte("offLocked") != 0;
ch.Favorites = mapping.GetByte("offIsFav") != 0 ? Favorites.A : 0;
if (ch.Favorites != 0)
ch.OldFavIndex[0] = ch.OldProgramNr;
this.DataRoot.AddChannel(list, ch);
}
}
#endregion
#region LoadDvbCTPresets
private void LoadDvbCTPresets(ChannelList list, string path)
{
if (!ReadAndValidateChannellibFile(path, out var data, out var recordSize, out var recordCount))
return;
// build a mapping of (onid,tsid,sid) => channel
var channelById = new Dictionary<ulong, Channel>();
foreach(var chan in list.Channels)
{
var ch = (Channel)chan;
var id = ((ulong)ch.OriginalNetworkId << 32) | ((ulong)ch.TransportStreamId << 16) | (uint)ch.ServiceId;
channelById[id] = ch;
}
// apply preset progNr (LCN?) to the channel and remember the preset index for it
var mapping = new DataMapping(this.ini.GetSection("CablePresetTable_entry"));
mapping.SetDataPtr(data, 20);
for (int i = 0; i < recordCount; i++, mapping.BaseOffset += recordSize)
{
var onid = mapping.GetWord("offOnid");
var tsid = mapping.GetWord("offTsid");
var sid = mapping.GetWord("offSid");
var id = ((ulong)onid << 32) | ((ulong)tsid << 16) | sid;
if (!channelById.TryGetValue(id, out var ch))
continue;
ch.PresetTableIndex = i;
var progNr = mapping.GetWord("offProgNr");
if (progNr != 0 && progNr != 0xFFFF)
ch.OldProgramNr = progNr;
}
}
#endregion
#region ReadAndValidateChannellibFile
private bool ReadAndValidateChannellibFile(string path, out byte[] data, out int recordSize, out int recordCount)
{
data = null;
recordSize = 0;
recordCount = 0;
if (!File.Exists(path))
return null;
return false;
var data = File.ReadAllBytes(path);
data = File.ReadAllBytes(path);
if (data.Length < 20)
return null;
return false;
var recordSize = BitConverter.ToInt32(data, 8);
var recordCount = BitConverter.ToInt32(data, 12);
recordSize = BitConverter.ToInt32(data, 8);
recordCount = BitConverter.ToInt32(data, 12);
if (data.Length != 20 + recordCount * recordSize)
throw new FileLoadException("Unsupported file content: " + path);
this.dataFilePaths.Add(path);
int baseOffset = 20;
for (int i = 0; i < recordCount; i++, baseOffset += recordSize)
{
uint checksum = BitConverter.ToUInt32(data, baseOffset + 0);
ushort progNr = BitConverter.ToUInt16(data, baseOffset + 122);
byte locked = data[baseOffset + 140];
int nameLen;
for (nameLen=0; nameLen<64; nameLen+=2)
if (data[baseOffset + 216 + nameLen] == 0)
break;
string channelName = Encoding.Unicode.GetString(data, baseOffset + 216, nameLen);
data[baseOffset + 0] = 0;
data[baseOffset + 1] = 0;
data[baseOffset + 2] = 0;
data[baseOffset + 3] = 0;
var crc = FaultyCrc32(data, baseOffset, recordSize);
if (crc != checksum)
throw new FileLoadException($"Invalid CRC in record {i} in {path}");
var ch = new ChannelInfo(list.SignalSource, i, progNr, channelName);
ch.Lock = locked != 0;
this.DataRoot.AddChannel(list, ch);
}
return data;
return true;
}
#endregion
#endregion
#region LoadDvbsSatellites()
private void LoadDvbsSatellites(string path)
@@ -397,13 +475,70 @@ namespace ChanSort.Loader.PhilipsBin
#region Save()
public override void Save(string tvOutputFile)
{
var dir = Path.GetDirectoryName(this.FileName);
var dir = Path.GetDirectoryName(this.FileName) ?? "";
var channellib = Path.Combine(dir, "channellib");
var s2channellib = Path.Combine(dir, "s2channellib");
// TODO: save cable and antenna channels
SaveDvbCTChannels(this.dvbtChannels, Path.Combine(channellib, "AntennaDigSrvTable"));
SaveDvbCTPresets(this.dvbtChannels, Path.Combine(channellib, "AntennaPresetTable"));
SaveDvbCTChannels(this.dvbcChannels, Path.Combine(channellib, "CableDigSrvTable"));
SaveDvbCTPresets(this.dvbcChannels, Path.Combine(channellib, "CablePresetTable"));
SaveDvbsChannels(Path.Combine(dir, "s2channellib", "service.dat"));
SaveDvbsFavorites(Path.Combine(dir, "s2channellib", "favorite.dat"));
SaveDvbsDbFileInfo(Path.Combine(dir, "s2channellib", "db_file_info.dat"));
SaveDvbsChannels(Path.Combine(s2channellib, "service.dat"));
SaveDvbsFavorites(Path.Combine(s2channellib, "favorite.dat"));
SaveDvbsDbFileInfo(Path.Combine(s2channellib, "db_file_info.dat"));
}
#endregion
#region SaveDvbCTChannels
private void SaveDvbCTChannels(ChannelList list, string path)
{
if (!ReadAndValidateChannellibFile(path, out var data, out var recordSize, out _))
return;
var mapping = new DataMapping(this.ini.GetSection("CableDigSrvTable_entry"));
mapping.SetDataPtr(data, 20);
foreach (var ch in list.Channels)
{
mapping.BaseOffset = 20 + (int)ch.RecordIndex * recordSize;
mapping.SetWord("offProgNr", ch.NewProgramNr);
mapping.SetByte("offLocked", ch.Lock ? 1 : 0);
mapping.SetByte("offIsFav", ch.Favorites == 0 ? 0 : 1);
mapping.SetDword("offChecksum", 0);
var crc = FaultyCrc32(data, mapping.BaseOffset, recordSize);
mapping.SetDword("offChecksum", crc);
}
File.WriteAllBytes(path, data);
}
#endregion
#region SaveDvbCTPresets
private void SaveDvbCTPresets(ChannelList list, string path)
{
if (!ReadAndValidateChannellibFile(path, out var data, out var recordSize, out _))
return;
var mapping = new DataMapping(this.ini.GetSection("CablePresetTable_entry"));
mapping.SetDataPtr(data, 20);
// update the preset records with new channel numbers
foreach (var chan in list.Channels)
{
if (!(chan is Channel ch) || ch.PresetTableIndex < 0)
continue;
mapping.BaseOffset = 20 + ch.PresetTableIndex * recordSize;
mapping.SetWord("offProgNr", ch.NewProgramNr);
mapping.SetDword("offChecksum", 0);
var crc = FaultyCrc32(data, mapping.BaseOffset, recordSize);
mapping.SetDword("offChecksum", crc);
}
File.WriteAllBytes(path, data);
}
#endregion

View File

@@ -1,5 +1,9 @@
#include "chansort.h"
/***********************************************************
* s2channellib / DVB-S files
***********************************************************/
struct Ph_NextPrevTableEntry
{
word next;
@@ -134,43 +138,131 @@ public struct Ph_FavoriteDat
dword crc32;
};
/***********************************************************
* channellib / antenna and cable files
***********************************************************/
public struct Ph_CableDigSrvTable
{
byte unk1[8];
dword unk1;
dword unk2;
dword chRecordSize;
dword channelCount;
byte unk2[4];
dword versionCode;
struct Ph_CableChannel
{
var off0 = current_offset;
dword checksum;
byte unk1[110];
byte unk1[20];
dword symbolRate;
byte unk2[20];
struct
{
word subFreq : 4;
word mhz : 12;
} freqTimes16;
word onid;
word sid;
word tsid;
byte unk3b[58];
word progNrMostly;
byte unk4[6];
word progNr;
byte unk2[6];
word progNr2;
byte unk2b[16];
byte unk5[22];
byte locked;
byte unk3[75];
byte isFav;
byte unk6[68];
wchar_t channelName[32];
byte unk4[chRecordSize - (current_offset - off0)];
} Channels[channelCount];
};
public struct Ph_CablePresetTable
public struct Ph_CableDigTSTable
{
byte unk1[8];
dword unk1;
dword unk2;
dword recordSize;
dword recordCount;
byte unk2[4];
dword versionCode;
struct Ph_CableChannel
{
var off0 = current_offset;
dword checksum;
dword unk1;
dword unk2;
struct
{
dword subFreq :4;
dword mhz : 28;
} freqInMhzTimes16a;
dword unk3;
dword unk4;
dword unk5;
dword symbolRate;
dword unk6;
dword unk7;
struct
{
dword subFreq :4;
dword mhz : 28;
} freqInMhzTimes16b;
word onid;
word nid;
word tsid;
word unk10;
byte unk4[recordSize - (current_offset - off0)];
} Transponders[recordCount];
};
public struct Ph_CableFrqMapTable
{
dword unk1;
dword unk2;
dword recordSize;
dword recordCount;
dword versionCode;
struct
{
var off0 = current_offset;
dword checksum;
struct
{
dword subFreq :4;
dword mhz : 28;
} freqInMhzTimes16;
dword symbolRate;
dword unk2;
word onid;
word tsid;
word unk5;
word unk6;
dword unk7;
byte unk[recordSize - (current_offset - off0)];
} Transponders[recordCount];
};
public struct Ph_CablePresetTable
{
dword unk1;
dword unk2;
dword recordSize;
dword recordCount;
dword versionCode;
struct
{
var off0 = current_offset;
byte unk1[12];
word unk2;
dword checksum;
struct
{
dword subFreq :4;
dword mhz : 28;
} freqInMhzTimes16;
word progNr;
word unk3;
word unk4;
word unk5;
word onid;
word tsid;
word sid;
byte unk[recordSize - (current_offset - off0)];
} ChanPreset[recordCount];
};

View File

@@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Linq;
using ChanSort.Api;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Test.Loader.PhilipsBin
{
[TestClass]
public class PhilipsChannellibTest
{
[TestMethod]
public void TestFiles1()
{
var baseDir = Path.GetDirectoryName(this.GetType().Assembly.Location);
var baseFile = Path.Combine(baseDir, "TestFiles1\\Repair\\ChannelList\\chanLst.bin");
var plugin = new ChanSort.Loader.PhilipsBin.SerializerPlugin();
var loader = plugin.CreateSerializer(baseFile);
loader.Load();
var list = loader.DataRoot.GetChannelList(SignalSource.DvbC);
Assert.AreEqual(179, list.Channels.Count);
Assert.AreEqual(179, list.Channels.Count(ch => !ch.IsDeleted));
var ch0 = list.Channels.FirstOrDefault(ch => ch.RecordIndex == 0);
Assert.AreEqual(41, ch0.OldProgramNr);
Assert.AreEqual("Passion HD", ch0.Name);
Assert.IsFalse(ch0.Lock);
Assert.AreEqual((Favorites)0, ch0.Favorites);
Assert.AreEqual(810, ch0.FreqInMhz);
Assert.AreEqual(9999, ch0.OriginalNetworkId);
Assert.AreEqual(461, ch0.TransportStreamId);
Assert.AreEqual(46102, ch0.ServiceId);
Assert.AreEqual(6900, ch0.SymbolRate);
}
}
}

View File

@@ -69,172 +69,173 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="PhilipsChannellibTest.cs" />
<Compile Include="PhilipsS2channellibTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="TestFiles1\Repair\ChannelList\chanLst.bin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\AntennaAnalogTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\AntennaDigSrvTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\AntennaDigTSTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\AntennaFrqMapTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\AntennaPresetTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\CableAnalogTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\CableDigSrvTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\CableDigTSTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\CableFrqMapTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\channellib\CablePresetTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\adk_user_pref.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\adk_user_pref_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\db_file_info.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\db_file_info_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\favorite.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\favorite_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\lnb.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\lnb_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\satellite.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\satellite_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\service.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\service_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\tuneinfo.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\tuneinfo_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\user_pref.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles1\Repair\ChannelList\s2channellib\user_pref_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\chanLst.bin">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\AntennaAnalogTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\AntennaDigSrvTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\AntennaDigTSTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\AntennaFrqMapTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\AntennaPresetTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\CableAnalogTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\CableDigSrvTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\CableDigTSTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\CableFrqMapTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\channellib\CablePresetTable">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\adk_user_pref.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\adk_user_pref_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\db_file_info.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\db_file_info_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\favorite.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\favorite_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\lnb.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\lnb_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\satellite.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\satellite_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\service.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\service_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\tuneinfo.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\tuneinfo_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\user_pref.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="TestFiles2\Repair\ChannelList\s2channellib\user_pref_backup.dat">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>