initial import

This commit is contained in:
hbeham
2013-03-31 14:09:38 +02:00
commit e194ff983b
110 changed files with 20082 additions and 0 deletions

View File

@@ -0,0 +1,72 @@
using System.Text;
using ChanSort.Api;
namespace ChanSort.Plugin.ScmFile
{
internal class AnalogChannelDataMapping : ChannelMappingBase
{
const string offFrequency = "offFrequency";
const string offChecksum = "offChecksum";
#region ctor()
public AnalogChannelDataMapping(IniFile.Section settings, int length) :
base(settings, length, new UnicodeEncoding(true, false))
{
}
#endregion
#region Favorites
public override Favorites Favorites
{
get
{
if (this.DataLength < 64)
return base.Favorites;
byte fav = 0;
byte mask = 0x01;
foreach (int off in this.GetOffsets(offFavorites))
{
if (this.GetByte(off) == 1)
fav |= mask;
mask <<= 1;
}
return (Favorites)fav;
}
set
{
if (this.DataLength < 64)
{
base.Favorites = value;
return;
}
int intValue = (int)value;
foreach (int off in this.GetOffsets(offFavorites))
{
if ((intValue & 1) != 0)
this.SetByte(off, 1);
intValue >>= 1;
}
}
}
#endregion
#region Frequency
public float Frequency
{
get { return this.GetFloat(offFrequency); }
set { this.SetFloat(offFrequency, value); }
}
#endregion
#region Checksum
public byte Checksum
{
get { return this.GetByte(offChecksum); }
set { this.SetByte(offChecksum, value); }
}
#endregion
}
}

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{A1C9A98D-368A-44E8-9B7F-7EACA46C9EC5}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ChanSort.Plugin.ScmFile</RootNamespace>
<AssemblyName>ChanSort.Plugin.ScmFile</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
</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>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<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>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
<CodeAnalysisFailOnMissingRules>false</CodeAnalysisFailOnMissingRules>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
<CodeAnalysisFailOnMissingRules>true</CodeAnalysisFailOnMissingRules>
</PropertyGroup>
<ItemGroup>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\DLL\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AnalogChannelDataMapping.cs" />
<Compile Include="DvbSChannelDataMapping.cs" />
<Compile Include="DvbCtChannelDataMapping.cs" />
<Compile Include="ModelConstants.cs" />
<Compile Include="ScmSerializer.cs" />
<Compile Include="ScmSerializerPlugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScmStructures.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.Plugin.ScmFile.ini">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,334 @@
[Series:B]
SatDataBase.dat = 145
TransponderDataBase.dat = 49
FineTune = 20
FineTune_Digital = 28
map-AirA = 28
map-AirD = 248
map-CableD = 248
map-SateD = 144
Favorites = 4
[Series:C]
SatDataBase.dat = 145
TransponderDataBase.dat = 45
map-AirA = 40
map-AirD = 292
map-CableD = 292
map-SateD = 144
Favorites = 4
[Series:D]
SatDataBase.dat = 145
TransponderDataBase.dat = 45
map-AirA = 64
map-AirD = 320
map-CableD = 320
map-SateD = 172
map-AstraHDPlusD = 212
Favorites = 5
[Series:E]
SatDataBase.dat = 145
TransponderDataBase.dat = 45
map-AirA = 64
map-AirD = 320
map-CableD = 320
map-SateD = 168
map-AstraHDPlusD = 212
Favorites = 5
[Analog:28]
; map-AirA and map-CableA for B series
offInUse = 0
maskInUse = 0x02
;offNameLength = 1
offProgramNr = 4
offFavorites =
offName = 12
lenName = 12
offChecksum = 27
[Analog:40]
; map-AirA and map-CableA for C series
offInUse = 1
maskInUse = 0x01
offSkip = 2
maskSkip = 0x01
offLock = 6
maskLock = 0x01
offTuned = 8
maskTuned = 0x01
offProgramNr = 9
offSlotNr = 16
offNameLength = 18
offName = 20
offFrequency = 32
offFavorites = 38
offChecksum = 39
[Analog:64]
; map-AirA and map-CableA for D series
offInUse = 1
maskInUse = 0x01
offSkip = 2
maskSkip = 0x01
offLock = 6
maskLock = 0x01
offTuned = 8
maskTuned = 0x01
offProgramNr = 9
offSlotNr = 16
offNameLength = 18
offName = 20
offFrequency = 32
offFavorite = 36,40,44,48,52
offChecksum = 63
[FineTune:20]
offIsCable = 0
maskIsCable = 0x01
offSlotNr = 4
offFrequency = 8
[FineTune_Digital:28]
offIsCable = 0
maskIsCable = 0x01
offChannelTransponder = 4
offFrequency = 16
[DvbCT:248]
; map-AirD and map-CableD for B series
offProgramNr = 0
offVideoPid = 2
offPcrPid = 4
offServiceId = 10
offStatus = 8
offQam = 7
offServiceType = 9
offEncrypted = 23
maskEncrypted = 0xff
offSymbolRate = 32
offLock = 244
maskLock = 0x01
offOriginalNetworkId = 12
offNetworkId = 14
offBouquet = 34
offChannelTransponder = 26
offLogicalProgramNr = 28
offTransportStreamId = 36
offName = 44
lenName = 100
offFavorites = 246
offChecksum = 247
offCodec =
offServiceProviderId =
offShortName =
lenShortName =
offVideoFormat =
[DvbCT:292]
; map-AirD and map-CableD for C series
offProgramNr = 0
offVideoPid = 2
offPcrPid = 4
offServiceId = 6
offStatus =
offQam = 12
offBandwidth = 14
offServiceType = 15
offCodec = 16
offHRes = 20
offVRes = 22
offEncrypted = 24
maskEncrypted = 0xff
offFrameRate = 25
offSymbolRate = 28
offLock = 31
maskLock = 0x01
offOriginalNetworkId = 32
offNetworkId = 34
offServiceProviderId = 40
offChannelTransponder = 42
offLogicalProgramNr = 44
offTransportStreamId = 48
offName = 64
lenName = 200
offShortName = 264
lenShortName = 18
offVideoFormat = 282
offFavorites = 289
offChecksum = 291
offBouquet =
[DvbCT:320]
; map-AirD and map-CableD for D and E series
offProgramNr = 0
offVideoPid = 2
offPcrPid = 4
offServiceId = 6
offStatus =
offQam = 12
offBandwidth = 14
offServiceType = 15
offCodec = 16
offHRes = 20
offVRes = 22
offEncrypted = 24
maskEncrypted = 0xff
offFrameRate = 25
offSymbolRate = 28
offLock = 31
maskLock = 0x01
offOriginalNetworkId = 32
offNetworkId = 34
offServiceProviderId = 40
offChannelTransponder = 42
offLogicalProgramNr = 44
offTransportStreamId = 48
offName = 64
lenName = 200
offShortName = 264
lenShortName = 18
offVideoFormat = 282
offFavorites = 292,296,300,304,308
offChecksum = 319
offBouquet =
[DvbS:144]
; map-SateD for B and C Series
offProgramNr = 0
offVideoPid = 2
offPcrPid = 4
offInUse = 7
maskInUse = 0x01
offLock = 13
maskLock = 0x01
offServiceType = 14
offServiceId = 16
offTransponderNr = 18
offSatelliteNr = 20
offTransportStreamId = 24
offOriginalNetworkId = 28
offHRes = 32
offVRes = 34
offName = 36
lenName = 100
offEncrypted = 136
maskEncrypted = 0x01
offBouquet = 138
offFavorites = 142
offChecksum = 143
offCodec =
offSymbolRate =
offNetworkId =
offServiceProviderId =
offChannelTransponder =
offLogicalProgramNr =
offShortName =
lenShortName =
offVideoFormat =
[DvbS:172]
; map-SateD for D Series
offProgramNr = 0
offVideoPid = 2
offPcrPid = 4
offInUse = 7
maskInUse = 0x01
offLock = 13
maskLock = 0x01
offServiceType = 14
offServiceId = 16
offTransponderNr = 18
offSatelliteNr = 20
offTransportStreamId = 24
offOriginalNetworkId = 28
offHRes = 32
offVRes = 34
offName = 36
lenName = 100
offEncrypted = 136
maskEncrypted = 0x01
offBouquet = 138
offFavorites = 140,144,148,152,156
offChecksum = 171
offCodec =
offSymbolRate =
offNetworkId =
offServiceProviderId =
offChannelTransponder =
offLogicalProgramNr =
offShortName =
lenShortName =
offVideoFormat =
[DvbS:168]
; map-SateD for E Series
offProgramNr = 0
offVideoPid = 2
offPcrPid = 4
offInUse = 7
maskInUse = 0x01
offLock = 13
maskLock = 0x01
offServiceType = 14
offServiceId = 16
offTransponderNr = 18
offSatelliteNr = 20
offTransportStreamId = 24
offOriginalNetworkId = 28
offHRes = 32
offVRes = 34
offName = 36
offEncrypted = 136
maskEncrypted = 0x01
lenName = 100
offBouquet = 138
offFavorites = 140,144,148,152,156
offChecksum = 167
offCodec =
offSymbolRate =
offNetworkId =
offServiceProviderId =
offChannelTransponder =
offLogicalProgramNr =
offShortName =
lenShortName =
offVideoFormat =
[AstraHDPlusD:212]
; map-AstraHDPlusD for D and E Series
offProgramNr = 0,20
offVideoPid =
offPcrPid =
offInUse = 14
maskInUse = 0xff
offLock =
maskLock = 0x01
offServiceType = 14
offServiceId = 16
offTransponderNr = 18
offSatelliteNr =
offTransportStreamId = 36
offOriginalNetworkId = 32
offHRes =
offVRes =
offName = 48
offEncrypted = 180
maskEncrypted = 0x01
lenName = 100
offBouquet = 138
offFavorites = 184,188,192,196,200
offChecksum = 211
offCodec =
offSymbolRate =
offNetworkId =
offServiceProviderId =
offChannelTransponder =
offLogicalProgramNr =
offShortName =
lenShortName =
offVideoFormat =

