mirror of
https://github.com/PredatH0r/ChanSort.git
synced 2026-01-28 10:09:02 +01:00
- re-added and reworked Hisense SVL_*.BIN loader (read-only atm)
This commit is contained in:
@@ -96,7 +96,12 @@ namespace ChanSort.Api
|
||||
/// A proxy channel is inserted into the current channel list when there was no match for a reference list channel
|
||||
/// </summary>
|
||||
public bool IsProxy => this.RecordIndex == -1;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// can be used to store the offset of the raw data in the input file, e.g. for re-parsing names with different encoding
|
||||
/// </summary>
|
||||
public int RawDataOffset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// arbitrary information that can be shown in a UI column to assist in analyzing a file format while coding a plugin
|
||||
/// </summary>
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
public int TransportStreamId { get; set; }
|
||||
public SignalSource SignalSource { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public Transponder(int id)
|
||||
{
|
||||
this.id = id;
|
||||
|
||||
@@ -50,4 +50,13 @@
|
||||
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="C:\Users\horst\.nuget\packages\sqlitepclraw.lib.e_sqlite3\2.1.2\buildTransitive\net461\..\..\runtimes\win-x86\native\e_sqlite3.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="C:\Users\horst\.nuget\packages\sqlitepclraw.lib.e_sqlite3\2.1.2\buildTransitive\net461\..\..\runtimes\win-x64\native\e_sqlite3.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="C:\Users\horst\.nuget\packages\sqlitepclraw.lib.e_sqlite3\2.1.2\buildTransitive\net461\..\..\runtimes\win-arm\native\e_sqlite3.dll" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -9,10 +9,14 @@ RecordSize=328
|
||||
ID=0
|
||||
BroadcastType=2
|
||||
ServiceType=3
|
||||
Nid=4
|
||||
Onid=6
|
||||
Tsid=8
|
||||
Frequency=16
|
||||
SymbolRate=28
|
||||
SymbolRate=20
|
||||
DvbsSymbolRate=28
|
||||
Name=216
|
||||
NameLength=96
|
||||
NameLength=32
|
||||
|
||||
|
||||
[SVL_Record]
|
||||
@@ -21,33 +25,32 @@ RecordSize=304
|
||||
RecordId=0
|
||||
ChannelId=6
|
||||
|
||||
HashcodeFieldMask=8
|
||||
HashcodeFieldMask_Name=0x01
|
||||
HashcodeFieldMask_ChannelId=0x02
|
||||
HashcodeFieldMask_BroadcastType=0x04
|
||||
HashcodeFieldMask_TslRecId=0x08
|
||||
HashcodeFieldMask_PrgNum=0x10
|
||||
HashcodeFieldMask_ShortName=0x20
|
||||
HashcodeFieldMask_Radio = 0x0400
|
||||
HashcodeFieldMask_Encrypted = 0x0800
|
||||
HashcodeFieldMask_Tv = 0x2000
|
||||
Hashcode=8
|
||||
Hashcode_Name=0x01
|
||||
Hashcode_ServiceId=0x02
|
||||
Hashcode_BroadcastType=0x04
|
||||
;Hashcode_TslRecId=0x08
|
||||
;Hashcode_PrgNum=0x10
|
||||
;Hashcode_ShortName=0x20
|
||||
|
||||
NwMask=12
|
||||
NwMask=8
|
||||
NwMask_Skip = 0x08
|
||||
NwMask_Fav1 = 0x10
|
||||
NwMask_Fav2 = 0x20
|
||||
NwMask_Fav3 = 0x40
|
||||
NwMask_Fav4 = 0x80
|
||||
NwMask_Lock = 0x80
|
||||
NwMask_Hide = 0x00
|
||||
NwMask_Lock = 0x100
|
||||
NwMask_Radio = 0x0400
|
||||
NwMask_Encrypted = 0x0800
|
||||
NwMask_Tv = 0x2000
|
||||
|
||||
OptionMask=16
|
||||
OptionMask=12
|
||||
MaskRename = 0x08
|
||||
MaskMoved = 0x400
|
||||
|
||||
OptionMask2=20
|
||||
OptionMask2=16
|
||||
|
||||
ProgramId=24
|
||||
ServiceId=24
|
||||
TslTableId=26
|
||||
TslRecordId=28
|
||||
NwlTableId=30
|
||||
@@ -63,16 +66,22 @@ BroadcastSystemData=136
|
||||
|
||||
[DVB_Data]
|
||||
ShortName=4
|
||||
ShortName_Size=16
|
||||
ShortNameLength=16
|
||||
LinkageMask=28
|
||||
LinkageMask_Ts=0x04
|
||||
|
||||
Onid=44
|
||||
Tsid=46
|
||||
Ssid=48
|
||||
Encrypted=64
|
||||
Sid=48
|
||||
DvbcTsid=118
|
||||
DvbcOnid=120
|
||||
ServiceType=129
|
||||
|
||||
[Columns]
|
||||
DVB_T=Position,OldProgramNr,Name,ShortName,Favorites,Lock,Skip,Encrypted,ChannelOrTransponder,FreqInMhz,ServiceTypeName
|
||||
DVB_C=Position,OldProgramNr,Name,ShortName,Favorites,Lock,Skip,Encrypted,ChannelOrTransponder,FreqInMhz,ServiceTypeName,SymbolRate
|
||||
DVB_S=Position,OldProgramNr,Name,ShortName,Favorites,Lock,Skip,Encrypted,FreqInMhz,ServiceTypeName,SymbolRate
|
||||
[FAV_Record]
|
||||
RecordSize=80
|
||||
SvlTableId=0
|
||||
SvlRecordId=2
|
||||
DisplayNumber=4
|
||||
DisplayNumberLength=10
|
||||
ChannelName=15
|
||||
ChannelNameLength=64
|
||||
|
||||
432
source/ChanSort.Loader.Hisense/HisBin/HisBinSerializer.cs
Normal file
432
source/ChanSort.Loader.Hisense/HisBin/HisBinSerializer.cs
Normal file
@@ -0,0 +1,432 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using ChanSort.Api;
|
||||
|
||||
namespace ChanSort.Loader.Hisense.HisBin;
|
||||
|
||||
/*
|
||||
* Loads Hisense HIS_SVL.BIN channel lists
|
||||
*
|
||||
* This binary format is based on a customized MediaTek format, which means that there may be many incompatible
|
||||
* variants that can't be identified and distinguished easily.
|
||||
* This loader only supports the known Hisense variant with 304 bytes per channel in HIS_SVL.BIN.
|
||||
*
|
||||
* See also the his-svl.h file in Information/FileStructures_for_HHD_Hex_Editor_Neo
|
||||
*
|
||||
* Some properties of these lists:
|
||||
* - channel records are physically ordered by their program number. All TV channels first, then radio, then data.
|
||||
* - favorite lists allow mixing channels from different inputs and also radio and TV
|
||||
* - character encoding seen as both implicit UTF8 or latin-1
|
||||
*/
|
||||
public class HisBinSerializer : SerializerBase
|
||||
{
|
||||
private readonly ChannelList dvbtChannels = new (SignalSource.DvbT | SignalSource.Tv | SignalSource.Radio, "DVB-T");
|
||||
private readonly ChannelList dvbcChannels = new (SignalSource.DvbC | SignalSource.Tv | SignalSource.Radio, "DVB-C");
|
||||
private readonly ChannelList dvbsChannels = new (SignalSource.DvbS | SignalSource.Tv | SignalSource.Radio, "DVB-S");
|
||||
private readonly ChannelList favChannels = new(SignalSource.All, "Fav") { IsMixedSourceFavoritesList = true };
|
||||
|
||||
private byte[] svlFileContent;
|
||||
private byte[] tslFileContent;
|
||||
private const int MaxFileSize = 4 << 20; // 4 MB
|
||||
|
||||
private int tSize, cSize, sSize;
|
||||
|
||||
private const string ERR_fileTooBig = "The file size {0} is larger than the allowed maximum of {1}.";
|
||||
private const string ERR_badFileFormat = "The content of the file doesn't match the expected format.";
|
||||
|
||||
private DataMapping svlMapping, tslMapping, dvbMapping, favMapping;
|
||||
private readonly Dictionary<int, Transponder> transponder = new ();
|
||||
|
||||
#region ctor()
|
||||
public HisBinSerializer(string inputFile) : base(inputFile)
|
||||
{
|
||||
this.Features.ChannelNameEdit = ChannelNameEditMode.All;
|
||||
this.Features.CanSkipChannels = true;
|
||||
this.Features.CanLockChannels = true;
|
||||
this.Features.CanHideChannels = false;
|
||||
this.Features.FavoritesMode = FavoritesMode.MixedSource;
|
||||
this.Features.MaxFavoriteLists = 4;
|
||||
this.ReadConfigurationFromIniFile();
|
||||
|
||||
this.DataRoot.AddChannelList(dvbcChannels);
|
||||
this.DataRoot.AddChannelList(dvbtChannels);
|
||||
this.DataRoot.AddChannelList(dvbsChannels);
|
||||
this.DataRoot.AddChannelList(favChannels);
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.PcrPid));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.VideoPid));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.AudioPid));
|
||||
list.VisibleColumnFieldNames.Remove(nameof(ChannelInfo.Satellite));
|
||||
list.VisibleColumnFieldNames.Add(nameof(ChannelInfo.ServiceType));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadConfigurationFromIniFile()
|
||||
|
||||
private void ReadConfigurationFromIniFile()
|
||||
{
|
||||
string iniFile = this.GetType().Assembly.Location.ToLower().Replace(".dll", ".ini");
|
||||
IniFile ini = new IniFile(iniFile);
|
||||
this.svlMapping = new DataMapping(ini.GetSection("SVL_Record"));
|
||||
this.svlMapping.DefaultEncoding = this.DefaultEncoding;
|
||||
this.tslMapping = new DataMapping(ini.GetSection("TSL_Record"));
|
||||
this.tslMapping.DefaultEncoding = this.DefaultEncoding;
|
||||
this.dvbMapping = new DataMapping(ini.GetSection("DVB_Data"));
|
||||
this.dvbMapping.DefaultEncoding = this.DefaultEncoding;
|
||||
this.favMapping = new DataMapping(ini.GetSection("FAV_Record"));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Load()
|
||||
|
||||
public override void Load()
|
||||
{
|
||||
var dir = Path.GetDirectoryName(this.FileName);
|
||||
var name = Path.GetFileNameWithoutExtension(this.FileName);
|
||||
var i = name.LastIndexOf('_');
|
||||
var basename = i < 0 ? name : name.Substring(0, i);
|
||||
this.FileName = Path.Combine(dir, basename + "_SVL.BIN");
|
||||
this.LoadTslFile(Path.Combine(dir, basename + "_TSL.BIN"));
|
||||
this.LoadSvlFile(this.FileName);
|
||||
this.LoadFavFile(Path.Combine(dir, basename + "_FAV.BIN"));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LoadTslFile()
|
||||
private void LoadTslFile(string fileName)
|
||||
{
|
||||
long fileSize = new FileInfo(fileName).Length;
|
||||
if (fileSize > MaxFileSize)
|
||||
throw new FileLoadException(string.Format(ERR_fileTooBig, fileSize, MaxFileSize));
|
||||
this.tslFileContent = File.ReadAllBytes(fileName);
|
||||
int off = 0;
|
||||
|
||||
tSize = this.ReadHeader(tslFileContent, ref off);
|
||||
cSize = this.ReadHeader(tslFileContent, ref off);
|
||||
sSize = this.ReadHeader(tslFileContent, ref off);
|
||||
this.ReadTransponder(ref off, tSize, 1, 1000000);
|
||||
this.ReadTransponder(ref off, cSize, 2, 1000000);
|
||||
this.ReadTransponder(ref off, sSize, 3, 1);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadTransponder()
|
||||
private void ReadTransponder(ref int off, int size, int table, int freqFactor)
|
||||
{
|
||||
int recordSize = tslMapping.Settings.GetInt("RecordSize");
|
||||
if (size % recordSize != 0)
|
||||
throw new FileLoadException(ERR_badFileFormat);
|
||||
int count = size / recordSize;
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
tslMapping.SetDataPtr(tslFileContent, off);
|
||||
var id = (table << 16) + tslMapping.GetWord("ID");
|
||||
var trans = new Transponder(id);
|
||||
trans.FrequencyInMhz = (decimal)tslMapping.GetDword("Frequency") / freqFactor;
|
||||
var sym = tslMapping.GetDword("SymbolRate");
|
||||
if (sym == 0)
|
||||
sym = tslMapping.GetDword("DvbsSymbolRate");
|
||||
trans.SymbolRate = (int)(sym > 1000000 ? sym / 1000 : sym);
|
||||
trans.OriginalNetworkId = tslMapping.GetWord("Onid");
|
||||
if (trans.OriginalNetworkId == 0) // some files have Onid=0 but provide a Nid, which seems to be the Onid
|
||||
trans.OriginalNetworkId = tslMapping.GetWord("Nid");
|
||||
trans.TransportStreamId = tslMapping.GetWord("Tsid");
|
||||
trans.Name = tslMapping.GetString("Name", tslMapping.Settings.GetInt("NameLength"));
|
||||
var z = trans.Name.IndexOf('\0');
|
||||
if (z >= 0)
|
||||
trans.Name = trans.Name.Substring(0, z);
|
||||
this.transponder.Add(id, trans);
|
||||
off += recordSize;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadSvlFile()
|
||||
|
||||
private void LoadSvlFile(string fileName)
|
||||
{
|
||||
long fileSize = new FileInfo(fileName).Length;
|
||||
if (fileSize > MaxFileSize)
|
||||
throw new FileLoadException(string.Format(ERR_fileTooBig, fileSize, MaxFileSize));
|
||||
this.svlFileContent = File.ReadAllBytes(this.FileName);
|
||||
int off = 0;
|
||||
|
||||
tSize = this.ReadHeader(svlFileContent, ref off);
|
||||
cSize = this.ReadHeader(svlFileContent, ref off);
|
||||
sSize = this.ReadHeader(svlFileContent, ref off);
|
||||
this.ReadChannelList(ref off, tSize, 1, dvbtChannels);
|
||||
this.ReadChannelList(ref off, cSize, 2, dvbcChannels);
|
||||
this.ReadChannelList(ref off, sSize, 3, dvbsChannels);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadHeader()
|
||||
private int ReadHeader(byte[] data, ref int off)
|
||||
{
|
||||
if (off + 40 > data.Length)
|
||||
throw new FileLoadException(ERR_badFileFormat);
|
||||
var blockSize = BitConverter.ToInt32(data, off + 36);
|
||||
if (off + blockSize > data.Length)
|
||||
throw new FileLoadException(ERR_badFileFormat);
|
||||
|
||||
off += 40;
|
||||
return blockSize;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadChannelList()
|
||||
private void ReadChannelList(ref int off, int size, int table, ChannelList channels)
|
||||
{
|
||||
int recordSize = svlMapping.Settings.GetInt("RecordSize");
|
||||
if (size % recordSize != 0)
|
||||
throw new FileLoadException(ERR_badFileFormat);
|
||||
int channelCount = size / recordSize;
|
||||
if (channelCount == 0)
|
||||
return;
|
||||
|
||||
var broadcastDataOffset = svlMapping.Settings.GetInt("BroadcastSystemData");
|
||||
var nameLength = svlMapping.Settings.GetInt("NameLength");
|
||||
var source = channels.SignalSource & (SignalSource.MaskAnalogDigital | SignalSource.MaskAntennaCableSat);
|
||||
for (int i = 0; i < channelCount; i++)
|
||||
{
|
||||
svlMapping.SetDataPtr(svlFileContent, off);
|
||||
dvbMapping.SetDataPtr(svlFileContent, off + broadcastDataOffset);
|
||||
var ci = ReadChannel(source, i, nameLength);
|
||||
if (ci != null)
|
||||
{
|
||||
this.DataRoot.AddChannel(channels, ci);
|
||||
this.favChannels.AddChannel(ci);
|
||||
}
|
||||
|
||||
off += recordSize;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadChannel()
|
||||
private ChannelInfo ReadChannel(SignalSource source, int index, int nameLength)
|
||||
{
|
||||
var id = svlMapping.GetWord("RecordId");
|
||||
ChannelInfo ci = new ChannelInfo(source, id, 0, "");
|
||||
ci.RecordOrder = index;
|
||||
ci.OldProgramNr = svlMapping.GetWord("ChannelId") >> 2;
|
||||
ci.RawDataOffset = svlMapping.BaseOffset;
|
||||
|
||||
var nwMask = svlMapping.GetDword("NwMask");
|
||||
ci.Skip = (nwMask & svlMapping.Settings.GetInt("NwMask_Skip")) == 0; // reverse logic!
|
||||
ci.Lock = (nwMask & svlMapping.Settings.GetInt("NwMask_Lock")) != 0;
|
||||
for (int i = 1; i <= 4; i++)
|
||||
{
|
||||
bool isFav = (nwMask & svlMapping.Settings.GetInt("NwMask_Fav" + i)) != 0;
|
||||
if (isFav)
|
||||
ci.Favorites |= (Favorites)(1 << (i-1));
|
||||
}
|
||||
ci.Encrypted = (nwMask & svlMapping.Settings.GetInt("NwMask_Encrypted")) != 0;
|
||||
|
||||
ci.Name = ReadString(svlMapping, "Name", nameLength);
|
||||
|
||||
var serviceType = svlMapping.GetByte("ServiceType");
|
||||
if (serviceType == 1)
|
||||
{
|
||||
ci.SignalSource |= SignalSource.Tv;
|
||||
ci.ServiceTypeName = "TV";
|
||||
}
|
||||
else if (serviceType == 2)
|
||||
{
|
||||
ci.SignalSource |= SignalSource.Radio;
|
||||
ci.ServiceTypeName = "Radio";
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.ServiceTypeName = "Data";
|
||||
}
|
||||
|
||||
ci.ServiceId = svlMapping.GetWord("ServiceId");
|
||||
|
||||
int transpTableId = svlMapping.GetWord("TslTableId");
|
||||
int transpRecordId = svlMapping.GetWord("TslRecordId");
|
||||
var transpId = (transpTableId << 16) + transpRecordId;
|
||||
var transp = this.transponder.TryGet(transpId);
|
||||
if (transp != null)
|
||||
{
|
||||
ci.Transponder = transp;
|
||||
ci.FreqInMhz = transp.FrequencyInMhz;
|
||||
ci.SymbolRate = transp.SymbolRate;
|
||||
switch (ci.SymbolRate) // can be either an enum for bandwidth 1=6 MHz, 2=7 MHz, 3=8 MHz - or the symbol rate
|
||||
{
|
||||
case 1: ci.SymbolRate = 6000; break;
|
||||
case 2: ci.SymbolRate = 7000; break;
|
||||
case 3: ci.SymbolRate = 8000; break;
|
||||
}
|
||||
ci.OriginalNetworkId = transp.OriginalNetworkId;
|
||||
ci.TransportStreamId = transp.TransportStreamId;
|
||||
ci.Provider = transp.Name;
|
||||
}
|
||||
|
||||
var bcastType = svlMapping.GetByte("BroadcastType");
|
||||
if (bcastType == 1)
|
||||
ReadAnalogData(ci);
|
||||
else if (bcastType == 2)
|
||||
ReadDvbData(ci);
|
||||
|
||||
return ci;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadAnalogData()
|
||||
private void ReadAnalogData(ChannelInfo ci)
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadDvbData()
|
||||
private void ReadDvbData(ChannelInfo ci)
|
||||
{
|
||||
var mask = dvbMapping.GetDword("LinkageMask");
|
||||
var tsFlag = dvbMapping.Settings.GetInt("LinkageMask_Ts");
|
||||
|
||||
if ((mask & tsFlag) != 0)
|
||||
{
|
||||
ci.OriginalNetworkId = dvbMapping.GetWord("Onid");
|
||||
ci.TransportStreamId = dvbMapping.GetWord("Tsid");
|
||||
ci.ServiceId = dvbMapping.GetWord("Sid");
|
||||
}
|
||||
|
||||
if ((ci.SignalSource & (SignalSource.MaskAnalogDigital | SignalSource.MaskAntennaCableSat)) == SignalSource.DvbC)
|
||||
{
|
||||
ci.OriginalNetworkId = dvbMapping.GetWord("DvbcOnid");
|
||||
ci.TransportStreamId = dvbMapping.GetWord("DvbcTsid");
|
||||
}
|
||||
|
||||
if ((ci.SignalSource & SignalSource.DvbT) == SignalSource.DvbT)
|
||||
ci.ChannelOrTransponder = LookupData.Instance.GetDvbtTransponder(ci.FreqInMhz).ToString();
|
||||
else if ((ci.SignalSource & SignalSource.DvbC) == SignalSource.DvbC)
|
||||
ci.ChannelOrTransponder = LookupData.Instance.GetDvbcChannelName(ci.FreqInMhz).ToString();
|
||||
|
||||
ci.ServiceType = dvbMapping.GetByte("ServiceType");
|
||||
if (ci.ServiceType != 0)
|
||||
ci.ServiceTypeName = LookupData.Instance.GetServiceTypeDescription(ci.ServiceType);
|
||||
|
||||
ci.ShortName = dvbMapping.GetString("ShortName", dvbMapping.Settings.GetInt("ShortNameLength"));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReadString()
|
||||
private string ReadString(DataMapping mapping, string name, int nameLength)
|
||||
{
|
||||
var str = mapping.GetString(name, nameLength);
|
||||
int term = str.IndexOf('\0');
|
||||
if (term >= 0)
|
||||
str = str.Substring(0, term);
|
||||
return str;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LoadFavFile()
|
||||
private void LoadFavFile(string filename)
|
||||
{
|
||||
if (!File.Exists(filename))
|
||||
return;
|
||||
var content = File.ReadAllBytes(filename);
|
||||
var favListSizes = new int[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
favListSizes[i] = BitConverter.ToInt32(content, i * 4);
|
||||
|
||||
var recSize = favMapping.Settings.GetInt("RecordSize");
|
||||
var dispNumLen = favMapping.Settings.GetInt("DisplayNumberLength");
|
||||
favMapping.SetDataPtr(content, 16 - recSize);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0, c = favListSizes[i] / recSize; j < c; j++)
|
||||
{
|
||||
favMapping.BaseOffset += recSize;
|
||||
|
||||
//if (favMapping.BaseOffset + recSize >= content.Length) //
|
||||
// break;
|
||||
|
||||
var tblId = favMapping.GetWord("SvlTableId");
|
||||
var recId = favMapping.GetWord("SvlRecordId");
|
||||
|
||||
var list = tblId == 1 ? dvbtChannels : tblId == 2 ? dvbcChannels : tblId == 3 ? dvbsChannels : null;
|
||||
if (list == null) // should never happen
|
||||
continue;
|
||||
|
||||
var chan = list.GetChannelById(recId);
|
||||
if (chan == null) // should never happen
|
||||
continue;
|
||||
|
||||
var dispNr = favMapping.GetString("DisplayNumber", dispNumLen);
|
||||
var nr = int.Parse(dispNr);
|
||||
chan.SetOldPosition(1 + i, nr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
// Saving ====================================
|
||||
|
||||
#region Save()
|
||||
public override void Save()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
// TODO
|
||||
// HIS_SVL
|
||||
// - update size in header
|
||||
// - write channels in new physical order
|
||||
// HIS_FAV
|
||||
}
|
||||
#endregion
|
||||
|
||||
// Infrastructure ============================
|
||||
|
||||
#region DefaultEncoding
|
||||
public override Encoding DefaultEncoding
|
||||
{
|
||||
get => base.DefaultEncoding;
|
||||
set
|
||||
{
|
||||
if (value == this.DefaultEncoding)
|
||||
return;
|
||||
base.DefaultEncoding = value;
|
||||
this.svlMapping.DefaultEncoding = value;
|
||||
this.tslMapping.DefaultEncoding = value;
|
||||
this.dvbMapping.DefaultEncoding = value;
|
||||
this.ReparseNames();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReparseNames()
|
||||
private void ReparseNames()
|
||||
{
|
||||
var nameLength = svlMapping.Settings.GetInt("NameLength");
|
||||
var shortNameLength = dvbMapping.Settings.GetInt("ShortNameLength");
|
||||
var dvbOffset = svlMapping.Settings.GetInt("BroadcastSystemData");
|
||||
|
||||
foreach (var list in this.DataRoot.ChannelLists)
|
||||
{
|
||||
if (list.IsMixedSourceFavoritesList)
|
||||
continue;
|
||||
foreach (var chan in list.Channels)
|
||||
{
|
||||
svlMapping.BaseOffset = chan.RawDataOffset;
|
||||
chan.Name = ReadString(svlMapping, "Name", nameLength);
|
||||
|
||||
dvbMapping.BaseOffset = chan.RawDataOffset + dvbOffset;
|
||||
chan.ShortName = ReadString(dvbMapping, "ShortName", shortNameLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace ChanSort.Loader.Hisense
|
||||
{
|
||||
public string DllName { get; set; }
|
||||
public string PluginName => "Hisense (channel.db, servicelist.db)";
|
||||
public string FileFilter => "*.db";
|
||||
public string FileFilter => "*.db;*.bin";
|
||||
|
||||
public SerializerBase CreateSerializer(string inputFile)
|
||||
{
|
||||
@@ -19,6 +19,8 @@ namespace ChanSort.Loader.Hisense
|
||||
if (name.Contains("servicelist")) // models 2017 and later
|
||||
return new ServicelistDb.ServicelistDbSerializer(inputFile);
|
||||
|
||||
if (name.StartsWith("his_") && name.EndsWith(".bin"))
|
||||
return new HisBin.HisBinSerializer(inputFile);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,51 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.TCL", "Chan
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.DBM", "ChanSort.Loader.DBM\ChanSort.Loader.DBM.csproj", "{C1FF21EB-1CA6-4CE9-8BA8-9FAF71C5D6A6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChanSort.Loader.VisionEdge4K", "ChanSort.Loader.VisionEdge4K\ChanSort.Loader.VisionEdge4K.csproj", "{71ABCE5E-A833-4729-BC30-35FF0AE01DCA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChanSort.Loader.VisionEdge4K", "ChanSort.Loader.VisionEdge4K\ChanSort.Loader.VisionEdge4K.csproj", "{71ABCE5E-A833-4729-BC30-35FF0AE01DCA}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HDD Hex Edit Neo", "HDD Hex Edit Neo", "{1BB3A27F-714C-42F0-A14E-8653B9AB8C24}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\chansort.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\chansort.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\cvt_database-dat.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\cvt_database-dat.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\dbm.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dbm.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_1-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_1-bin.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_2-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\dtv_cmdb_2-bin.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\get_doc_size.js = Information\FileStructures_for_HHD_Hex_Editor_Neo\get_doc_size.js
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\his-svl.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\his-svl.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\LaSat_lst.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\LaSat_lst.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\panasonic_idtvChannelBin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\panasonic_idtvChannelBin.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_chanLst-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_chanLst-bin.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_dat.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_dat.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_mgr_472.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_mgr_472.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_mgr_476.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_mgr_476.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_mgr_480.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_mgr_480.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_SatelliteDb-bin.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\philips_SatelliteDb-bin.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-map-Analog.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-map-Analog.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-map-Digital.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-map-Digital.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-map-Satellite.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-map-Satellite.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-SatDataBase.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-SatDataBase.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-TransponderDataBase.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\scm-TransponderDataBase.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-084-LP.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-084-LP.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-164_LH3000.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-164_LH3000.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-164_LH_LU_LF.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-164_LH_LU_LF.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-176-LD_LE_LK_LX_LW45_LW54.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-176-LD_LE_LK_LX_LW45_LW54.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-180-PT.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-180-PT.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-184-LH250C.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-184-LH250C.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-184-LV_LW_LK950S.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-184-LV_LW_LK950S.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-188-LM611S.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-188-LM611S.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-192-LM_LS.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-192-LM_LS.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-212-LT.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-212-LT.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-212-PN.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-212-PN.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-224-LN.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-224-LN.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-244-LB550U.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-244-LB550U.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-256-LA.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-256-LA.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-256-LH.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-256-LH.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-256-LY.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-256-LY.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-260-LA.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-260-LA.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-280-LB580.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-280-LB580.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-common.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-common.h
|
||||
Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-satellite.h = Information\FileStructures_for_HHD_Hex_Editor_Neo\tll-satellite.h
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -1328,6 +1372,9 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{1BB3A27F-714C-42F0-A14E-8653B9AB8C24} = {67AED502-8AEB-45F2-9B95-AC42B6A5D2C4}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BBF1F6CB-9445-4F6C-A69A-15C4DA246814}
|
||||
EndGlobalSection
|
||||
|
||||
@@ -35,3 +35,9 @@ enum ServiceType : byte
|
||||
Option = 211
|
||||
};
|
||||
|
||||
|
||||
function trim(str)
|
||||
{
|
||||
var i = find(str, "\0");
|
||||
return i < 0 ? str : substring(str, 0, i);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
#include "chansort.h"
|
||||
|
||||
// common ---------------------------
|
||||
|
||||
enum TableId : word
|
||||
{
|
||||
Antenna = 1, Cable = 2, Sat = 3
|
||||
};
|
||||
|
||||
struct Header
|
||||
{
|
||||
word id;
|
||||
char name[34];
|
||||
dword size;
|
||||
};
|
||||
|
||||
enum BroadcastType : byte
|
||||
{
|
||||
Analog = 1,
|
||||
Dvb = 2,
|
||||
};
|
||||
|
||||
// TSL ------------------------------
|
||||
|
||||
enum Medium : byte
|
||||
{
|
||||
DigAnt = 1,
|
||||
DigCable = 2,
|
||||
DigSat = 3,
|
||||
AnaAnt = 4,
|
||||
AnaCable = 5,
|
||||
AnaSat = 6
|
||||
};
|
||||
|
||||
enum HisServiceType : byte
|
||||
{
|
||||
TV = 1, Radio = 2, App = 3
|
||||
};
|
||||
|
||||
enum BandwidthType { Unknown, Mhz6, Mhz7, Mhz8 };
|
||||
|
||||
struct TslRecord
|
||||
{
|
||||
var off0 = current_offset;
|
||||
word id;
|
||||
|
||||
BroadcastType broadcastType;
|
||||
Medium medium;
|
||||
word nid;
|
||||
word onid;
|
||||
word tsid;
|
||||
word nwlRecId;
|
||||
byte nwlVal;
|
||||
byte u1[3];
|
||||
|
||||
dword freq;
|
||||
union
|
||||
{
|
||||
dword symRate;
|
||||
BandwidthType bwType;
|
||||
} bandwidth;
|
||||
byte u2[192];
|
||||
byte name[32];
|
||||
var off1 = current_offset;
|
||||
byte padding[tslRecordSize - (off1 - off0) - 12];
|
||||
dword mask;
|
||||
word nwlTblId;
|
||||
word nwlRecId;
|
||||
word satTblId;
|
||||
word satRecId;
|
||||
};
|
||||
|
||||
public struct HIS_TSL
|
||||
{
|
||||
var tslRecordSize = 328;
|
||||
Header tsl1;
|
||||
Header tsl2;
|
||||
Header tsl3;
|
||||
|
||||
var count = tsl1.size / tslRecordSize;
|
||||
TslRecord antenna[count];
|
||||
|
||||
var count = tsl2.size / tslRecordSize;
|
||||
TslRecord cable[count];
|
||||
|
||||
var count = tsl3.size / tslRecordSize;
|
||||
TslRecord sat[count];
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// SVL ------------------------------
|
||||
|
||||
// bit values defined in https://patents.google.com/patent/CN102523534B/en
|
||||
|
||||
enum NwMask : dword
|
||||
{
|
||||
Skip = 1 << 3,
|
||||
Fav1 = 1 << 4,
|
||||
Fav2 = 1 << 5,
|
||||
Fav3 = 1 << 6,
|
||||
Fav4 = 1 << 7,
|
||||
Lock = 1 << 8
|
||||
};
|
||||
|
||||
enum OptionMask : dword
|
||||
{
|
||||
Rename = 1 << 3,
|
||||
Moved = 1 << 10
|
||||
};
|
||||
|
||||
enum Option2Mask : dword
|
||||
{
|
||||
Unknown = 0
|
||||
};
|
||||
|
||||
enum Hashcode : dword
|
||||
{
|
||||
Name = 0x0001,
|
||||
ServiceId = 0x0002,
|
||||
BroadcastType = 0x0004,
|
||||
TlsRecId = 0x0008,
|
||||
PrgNum = 0x0010,
|
||||
ShortName = 0x0020,
|
||||
Radio = 0x0400, // guess
|
||||
Encrypted = 0x0800, // guess
|
||||
Tv = 0x2000 // guess
|
||||
};
|
||||
|
||||
enum DvbServiceRunningStatus : dword
|
||||
{
|
||||
Unknown,
|
||||
Undefined,
|
||||
NotRunning,
|
||||
StartInSeconds,
|
||||
Pausing,
|
||||
Running,
|
||||
OffAir
|
||||
};
|
||||
|
||||
enum LinkageMask : dword
|
||||
{
|
||||
Nid = 0x01,
|
||||
Onid = 0x02,
|
||||
Tsid = 0x04
|
||||
};
|
||||
|
||||
struct DvbId
|
||||
{
|
||||
word onid;
|
||||
word tsid;
|
||||
word sid;
|
||||
};
|
||||
|
||||
enum DvbReplacementMask: dword
|
||||
{
|
||||
CaReplacement = 0x01,
|
||||
ServiceReplacement = 0x02,
|
||||
CmpltEitSch = 0x04,
|
||||
EpgPid = 0x08
|
||||
};
|
||||
|
||||
struct SvlDvb
|
||||
{
|
||||
dword reserved;
|
||||
byte shortName[18];
|
||||
word caSystemId;
|
||||
DvbServiceRunningStatus runningStatus;
|
||||
DvbReplacementMask replacementMask;
|
||||
DvbId caReplacement;
|
||||
DvbId svcReplacement;
|
||||
DvbId cmplEitSchOn;
|
||||
DvbId hdSimulcastOn;
|
||||
DvbId orig;
|
||||
word epgPid;
|
||||
bool freeCaMode;
|
||||
byte ciHostShunningMode;
|
||||
|
||||
dword ciPlusPrevChannelId;
|
||||
byte ciPlusCiTuneService;
|
||||
byte nonStandard[10];
|
||||
|
||||
byte downmixMode;
|
||||
byte subtitlePref1[4];
|
||||
byte subtitlePref2[4];
|
||||
qword svcTimeStarted;
|
||||
qword svcTimeDuration;
|
||||
word lastViewSvlTableId;
|
||||
word lastViewSvlRecordId;
|
||||
byte mfType;
|
||||
bool eitPfFlag;
|
||||
word curLcn;
|
||||
word origLcn;
|
||||
word lcnIndex;
|
||||
word dvbcTsid;
|
||||
word dvbcOnid;
|
||||
byte audioIndex;
|
||||
bool dvbsDpIdFlag;
|
||||
word dvbsDpTsid;
|
||||
word dvbsDpSid;
|
||||
bool hbbtvOff;
|
||||
byte sdtServiceType;
|
||||
byte doNotScramble;
|
||||
byte dadInfo[33];
|
||||
};
|
||||
|
||||
[display(format("{0} - {1}", header.channelId.progNr, trim(header.name)))]
|
||||
struct SvlRecord
|
||||
{
|
||||
// different sizes possible: 304 (observed), 308, and lots of smaller ones
|
||||
var off0 = current_offset;
|
||||
word recordId;
|
||||
struct
|
||||
{
|
||||
dword nonStandard;
|
||||
struct
|
||||
{
|
||||
word unk : 2;
|
||||
word progNr : 14;
|
||||
} channelId;
|
||||
union
|
||||
{
|
||||
// !! file uses a different field order than documentation/definition !!
|
||||
// Hisense seems to have accidentally put the hashcode and nwMask to the same location
|
||||
// and there's indication that Skip is actually reversed (1=noskip)
|
||||
Hashcode hashcode;
|
||||
NwMask nwMask;
|
||||
} hashcodeAndNwMask;
|
||||
OptionMask optionMask;
|
||||
Option2Mask option2Mask;
|
||||
dword unknown;
|
||||
word serviceId;
|
||||
word tslTableId;
|
||||
word tslRecordId;
|
||||
word nwlTableId;
|
||||
word nwlRecordId;
|
||||
word satTableId;
|
||||
word satRecordId;
|
||||
BroadcastType broadcastType;
|
||||
HisServiceType serviceType;
|
||||
byte name[65];
|
||||
byte nonStandard2[3];
|
||||
byte customData[8];
|
||||
byte privateData[20];
|
||||
} header;
|
||||
|
||||
union
|
||||
{
|
||||
SvlDvb dvb;
|
||||
byte padding[168];
|
||||
} broadcastSystemData;
|
||||
var off1 = current_offset;
|
||||
byte padding[svlRecordSize - (off1 - off0)];
|
||||
};
|
||||
|
||||
public struct HIS_SVL
|
||||
{
|
||||
var svlRecordSize = 304;
|
||||
|
||||
Header svl1;
|
||||
Header svl2;
|
||||
Header svl3;
|
||||
|
||||
var count = svl1.size / svlRecordSize;
|
||||
SvlRecord antenna[count];
|
||||
|
||||
var count = svl2.size / svlRecordSize;
|
||||
SvlRecord cable[count];
|
||||
|
||||
var count = svl3.size / svlRecordSize;
|
||||
SvlRecord sat[count];
|
||||
};
|
||||
|
||||
|
||||
|
||||
// HIS_FAV -----------------------------------
|
||||
|
||||
[display(format("{0} - {1}", trim(progNumDisplayInFavList), trim(name)))]
|
||||
struct FavRecord
|
||||
{
|
||||
word svlTableId;
|
||||
word svlRecordId;
|
||||
char progNumDisplayInFavList[11];
|
||||
char name[65];
|
||||
};
|
||||
|
||||
public struct HIS_FAV
|
||||
{
|
||||
dword fav1size;
|
||||
dword fav2size;
|
||||
dword fav3size;
|
||||
dword fav4size;
|
||||
|
||||
FavRecord fav1[fav1size / sizeof(FavRecord)];
|
||||
FavRecord fav2[fav2size / sizeof(FavRecord)];
|
||||
FavRecord fav3[fav3size / sizeof(FavRecord)];
|
||||
FavRecord fav4[fav4size / sizeof(FavRecord)];
|
||||
};
|
||||
Reference in New Issue
Block a user