mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-01-23 07:42:05 +01:00
added first draft of Philips "Repair/ChannelList/s2channellib/*.dat" loader.
currently supports: - read and write of satellite channels (incl. sorted favorites and "locked" flag) - read-only of digital cable/antenna files (still missing transponder information)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
source/ChanSort.opensdf
|
||||
/source/.vs/
|
||||
/source/packages/
|
||||
/source/ChanSort.Loader.PhilipsBin/DllClient.cs
|
||||
|
||||
@@ -49,8 +49,8 @@ namespace ChanSort.Api
|
||||
this.Warnings.AppendFormat("Duplicate transponder data record for satellite #{0} with id {1}\r\n", sat?.Id, trans.Id);
|
||||
return;
|
||||
}
|
||||
if (sat != null)
|
||||
sat.Transponder.Add(trans.Id, trans);
|
||||
|
||||
sat?.Transponder.Add(trans.Id, trans);
|
||||
this.Transponder.Add(trans.Id, trans);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
// To get the same CRC32 values that an LSB-first implementation would produce,
|
||||
// all bits in the input bytes, the polynomial (=> 0xEDB88320) and the resulting crc need to be reversed (msb to lsb)
|
||||
|
||||
public const uint NormalPoly = 0x04C11DB7;
|
||||
public const uint ReversedPoly = 0xEDB88320;
|
||||
private const uint CrcMask = 0xFFFFFFFF;
|
||||
private const uint CrcPoly = 0x04C11DB7;
|
||||
|
||||
public static Crc32 Normal = new Crc32(true);
|
||||
public static Crc32 Reversed = new Crc32(false);
|
||||
public static Crc32 Normal = new Crc32(true, NormalPoly);
|
||||
public static Crc32 Reversed = new Crc32(false, NormalPoly);
|
||||
private static readonly byte[] BitReversedBytes = new byte[256];
|
||||
|
||||
private readonly uint[] crc32Table;
|
||||
@@ -20,7 +21,6 @@
|
||||
|
||||
static Crc32()
|
||||
{
|
||||
InitCrc32Table();
|
||||
InitReversedBitOrderTable();
|
||||
}
|
||||
|
||||
@@ -42,11 +42,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static uint[] InitCrc32Table()
|
||||
/// <param name="msbFirst">true for using the "left shift" most-significant-bit-first algorithm</param>
|
||||
/// <param name="poly"></param>
|
||||
public Crc32(bool msbFirst, uint poly)
|
||||
{
|
||||
this.msbFirst = msbFirst;
|
||||
this.crc32Table = InitCrc32Table(poly);
|
||||
}
|
||||
|
||||
#region InitCrc32Table()
|
||||
private uint[] InitCrc32Table(uint poly)
|
||||
{
|
||||
var crcTable = new uint[256];
|
||||
var poly = CrcPoly;
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i << 24;
|
||||
@@ -65,13 +74,6 @@
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <param name="msbFirst">true for using the "left shift" MSB-first algorithm with polynomial 0x04C11Db7. false to use "right shift" with polynomial 0xEDB883320</param>
|
||||
public Crc32(bool msbFirst = true)
|
||||
{
|
||||
this.msbFirst = msbFirst;
|
||||
crc32Table = InitCrc32Table();
|
||||
}
|
||||
|
||||
#region CalcCrc32()
|
||||
public uint CalcCrc32(byte[] data, int start, int length)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,30 @@ namespace ChanSort.Api
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetMask()
|
||||
public int GetMask(string key)
|
||||
{
|
||||
var list = settings.GetIntList(key);
|
||||
if (list != null && list.Length > 0)
|
||||
return list[0];
|
||||
list = settings.GetIntList("mask" + key);
|
||||
if (list != null && list.Length > 0)
|
||||
return list[0];
|
||||
return -1;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetConst()
|
||||
public int GetConst(string key, int defaultValue)
|
||||
{
|
||||
var list = settings.GetIntList(key);
|
||||
if (list != null && list.Length > 0)
|
||||
return list[0];
|
||||
return defaultValue;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public IniFile.Section Settings { get { return this.settings; } }
|
||||
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace ChanSort.Api
|
||||
|
||||
#region GetInt16/32()
|
||||
|
||||
public static int GetInt16(byte[] data, int offset, bool littleEndian)
|
||||
public static int GetInt16(this byte[] data, int offset, bool littleEndian = true)
|
||||
{
|
||||
return littleEndian ? BitConverter.ToInt16(data, offset) : (data[offset] << 8) + data[offset + 1];
|
||||
}
|
||||
|
||||
public static int GetInt32(byte[] data, int offset, bool littleEndian)
|
||||
public static int GetInt32(this byte[] data, int offset, bool littleEndian = true)
|
||||
{
|
||||
return littleEndian ? BitConverter.ToInt32(data, offset) :
|
||||
(data[offset] << 24) + (data[offset + 1] << 16) + (data[offset + 2] << 8) + data[offset + 3];
|
||||
@@ -45,7 +45,7 @@ namespace ChanSort.Api
|
||||
|
||||
#region SetInt16/32()
|
||||
|
||||
public static void SetInt16(byte[] data, int offset, int value, bool littleEndian = true)
|
||||
public static void SetInt16(this byte[] data, int offset, int value, bool littleEndian = true)
|
||||
{
|
||||
if (littleEndian)
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace ChanSort.Api
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetInt32(byte[] data, int offset, int value, bool littleEndian = true)
|
||||
public static void SetInt32(this byte[] data, int offset, int value, bool littleEndian = true)
|
||||
{
|
||||
if (littleEndian)
|
||||
{
|
||||
@@ -82,11 +82,10 @@ namespace ChanSort.Api
|
||||
|
||||
public static void MemCopy(byte[] source, int sourceIndex, byte[] dest, int destIndex, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
dest[destIndex + i] = source[sourceIndex + i];
|
||||
Array.Copy(source, sourceIndex, dest, destIndex, count);
|
||||
}
|
||||
|
||||
public static void MemSet(byte[] data, int offset, byte value, int count)
|
||||
public static void MemSet(this byte[] data, int offset, byte value, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
data[offset++] = value;
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ChanSort.Loader.PhilipsBin</RootNamespace>
|
||||
<AssemblyName>ChanSort.Loader.PhilipsBin</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Serializer.cs" />
|
||||
<Compile Include="SerializerPlugin.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChanSort.Api\ChanSort.Api.csproj">
|
||||
<Project>{dccffa08-472b-4d17-bb90-8f513fc01392}</Project>
|
||||
<Name>ChanSort.Api</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ChanSort.Loader.PhilipsBin.ini">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
[service.dat_entry]
|
||||
offPcrPid=0
|
||||
maskPcrPid=0x1FFF
|
||||
offLocked=3
|
||||
maskLocked=0x10
|
||||
offOnid=4
|
||||
offTsid=6
|
||||
offSid=8
|
||||
offTransponderIndex=10
|
||||
offVpid=16
|
||||
maskVpid=0x1FFF
|
||||
offIsFav=17
|
||||
maskIsFav=0x80
|
||||
offProgNr=20
|
||||
offName=28
|
||||
lenName=32
|
||||
offProvider=60
|
||||
lenProvider=32
|
||||
|
||||
36
source/ChanSort.Loader.PhilipsBin/Properties/AssemblyInfo.cs
Normal file
36
source/ChanSort.Loader.PhilipsBin/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("ChanSort.Loader.PhilipsBin")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ChanSort.Loader.PhilipsBin")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1f52b5ec-a2f1-4e53-9e1a-4658296c5bb5")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
505
source/ChanSort.Loader.PhilipsBin/Serializer.cs
Normal file
505
source/ChanSort.Loader.PhilipsBin/Serializer.cs
Normal file
@@ -0,0 +1,505 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.PhilipsBin
|
||||
{
|
||||
|
||||
class Serializer : SerializerBase
|
||||
{
|
||||
private readonly ChannelList dvbtChannels = new ChannelList(SignalSource.DvbCT, "DVB-T");
|
||||
private readonly ChannelList dvbcChannels = new ChannelList(SignalSource.DvbCT, "DVB-C");
|
||||
private readonly ChannelList satChannels = new ChannelList(SignalSource.DvbS, "DVB-S");
|
||||
private readonly ChannelList favChannels = new ChannelList(SignalSource.All, "Favorites");
|
||||
|
||||
|
||||
private readonly IniFile ini;
|
||||
private byte[] dvbcData, dvbtData, dvbsData;
|
||||
|
||||
private readonly List<string> dataFilePaths = new List<string>();
|
||||
|
||||
#region ctor()
|
||||
public Serializer(string inputFile) : base(inputFile)
|
||||
{
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.None;
|
||||
this.Features.CanSkipChannels = false;
|
||||
this.Features.CanLockChannels = true;
|
||||
this.Features.CanHideChannels = false;
|
||||
this.Features.DeleteMode = DeleteMode.NotSupported;
|
||||
this.Features.CanSaveAs = false;
|
||||
this.Features.SupportedFavorites = Favorites.A;
|
||||
this.Features.SortedFavorites = true;
|
||||
this.Features.AllowGapsInFavNumbers = false;
|
||||
this.Features.CanEditFavListNames = false;
|
||||
|
||||
this.DataRoot.AddChannelList(this.dvbtChannels);
|
||||
this.DataRoot.AddChannelList(this.dvbcChannels);
|
||||
this.DataRoot.AddChannelList(this.satChannels);
|
||||
//this.DataRoot.AddChannelList(this.favChannels);
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
list.VisibleColumnFieldNames.Remove("Skip");
|
||||
list.VisibleColumnFieldNames.Remove("ShortName");
|
||||
}
|
||||
|
||||
var supportedColumns = new[] {"OldPosition", "Position", "Name", "Lock"};
|
||||
this.satChannels.VisibleColumnFieldNames.Remove("AudioPid");
|
||||
this.satChannels.VisibleColumnFieldNames.Remove("ServiceTypeName");
|
||||
this.satChannels.VisibleColumnFieldNames.Remove("Encrypted");
|
||||
this.satChannels.VisibleColumnFieldNames.Remove("Hidden");
|
||||
//this.satChannels.VisibleColumnFieldNames.Clear();
|
||||
//foreach(var supportedColumn in supportedColumns)
|
||||
// this.satChannels.VisibleColumnFieldNames.Add(supportedColumn);
|
||||
|
||||
this.favChannels.IsMixedSourceFavoritesList = true;
|
||||
this.ini = new IniFile("ChanSort.Loader.PhilipsBin.ini");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Load()
|
||||
public override void Load()
|
||||
{
|
||||
if (!SetFileNameToChanLstBin())
|
||||
throw new FileLoadException("Unsupported folder structure. Required files are:\n"
|
||||
+ "ChannelList\\chanLst.bin\n"
|
||||
+ "ChannelList\\channellib\\CableDigSrvTable\n"
|
||||
+ "ChannelList\\s2channellib\\service.dat");
|
||||
|
||||
var dir = Path.GetDirectoryName(this.FileName);
|
||||
dvbtData = LoadDvbCT(dvbtChannels, Path.Combine(dir, "channellib", "AntennaDigSrvTable"));
|
||||
dvbcData = LoadDvbCT(dvbcChannels, Path.Combine(dir, "channellib", "CableDigSrvTable"));
|
||||
|
||||
LoadDvbsSatellites(Path.Combine(dir, "s2channellib", "satellite.dat"));
|
||||
LoadDvbsTransponders(Path.Combine(dir, "s2channellib", "tuneinfo.dat"));
|
||||
dvbsData = 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");
|
||||
if (File.Exists(db_file_info))
|
||||
this.dataFilePaths.Add(db_file_info);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SetFileNameToChanLstBin()
|
||||
private bool SetFileNameToChanLstBin()
|
||||
{
|
||||
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);
|
||||
dirName = Path.GetFileName(dir);
|
||||
}
|
||||
|
||||
if (StringComparer.InvariantCultureIgnoreCase.Compare(dirName, "ChannelList") != 0)
|
||||
return false;
|
||||
|
||||
var chanLstBin = Path.Combine(dir, "chanLst.bin");
|
||||
if (!File.Exists(chanLstBin))
|
||||
return false;
|
||||
|
||||
if (!File.Exists(Path.Combine(dir, "channellib", "CableDigSrvTable")))
|
||||
return false;
|
||||
if (!File.Exists(Path.Combine(dir, "s2channellib", "service.dat")))
|
||||
return false;
|
||||
|
||||
this.FileName = chanLstBin; // this file is used as a fixed reference point for the whole directory structure
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadDvbCT
|
||||
private byte[] LoadDvbCT(ChannelList list, string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return null;
|
||||
|
||||
var data = File.ReadAllBytes(path);
|
||||
if (data.Length < 20)
|
||||
return null;
|
||||
|
||||
var recordSize = BitConverter.ToInt32(data, 8);
|
||||
var 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;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region LoadDvbsSatellites()
|
||||
private void LoadDvbsSatellites(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
var data = File.ReadAllBytes(path);
|
||||
if (data.Length < 4)
|
||||
return;
|
||||
var checksum = BitConverter.ToUInt32(data, data.Length - 4);
|
||||
var crc = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4);
|
||||
if (checksum != crc)
|
||||
return;
|
||||
int recordSize = BitConverter.ToInt32(data, 4);
|
||||
int recordCount = BitConverter.ToInt32(data, 8);
|
||||
|
||||
// 12 byte header, table of (next, prev) transponder, records, crc32
|
||||
if (data.Length != 12 + recordCount * 4 + recordCount * recordSize + 4)
|
||||
return;
|
||||
|
||||
var baseOffset = 12 + recordCount * 4;
|
||||
for (int i = 0; i < recordCount; i++, baseOffset += recordSize)
|
||||
{
|
||||
if (data[baseOffset + 0] == 0)
|
||||
continue;
|
||||
|
||||
var s = new Satellite(i);
|
||||
var pos = (sbyte)data[baseOffset + 8];
|
||||
s.OrbitalPosition = pos < 0 ? -pos + "W" : pos + "E";
|
||||
s.Name = this.DefaultEncoding.GetString(data, baseOffset + 16, 16).TrimEnd('\0');
|
||||
this.DataRoot.AddSatellite(s);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadDvbsTransponders
|
||||
private void LoadDvbsTransponders(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
var data = File.ReadAllBytes(path);
|
||||
if (data.Length < 4)
|
||||
return;
|
||||
var checksum = BitConverter.ToUInt32(data, data.Length - 4);
|
||||
var crc = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4);
|
||||
if (checksum != crc)
|
||||
return;
|
||||
int recordSize = BitConverter.ToInt32(data, 4);
|
||||
int recordCount = BitConverter.ToInt32(data, 8);
|
||||
|
||||
// 12 byte header, table of (next, prev) transponder, records, crc32
|
||||
if (data.Length != 12 + recordCount * 4 + recordCount * recordSize + 4)
|
||||
return;
|
||||
|
||||
var baseOffset = 12 + recordCount * 4;
|
||||
for (int i = 0; i < recordCount; i++, baseOffset += recordSize)
|
||||
{
|
||||
var symRate = BitConverter.ToUInt16(data, baseOffset + 0);
|
||||
if (symRate == 0xFFFF)
|
||||
continue;
|
||||
|
||||
var tsid = BitConverter.ToUInt16(data, baseOffset + 16);
|
||||
var onid = BitConverter.ToUInt16(data, baseOffset + 18);
|
||||
|
||||
var t = new Transponder(i);
|
||||
t.SymbolRate = symRate;
|
||||
t.FrequencyInMhz = BitConverter.ToUInt16(data, baseOffset + 2);
|
||||
var satIndex = data[baseOffset + 6] >> 4; // guesswork
|
||||
t.Satellite = DataRoot.Satellites.TryGet(satIndex);
|
||||
t.TransportStreamId = tsid;
|
||||
t.OriginalNetworkId = onid;
|
||||
this.DataRoot.AddTransponder(t.Satellite, t);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadDvbS
|
||||
private byte[] LoadDvbS(ChannelList list, string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return null;
|
||||
|
||||
var data = File.ReadAllBytes(path);
|
||||
if (data.Length < 4)
|
||||
return null;
|
||||
|
||||
var checksum = BitConverter.ToUInt32(data, data.Length - 4);
|
||||
|
||||
var crcObj = new Crc32(false, Crc32.NormalPoly);
|
||||
var crc = ~crcObj.CalcCrc32(data, 0, data.Length - 4);
|
||||
if (checksum != crc)
|
||||
throw new FileLoadException("Invalid CRC32 in " + path);
|
||||
|
||||
int recordSize = BitConverter.ToInt32(data, 4);
|
||||
int recordCount = BitConverter.ToInt32(data, 8);
|
||||
|
||||
// 12 bytes header, then a "next/prev" table, then the service records, then a CRC32
|
||||
// the "next/prev" table is a ring-list, every entry consists of 2 ushorts with the next and previous channel, wrapping around on the ends
|
||||
if (data.Length != 12 + recordCount * 4 + recordCount * recordSize + 4)
|
||||
throw new FileLoadException("Unsupported file content: " + path);
|
||||
|
||||
this.dataFilePaths.Add(path);
|
||||
|
||||
var dvbStringDecoder = new DvbStringDecoder(this.DefaultEncoding);
|
||||
|
||||
var mapping = new DataMapping(this.ini.GetSection("service.dat_entry"));
|
||||
mapping.SetDataPtr(data, 12 + recordCount * 4);
|
||||
for (int i = 0; i < recordCount; i++, mapping.BaseOffset += recordSize)
|
||||
{
|
||||
var ch = new ChannelInfo(list.SignalSource, i, 0, null);
|
||||
|
||||
var progNr = mapping.GetWord("offProgNr");
|
||||
var transponderId = mapping.GetWord("offTransponderIndex");
|
||||
if (progNr == 0xFFFF || transponderId == 0xFFFF)
|
||||
{
|
||||
ch.IsDeleted = true;
|
||||
ch.OldProgramNr = -1;
|
||||
DataRoot.AddChannel(list, ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
ch.PcrPid = mapping.GetWord("offPcrPid") & mapping.GetMask("maskPcrPid");
|
||||
ch.Lock = mapping.GetFlag("Locked");
|
||||
ch.OriginalNetworkId = mapping.GetWord("OffOnid"); // can be 0 in some lists
|
||||
ch.TransportStreamId = mapping.GetWord("offTsid");
|
||||
ch.ServiceId = mapping.GetWord("offSid");
|
||||
|
||||
ch.VideoPid = mapping.GetWord("offVpid") & mapping.GetMask("maskVpid");
|
||||
//ch.Favorites = mapping.GetFlag("IsFav") ? Favorites.A : 0; // setting this here would mess up the proper order
|
||||
ch.OldProgramNr = progNr;
|
||||
|
||||
dvbStringDecoder.GetChannelNames(data, mapping.BaseOffset + mapping.GetConst("offName",0), mapping.GetConst("lenName", 0), out var longName, out var shortName);
|
||||
ch.Name = longName.TrimEnd('\0');
|
||||
ch.ShortName = shortName.TrimEnd('\0');
|
||||
|
||||
dvbStringDecoder.GetChannelNames(data, mapping.BaseOffset + mapping.GetConst("offProvider", 0), mapping.GetConst("lenProvider", 0), out var provider, out _);
|
||||
ch.Provider = provider.TrimEnd('\0');
|
||||
|
||||
if (this.DataRoot.Transponder.TryGetValue(transponderId, out var t))
|
||||
{
|
||||
ch.Transponder = t;
|
||||
ch.FreqInMhz = t.FrequencyInMhz;
|
||||
ch.SymbolRate = t.SymbolRate;
|
||||
ch.SatPosition = t.Satellite?.OrbitalPosition;
|
||||
ch.Satellite = t.Satellite?.Name;
|
||||
if (ch.OriginalNetworkId == 0)
|
||||
ch.OriginalNetworkId = t.OriginalNetworkId;
|
||||
if (ch.TransportStreamId == 0)
|
||||
ch.TransportStreamId = t.TransportStreamId;
|
||||
}
|
||||
|
||||
this.DataRoot.AddChannel(list, ch);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadDvbsFavorites
|
||||
private void LoadDvbsFavorites(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
var data = File.ReadAllBytes(path);
|
||||
if (data.Length < 4)
|
||||
return;
|
||||
var checksum = BitConverter.ToUInt32(data, data.Length - 4);
|
||||
var crc = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4);
|
||||
if (checksum != crc)
|
||||
return;
|
||||
|
||||
int dataSize = BitConverter.ToInt32(data, 0);
|
||||
var recordSize = 4;
|
||||
var recordCount = (dataSize - 4) / recordSize;
|
||||
|
||||
// 4 byte header, data, crc32
|
||||
if (data.Length != 4 + dataSize + 4)
|
||||
return;
|
||||
|
||||
int firstFavIndex = BitConverter.ToInt16(data, 4);
|
||||
int favCount = BitConverter.ToInt16(data, 6);
|
||||
if (favCount > recordCount || firstFavIndex < 0 || firstFavIndex >= recordCount)
|
||||
return;
|
||||
|
||||
this.dataFilePaths.Add(path);
|
||||
|
||||
var baseOffset = 8;
|
||||
for (int i = 0, curFav = firstFavIndex; i < favCount; i++)
|
||||
{
|
||||
this.satChannels.Channels[curFav].SetOldPosition(1, i + 1);
|
||||
curFav = BitConverter.ToInt16(data, baseOffset + curFav * 4 + 2);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region GetDataFilePaths
|
||||
|
||||
/// <summary>
|
||||
/// List of files for backup/restore
|
||||
/// </summary>
|
||||
public override IEnumerable<string> GetDataFilePaths() => this.dataFilePaths;
|
||||
#endregion
|
||||
|
||||
|
||||
#region Save()
|
||||
public override void Save(string tvOutputFile)
|
||||
{
|
||||
var dir = Path.GetDirectoryName(this.FileName);
|
||||
|
||||
// TODO: save cable and antenna channels
|
||||
|
||||
SaveDvbsChannels(Path.Combine(dir, "s2channellib", "service.dat"));
|
||||
SaveDvbsFavorites(Path.Combine(dir, "s2channellib", "favorite.dat"));
|
||||
SaveDvbsDbFileInfo(Path.Combine(dir, "s2channellib", "db_file_info.dat"));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SaveDvbsChannels
|
||||
private void SaveDvbsChannels(string path)
|
||||
{
|
||||
byte[] deletedChannelData = {
|
||||
0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc2, 0x3f, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
var data = File.ReadAllBytes(path);
|
||||
int recordSize = BitConverter.ToInt32(data, 4);
|
||||
int recordCount = BitConverter.ToInt32(data, 8);
|
||||
|
||||
var mapping = new DataMapping(this.ini.GetSection("service.dat_entry"));
|
||||
mapping.SetDataPtr(data, 12 + recordCount * 4);
|
||||
|
||||
foreach (var ch in this.satChannels.Channels)
|
||||
{
|
||||
mapping.BaseOffset = 12 + recordCount * 4 + (int)ch.RecordIndex * recordSize;
|
||||
if (ch.IsDeleted)
|
||||
{
|
||||
Array.Copy(deletedChannelData, 0, data, mapping.BaseOffset, Math.Min(deletedChannelData.Length, recordSize));
|
||||
continue;
|
||||
}
|
||||
mapping.SetWord("offProgNr", ch.NewProgramNr);
|
||||
mapping.SetFlag("IsFav", ch.Favorites != 0);
|
||||
mapping.SetFlag("Locked", ch.Lock);
|
||||
}
|
||||
|
||||
var crc32 = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4);
|
||||
data.SetInt32(data.Length-4, (int)crc32);
|
||||
File.WriteAllBytes(path, data);
|
||||
|
||||
var backupFile = path.Replace(".dat", "_backup.dat");
|
||||
File.WriteAllBytes(backupFile, data);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SaveDvbsFavorites
|
||||
private void SaveDvbsFavorites(string path)
|
||||
{
|
||||
var data = File.ReadAllBytes(path);
|
||||
|
||||
int dataSize = BitConverter.ToInt32(data, 0);
|
||||
var recordSize = 4;
|
||||
var recordCount = (dataSize - 4) / recordSize;
|
||||
|
||||
var favList = this.satChannels.Channels.Where(c => c.FavIndex[0] != -1).OrderBy(c => c.FavIndex[0]).ToList();
|
||||
var favCount = favList.Count;
|
||||
var firstFavIndex = favCount == 0 ? -1 : (int)favList[0].RecordIndex;
|
||||
data.SetInt16(4, firstFavIndex);
|
||||
data.SetInt16(6, favCount);
|
||||
data.MemSet(8, 0xFF, recordCount * 4);
|
||||
if (favCount > 0)
|
||||
{
|
||||
var prevFav = (int) favList[favList.Count - 1].RecordIndex;
|
||||
var curFav = firstFavIndex;
|
||||
var nextFav = (int) favList[1 % favCount].RecordIndex;
|
||||
for (int i = 0; i < favCount; i++)
|
||||
{
|
||||
var ch = favList[i];
|
||||
var off = 8 + (int) ch.RecordIndex * 4;
|
||||
data.SetInt16(off + 0, prevFav);
|
||||
data.SetInt16(off + 2, nextFav);
|
||||
prevFav = curFav;
|
||||
curFav = nextFav;
|
||||
nextFav = (int) favList[(i + 2) % favCount].RecordIndex;
|
||||
}
|
||||
}
|
||||
|
||||
var crc32 = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4);
|
||||
data.SetInt32(data.Length - 4, (int)crc32);
|
||||
File.WriteAllBytes(path, data);
|
||||
|
||||
var backupFile = path.Replace(".dat", "_backup.dat");
|
||||
File.WriteAllBytes(backupFile, data);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SaveDvbsDbFileInfo
|
||||
private void SaveDvbsDbFileInfo(string path)
|
||||
{
|
||||
var data = File.ReadAllBytes(path);
|
||||
// the ushort at offset 10 is incremented by 4 every time a change is made to the list (maybe the lower 2 bits of that fields are used for something else)
|
||||
var offset = 10;
|
||||
data.SetInt16(offset,data.GetInt16(offset) + 4);
|
||||
|
||||
var crc32 = ~Crc32.Reversed.CalcCrc32(data, 0, data.Length - 4);
|
||||
data.SetInt32(data.Length - 4, (int)crc32);
|
||||
File.WriteAllBytes(path, data);
|
||||
|
||||
var backupFile = path.Replace(".dat", "_backup.dat");
|
||||
File.WriteAllBytes(backupFile, data);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region FaultyCrc32
|
||||
public uint FaultyCrc32(byte[] bytes, int start, int count)
|
||||
{
|
||||
var crc = 0xFFFFFFFF;
|
||||
var off = start;
|
||||
for (int i = 0; i < count; i++, off++)
|
||||
{
|
||||
var b = bytes[off];
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
crc <<= 1;
|
||||
var b1 = (uint)b >> 7;
|
||||
var b2 = crc >> 31;
|
||||
if (b1 != b2)
|
||||
crc ^= 0x04C11DB7;
|
||||
b <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
16
source/ChanSort.Loader.PhilipsBin/SerializerPlugin.cs
Normal file
16
source/ChanSort.Loader.PhilipsBin/SerializerPlugin.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.PhilipsBin
|
||||
{
|
||||
public class SerializerPlugin : ISerializerPlugin
|
||||
{
|
||||
public string DllName { get; set; }
|
||||
public string PluginName => "Philips .bin/.dat";
|
||||
public string FileFilter => "*.bin;*.dat;*";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
return new Serializer(inputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Loader.VDR", "Test.Loa
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.M3u", "ChanSort.Loader.M3u\ChanSort.Loader.M3u.csproj", "{484028B6-3AAE-4F7E-A88A-76BEEB70203B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.PhilipsBin", "ChanSort.Loader.PhilipsBin\ChanSort.Loader.PhilipsBin.csproj", "{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -422,6 +424,18 @@ Global
|
||||
{484028B6-3AAE-4F7E-A88A-76BEEB70203B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{484028B6-3AAE-4F7E-A88A-76BEEB70203B}.Release|x86.ActiveCfg = Release|x86
|
||||
{484028B6-3AAE-4F7E-A88A-76BEEB70203B}.Release|x86.Build.0 = Release|x86
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Debug|x86.Build.0 = Debug|x86
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1F52B5EC-A2F1-4E53-9E1A-4658296C5BB5}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -484,6 +484,10 @@
|
||||
<Project>{68da8072-3a29-4076-9f64-d66f38349585}</Project>
|
||||
<Name>ChanSort.Loader.Panasonic</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.PhilipsBin\ChanSort.Loader.PhilipsBin.csproj">
|
||||
<Project>{1f52b5ec-a2f1-4e53-9e1a-4658296c5bb5}</Project>
|
||||
<Name>ChanSort.Loader.PhilipsBin</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\ChanSort.Loader.PhilipsXml\ChanSort.Loader.PhilipsXml.csproj">
|
||||
<Project>{d7bafd55-50f5-46c3-a76b-2193bed5358f}</Project>
|
||||
<Name>ChanSort.Loader.PhilipsXml</Name>
|
||||
|
||||
@@ -6,36 +6,167 @@ struct Ph_NextPrevTableEntry
|
||||
word prev;
|
||||
};
|
||||
|
||||
struct Ph_Channel
|
||||
public struct Ph_DbFileInfoDat
|
||||
{
|
||||
dword dataSize;
|
||||
var off0 = current_offset;
|
||||
byte unk1[6];
|
||||
struct
|
||||
{
|
||||
word unk : 2;
|
||||
word seqNr : 14;
|
||||
} seq;
|
||||
byte unk[dataSize - (current_offset - off0)];
|
||||
dword crc32;
|
||||
};
|
||||
|
||||
public struct Ph_SatelliteDat
|
||||
{
|
||||
word pcrPid;
|
||||
word unk1;
|
||||
word onid;
|
||||
word tsid;
|
||||
word sid;
|
||||
word unk3;
|
||||
word unk4;
|
||||
word unk5;
|
||||
word vpid;
|
||||
word unk6;
|
||||
word progNr;
|
||||
word unk7;
|
||||
word unk8;
|
||||
word unk9;
|
||||
char channelName[32];
|
||||
char providerName[32];
|
||||
char unk9[40];
|
||||
word unk2;
|
||||
dword recordSize;
|
||||
dword recordCount;
|
||||
Ph_NextPrevTableEntry NextPrevTable[recordCount];
|
||||
struct
|
||||
{
|
||||
var off0 = current_offset;
|
||||
dword oneShiftLeftSatIndex;
|
||||
word unk1;
|
||||
word unk2;
|
||||
byte orbitalPos;
|
||||
byte unk3[7];
|
||||
char name[16];
|
||||
byte unk[recordSize - (current_offset - off0)];
|
||||
} Satellites[recordCount];
|
||||
dword crc32;
|
||||
};
|
||||
|
||||
public struct Ph_TuneinfoDat
|
||||
{
|
||||
word unk1;
|
||||
word unk2;
|
||||
dword recordSize;
|
||||
dword recordCount;
|
||||
Ph_NextPrevTableEntry NextPrevTable[recordCount];
|
||||
struct
|
||||
{
|
||||
var off0 = current_offset;
|
||||
word symbolRate;
|
||||
word freqInMhz;
|
||||
word unk1;
|
||||
struct
|
||||
{
|
||||
byte unk : 4;
|
||||
byte satIndex: 4;
|
||||
} u1a;
|
||||
byte unk2[9];
|
||||
word tsid;
|
||||
word onid;
|
||||
word unk3;
|
||||
char networkName[32];
|
||||
word unk4;
|
||||
byte unk[recordSize - (current_offset - off0)];
|
||||
} Transponders[recordCount];
|
||||
dword crc32;
|
||||
};
|
||||
|
||||
public struct Ph_ServiceDat
|
||||
{
|
||||
word unk1;
|
||||
word chanCount;
|
||||
word chanSize;
|
||||
word unk2;
|
||||
word chanCount2;
|
||||
word unk3;
|
||||
dword chanSize;
|
||||
dword chanCount;
|
||||
Ph_NextPrevTableEntry NextPrevTable[chanCount];
|
||||
Ph_Channel Channels[chanCount];
|
||||
struct
|
||||
{
|
||||
var off0 = current_offset;
|
||||
struct
|
||||
{
|
||||
word pid : 13;
|
||||
word unk : 3;
|
||||
} pcrPid;
|
||||
byte unk1a;
|
||||
struct
|
||||
{
|
||||
byte unk : 4;
|
||||
byte locked : 1;
|
||||
byte unk2 : 3;
|
||||
} flags;
|
||||
word onid;
|
||||
word tsid;
|
||||
word sid;
|
||||
word transponderIndex;
|
||||
word unk4;
|
||||
word unk5;
|
||||
struct
|
||||
{
|
||||
word vpid : 13;
|
||||
word unk : 2;
|
||||
word isFav : 1;
|
||||
} vpid;
|
||||
word unk6;
|
||||
word progNr;
|
||||
word unk7;
|
||||
word unk8;
|
||||
word unk9;
|
||||
char channelName[32];
|
||||
char providerName[32];
|
||||
byte unk9[chanSize - (current_offset - off0)];
|
||||
} Channels[chanCount];
|
||||
[description("CRC32 MSBit first, init=0xFFFFFFFF, poly=0xEDB88320, post=0xFFFFFFFF, as int32 little-endian")]
|
||||
dword crc32;
|
||||
};
|
||||
|
||||
public struct Ph_FavoriteDat
|
||||
{
|
||||
dword dataSize;
|
||||
short firstIndex;
|
||||
short count;
|
||||
struct
|
||||
{
|
||||
short prev;
|
||||
short next;
|
||||
} Table[dataSize/4-1];
|
||||
dword crc32;
|
||||
};
|
||||
|
||||
|
||||
public struct Ph_CableDigSrvTable
|
||||
{
|
||||
byte unk1[8];
|
||||
dword chRecordSize;
|
||||
dword channelCount;
|
||||
byte unk2[4];
|
||||
struct Ph_CableChannel
|
||||
{
|
||||
var off0 = current_offset;
|
||||
dword checksum;
|
||||
byte unk1[110];
|
||||
word progNr;
|
||||
byte unk2[6];
|
||||
word progNr2;
|
||||
byte unk2b[16];
|
||||
byte locked;
|
||||
byte unk3[75];
|
||||
wchar_t channelName[32];
|
||||
byte unk4[chRecordSize - (current_offset - off0)];
|
||||
} Channels[channelCount];
|
||||
};
|
||||
|
||||
public struct Ph_CablePresetTable
|
||||
{
|
||||
byte unk1[8];
|
||||
dword recordSize;
|
||||
dword recordCount;
|
||||
byte unk2[4];
|
||||
struct
|
||||
{
|
||||
var off0 = current_offset;
|
||||
byte unk1[12];
|
||||
word unk2;
|
||||
word unk3;
|
||||
word unk4;
|
||||
word unk5;
|
||||
byte unk[recordSize - (current_offset - off0)];
|
||||
} ChanPreset[recordCount];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user