View File

@@ -0,0 +1,63 @@
using System.Text;
using ChanSort.Api;
namespace ChanSort.Plugin.ScmFile
{
internal class DvbCtChannelDataMapping : DvbChannelMappingBase
{
const string offChecksum = "offChecksum";
#region ctor()
public DvbCtChannelDataMapping(IniFile.Section settings, int dataLength)
: base(settings, dataLength, new UnicodeEncoding(true, false))
{
}
#endregion
#region Checksum
public byte Checksum
{
get { return this.GetByte(offChecksum); }
set { this.SetByte(offChecksum, value); }
}
#endregion
#region Favorites
public override Favorites Favorites
{
get
{
if (this.DataLength < 320)
return base.Favorites;
byte fav = 0;
byte mask = 0x01;
foreach (int off in this.GetOffsets(offFavorites))
{
if (this.GetByte(off) == 1)
fav |= mask;
mask <<= 1;
}
return (Favorites)fav;
}
set
{
if (this.DataLength < 320)
{
base.Favorites = value;
return;
}
int intValue = (int)value;
foreach (int off in this.GetOffsets(offFavorites))
{
if ((intValue & 1) != 0)
this.SetByte(off, 1);
intValue >>= 1;
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,83 @@
using System.Text;
using ChanSort.Api;
namespace ChanSort.Plugin.ScmFile
{
internal class DvbSChannelDataMapping : DvbChannelMappingBase
{
private const string offChecksum = "offChecksum";
private const string offTransponderNr = "offTransponderNr";
private const string offSatelliteNr = "offSatelliteNr";
private readonly bool hasExtendedFavorites;
#region ctor()
public DvbSChannelDataMapping(IniFile.Section settings, int dataLength)
: base(settings, dataLength, new UnicodeEncoding(true, false))
{
this.hasExtendedFavorites = dataLength >= 168;
}
#endregion
#region TransponderNr
public ushort TransponderNr
{
get { return this.GetWord(offTransponderNr); }
set { this.SetWord(offTransponderNr, value); }
}
#endregion
#region SatelliteNr
public ushort SatelliteNr
{
get { return this.GetWord(offSatelliteNr); }
set { this.SetWord(offSatelliteNr, value); }
}
#endregion
#region Favorites
public override Favorites Favorites
{
get
{
if (!this.hasExtendedFavorites)
return base.Favorites;
byte fav = 0;
byte mask = 0x01;
foreach (int off in this.GetOffsets(offFavorites))
{
if (this.GetDword(off) == 1)
fav |= mask;
mask <<= 1;
}
return (Favorites)fav;
}
set
{
if (!this.hasExtendedFavorites)
{
base.Favorites = value;
return;
}
int intValue = (int)value;
foreach (int off in this.GetOffsets(offFavorites))
{
if ((intValue & 1) != 0)
this.SetDword(off, 1);
intValue >>= 1;
}
}
}
#endregion
#region Checksum
public byte Checksum
{
get { return this.GetByte(offChecksum); }
set { this.SetByte(offChecksum, value); }
}
#endregion
}
}

View File

@@ -0,0 +1,34 @@
using ChanSort.Api;
namespace ChanSort.Plugin.ScmFile
{
internal class ModelConstants
{
public readonly int dvbsSatelliteLength;
public readonly int dvbsTransponderLength;
public readonly int dvbsChannelLength;
public readonly int dvbtChannelLength;
public readonly int avbtChannelLength;
public readonly int hdplusChannelLength;
public readonly int avbtFineTuneLength;
public readonly int dvbtFineTuneLength;
public readonly Favorites supportedFavorites;
public ModelConstants(IniFile.Section iniSection)
{
this.avbtChannelLength = iniSection.GetInt("map-AirA");
this.dvbtChannelLength = iniSection.GetInt("map-AirD");
this.dvbsChannelLength = iniSection.GetInt("map-SateD");
this.hdplusChannelLength = iniSection.GetInt("map-AstraHDPlusD");
this.dvbsSatelliteLength = iniSection.GetInt("SatDataBase.dat");
this.dvbsTransponderLength = iniSection.GetInt("TransponderDataBase.dat");
this.avbtFineTuneLength = iniSection.GetInt("FineTune");
this.dvbtFineTuneLength = iniSection.GetInt("FineTune_Digital");
int numFavorites = iniSection.GetInt("Favorites");
int mask = 0;
for (int i = 0; i < numFavorites; i++)
mask = (mask << 1) | 1;
this.supportedFavorites = (Favorites)mask;
}
}
}

View 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.Plugin.ScmFile")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ChanSort.Plugin.ScmFile")]
[assembly: AssemblyCopyright("Copyright © 2012")]
[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("6f59ac5a-afba-42e3-a63e-c74793c15980")]
// 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")]

View File

@@ -0,0 +1,740 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using ChanSort.Api;
using ICSharpCode.SharpZipLib.Zip;
namespace ChanSort.Plugin.ScmFile
{
class ScmSerializer : SerializerBase
{
private readonly Dictionary<string, ModelConstants> modelConstants = new Dictionary<string, ModelConstants>();
private readonly MappingPool<AnalogChannelDataMapping> analogMappings = new MappingPool<AnalogChannelDataMapping>("Analog");
private readonly MappingPool<DvbCtChannelDataMapping> dvbctMappings = new MappingPool<DvbCtChannelDataMapping>("DVB-C/T");
private readonly MappingPool<DvbSChannelDataMapping> dvbsMappings = new MappingPool<DvbSChannelDataMapping>("DVB-S");
private readonly MappingPool<DvbSChannelDataMapping> hdplusMappings = new MappingPool<DvbSChannelDataMapping>("AstraHDPlus");
private readonly MappingPool<DataMapping> analogFineTuneMappings = new MappingPool<DataMapping>("FineTune");
private readonly ChannelList avbtChannels = new ChannelList(SignalSource.AnalogT, SignalType.Mixed);
private readonly ChannelList avbcChannels = new ChannelList(SignalSource.AnalogC, SignalType.Mixed);
private readonly ChannelList dvbcChannels = new ChannelList(SignalSource.DvbC, SignalType.Mixed);
private readonly ChannelList dvbtChannels = new ChannelList(SignalSource.DvbT, SignalType.Mixed);
private readonly ChannelList dvbsChannels = new ChannelList(SignalSource.DvbS, SignalType.Mixed);
private readonly ChannelList hdplusChannels = new ChannelList(SignalSource.HdPlusD, SignalType.Mixed);
private readonly Dictionary<int, decimal> avbtFrequency = new Dictionary<int, decimal>();
private readonly Dictionary<int, decimal> avbcFrequency = new Dictionary<int, decimal>();
private byte[] avbtFileContent;
private byte[] avbcFileContent;
private byte[] dvbtFileContent;
private byte[] dvbcFileContent;
private byte[] dvbsFileContent;
private byte[] hdplusFileContent;
private UnsortedChannelMode unsortedChannelMode;
private ModelConstants c;
#region ctor()
public ScmSerializer(string inputFile) : base(inputFile)
{
this.ReadConfigurationFromIniFile();
}
#endregion
#region DisplayName
public override string DisplayName { get { return "Samsung *.scm Loader"; } }
#endregion
#region ReadConfigurationFromIniFile()
private void ReadConfigurationFromIniFile()
{
string iniFile = Assembly.GetExecutingAssembly().Location.Replace(".dll", ".ini");
IniFile ini = new IniFile(iniFile);
foreach (var section in ini.Sections)
{
int idx = section.Name.IndexOf(":");
int len=0;
if (idx >= 0)
int.TryParse(section.Name.Substring(idx + 1), out len);
if (section.Name.StartsWith("Series:"))
modelConstants.Add(section.Name, new ModelConstants(section));
else if (section.Name.StartsWith("Analog:"))
analogMappings.AddMapping(new AnalogChannelDataMapping(section, len));
else if (section.Name.StartsWith("DvbCT:"))
dvbctMappings.AddMapping(new DvbCtChannelDataMapping(section, len));
else if (section.Name.StartsWith("DvbS:"))
dvbsMappings.AddMapping(new DvbSChannelDataMapping(section, len));
else if (section.Name.StartsWith("FineTune:"))
analogFineTuneMappings.AddMapping(new DataMapping(section, len, null));
else if (section.Name.StartsWith("AstraHDPlusD:"))
hdplusMappings.AddMapping(new DvbSChannelDataMapping(section, len));
}
}
#endregion
#region Load()
public override void Load()
{
using (ZipFile zip = new ZipFile(this.FileName))
{
DetectModelConstants(zip);
DataRoot.SupportedFavorites = c.supportedFavorites;
ReadAnalogFineTuning(zip);
ReadAnalogChannels(zip, "map-AirA", this.avbtChannels, out this.avbtFileContent, this.avbtFrequency);
ReadAnalogChannels(zip, "map-CableA", this.avbcChannels, out this.avbcFileContent, this.avbcFrequency);
ReadDvbctChannels(zip, "map-AirD", this.dvbtChannels, out this.dvbtFileContent);
ReadDvbctChannels(zip, "map-CableD", this.dvbcChannels, out this.dvbcFileContent);
ReadSatellites(zip);
ReadTransponder(zip, "TransponderDataBase.dat");
ReadTransponder(zip, "UserTransponderDataBase.dat");
ReadDvbsChannels(zip);
ReadAstraHdPlusChannels(zip);
}
}
#endregion
#region DetectModelConstants()
private void DetectModelConstants(ZipFile zip)
{
if (DetectModelFromCloneInfoFile(zip)) return;
if (DetectModelFromContentFileLengths(zip)) return;
if (DetectModelFromFileName()) return;
throw new IOException("Unable to determine TV model from file content or name");
}
#endregion
#region DetectModelFromFileName()
private bool DetectModelFromFileName()
{
string file = Path.GetFileName(this.FileName);
System.Text.RegularExpressions.Regex regex =
new System.Text.RegularExpressions.Regex("channel_list_[A-Z]{2}[0-9]{2}([A-Z])[0-9A-Z]+_[0-9]+\\.scm");
var match = regex.Match(file);
if (match.Success)
{
string series = match.Groups[1].Value;
if (this.modelConstants.TryGetValue("Series:" + series, out this.c))
return true;
}
return false;
}
#endregion
#region DetectModelFromCloneInfoFile()
private bool DetectModelFromCloneInfoFile(ZipFile zip)
{
byte[] cloneInfo = ReadFileContent(zip, "CloneInfo");
if (cloneInfo == null)
{
this.c = this.modelConstants["Series:B"];
return true;
}
if (cloneInfo.Length >= 9)
{
char series = (char) cloneInfo[8];
if (this.modelConstants.TryGetValue("Series:" + series, out this.c))
return true;
}
return false;
}
#endregion
#region DetectModelFromContentFileLengths()
private bool DetectModelFromContentFileLengths(ZipFile zip)
{
string[] candidates = new[]
{
DetectModelFromAirAOrCableA(zip),
DetectModelFromAirDOrCableD(zip),
DetectModelFromSateD(zip),
DetectModelFromTranspoderDatabase(zip)
};
string validCandidates = "BCDE";
foreach (var candidateList in candidates)
{
if (candidateList == null)
continue;
string newValidCandidats = "";
foreach (var candidate in candidateList)
{
if (validCandidates.Contains(candidate))
newValidCandidats += candidate;
}
validCandidates = newValidCandidats;
}
if (validCandidates.Length != 1)
return false;
this.modelConstants.TryGetValue("Series:" + validCandidates, out this.c);
return true;
}
#endregion
#region DetectModelFromAirAOrCableA()
private string DetectModelFromAirAOrCableA(ZipFile zip)
{
var entry = zip.GetEntry("map-AirA") ?? zip.GetEntry("map-CableA");
if (entry == null)
return null;
var candidates = "";
if (entry.Size % 28000 == 0)
candidates += "B";
if (entry.Size % 40000 == 0)
candidates += "C";
if (entry.Size % 64000 == 0)
candidates += "DE";
return candidates;
}
#endregion
#region DetectModelFromAirDOrCableD()
private string DetectModelFromAirDOrCableD(ZipFile zip)
{
var entry = zip.GetEntry("map-AirD") ?? zip.GetEntry("map-CableD");
if (entry == null)
return null;
var candidates = "";
if (entry.Size % 248 == 0)
candidates += "B";
if (entry.Size % 292 == 0)
candidates += "C";
if (entry.Size % 320 == 0)
candidates += "DE";
return candidates;
}
#endregion
#region DetectModelFromSateD()
private string DetectModelFromSateD(ZipFile zip)
{
var entry = zip.GetEntry("map-SateD");
if (entry == null)
return null;
var candidates = "";
if (entry.Size % 144 == 0)
candidates += "BC";
if (entry.Size % 172 == 0)
candidates += "D";
if (entry.Size % 168 == 0)
candidates += "E";
return candidates;
}
#endregion
#region DetectModelFromTranspoderDatabase()
private string DetectModelFromTranspoderDatabase(ZipFile zip)
{
var entry = zip.GetEntry("TransponderDatabase.dat");
if (entry == null)
return null;
var size = entry.Size - 4;
var candidates = "";
if (size%49 == 0)
candidates += "B";
if (size%45 == 0)
candidates += "CDE";
return candidates;
}
#endregion
#region ReadAnalogFineTuning()
private unsafe void ReadAnalogFineTuning(ZipFile zip)
{
int entrySize = c.avbtFineTuneLength;
if (entrySize == 0)
return;
byte[] data = ReadFileContent(zip, "FineTune");
if (data == null)
return;
var mapping = analogFineTuneMappings.GetMapping(c.avbtFineTuneLength);
fixed (byte* ptr = data)
{
mapping.DataPtr = ptr;
int count = data.Length / mapping.DataLength;
for (int i = 0; i < count; i++)
{
bool isCable = mapping.GetFlag("offIsCable", "maskIsCable"); // HACK: this is just a guess
int slot = mapping.GetWord("offSlotNr");
float freq = mapping.GetFloat("offFrequency");
var dict = isCable ? avbcFrequency : avbtFrequency;
dict[slot] = (decimal)freq;
mapping.Next();
}
}
}
#endregion
#region ReadAnalogChannels()
private unsafe void ReadAnalogChannels(ZipFile zip, string fileName, ChannelList list, out byte[] data, Dictionary<int,decimal> freq)
{
data = null;
int entrySize = c.avbtChannelLength;
if (entrySize == 0)
return;
data = ReadFileContent(zip, fileName);
if (data == null)
return;
this.DataRoot.AddChannelList(list);
fixed (byte* ptr = data)
{
var rawChannel = analogMappings.GetMapping(entrySize);
rawChannel.DataPtr = ptr;
int count = data.Length / entrySize;
for (int slotIndex = 0; slotIndex < count; slotIndex++)
{
MapAnalogChannel(rawChannel, slotIndex, list, freq);
rawChannel.DataPtr += entrySize;
}
}
}
#endregion
#region MapAnalogChannel()
private unsafe void MapAnalogChannel(AnalogChannelDataMapping rawChannel, int slotIndex, ChannelList list, Dictionary<int,decimal> freq)
{
if (!rawChannel.InUse)
return;
if (rawChannel.Checksum != CalcChecksum(rawChannel.DataPtr, c.avbtChannelLength))
this.DataRoot.Warnings.AppendFormat("{0}: Incorrect checksum for channel index {1}\r\n", list, slotIndex);
ChannelInfo ci = new ChannelInfo(list.SignalSource, list.SignalType, slotIndex, rawChannel.ProgramNr, rawChannel.Name);
ci.FreqInMhz = (decimal)Math.Round(rawChannel.Frequency, 2);
if (ci.FreqInMhz == 0)
ci.FreqInMhz = freq.TryGet(ci.RecordIndex);
if (ci.FreqInMhz == 0)
ci.FreqInMhz = slotIndex;
ci.Lock = rawChannel.Lock;
ci.Skip = rawChannel.Skip;
ci.Favorites = rawChannel.Favorites;
this.DataRoot.AddChannel(list, ci);
}
#endregion
#region ReadDvbctChannels()
private unsafe void ReadDvbctChannels(ZipFile zip, string fileName, ChannelList list, out byte[] data)
{
data = null;
int entrySize = c.dvbtChannelLength;
if (entrySize == 0)
return;
data = ReadFileContent(zip, fileName);
if (data == null)
return;
this.DataRoot.AddChannelList(list);
fixed (byte* ptr = data)
{
DvbCtChannelDataMapping rawChannel = dvbctMappings.GetMapping(entrySize);
rawChannel.DataPtr = ptr;
int count = data.Length / entrySize;
for (int slotIndex = 0; slotIndex < count; slotIndex++)
{
MapDvbctChannel(rawChannel, slotIndex, list);
rawChannel.Next();
}
}
}
#endregion
#region MapDvbctChannel()
private unsafe void MapDvbctChannel(DvbCtChannelDataMapping rawChannel, int slotIndex, ChannelList list)
{
if (rawChannel.ProgramNr == 0)
return;
if (rawChannel.Checksum != CalcChecksum(rawChannel.DataPtr, rawChannel.DataLength))
this.DataRoot.Warnings.AppendFormat("{0}: Incorrect checksum for channel index {1}\r\n", list, slotIndex);
ChannelInfo ci = new ChannelInfo(list.SignalSource, list.SignalType, slotIndex, rawChannel.ProgramNr, rawChannel.Name);
ci.VideoPid = rawChannel.VideoPid;
ci.ServiceId = rawChannel.ServiceId;
ci.ServiceType = rawChannel.ServiceType;
ci.TransportStreamId = rawChannel.TransportStreamId;
ci.FreqInMhz = LookupData.Instance.GetDvbtTransponderFrequency(rawChannel.ChannelOrTransponder);
ci.OriginalNetworkId = rawChannel.OriginalNetworkId;
ci.Favorites = rawChannel.Favorites;
ci.Lock = rawChannel.Lock;
ci.ShortName = rawChannel.ShortName;
ci.SymbolRate = rawChannel.SymbolRate;
ci.Encrypted = rawChannel.Encrypted;
ci.ChannelOrTransponder = rawChannel.ChannelOrTransponder.ToString();
this.DataRoot.AddChannel(list, ci);
}
#endregion
#region ReadSatellites()
private unsafe void ReadSatellites(ZipFile zip)
{
byte[] data = ReadFileContent(zip, "SatDataBase.dat");
if (data == null)
return;
var utf16Encoding = new UnicodeEncoding(false, false);
fixed (byte* ptr = data)
{
int count = data.Length/this.c.dvbsSatelliteLength;
for (int i = 0; i < count; i++)
{
SatDataBase* sat = (SatDataBase*)(ptr + 4 + i * this.c.dvbsSatelliteLength);
if (sat->Magic0x55 != 0x55)
throw new IOException("Unknown SatDataBase.dat format");
string name = utf16Encoding.GetString((byte*)sat->Name, 64*2);
string location = string.Format("{0}.{1}{2}", sat->LongitudeTimes10/10, sat->LongitudeTimes10%10, sat->IsWest != 0 ? "W" : "E");
Satellite satellite = new Satellite(sat->SatelliteNr);
satellite.Name = name;
satellite.OrbitalPosition = location;
this.DataRoot.Satellites.Add(sat->SatelliteNr, satellite);
}
}
}
#endregion
#region ReadTransponder()
private unsafe void ReadTransponder(ZipFile zip, string fileName)
{
byte[] data = ReadFileContent(zip, fileName);
if (data == null)
return;
fixed (byte* ptr = data)
{
int count = data.Length/c.dvbsTransponderLength;
for (int i=0; i<count; i++)
{
int baseOffset = 4 + i*c.dvbsTransponderLength;
TransponderDataBase* trans = (TransponderDataBase*) (ptr + baseOffset);
if (trans->Magic0x55 == 0)
continue;
if (trans->TransponderNr == 0)
continue;
var sat = this.DataRoot.Satellites.TryGet(trans->SatelliteNr);
if (sat == null)
{
DataRoot.Warnings.Append(string.Format("Transponder #{0} references invalid satellite #{1}",
trans->TransponderNr, trans->SatelliteNr));
continue;
}
Transponder transponder = new Transponder(trans->TransponderNr);
transponder.FrequencyInMhz = (uint) (trans->Frequency/1000);
transponder.Polarity = trans->IsVerticalPolarity == 1 ? 'V' : 'H';
transponder.SymbolRate = trans->SymbolRate/1000;
this.DataRoot.AddTransponder(sat, transponder);
}
}
}
#endregion
#region ReadDvbsChannels()
private unsafe void ReadDvbsChannels(ZipFile zip)
{
this.dvbsFileContent = ReadFileContent(zip, "map-SateD");
if (this.dvbsFileContent == null)
return;
this.DataRoot.AddChannelList(this.dvbsChannels);
fixed (byte* ptr = this.dvbsFileContent)
{
int entrySize = c.dvbsChannelLength;
int count = this.dvbsFileContent.Length/entrySize;
DvbSChannelDataMapping mapping = dvbsMappings.GetMapping(entrySize);
mapping.DataPtr = ptr;
for (int slotIndex = 0; slotIndex < count; slotIndex++)
{
MapDvbsChannel(this.dvbsChannels, mapping, slotIndex);
mapping.Next();
}
}
}
#endregion
#region MapDvbsChannel()
private void MapDvbsChannel(ChannelList channelList, DvbSChannelDataMapping rawChannel, int slotIndex)
{
if (!rawChannel.InUse)
return;
Transponder transponder = this.DataRoot.Transponder.TryGet(rawChannel.TransponderNr);
Satellite satellite = transponder == null ? null : transponder.Satellite;
string satPosition = satellite != null ? satellite.OrbitalPosition : "#" + rawChannel.SatelliteNr;
string satName = satellite != null ? satellite.Name : null;
ChannelInfo ci = new ChannelInfo(channelList.SignalSource, SignalType.Mixed, slotIndex, rawChannel.ProgramNr, rawChannel.Name);
ci.Satellite = satName;
ci.SatPosition = satPosition;
ci.VideoPid = rawChannel.VideoPid;
ci.ServiceId = rawChannel.ServiceId;
ci.ServiceType = rawChannel.ServiceType;
ci.TransportStreamId = rawChannel.TransportStreamId;
ci.OriginalNetworkId = rawChannel.OriginalNetworkId;
ci.Favorites = rawChannel.Favorites;
ci.Encrypted = rawChannel.Encrypted;
ci.Lock = rawChannel.Lock;
ci.ShortName = rawChannel.ShortName;
if (transponder != null)
{
ci.Transponder = transponder;
ci.FreqInMhz = transponder.FrequencyInMhz;
ci.ChannelOrTransponder = this.GetTransponderChannelNumber((ushort)transponder.FrequencyInMhz);
ci.SymbolRate = transponder.SymbolRate;
ci.Polarity = transponder.Polarity;
}
this.DataRoot.AddChannel(channelList, ci);
}
#endregion
#region GetTransponderChannelNumber()
private string GetTransponderChannelNumber(ushort frequency)
{
int nr = LookupData.Instance.GetTransponderNumber(frequency);
return nr <= 0 ? "" : nr.ToString("d3");
}
#endregion
#region ReadAstraHdPlusChannels()
private unsafe void ReadAstraHdPlusChannels(ZipFile zip)
{
this.hdplusFileContent = ReadFileContent(zip, "map-AstraHDPlusD");
if (hdplusFileContent == null || c.hdplusChannelLength == 0)
return;
this.DataRoot.AddChannelList(this.hdplusChannels);
fixed (byte* ptr = hdplusFileContent)
{
int entrySize = c.hdplusChannelLength;
int count = hdplusFileContent.Length / entrySize;
DvbSChannelDataMapping mapping = hdplusMappings.GetMapping(entrySize);
mapping.DataPtr = ptr;
for (int slotIndex = 0; slotIndex < count; slotIndex++)
{
MapDvbsChannel(this.hdplusChannels, mapping, slotIndex);
mapping.Next();
}
}
}
#endregion
#region ReadFileContent()
private static byte[] ReadFileContent(ZipFile zip, string fileName)
{
var entry = zip.GetEntry(fileName);
if (entry == null)
return null;
byte[] data = new byte[entry.Size];
using (var stream = zip.GetInputStream(entry))
{
stream.Read(data, 0, data.Length);
}
return data;
}
#endregion
private unsafe delegate void UpdateFunc(ChannelInfo channelInfo, byte* fileContent);
#region Save()
public override unsafe void Save(string tvOutputFile, string csvOutputFile, UnsortedChannelMode unsortedMode)
{
this.unsortedChannelMode = unsortedMode;
if (tvOutputFile != this.FileName)
{
File.Copy(this.FileName, tvOutputFile);
this.FileName = tvOutputFile;
}
using (ZipFile zip = new ZipFile(tvOutputFile))
{
zip.BeginUpdate();
this.SaveChannels(zip, "map-AirA", this.avbtChannels, this.UpdateAnalogChannel, ref this.avbtFileContent);
this.SaveChannels(zip, "map-CableA", this.avbcChannels, this.UpdateAnalogChannel, ref this.avbcFileContent);
this.SaveChannels(zip, "map-AirD", this.dvbtChannels, this.UpdateDvbctChannel, ref this.dvbtFileContent);
this.SaveChannels(zip, "map-CableD", this.dvbcChannels, this.UpdateDvbctChannel, ref this.dvbcFileContent);
this.SaveChannels(zip, "map-SateD", this.dvbsChannels, this.UpdateDvbsChannel, ref this.dvbsFileContent);
this.SaveChannels(zip, "map-AstraHDPlusD", this.hdplusChannels, this.UpdateHdPlusChannel, ref this.hdplusFileContent);
zip.CommitUpdate();
}
}
#endregion
#region SaveChannels()
private unsafe void SaveChannels(ZipFile zip, string fileName, ChannelList channels, UpdateFunc updateChannel, ref byte[] fileContent)
{
if (fileContent == null)
return;
zip.Delete(fileName);
string tempFilePath = Path.GetTempFileName();
using (var stream = new FileStream(tempFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
this.WriteChannels(channels, updateChannel, fileContent, stream);
stream.Flush();
stream.Seek(0, SeekOrigin.Begin);
int size = (int)new FileInfo(tempFilePath).Length;
fileContent = new byte[size];
stream.Read(fileContent, 0, size);
}
zip.Add(tempFilePath, fileName);
}
#endregion
#region WriteChannels()
private unsafe void WriteChannels(ChannelList list, UpdateFunc updateChannel, byte[] fileContent, FileStream stream)
{
fixed (byte* ptr = fileContent)
{
int maxSlot = 0;
foreach (var channel in list.Channels.OrderBy(ChannelComparer))
{
if (channel.RecordIndex < 0) // channel only exists in reference list
continue;
int newProgNr;
if (channel.NewProgramNr == 0 && this.unsortedChannelMode == UnsortedChannelMode.Hide)
newProgNr = 0;
else
{
newProgNr = channel.NewProgramNr != 0 ? channel.NewProgramNr : ++maxSlot;
if (newProgNr > maxSlot)
maxSlot = channel.NewProgramNr;
}
var channels = new List<ChannelInfo>();
channels.Add(channel);
channels.AddRange(channel.Duplicates);
foreach (var channelInstance in channels)
{
channelInstance.OldProgramNr = newProgNr;
updateChannel(channelInstance, ptr);
}
}
stream.Write(fileContent, 0, fileContent.Length);
#if false
if (count == 0 || count%padToPageSize != 0)
{
byte[] padding = new byte[(padToPageSize - count%padToPageSize) * entrySize];
stream.Write(padding, 0, padding.Length);
}
#endif
}
}
#endregion
#region UpdateAnalogChannel()
private unsafe void UpdateAnalogChannel(ChannelInfo channel, byte* ptr)
{
AnalogChannelDataMapping raw = analogMappings.GetMapping(c.avbtChannelLength);
int startOffset = channel.RecordIndex * raw.DataLength;
raw.DataPtr = ptr + startOffset;
raw.ProgramNr = (ushort)channel.OldProgramNr;
raw.Favorites = channel.Favorites;
raw.Lock = channel.Lock;
raw.Checksum = CalcChecksum(raw.DataPtr, raw.DataLength);
}
#endregion
#region UpdateDvbctChannel()
private unsafe void UpdateDvbctChannel(ChannelInfo channel, byte* ptr)
{
DvbCtChannelDataMapping raw = dvbctMappings.GetMapping(c.dvbtChannelLength);
int startOffset = channel.RecordIndex * raw.DataLength;
raw.DataPtr = ptr + startOffset;
raw.ProgramNr = (ushort)channel.OldProgramNr;
raw.Favorites = channel.Favorites;
raw.Lock = channel.Lock;
raw.Checksum = CalcChecksum(raw.DataPtr, raw.DataLength);
}
#endregion
#region UpdateDvbsChannel()
private unsafe void UpdateDvbsChannel(ChannelInfo channel, byte* ptr)
{
DvbSChannelDataMapping raw = dvbsMappings.GetMapping(c.dvbsChannelLength);
int startOffset = channel.RecordIndex*raw.DataLength;
raw.DataPtr = (ptr + startOffset);
raw.ProgramNr = (ushort)channel.OldProgramNr;
raw.Favorites = channel.Favorites;
raw.Lock = channel.Lock;
raw.Checksum = CalcChecksum(raw.DataPtr, raw.DataLength);
}
#endregion
#region UpdateHdPlusChannel()
private unsafe void UpdateHdPlusChannel(ChannelInfo channel, byte* ptr)
{
DvbSChannelDataMapping raw = hdplusMappings.GetMapping(c.hdplusChannelLength);
int startOffset = channel.RecordIndex * raw.DataLength;
raw.DataPtr = (ptr + startOffset);
raw.ProgramNr = (ushort)channel.OldProgramNr;
raw.Favorites = channel.Favorites;
raw.Lock = channel.Lock;
raw.Checksum = CalcChecksum(raw.DataPtr, raw.DataLength);
}
#endregion
#region CalcChecksum()
private static unsafe byte CalcChecksum(byte* ptr, int length)
{
byte checksum = 0;
for (int i = 1; i < length; i++)
checksum += *ptr++;
return checksum;
}
#endregion
#region ChannelComparer()
private string ChannelComparer(ChannelInfo channel)
{
if (channel.NewProgramNr != 0)
return "A" + channel.NewProgramNr.ToString("d4");
if (channel.OldProgramNr != 0)
{
if (this.unsortedChannelMode == UnsortedChannelMode.AppendInOrder)
return "B" + channel.OldProgramNr.ToString("d4");
return "B" + channel.Name;
}
return "Z";
}
#endregion
public override void ShowDeviceSettingsForm(object parentWindow)
{
MessageBox.Show((Form) parentWindow, "Sorry, ChanSort currently doesn't support any settings for your TV model.",
"Device Settings",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}

View File

@@ -0,0 +1,15 @@
using ChanSort.Api;
namespace ChanSort.Plugin.ScmFile
{
public class ScmSerializerPlugin : ISerializerPlugin
{
public string PluginName { get { return "Samsung *.scm Loader"; } }
public string FileFilter { get { return "*.scm"; } }
public SerializerBase CreateSerializer(string inputFile)
{
return new ScmSerializer(inputFile);
}
}
}

View File

@@ -0,0 +1,97 @@
using System.Runtime.InteropServices;
namespace ChanSort.Plugin.ScmFile
{
[StructLayout(LayoutKind.Sequential, Pack=1)]
unsafe struct SatDataBase
{
public byte Magic0x55;
public int SatelliteNr;
public int TransponderCount;
public fixed ushort Name[64];
public int IsWest;
public int LongitudeTimes10;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct TransponderDataBase
{
public byte Magic0x55;
public int TransponderNr;
public int SatelliteNr;
public int Frequency;
public int SymbolRate;
public int IsVerticalPolarity;
public int Modulation;
public int CodeRate;
public int Unknown1;
public int Unknown2;
public int Unknown3;
public int Unknown4;
};
#if false
[StructLayout(LayoutKind.Sequential, Pack=1)]
unsafe struct MapSateD
{
public ushort ChannelNumber;
public ushort VideoPid;
public ushort Pid;
public byte Mpeg4;
public byte Unknown8;
public ushort Unknown9;
public ushort Unknonw11;
public ushort Unknown13;
public byte ServiceType;
public byte Unknown16;
public ushort ServiceId;
public ushort TransponderNr;
public ushort SatelliteNr;
public ushort Unknown23;
public ushort TransportStreamId;
public ushort Unknown27;
public ushort OriginalNetworkId;
public ushort Unknown31;
public ushort HRes;
public ushort VRes;
public fixed ushort NameInBigEndianUtf16[51];
public ushort Bouquet;
public byte Unknown141;
public byte Locked;
public byte Favorites;
public byte ChecksumCSeries;
public fixed byte Padding [28];
}
#endif
#if false
[StructLayout(LayoutKind.Sequential, Pack = 1)]
unsafe struct MapAirD
{
public ushort ChannelNumber;
public ushort VideoPid;
public ushort PcrPid;
public ushort ServiceId;
public ushort Status;
public ushort Unknown11;
public ushort Qam;
public byte ServiceType;
public byte Codec;
public fixed byte Unknown17 [7];
public byte Encrypted;
public fixed byte Unknown25 [3];
public ushort Frequency;
public ushort LogicalChannelNumber;
public fixed byte Unknown31 [2];
public ushort SymbolRate;
public ushort Bouquet;
public ushort TransportStreamId;
public fixed byte Unknown39 [5];
public fixed ushort NameInBigEndianUtf16[100];
public byte Unknown244;
public ushort Locked;
public byte FavoritesX79;
public byte ChecksumBSeries;
public fixed byte PaddingCSeries [292 - 248];
}
#endif
}