Added rudimentary (and very buggy!) support for reading MediaHighway2 EPG.
This commit is contained in:
parent
226901607c
commit
6302a25f26
1
.gitignore
vendored
1
.gitignore
vendored
@ -113,3 +113,4 @@ imgui.ini
|
||||
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/bin/Debug/net8.0
|
||||
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj/Debug/net8.0
|
||||
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj
|
||||
/.vs/skyscraper8/CopilotIndices/17.14.827.52834
|
||||
|
||||
@ -178,9 +178,24 @@ namespace skyscraper5.Data.PostgreSql
|
||||
|
||||
private void UpdateDvbNipPrivateDataSpecifier(NpgsqlConnection connection, Tuple<ushort, ushort, ushort, ushort, uint> coordinates, DateTime versionUpdate, List<string> privateDataSessions)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
DateTime localUpdate = new DateTime(versionUpdate.Year, versionUpdate.Month, versionUpdate.Day,
|
||||
versionUpdate.Hour, versionUpdate.Minute, versionUpdate.Second, DateTimeKind.Local);
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText = "UPDATE dvbnip_private_data_specifiers SET version_update = @vu, sessions = @s WHERE nid = @nid AND cid = @cid AND lid=@lid AND sid=@sid AND private_data_specifier = @pds";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, (int)coordinates.Item1);
|
||||
command.Parameters.AddWithValue("@cid", NpgsqlDbType.Integer, (int)coordinates.Item2);
|
||||
command.Parameters.AddWithValue("@lid", NpgsqlDbType.Integer, (int)coordinates.Item3);
|
||||
command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)coordinates.Item4);
|
||||
command.Parameters.AddWithValue("@pds", NpgsqlDbType.Bigint, (long)coordinates.Item5);
|
||||
command.Parameters.AddWithValue("@vu", NpgsqlDbType.Timestamp, localUpdate);
|
||||
command.Parameters.AddWithValue("@s", NpgsqlDbType.Json, JsonConvert.SerializeObject(privateDataSessions));
|
||||
int executeNonQuery = command.ExecuteNonQuery();
|
||||
if (executeNonQuery != 1)
|
||||
{
|
||||
throw new DataException(String.Format("Expected to insert {0} rows, but it were {1}", 1, executeNonQuery));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool[] _dvbNipKnownNetworks;
|
||||
public bool DvbNipTestForNetwork(BroadcastNetworkType network)
|
||||
{
|
||||
|
||||
@ -182,7 +182,7 @@ namespace skyscraper5.Data.PostgreSql
|
||||
private void AddDvbiServiceToServiceList(NpgsqlConnection x, string id, string serviceListId)
|
||||
{
|
||||
NpgsqlCommand checkCommand = x.CreateCommand();
|
||||
checkCommand.CommandText = "SELECT dateadded FROM dvbi_services_to_service_lists WHERE service = @service AND service_list = @service_list";
|
||||
checkCommand.CommandText = "SELECT dateadded FROM dvbi_services_to_service_lists WHERE service = @service AND service_list = @servicelist";
|
||||
checkCommand.Parameters.AddWithValue("@service", NpgsqlDbType.Text, id);
|
||||
checkCommand.Parameters.AddWithValue("@servicelist", NpgsqlDbType.Text, serviceListId);
|
||||
NpgsqlDataReader dataReader = checkCommand.ExecuteReader();
|
||||
|
||||
@ -18,7 +18,7 @@ namespace skyscraper5.Data.PostgreSql
|
||||
connectionStringBuilder = stringBuilder;
|
||||
}
|
||||
|
||||
private NpgsqlConnectionStringBuilder connectionStringBuilder;
|
||||
internal NpgsqlConnectionStringBuilder connectionStringBuilder;
|
||||
|
||||
|
||||
public bool TestForRelatedContent(EitEvent lEvent, RctLinkInfo rctLinkInfo)
|
||||
@ -157,10 +157,15 @@ namespace skyscraper5.Data.PostgreSql
|
||||
connection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private PostgresqlToken pluginToken;
|
||||
public object[] GetPluginConnector()
|
||||
{
|
||||
return new object[] { connectionStringBuilder };
|
||||
if (pluginToken == null)
|
||||
{
|
||||
pluginToken = new PostgresqlToken(this);
|
||||
}
|
||||
return new object[] { pluginToken };
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Npgsql;
|
||||
|
||||
namespace skyscraper5.Data.PostgreSql
|
||||
{
|
||||
public class PostgresqlToken
|
||||
{
|
||||
private readonly PostgresqlDataStore _postgresqlDataStore;
|
||||
|
||||
public PostgresqlToken(PostgresqlDataStore postgresqlDataStore)
|
||||
{
|
||||
_postgresqlDataStore = postgresqlDataStore;
|
||||
}
|
||||
|
||||
public NpgsqlConnection GetConnection()
|
||||
{
|
||||
return new NpgsqlConnection(_postgresqlDataStore.connectionStringBuilder.ToString());
|
||||
}
|
||||
|
||||
public void EnqueueTask(WriterTask task)
|
||||
{
|
||||
_postgresqlDataStore.EnqueueTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,15 +9,17 @@ using Npgsql;
|
||||
|
||||
namespace skyscraper5.Data.PostgreSql
|
||||
{
|
||||
public partial class PostgresqlDataStore
|
||||
public delegate void WriterTask(NpgsqlConnection connection);
|
||||
|
||||
public partial class PostgresqlDataStore
|
||||
{
|
||||
private Thread _writerThread;
|
||||
|
||||
private delegate void WriterTask(NpgsqlConnection connection);
|
||||
|
||||
|
||||
private Queue<WriterTask> _writerTasks;
|
||||
|
||||
private void EnqueueTask(WriterTask task)
|
||||
internal void EnqueueTask(WriterTask task)
|
||||
{
|
||||
if (_writerTasks == null)
|
||||
{
|
||||
|
||||
@ -0,0 +1,219 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The reply codes from the protocol collectors.
|
||||
/// </summary>
|
||||
public enum CollectorReply
|
||||
{
|
||||
/// <summary>
|
||||
/// The collection was successful.
|
||||
/// </summary>
|
||||
OK,
|
||||
/// <summary>
|
||||
/// The collection failed.
|
||||
/// </summary>
|
||||
GeneralFailure,
|
||||
/// <summary>
|
||||
/// There was a format error in the received data.
|
||||
/// </summary>
|
||||
FatalFormatError,
|
||||
/// <summary>
|
||||
/// The was an error loading the reference data.
|
||||
/// </summary>
|
||||
ReferenceDataError,
|
||||
/// <summary>
|
||||
/// There was an error in the broadcast data.
|
||||
/// </summary>
|
||||
BroadcastDataError,
|
||||
/// <summary>
|
||||
/// The collection was cancelled.
|
||||
/// </summary>
|
||||
Cancelled
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current scope
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum Scope
|
||||
{
|
||||
/// <summary>
|
||||
/// No scope restrictions
|
||||
/// </summary>
|
||||
All = 0x7fffffff,
|
||||
/// <summary>
|
||||
/// Program Map table
|
||||
/// </summary>
|
||||
PMT = 0x0002,
|
||||
/// <summary>
|
||||
/// Program Association table
|
||||
/// </summary>
|
||||
PAT = 0x0004,
|
||||
/// <summary>
|
||||
/// Network Information table
|
||||
/// </summary>
|
||||
NIT = 0x0008,
|
||||
/// <summary>
|
||||
/// Bouquet Association table
|
||||
/// </summary>
|
||||
BAT = 0x0010,
|
||||
/// <summary>
|
||||
/// Service Description table
|
||||
/// </summary>
|
||||
SDT = 0x0020,
|
||||
/// <summary>
|
||||
/// Event Information table
|
||||
/// </summary>
|
||||
EIT = 0x0040,
|
||||
/// <summary>
|
||||
/// Time and Date table
|
||||
/// </summary>
|
||||
TDT = 0x0080,
|
||||
/// <summary>
|
||||
/// Time offset table
|
||||
/// </summary>
|
||||
TOT = 0x0100,
|
||||
/// <summary>
|
||||
/// Running Status table
|
||||
/// </summary>
|
||||
RST = 0x0200,
|
||||
/// <summary>
|
||||
/// Stuffing table
|
||||
/// </summary>
|
||||
ST = 0x0400,
|
||||
/// <summary>
|
||||
/// Discontinuity Information table
|
||||
/// </summary>
|
||||
DIT = 0x0800,
|
||||
/// <summary>
|
||||
/// Selection Information table
|
||||
/// </summary>
|
||||
SIT = 0x1000,
|
||||
/// <summary>
|
||||
/// Application Information table
|
||||
/// </summary>
|
||||
AIT = 0x2000,
|
||||
/// <summary>
|
||||
/// DSMCC sections
|
||||
/// </summary>
|
||||
DSMCC = 0x4000,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The action to take for non-Ascii characters in text strings.
|
||||
/// </summary>
|
||||
public enum ReplaceMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The non-ASCII character is removed.
|
||||
/// </summary>
|
||||
Ignore,
|
||||
/// <summary>
|
||||
/// The non-ASCII character is set to space.
|
||||
/// </summary>
|
||||
SetToSpace,
|
||||
/// <summary>
|
||||
/// The non-ASCII character is not changed in the output text.
|
||||
/// </summary>
|
||||
TransferUnchanged,
|
||||
/// <summary>
|
||||
/// The non-ASCII character is converted to its ASCII equivalent (EIT 0x8a only at present)
|
||||
/// </summary>
|
||||
Convert,
|
||||
/// <summary>
|
||||
/// The non-ASCII character is converted using the byte conversion table)
|
||||
/// </summary>
|
||||
ConvertUsingTable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The data broadcast ID values.
|
||||
/// </summary>
|
||||
public enum DataBroadcastId
|
||||
{
|
||||
/// <summary>
|
||||
/// DVB data pipe.
|
||||
/// </summary>
|
||||
DvbDataPipe = 0x0001, // EN 301 192 section 4.2.1
|
||||
/// <summary>
|
||||
/// Asynchronous data stream
|
||||
/// </summary>
|
||||
AsyncDataStream = 0x0002, // EN 301 192 section 5.2.1
|
||||
/// <summary>
|
||||
/// Synchronous data stream
|
||||
/// </summary>
|
||||
SynchronousDataStream = 0x0003, // EN 301 192 section 6.2.1
|
||||
/// <summary>
|
||||
/// Synchronous data streams
|
||||
/// </summary>
|
||||
SynchronousDataStreams = 0x0004, // EN 301 192 section 6.2.1
|
||||
/// <summary>
|
||||
/// Multiprotocol encapsulation
|
||||
/// </summary>
|
||||
MultiProtocolEncapsulation = 0x0005, // EN 301 192 section 4.2.1
|
||||
/// <summary>
|
||||
/// Data carousel
|
||||
/// </summary>
|
||||
DataCarousel = 0x0006,
|
||||
/// <summary>
|
||||
/// Object carousel
|
||||
/// </summary>
|
||||
ObjectCarousel = 0x0007,
|
||||
/// <summary>
|
||||
/// DVB ATM stream
|
||||
/// </summary>
|
||||
DvbAtmStream = 0x0008,
|
||||
/// <summary>
|
||||
/// Higher protocol asynchronous stream
|
||||
/// </summary>
|
||||
HigherProtcolAsyncStream = 0x0009,
|
||||
/// <summary>
|
||||
/// System software update service
|
||||
/// </summary>
|
||||
SsuService = 0x000a,
|
||||
/// <summary>
|
||||
/// IP/MAC notification service
|
||||
/// </summary>
|
||||
IpMacNotificationService = 0x000b,
|
||||
/// <summary>
|
||||
/// MHP object carousel
|
||||
/// </summary>
|
||||
MhpObjectCarousel = 0x00f0, // TS 101 812
|
||||
/// <summary>
|
||||
/// MHP multiprotocol encapsulation
|
||||
/// </summary>
|
||||
MhpMultiProtoclEncapsulation = 0x000f1, // TS 101 812
|
||||
/// <summary>
|
||||
/// MHP application presence
|
||||
/// </summary>
|
||||
MhpApplicationPresence = 0x00f2,
|
||||
/// <summary>
|
||||
/// MHEG5 stream
|
||||
/// </summary>
|
||||
Mheg5 = 0x0106
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,181 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a MediaHighway2 category section.
|
||||
/// </summary>
|
||||
public class MediaHighway2CategorySection
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the collection of categories.
|
||||
/// </summary>
|
||||
public Collection<MediaHighwayCategoryEntry> Categories
|
||||
{
|
||||
get
|
||||
{
|
||||
if (categories == null)
|
||||
categories = new Collection<MediaHighwayCategoryEntry>();
|
||||
return (categories);
|
||||
}
|
||||
}
|
||||
|
||||
private int categoryCount;
|
||||
|
||||
private Collection<MediaHighwayCategoryEntry> categories;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighway2CategorySection class.
|
||||
/// </summary>
|
||||
internal MediaHighway2CategorySection() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the section.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the section.</param>
|
||||
/// <param name="index">The index of the first byte of the data portion.</param>
|
||||
/// <returns>True if the section is an MHW2 category section; false otherwise.</returns>
|
||||
internal bool Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
if (byteData[lastIndex] != 0x01)
|
||||
return (false);
|
||||
|
||||
lastIndex++;
|
||||
|
||||
categoryCount = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
try
|
||||
{
|
||||
int p1 = 0;
|
||||
int p2 = 0;
|
||||
|
||||
string themeName = null;
|
||||
|
||||
for (int themeIndex = 0; themeIndex < categoryCount; themeIndex++)
|
||||
{
|
||||
p1 = ((byteData[lastIndex + (themeIndex * 2)] << 8) | byteData[lastIndex + 1 + (themeIndex * 2)]) + 3;
|
||||
|
||||
for (int descriptionIndex = 0; descriptionIndex <= (byteData[p1] & 0x3f); descriptionIndex++)
|
||||
{
|
||||
p2 = ((byteData[p1 + 1 + (descriptionIndex * 2)] << 8) | byteData[p1 + 2 + (descriptionIndex * 2)] + 3);
|
||||
|
||||
MediaHighwayCategoryEntry categoryEntry = new MediaHighwayCategoryEntry();
|
||||
|
||||
categoryEntry.Number = ((themeIndex & 0x3f) << 6) | (descriptionIndex & 0x3f);
|
||||
if (descriptionIndex == 0)
|
||||
{
|
||||
themeName = Utils.GetString(byteData, p2 + 1, byteData[p2] & 0x1f, ReplaceMode.TransferUnchanged).Trim();
|
||||
categoryEntry.Description = themeName;
|
||||
}
|
||||
else
|
||||
categoryEntry.Description = themeName + " " + Utils.GetString(byteData, p2 + 1, byteData[p2] & 0x1f, ReplaceMode.TransferUnchanged).Trim();
|
||||
|
||||
Categories.Add(categoryEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("The MediaHighway2 Category Section message is short"));
|
||||
}
|
||||
|
||||
Validate();
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Validate the section fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A section field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "MHW2 CATEGORY SECTION");
|
||||
|
||||
if (categories != null)
|
||||
{
|
||||
foreach (MediaHighwayCategoryEntry categoryEntry in categories)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
categoryEntry.LogMessage();
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an MPEG2 section from the Open TV Title table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section.</param>
|
||||
public static MediaHighway2CategorySection ProcessMediaHighwayCategoryTable(byte[] byteData)
|
||||
{
|
||||
Mpeg2BasicHeader mpeg2Header = new Mpeg2BasicHeader();
|
||||
|
||||
try
|
||||
{
|
||||
mpeg2Header.Process(byteData);
|
||||
|
||||
MediaHighway2CategorySection categorySection = new MediaHighway2CategorySection();
|
||||
bool process = categorySection.Process(byteData, mpeg2Header.Index);
|
||||
if (process)
|
||||
{
|
||||
categorySection.LogMessage();
|
||||
return (categorySection);
|
||||
}
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Logger.Instance.Write("<e> Category section parsing failed: " + e.Message);
|
||||
return (null);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,170 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a MediaHighway2 channel section.
|
||||
/// </summary>
|
||||
public class MediaHighway2ChannelSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the collection of channels.
|
||||
/// </summary>
|
||||
public Collection<MediaHighwayChannelInfoEntry> Channels
|
||||
{
|
||||
get
|
||||
{
|
||||
if (channels == null)
|
||||
channels = new Collection<MediaHighwayChannelInfoEntry>();
|
||||
return (channels);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] fillBytes;
|
||||
private int channelCount;
|
||||
|
||||
private Collection<MediaHighwayChannelInfoEntry> channels;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighway2ChannelSection class.
|
||||
/// </summary>
|
||||
internal MediaHighway2ChannelSection() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the section.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the section.</param>
|
||||
/// <param name="index">The index of the first byte of the data portion.</param>
|
||||
/// <returns>True if the section is an MHW2 channel section; false otherwise.</returns>
|
||||
internal bool Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
/*if (byteData[lastIndex] != 0x00 && byteData[lastIndex] != 0x02 && byteData[lastIndex] != 0x03)*/
|
||||
if (byteData[lastIndex] != 0x00)
|
||||
return (false);
|
||||
|
||||
try
|
||||
{
|
||||
fillBytes = Utils.GetBytes(byteData, lastIndex, 117);
|
||||
lastIndex += fillBytes.Length;
|
||||
|
||||
channelCount = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
int nameIndex = lastIndex + (8 * channelCount);
|
||||
|
||||
while (Channels.Count < channelCount)
|
||||
{
|
||||
MediaHighwayChannelInfoEntry channelEntry = new MediaHighwayChannelInfoEntry();
|
||||
channelEntry.Process(byteData, lastIndex, nameIndex);
|
||||
Channels.Add(channelEntry);
|
||||
|
||||
lastIndex = channelEntry.Index;
|
||||
nameIndex = channelEntry.NameIndex;
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("The MediaHighway2 Channel Section message is short"));
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
Validate();
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the section fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A section field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "MHW2 CHANNEL SECTION");
|
||||
|
||||
if (channels != null)
|
||||
{
|
||||
foreach (MediaHighwayChannelInfoEntry channelInfoEntry in channels)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
channelInfoEntry.LogMessage();
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an MPEG2 section from the Open TV Title table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section.</param>
|
||||
public static MediaHighway2ChannelSection ProcessMediaHighwayChannelTable(byte[] byteData)
|
||||
{
|
||||
Mpeg2BasicHeader mpeg2Header = new Mpeg2BasicHeader();
|
||||
|
||||
try
|
||||
{
|
||||
mpeg2Header.Process(byteData);
|
||||
|
||||
MediaHighway2ChannelSection channelSection = new MediaHighway2ChannelSection();
|
||||
bool process = channelSection.Process(byteData, mpeg2Header.Index);
|
||||
if (process)
|
||||
{
|
||||
channelSection.LogMessage();
|
||||
return (channelSection);
|
||||
}
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Logger.Instance.Write("<e> Channel section parsing failed: " + e.Message);
|
||||
return (null);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,190 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes MediaHighway2 summary data.
|
||||
/// </summary>
|
||||
public class MediaHighway2SummaryData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the event identification.
|
||||
/// </summary>
|
||||
public int EventID { get { return (eventID); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the short description of the event.
|
||||
/// </summary>
|
||||
public string ShortDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
return shortDescription;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the unidentified data.
|
||||
/// </summary>
|
||||
public byte[] Unknown { get { return (unknown); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the summary data.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The summary data has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("MediaHighway2SummaryData: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int eventID;
|
||||
private string shortDescription;
|
||||
private byte[] unknown;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
int summaryLength;
|
||||
int lineCount;
|
||||
int lineLength;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighway2SummaryData class.
|
||||
/// </summary>
|
||||
public MediaHighway2SummaryData() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the summary data.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the summary data.</param>
|
||||
/// <param name="index">Index of the first byte of the summary data in the MPEG2 section.</param>
|
||||
/// <returns>True if the block contains data; false otherwise.</returns>
|
||||
internal bool Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
eventID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
unknown = Utils.GetBytes(byteData, lastIndex, 9);
|
||||
lastIndex += unknown.Length;
|
||||
|
||||
if (unknown[1] != 0x00)
|
||||
{
|
||||
if (DebugEntry.IsDefined(DebugName.Mhw2Unknown))
|
||||
{
|
||||
Logger.Instance.Write("Index: " + index);
|
||||
Logger.Instance.Dump("Unknown Data Block", byteData, byteData.Length);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (unknown[2] != 0x00 && unknown[2] != 0x01)
|
||||
{
|
||||
if (DebugEntry.IsDefined(DebugName.Mhw2Unknown))
|
||||
{
|
||||
Logger.Instance.Write("Index: " + index);
|
||||
Logger.Instance.Dump("Unknown Data Block", byteData, byteData.Length);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
summaryLength = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
if (summaryLength == 0)
|
||||
{
|
||||
if (DebugEntry.IsDefined(DebugName.Mhw2Unknown))
|
||||
{
|
||||
Logger.Instance.Write("Index: " + index);
|
||||
Logger.Instance.Dump("Summary Length Zero", byteData, byteData.Length);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
shortDescription = Utils.GetString(byteData, lastIndex, summaryLength, ReplaceMode.TransferUnchanged);
|
||||
lastIndex += summaryLength;
|
||||
|
||||
lineCount = byteData[lastIndex] & 0x0f;
|
||||
lastIndex++;
|
||||
|
||||
while (lineCount > 0)
|
||||
{
|
||||
lineLength = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
if (lineLength > 0)
|
||||
{
|
||||
shortDescription += " " + Utils.GetString(byteData, lastIndex, lineLength, ReplaceMode.TransferUnchanged);
|
||||
lastIndex += lineLength;
|
||||
}
|
||||
|
||||
lineCount--;
|
||||
}
|
||||
|
||||
Validate();
|
||||
|
||||
return (true);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
byte[] data = (Utils.GetBytes(byteData, 0, byteData.Length));
|
||||
Logger.Instance.Dump("Exception Data", data, data.Length);
|
||||
throw (new ArgumentOutOfRangeException("The MediaHighway2 Summary Data message is short"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the summary data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A summary data field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the summary data fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "MHW2 SUMMARY DATA: Event ID: " + eventID +
|
||||
" Unknown: " + Utils.ConvertToHex(unknown) +
|
||||
" Short desc: " + shortDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,103 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a MediaHighway2 Summary section.
|
||||
/// </summary>
|
||||
public class MediaHighway2SummarySection
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the summary data for this section.
|
||||
/// </summary>
|
||||
public MediaHighway2SummaryData SummaryData { get { return (summaryData); } }
|
||||
|
||||
private MediaHighway2SummaryData summaryData;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighway2SummarySection class.
|
||||
/// </summary>
|
||||
internal MediaHighway2SummarySection() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the section.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the summary data.</param>
|
||||
/// <param name="index">Index of the first byte of the summary data in the MPEG2 section.</param>
|
||||
/// <returns>True if the block contains data; false otherwise.</returns>
|
||||
internal bool Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
summaryData = new MediaHighway2SummaryData();
|
||||
return(summaryData.Process(byteData, lastIndex));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
summaryData.LogMessage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an MPEG2 section from the MediaHighway1 summary table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section.</param>
|
||||
/// <returns>A MediaHighway2SummarySection instance.</returns>
|
||||
public static MediaHighway2SummarySection ProcessMediaHighwaySummaryTable(byte[] byteData)
|
||||
{
|
||||
Mpeg2BasicHeader mpeg2Header = new Mpeg2BasicHeader();
|
||||
|
||||
try
|
||||
{
|
||||
mpeg2Header.Process(byteData);
|
||||
|
||||
MediaHighway2SummarySection summarySection = new MediaHighway2SummarySection();
|
||||
bool process = summarySection.Process(byteData, mpeg2Header.Index);
|
||||
if (process)
|
||||
{
|
||||
summarySection.LogMessage();
|
||||
return (summarySection);
|
||||
}
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Logger.Instance.Write("<e> Summary section parsing failed: " + e.Message);
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,222 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes MediaHighway2 title data.
|
||||
/// </summary>
|
||||
public class MediaHighway2TitleData
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the channel identification.
|
||||
/// </summary>
|
||||
public int ChannelID { get { return (channelID); } }
|
||||
/// <summary>
|
||||
/// Get the event identification.
|
||||
/// </summary>
|
||||
public int EventID { get { return (eventID); } }
|
||||
/// <summary>
|
||||
/// Get the start time of the event.
|
||||
/// </summary>
|
||||
public DateTime StartTime { get { return (baseDate + new TimeSpan(hours, minutes, 0)); }}
|
||||
/// <summary>
|
||||
/// Get the duration of the event.
|
||||
/// </summary>
|
||||
public TimeSpan Duration { get { return (duration); } }
|
||||
/// <summary>
|
||||
/// Get the theme identification of the event.
|
||||
/// </summary>
|
||||
public int CategoryID { get { return ((mainCategory << 6) + subCategory); } }
|
||||
/// <summary>
|
||||
/// Get the theme group of the event.
|
||||
/// </summary>
|
||||
public int MainCategory { get { return (mainCategory); } }
|
||||
/// <summary>
|
||||
/// Get the theme subgroup of the event.
|
||||
/// </summary>
|
||||
public int SubCategory { get { return (subCategory); } }
|
||||
/// <summary>
|
||||
/// Get the name of the event.
|
||||
/// </summary>
|
||||
public string EventName { get { return (eventName); } }
|
||||
/// <summary>
|
||||
/// Get the unknown data.
|
||||
/// </summary>
|
||||
public byte[] Unknown
|
||||
{
|
||||
get
|
||||
{
|
||||
byte[] outputBytes = new byte[unknown0.Length + unknown1.Length + unknown2.Length];
|
||||
unknown0.CopyTo(outputBytes, 0);
|
||||
unknown1.CopyTo(outputBytes, unknown0.Length);
|
||||
unknown2.CopyTo(outputBytes, unknown0.Length + unknown1.Length);
|
||||
return (outputBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the title data.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The title data has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("MediaHighway2TitleData: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] unknown0;
|
||||
private int channelID;
|
||||
private byte[] unknown1;
|
||||
private int mainCategory;
|
||||
private DateTime baseDate;
|
||||
private int hours;
|
||||
private int minutes;
|
||||
private byte[] unknown2;
|
||||
private TimeSpan duration;
|
||||
private string eventName;
|
||||
private int subCategory;
|
||||
private int eventID;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighway2TitleData class.
|
||||
/// </summary>
|
||||
public MediaHighway2TitleData() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the title data.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the title data.</param>
|
||||
/// <param name="index">Index of the first byte of the title data in the MPEG2 section.</param>
|
||||
internal void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
unknown0 = Utils.GetBytes(byteData, 3, 15);
|
||||
|
||||
channelID = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
unknown1 = Utils.GetBytes(byteData, lastIndex, 10);
|
||||
lastIndex += unknown1.Length;
|
||||
|
||||
mainCategory = byteData[7] & 0x0f;
|
||||
|
||||
baseDate = getDate(Utils.Convert2BytesToInt(byteData, lastIndex));
|
||||
lastIndex += 2;
|
||||
|
||||
hours = ((byteData[lastIndex] >> 4) * 10) + (byteData[lastIndex] & 0x0f);
|
||||
lastIndex++;
|
||||
|
||||
minutes = ((byteData[lastIndex] >> 4) * 10) + (byteData[lastIndex] & 0x0f);
|
||||
lastIndex++;
|
||||
|
||||
unknown2 = Utils.GetBytes(byteData, lastIndex, 1);
|
||||
lastIndex += unknown2.Length;
|
||||
|
||||
int durationMinutes = (byteData[lastIndex] << 4) + (byteData[lastIndex + 1] >> 4);
|
||||
duration = new TimeSpan(durationMinutes / 60, durationMinutes % 60, 0);
|
||||
lastIndex += 2;
|
||||
|
||||
int eventNameLength = byteData[lastIndex] & 0x3f;
|
||||
lastIndex++;
|
||||
|
||||
eventName = Utils.GetString(byteData, lastIndex, eventNameLength, ReplaceMode.TransferUnchanged);
|
||||
lastIndex += eventNameLength;
|
||||
|
||||
subCategory = byteData[lastIndex] & 0x3f;
|
||||
lastIndex++;
|
||||
|
||||
eventID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime getDate(int mjd)
|
||||
{
|
||||
int j = mjd + 2400001 + 68569;
|
||||
int c = 4 * j / 146097;
|
||||
j = j - (146097 * c + 3) / 4;
|
||||
|
||||
int y = 4000 * (j + 1) / 1461001;
|
||||
j = j - 1461 * y / 4 + 31;
|
||||
int m = 80 * j / 2447;
|
||||
|
||||
int day = j - 2447 * m / 80;
|
||||
j = m / 11;
|
||||
int month = m + 2 - (12 * j);
|
||||
int year = 100 * (c - 49) + y + j;
|
||||
|
||||
return (new DateTime(year, month, day));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the title data fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A title data field is not valid.
|
||||
/// </exception>
|
||||
public void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the title data fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "MHW2 TITLE DATA: Channel ID: " + channelID +
|
||||
" Unknown0: " + Utils.ConvertToHex(unknown0) +
|
||||
" Unknown1: " + Utils.ConvertToHex(unknown1) +
|
||||
" Main cat: " + mainCategory +
|
||||
" Base date: " + baseDate +
|
||||
" Hours: " + hours +
|
||||
" Minutes: " + minutes +
|
||||
" Unknown2: " + Utils.ConvertToHex(unknown2) +
|
||||
" Duration: " + duration +
|
||||
" Event name: " + eventName +
|
||||
" Sub cat: " + mainCategory +
|
||||
" Event ID: " + eventID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,164 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a MediaHighway2 Title section.
|
||||
/// </summary>
|
||||
public class MediaHighway2TitleSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the title data for this section.
|
||||
/// </summary>
|
||||
public Collection<MediaHighway2TitleData> Titles { get { return (titles); } }
|
||||
|
||||
private byte[] unknown;
|
||||
private Collection<MediaHighway2TitleData> titles;
|
||||
|
||||
private int lastIndex = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighway2TitleSection class.
|
||||
/// </summary>
|
||||
internal MediaHighway2TitleSection()
|
||||
{
|
||||
titles = new Collection<MediaHighway2TitleData>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse the section.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the section.</param>
|
||||
/// <param name="index">Index of the first byte of the title section in the MPEG2 section.</param>
|
||||
/// <returns>True if the section is an MHW2 title section; false otherwise.</returns>
|
||||
internal bool Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
/*int checkIndex = 18;
|
||||
bool process = false;
|
||||
|
||||
while (checkIndex < byteData.Length)
|
||||
{
|
||||
process = false;
|
||||
checkIndex += 7;
|
||||
|
||||
if (checkIndex < byteData.Length)
|
||||
{
|
||||
checkIndex += 3;
|
||||
|
||||
if (checkIndex < byteData.Length)
|
||||
{
|
||||
if (byteData[checkIndex] > 0xc0)
|
||||
{
|
||||
checkIndex += (byteData[checkIndex] - 0xc0);
|
||||
checkIndex += 4;
|
||||
|
||||
if (checkIndex < byteData.Length)
|
||||
{
|
||||
if (byteData[checkIndex] == 0xff)
|
||||
{
|
||||
checkIndex += 1;
|
||||
process = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!process)
|
||||
return (false);*/
|
||||
|
||||
/*Logger.Instance.Dump("Title Section", byteData, byteData.Length);*/
|
||||
|
||||
unknown = Utils.GetBytes(byteData, lastIndex, 15);
|
||||
lastIndex += unknown.Length;
|
||||
|
||||
while (lastIndex < byteData.Length)
|
||||
{
|
||||
MediaHighway2TitleData title = new MediaHighway2TitleData();
|
||||
title.Process(byteData, lastIndex);
|
||||
|
||||
titles.Add(title);
|
||||
lastIndex = title.Index;
|
||||
}
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
if (titles != null)
|
||||
{
|
||||
Logger.IncrementProtocolIndent();
|
||||
|
||||
foreach (MediaHighway2TitleData title in titles)
|
||||
title.LogMessage();
|
||||
|
||||
Logger.DecrementProtocolIndent();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process an MPEG2 section from the MediaHighway title table.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section.</param>
|
||||
/// <returns>A MediaHighway2TitleSection instance.</returns>
|
||||
public static MediaHighway2TitleSection ProcessMediaHighwayTitleTable(byte[] byteData)
|
||||
{
|
||||
Mpeg2BasicHeader mpeg2Header = new Mpeg2BasicHeader();
|
||||
|
||||
try
|
||||
{
|
||||
mpeg2Header.Process(byteData);
|
||||
|
||||
MediaHighway2TitleSection titleSection = new MediaHighway2TitleSection();
|
||||
bool process = titleSection.Process(byteData, mpeg2Header.Index);
|
||||
if (process)
|
||||
{
|
||||
titleSection.LogMessage();
|
||||
return (titleSection);
|
||||
}
|
||||
else
|
||||
return (null);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException e)
|
||||
{
|
||||
Logger.Instance.Write("<e> Title section parsing failed: " + e.Message);
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a MediaHighway category entry.
|
||||
/// </summary>
|
||||
public class MediaHighwayCategoryEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Get or set the category number.
|
||||
/// </summary>
|
||||
public int Number
|
||||
{
|
||||
get { return (number); }
|
||||
set { number = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the category description.
|
||||
/// </summary>
|
||||
public string Description
|
||||
{
|
||||
get { return (description); }
|
||||
set { description = value; }
|
||||
}
|
||||
|
||||
private int number;
|
||||
private string description;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighwayCategoryEntry class.
|
||||
/// </summary>
|
||||
public MediaHighwayCategoryEntry() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the section fields.
|
||||
/// </summary>
|
||||
public void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "MHW CATEGORY ENTRY: Number: " + number +
|
||||
" Description: " + description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,214 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
using DomainObjects;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a MediaHighway channel info entry.
|
||||
/// </summary>
|
||||
public class MediaHighwayChannelInfoEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the original network ID for the channel.
|
||||
/// </summary>
|
||||
public int OriginalNetworkID { get { return (originalNetworkID); } }
|
||||
/// <summary>
|
||||
/// Get the transport stream ID for the channel.
|
||||
/// </summary>
|
||||
public int TransportStreamID { get { return (transportStreamID); } }
|
||||
/// <summary>
|
||||
/// Get the service ID for the channel.
|
||||
/// </summary>
|
||||
public int ServiceID { get { return (serviceID); } }
|
||||
/// <summary>
|
||||
/// Get the name of the channel.
|
||||
/// </summary>
|
||||
public string Name { get { return (name); } }
|
||||
/// <summary>
|
||||
/// Get the unknown data.
|
||||
/// </summary>
|
||||
public byte[] Unknown { get { return (unknown); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the section following this entry.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The entry has not been processed.
|
||||
/// </exception>
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("MediaHighwayChannelEntry: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next name byte in the section following this entry.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The entry has not been processed.
|
||||
/// </exception>
|
||||
public int NameIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (nameIndex == -1)
|
||||
throw (new InvalidOperationException("MediaHighwayChannelEntry: Name index requested before block processed"));
|
||||
return (nameIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the length of the entry.
|
||||
/// </summary>
|
||||
public int Length { get { return (length); } }
|
||||
|
||||
private int originalNetworkID;
|
||||
private int transportStreamID;
|
||||
private int serviceID;
|
||||
private string name;
|
||||
private byte[] unknown;
|
||||
|
||||
private int lastIndex = -1;
|
||||
private int nameIndex;
|
||||
private int length;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the MediaHighwayChannelInfoEntry.
|
||||
/// </summary>
|
||||
public MediaHighwayChannelInfoEntry() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the MHW1 descriptor.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the entry.</param>
|
||||
/// <param name="index">Index of the first byte in the MPEG2 section of the entry.</param>
|
||||
internal void Process(byte[] byteData, int index)
|
||||
{
|
||||
lastIndex = index;
|
||||
|
||||
try
|
||||
{
|
||||
originalNetworkID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
transportStreamID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
serviceID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
name = Utils.GetString(byteData, lastIndex, 16, ReplaceMode.TransferUnchanged).Trim();
|
||||
lastIndex += 16;
|
||||
|
||||
length = lastIndex - index;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("The MediaHighway Channel Info Entry message is short"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse the MHW2 descriptor.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the entry.</param>
|
||||
/// <param name="index">Index of the first byte in the MPEG2 section of the entry.</param>
|
||||
/// <param name="nameLengthIndex">Index of the first byte channel name in the MPEG2 section of the entry.</param>
|
||||
internal void Process(byte[] byteData, int index, int nameLengthIndex)
|
||||
{
|
||||
lastIndex = index;
|
||||
nameIndex = nameLengthIndex;
|
||||
|
||||
try
|
||||
{
|
||||
originalNetworkID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
transportStreamID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
serviceID = Utils.Convert2BytesToInt(byteData, lastIndex);
|
||||
lastIndex += 2;
|
||||
|
||||
unknown = Utils.GetBytes(byteData, lastIndex, 2);
|
||||
lastIndex += unknown.Length;
|
||||
|
||||
int nameLength = (int)byteData[nameIndex] & 0x3f;
|
||||
nameIndex++;
|
||||
|
||||
name = Utils.GetString(byteData, nameIndex, nameLength, ReplaceMode.TransferUnchanged).Trim();
|
||||
nameIndex += nameLength;
|
||||
|
||||
length = lastIndex - index;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("The MediaHighway Channel Info Entry message is short"));
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the entry fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A descriptor field is not valid.
|
||||
/// </exception>
|
||||
internal void Validate() { }
|
||||
|
||||
/// <summary>
|
||||
/// Log the entry fields.
|
||||
/// </summary>
|
||||
internal void LogMessage()
|
||||
{
|
||||
if (Logger.ProtocolLogger == null)
|
||||
return;
|
||||
|
||||
string unknownString;
|
||||
if (unknown == null)
|
||||
unknownString = "n/a";
|
||||
else
|
||||
unknownString = Utils.ConvertToHex(unknown);
|
||||
|
||||
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "MHW CHANNEL INFO ENTRY: ONID: " + originalNetworkID +
|
||||
" TSID: " + transportStreamID +
|
||||
" SID: " + serviceID +
|
||||
" Name: " + name +
|
||||
" Unknown: " + unknownString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,134 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Copyright © 2005-2020 nzsjb //
|
||||
// //
|
||||
// This Program is free software; you can redistribute it and/or modify //
|
||||
// it under the terms of the GNU General Public License as published by //
|
||||
// the Free Software Foundation; either version 2, or (at your option) //
|
||||
// any later version. //
|
||||
// //
|
||||
// This Program is distributed in the hope that it will be useful, //
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||
// GNU General Public License for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with GNU Make; see the file COPYING. If not, write to //
|
||||
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
|
||||
// http://www.gnu.org/copyleft/gpl.html //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
using System;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
/// <summary>
|
||||
/// The class that describes a basic MPEG2 section header.
|
||||
/// </summary>
|
||||
public class Mpeg2BasicHeader
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the table identification.
|
||||
/// </summary>
|
||||
public int TableID { get { return (tableID); } }
|
||||
/// <summary>
|
||||
/// Get the section length.
|
||||
/// </summary>
|
||||
public int SectionLength { get { return (sectionLength); } }
|
||||
/// <summary>
|
||||
/// Return true if the section is private data; false otherwise.
|
||||
/// </summary>
|
||||
public bool PrivateIndicator { get { return (privateIndicator); } }
|
||||
/// <summary>
|
||||
/// Return true if the sysntax indicator is set; false otherwise.
|
||||
/// </summary>
|
||||
public bool SyntaxIndicator { get { return (syntaxIndicator); } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the next byte in the MPEG2 section following the header.
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// The header has not been processed.
|
||||
/// </exception>
|
||||
public virtual int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
if (lastIndex == -1)
|
||||
throw (new InvalidOperationException("Mpeg2BasicHeader: Index requested before block processed"));
|
||||
return (lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private int tableID;
|
||||
private int sectionLength;
|
||||
private bool privateIndicator;
|
||||
private bool syntaxIndicator;
|
||||
|
||||
private int lastIndex = -1;
|
||||
private int dataLength;
|
||||
|
||||
// MPEG basic header layout is as follows
|
||||
//
|
||||
// tableID byte uimsbf
|
||||
//
|
||||
// section syntax ind 1 bit bslbf
|
||||
// private indicator 1 bit bslbf
|
||||
// reserved 2 bits bslbf
|
||||
// section length 12 bits uimsbf
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the Mpeg2BasicHeader class.
|
||||
/// </summary>
|
||||
public Mpeg2BasicHeader() { }
|
||||
|
||||
/// <summary>
|
||||
/// Parse the header.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The MPEG2 section containing the header.</param>
|
||||
public virtual void Process(byte[] byteData)
|
||||
{
|
||||
lastIndex = 0;
|
||||
dataLength = byteData.Length;
|
||||
|
||||
try
|
||||
{
|
||||
tableID = (int)byteData[lastIndex];
|
||||
lastIndex++;
|
||||
|
||||
syntaxIndicator = (byteData[lastIndex] & 0x80) != 0;
|
||||
privateIndicator = (byteData[lastIndex] & 0x40) != 0;
|
||||
sectionLength = ((byteData[lastIndex] & 0x0f) * 256) + (int)byteData[lastIndex + 1];
|
||||
lastIndex += 2;
|
||||
|
||||
Validate();
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("MPEG2 basic header is short"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validate the header fields.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">
|
||||
/// A header field is not valid.
|
||||
/// </exception>
|
||||
public virtual void Validate()
|
||||
{
|
||||
if (dataLength > 4096)
|
||||
throw (new ArgumentOutOfRangeException("MPEG2 Section data length wrong"));
|
||||
|
||||
if (sectionLength < 1 || sectionLength > dataLength - 3)
|
||||
throw (new ArgumentOutOfRangeException("MPEG2 Section length wrong"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log the header fields.
|
||||
/// </summary>
|
||||
public virtual void LogMessage() { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
using System;
|
||||
using DomainObjects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper.Text;
|
||||
|
||||
namespace DVBServices
|
||||
{
|
||||
@ -63,5 +66,77 @@ namespace DVBServices
|
||||
|
||||
return ((char)('a' + (value - 10)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get subset of bytes from an array.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The array of bytes.</param>
|
||||
/// <param name="offset">The index of the first byte of the subset.</param>
|
||||
/// <param name="length">The length of the subset.</param>
|
||||
/// <returns>The subset of bytes.</returns>
|
||||
public static byte[] GetBytes(byte[] byteData, int offset, int length)
|
||||
{
|
||||
if (length < 1)
|
||||
throw (new ArgumentOutOfRangeException("GetBytes length wrong"));
|
||||
|
||||
try
|
||||
{
|
||||
byte[] outputBytes = new byte[length];
|
||||
|
||||
for (int index = 0; index < length; index++)
|
||||
outputBytes[index] = byteData[offset + index];
|
||||
|
||||
return (outputBytes);
|
||||
}
|
||||
catch (OutOfMemoryException)
|
||||
{
|
||||
throw (new ArgumentOutOfRangeException("GetBytes length wrong"));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert 2 bytes to an integer with the most significant byte first.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The byte array containing the byes to convert.</param>
|
||||
/// <param name="index">The index of the first byte in the array.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static int Convert2BytesToInt(byte[] byteData, int index)
|
||||
{
|
||||
return (Convert2BytesToInt(byteData, index, 0xff));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert 2 bytes to an integer with the most significant byte first and a mask.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The byte array containing the byes to convert.</param>
|
||||
/// <param name="index">The index of the first byte in the array.</param>
|
||||
/// <param name="mask">The mask for the most significant byte.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static int Convert2BytesToInt(byte[] byteData, int index, byte mask)
|
||||
{
|
||||
return (((byteData[index] & mask) * 256) + (int)byteData[index + 1]);
|
||||
}
|
||||
|
||||
private static En300468AnnexATextDecoder _encodingProvider;
|
||||
/// <summary>
|
||||
/// Convert a subset of an array of text bytes to a string.
|
||||
/// </summary>
|
||||
/// <param name="byteData">The array of bytes.</param>
|
||||
/// <param name="offset">The index of the first byte to be converted.</param>
|
||||
/// <param name="length">The number of bytes to be converted.</param>
|
||||
/// <param name="replaceMode">Action to be taken for non-Ascii bytes.</param>
|
||||
/// <returns>The converted string.</returns>
|
||||
public static string GetString(byte[] byteData, int offset, int length, ReplaceMode replaceMode)
|
||||
{
|
||||
if (_encodingProvider == null)
|
||||
{
|
||||
_encodingProvider = En300468AnnexATextDecoder.GetInstance();
|
||||
}
|
||||
|
||||
string temp = _encodingProvider.Decode(byteData, offset, length);
|
||||
if (temp == null)
|
||||
temp = "";
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,14 @@ namespace DomainObjects
|
||||
}
|
||||
}
|
||||
|
||||
public static string ProtocolIndent
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string(' ', indentation);
|
||||
}
|
||||
}
|
||||
|
||||
private class EPGCollector
|
||||
{
|
||||
|
||||
@ -47,5 +55,90 @@ namespace DomainObjects
|
||||
Write("============================ " + identity + " ==============================");
|
||||
Write("");
|
||||
}
|
||||
|
||||
private static int indentation;
|
||||
public static void IncrementProtocolIndent()
|
||||
{
|
||||
indentation++;
|
||||
}
|
||||
|
||||
public static void DecrementProtocolIndent()
|
||||
{
|
||||
indentation--;
|
||||
if (indentation <= -1)
|
||||
{
|
||||
indentation = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private class EPGCollectorProtocolLogger
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private static Logger _protocolLogger;
|
||||
public static Logger ProtocolLogger
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_protocolLogger == null)
|
||||
{
|
||||
_protocolLogger = new Logger();
|
||||
_protocolLogger._realLogger = PluginLogManager.GetLogger(typeof(EPGCollectorProtocolLogger));
|
||||
}
|
||||
|
||||
return _protocolLogger;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dump(string identity, byte[] buffer, int length)
|
||||
{
|
||||
Dump(identity, buffer, 0, length);
|
||||
}
|
||||
|
||||
public void Dump(string identity, byte[] buffer, int offset, int length)
|
||||
{
|
||||
Write("============================ " + identity + " starting ==============================");
|
||||
|
||||
StringBuilder loggerLineHex = new StringBuilder("0000 ");
|
||||
StringBuilder loggerLineChar = new StringBuilder();
|
||||
int lineIndex = 0;
|
||||
|
||||
for (int index = 0; index < length; index++)
|
||||
{
|
||||
if (lineIndex == 16)
|
||||
{
|
||||
Write(loggerLineHex.ToString() + " " + loggerLineChar.ToString());
|
||||
loggerLineHex.Remove(0, loggerLineHex.Length);
|
||||
loggerLineChar.Remove(0, loggerLineChar.Length);
|
||||
loggerLineHex.Append(index.ToString("0000 "));
|
||||
lineIndex = 0;
|
||||
}
|
||||
|
||||
loggerLineHex.Append(getHex(buffer[index + offset] >> 4));
|
||||
loggerLineHex.Append(getHex(buffer[index + offset] & 0x0f));
|
||||
loggerLineHex.Append(' ');
|
||||
|
||||
if (buffer[index + offset] > ' ' - 1 && buffer[index + offset] < 0x7f)
|
||||
loggerLineChar.Append((char)buffer[index + offset]);
|
||||
else
|
||||
loggerLineChar.Append('.');
|
||||
|
||||
lineIndex++;
|
||||
}
|
||||
|
||||
if (loggerLineHex.Length != 0)
|
||||
Write(loggerLineHex.ToString() + " " + loggerLineChar.ToString());
|
||||
|
||||
Write("============================ " + identity + " ending ==============================");
|
||||
}
|
||||
|
||||
private char getHex(int dataChar)
|
||||
{
|
||||
if (dataChar < 10)
|
||||
return ((char)('0' + dataChar));
|
||||
|
||||
return ((char)('a' + dataChar - 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,14 +9,16 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
[SkyscraperPlugin]
|
||||
internal class FreesatBatSdtContestant : Contestant
|
||||
{
|
||||
public FreesatBatSdtContestant(int pid) : base("Freesat BAT/SDT", pid)
|
||||
{
|
||||
PacketProcessor = new PacketDiscarder();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
@ -29,7 +31,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
if (freesatScraper == null)
|
||||
{
|
||||
freesatScraper = new FreesatTunnelScraper();
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||
}
|
||||
|
||||
@ -4,13 +4,14 @@ using skyscraper5.Mpeg2.Descriptors;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
[SkyscraperPlugin]
|
||||
internal class FreesatEpgContestant : Contestant
|
||||
@ -18,6 +19,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
public FreesatEpgContestant(int pid)
|
||||
: base("Freesat EPG", pid)
|
||||
{
|
||||
PacketProcessor = new PacketDiscarder();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
@ -30,7 +32,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
if (freesatScraper == null)
|
||||
{
|
||||
freesatScraper = new FreesatTunnelScraper();
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||
}
|
||||
|
||||
@ -4,13 +4,14 @@ using skyscraper5.Mpeg2.Descriptors;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
[SkyscraperPlugin]
|
||||
internal class FreesatNitContestant : Contestant
|
||||
@ -18,6 +19,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
public FreesatNitContestant(int pid)
|
||||
: base("Freesat Network Information", pid)
|
||||
{
|
||||
PacketProcessor = new PacketDiscarder();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
@ -30,7 +32,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
if (freesatScraper == null)
|
||||
{
|
||||
freesatScraper = new FreesatTunnelScraper();
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||
}
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
using skyscraper5.Mpeg2.Descriptors;
|
||||
using skyscraper5.Dvb.Psi;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Mpeg2.Descriptors;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Dvb.Psi;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
[SkyscraperPlugin]
|
||||
internal class FreesatTdtContestant : Contestant
|
||||
@ -18,6 +19,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
public FreesatTdtContestant(int pid)
|
||||
: base("Freesat Timestamp", pid)
|
||||
{
|
||||
PacketProcessor = new PacketDiscarder();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
@ -30,7 +32,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
if (freesatScraper == null)
|
||||
{
|
||||
freesatScraper = new FreesatTunnelScraper();
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper8.EPGCollectorPort.Properties;
|
||||
using skyscraper8.Skyscraper.Text;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
[SkyscraperPlugin]
|
||||
[EncodingTypeId(0x01)]
|
||||
@ -3,11 +3,12 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Data.PostgreSql;
|
||||
using skyscraper5.Dvb.Psi.Model;
|
||||
using skyscraper5.Ietf.Rfc971;
|
||||
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
internal interface IFreesatTunnelDataStorage
|
||||
{
|
||||
@ -28,6 +29,9 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
||||
case InMemoryPluginToken t1:
|
||||
_storageEngine = new FreesatTunnelDataStorageInMemory();
|
||||
break;
|
||||
case PostgresqlToken t2:
|
||||
_storageEngine = new FreesatTunnelDataStoragePostgresql(t2);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(o.GetType().FullName);
|
||||
}
|
||||
@ -0,0 +1,201 @@
|
||||
using Npgsql;
|
||||
using NpgsqlTypes;
|
||||
using skyscraper5.Data.PostgreSql;
|
||||
using skyscraper5.Dvb.Psi.Model;
|
||||
using skyscraper5.Skyscraper.Scraper.Storage.Utilities;
|
||||
using System.Data.Common;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat;
|
||||
|
||||
class FreesatTunnelDataStoragePostgresql : IFreesatTunnelDataStorage
|
||||
{
|
||||
private readonly PostgresqlToken token;
|
||||
public FreesatTunnelDataStoragePostgresql(PostgresqlToken t2)
|
||||
{
|
||||
token = t2;
|
||||
}
|
||||
|
||||
private HashSet<DatabaseKeyEitEvent> knownEitEvents;
|
||||
|
||||
public bool StoreEitEvent(EitEvent eitEvent)
|
||||
{
|
||||
if (knownEitEvents == null)
|
||||
knownEitEvents = new HashSet<DatabaseKeyEitEvent>();
|
||||
DatabaseKeyEitEvent key = new DatabaseKeyEitEvent(eitEvent.ServiceId, eitEvent.TransportStreamId, eitEvent.OriginalNetworkId, eitEvent.EventId, eitEvent.StartTime);
|
||||
if (knownEitEvents.Contains(key))
|
||||
return false;
|
||||
if (TestForEitEvent(key))
|
||||
{
|
||||
knownEitEvents.Add(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
token.EnqueueTask(x => WriteEitEvent(x, eitEvent));
|
||||
knownEitEvents.Add(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void WriteEitEvent(NpgsqlConnection connection, EitEvent eitEvent)
|
||||
{
|
||||
DatabaseKeyEitEvent key = new DatabaseKeyEitEvent(eitEvent.ServiceId, eitEvent.TransportStreamId, eitEvent.OriginalNetworkId, eitEvent.EventId, eitEvent.StartTime);
|
||||
if (TestForEitEventEx(key, connection))
|
||||
{
|
||||
return;
|
||||
}
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText =
|
||||
"INSERT INTO freesat_eit " +
|
||||
"(sid, tsid, onid, event_id, start_time, event) " +
|
||||
"VALUES " +
|
||||
"(@sid, @tsid, @onid, @event_id, @start_time, @event)";
|
||||
|
||||
command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
|
||||
command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
|
||||
command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
|
||||
command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
|
||||
command.Parameters.AddWithValue("@event", NpgsqlDbType.Json, JsonConvert.SerializeObject(eitEvent));
|
||||
int executeNonQuery = command.ExecuteNonQuery();
|
||||
if (executeNonQuery != 1)
|
||||
throw new NotImplementedException(string.Format("Wanted to insert 1 line, but it was {0}", executeNonQuery));
|
||||
}
|
||||
|
||||
private bool TestForEitEvent(DatabaseKeyEitEvent eitEvent)
|
||||
{
|
||||
using (NpgsqlConnection conn = token.GetConnection())
|
||||
{
|
||||
conn.Open();
|
||||
return TestForEitEventEx(eitEvent, conn);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TestForEitEventEx(DatabaseKeyEitEvent eitEvent, NpgsqlConnection conn)
|
||||
{
|
||||
NpgsqlCommand command = conn.CreateCommand();
|
||||
command.CommandText =
|
||||
"SELECT dateadded FROM freesat_eit WHERE sid = @sid AND tsid = @tsid AND onid = @onid AND event_id = @event_id AND start_time = @start_time";
|
||||
command.Parameters.AddWithValue("@sid", NpgsqlDbType.Integer, (int)eitEvent.ServiceId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)eitEvent.TransportStreamId);
|
||||
command.Parameters.AddWithValue("@onid", NpgsqlDbType.Integer, (int)eitEvent.OriginalNetworkId);
|
||||
command.Parameters.AddWithValue("@event_id", NpgsqlDbType.Integer, (int)eitEvent.EventId);
|
||||
command.Parameters.AddWithValue("@start_time", NpgsqlDbType.Timestamp, eitEvent.StartTime);
|
||||
NpgsqlDataReader dataReader = command.ExecuteReader();
|
||||
bool result = dataReader.Read();
|
||||
dataReader.Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
private HashSet<DatabaseKeyNitNetwork> _knownUpdatedNitNetworks;
|
||||
public void StoreNitNetwork(NitNetwork nitNetwork)
|
||||
{
|
||||
if (_knownUpdatedNitNetworks == null)
|
||||
_knownUpdatedNitNetworks = new HashSet<DatabaseKeyNitNetwork>();
|
||||
|
||||
DatabaseKeyNitNetwork key = new DatabaseKeyNitNetwork(nitNetwork.NetworkId);
|
||||
token.EnqueueTask(x => WriteNit(x, nitNetwork));
|
||||
knownNitNetworks.Add(key);
|
||||
_knownUpdatedNitNetworks.Add(key);
|
||||
}
|
||||
|
||||
private void WriteNit(NpgsqlConnection connection, NitNetwork nitNetwork)
|
||||
{
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText =
|
||||
"INSERT INTO freesat_nit (id, network) " +
|
||||
"VALUES (@id, @network)";
|
||||
command.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)nitNetwork.NetworkId);
|
||||
command.Parameters.AddWithValue("@network", NpgsqlDbType.Json, JsonConvert.SerializeObject(nitNetwork));
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private HashSet<DatabaseKeyNitNetwork> knownNitNetworks;
|
||||
public bool TestNitNetwork(NitNetwork nitNetwork)
|
||||
{
|
||||
if (knownNitNetworks == null)
|
||||
knownNitNetworks = new HashSet<DatabaseKeyNitNetwork>();
|
||||
|
||||
DatabaseKeyNitNetwork key = new DatabaseKeyNitNetwork(nitNetwork.NetworkId);
|
||||
if (knownNitNetworks.Contains(key))
|
||||
return true;
|
||||
|
||||
bool result = false;
|
||||
using (NpgsqlConnection conn = token.GetConnection())
|
||||
{
|
||||
conn.Open();
|
||||
NpgsqlCommand command = conn.CreateCommand();
|
||||
command.CommandText = "SELECT dateadded FROM freesat_nit WHERE id = @id";
|
||||
command.Parameters.AddWithValue("@id", NpgsqlDbType.Integer, (int)nitNetwork.NetworkId);
|
||||
NpgsqlDataReader dataReader = command.ExecuteReader();
|
||||
result = dataReader.Read();
|
||||
dataReader.Close();
|
||||
dataReader.Dispose();
|
||||
command.Dispose();
|
||||
conn.Close();
|
||||
}
|
||||
|
||||
if (result)
|
||||
knownNitNetworks.Add(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
private HashSet<DatabaseKeyNitTs> _knownNitTs;
|
||||
public bool TestForNitTransportStream(ushort networkId, NitTransportStream transportStream)
|
||||
{
|
||||
if (_knownNitTs == null)
|
||||
_knownNitTs = new HashSet<DatabaseKeyNitTs>();
|
||||
|
||||
DatabaseKeyNitTs key = new DatabaseKeyNitTs(networkId, transportStream.TransportStreamId);
|
||||
if (_knownNitTs.Contains(key))
|
||||
return true;
|
||||
|
||||
bool result = false;
|
||||
using (NpgsqlConnection conn = token.GetConnection())
|
||||
{
|
||||
conn.Open();
|
||||
NpgsqlCommand command = conn.CreateCommand();
|
||||
command.CommandText =
|
||||
"SELECT dateadded FROM freesat_nit_transport_stream WHERE nid = @nid AND tsid = @tsid";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, (int)networkId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId);
|
||||
NpgsqlDataReader dataReader = command.ExecuteReader();
|
||||
result = dataReader.Read();
|
||||
dataReader.Close();
|
||||
command.Dispose();
|
||||
}
|
||||
|
||||
if (result)
|
||||
_knownNitTs.Add(key);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private HashSet<DatabaseKeyNitTs> _knownUpdatedNitTransportStream;
|
||||
public void StoreNitTransportStream(ushort networkId, NitTransportStream transportStream)
|
||||
{
|
||||
token.EnqueueTask(x => WriteNitTransportStream(x, networkId, transportStream));
|
||||
DatabaseKeyNitTs ts = new DatabaseKeyNitTs(networkId, transportStream.TransportStreamId);
|
||||
_knownNitTs.Add(ts);
|
||||
if (_knownUpdatedNitTransportStream == null)
|
||||
return;
|
||||
_knownUpdatedNitTransportStream.Add(ts);
|
||||
}
|
||||
|
||||
private void WriteNitTransportStream(NpgsqlConnection conn, ushort networkId, NitTransportStream transportStream)
|
||||
{
|
||||
/*if (TestForNitTransportStream(networkId, transportStream))
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
NpgsqlCommand command = conn.CreateCommand();
|
||||
command.CommandText =
|
||||
"insert into freesat_nit_transport_stream (nid, tsid, transport_stream) " +
|
||||
"values " +
|
||||
"(@nid,@tsid,@transport_stream);";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, (int)networkId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, (int)transportStream.TransportStreamId);
|
||||
command.Parameters.AddWithValue("@transport_stream", NpgsqlDbType.Json, JsonConvert.SerializeObject(transportStream));
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
using skyscraper5.Dvb.Descriptors;
|
||||
using skyscraper5.Dvb.Psi;
|
||||
using skyscraper5.Dvb.Psi.Model;
|
||||
using skyscraper8.EPGCollectorPort.SkyscraperSide;
|
||||
using skyscraper8.Skyscraper.Scraper.Storage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -10,7 +9,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper8.Skyscraper.Plugins;
|
||||
|
||||
namespace skyscraper5.Skyscraper.Scraper
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||
{
|
||||
internal class FreesatTunnelScraper : IBatEventHandler, ISdtEventHandler, ITdtEventHandler, ITotEventHandler, IEitEventHandler, INitEventHandler
|
||||
{
|
||||
@ -72,7 +71,8 @@ namespace skyscraper5.Skyscraper.Scraper
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "NIT Network {0} Transport Stream {1}", networkId, transportStream.TransportStreamId);
|
||||
_dataStorage.StoreNitTransportStream(networkId, transportStream);
|
||||
}
|
||||
_hostNotification.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNitNetwork(NitNetwork nitNetwork)
|
||||
@ -81,7 +81,8 @@ namespace skyscraper5.Skyscraper.Scraper
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "NIT Network {0}", nitNetwork.NetworkId);
|
||||
_dataStorage.StoreNitNetwork(nitNetwork);
|
||||
}
|
||||
_hostNotification.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private EitEvent[] runningEvents;
|
||||
@ -90,26 +91,25 @@ namespace skyscraper5.Skyscraper.Scraper
|
||||
if (_dataStorage.StoreEitEvent(eitEvent))
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "EIT Event: {0}", eitEvent.EventName);
|
||||
_hostNotification.Invoke();
|
||||
}
|
||||
|
||||
if (eitEvent.RunningStatus == RunningStatus.Running)
|
||||
{
|
||||
if (runningEvents == null)
|
||||
runningEvents = new EitEvent[UInt16.MaxValue];
|
||||
runningEvents = new EitEvent[ushort.MaxValue];
|
||||
runningEvents[eitEvent.ServiceId] = eitEvent;
|
||||
}
|
||||
}
|
||||
|
||||
private PluginLogger _logger;
|
||||
private IFreesatTunnelDataStorage _dataStorage;
|
||||
public void ConnectToStorage(object[] getPluginConnector)
|
||||
private Action _hostNotification;
|
||||
public void ConnectToStorage(object[] getPluginConnector, Action onPluginEvent)
|
||||
{
|
||||
if (_dataStorage == null)
|
||||
{
|
||||
_dataStorage = new FreesatTunnelDataStorage(getPluginConnector);
|
||||
}
|
||||
|
||||
_logger = PluginLogManager.GetLogger(this.GetType());
|
||||
_dataStorage = new FreesatTunnelDataStorage(getPluginConnector);
|
||||
_logger = PluginLogManager.GetLogger(GetType());
|
||||
_hostNotification = onPluginEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
using DVBServices;
|
||||
using skyscraper5.Mpeg2;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper8.Skyscraper.Plugins;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2
|
||||
{
|
||||
//Look for PIDs 0x231, 0x234, and 0x236
|
||||
[SkyscraperPlugin]
|
||||
[Experimental]
|
||||
class Mhw2Contestant : Contestant, Mhw2EventHandler
|
||||
{
|
||||
|
||||
public Mhw2Contestant(int pid) : base("MediaHighway 2", pid)
|
||||
{
|
||||
PacketProcessor = new PsiDecoder(pid, new Mhw2Parser(this));
|
||||
if (_logger == null)
|
||||
{
|
||||
_logger = PluginLogManager.GetLogger(GetType());
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
|
||||
{
|
||||
Mhw2Scraper mhw2Scraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is Mhw2Scraper) as Mhw2Scraper;
|
||||
if (mhw2Scraper == null)
|
||||
{
|
||||
mhw2Scraper = new Mhw2Scraper(skyscraperContext);
|
||||
skyscraperContext.PluginContext.Add(mhw2Scraper);
|
||||
}
|
||||
|
||||
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new Mhw2Parser(mhw2Scraper)));
|
||||
}
|
||||
|
||||
public override void Introduce(ProgramContext programContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private byte[] deadSections;
|
||||
private static PluginLogger _logger;
|
||||
|
||||
public void OnNonMhw2Traffic(int sourcePid, int sectionTableId, byte mhwType)
|
||||
{
|
||||
if (deadSections == null)
|
||||
deadSections = new byte[byte.MaxValue];
|
||||
deadSections[sectionTableId]++;
|
||||
|
||||
if (deadSections[sectionTableId] == 1)
|
||||
Score--;
|
||||
}
|
||||
|
||||
public void OnMhw2Channels(int sourcePid, MediaHighway2ChannelSection channelSection)
|
||||
{
|
||||
if (channelSection == null)
|
||||
return;
|
||||
|
||||
if (channelSection.Channels.Count > 0)
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "Found MHW2 Channel Section in PID {0}", sourcePid);
|
||||
Score += channelSection.Channels.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMhw2Categories(int sourcePid, MediaHighway2CategorySection categorySection)
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "Found MHW2 Category Section in PID {0}", sourcePid);
|
||||
Score += categorySection.Categories.Count;
|
||||
}
|
||||
|
||||
public void OnMhw2Titles(int sourcePid, MediaHighway2TitleSection titleSection)
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "Found MHW2 Title Section in PID {0}", sourcePid);
|
||||
Score++;
|
||||
}
|
||||
|
||||
public void OnMhw2Summary(int sourcePid, MediaHighway2SummarySection summarySection)
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "Found MHW2 Summary Section in PID {0}", sourcePid);
|
||||
Score++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2
|
||||
{
|
||||
internal class Mhw2EventBinder
|
||||
{
|
||||
public int EventId { get; }
|
||||
|
||||
public Mhw2EventBinder(int eventId)
|
||||
{
|
||||
EventId = eventId;
|
||||
}
|
||||
|
||||
public string EventName { get; set; }
|
||||
public int CategoryID { get; set; }
|
||||
public int ChannelID { get; set; }
|
||||
public TimeSpan Duration { get; set; }
|
||||
public int MainCategory { get; set; }
|
||||
public DateTime StartTime { get; set; }
|
||||
public int SubCategory { get; set; }
|
||||
|
||||
public string ShortDescription { get; set; }
|
||||
public bool ShortDescriptionSeen { get; set; }
|
||||
public bool TitleDataSeen { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DVBServices;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2
|
||||
{
|
||||
internal interface Mhw2EventHandler
|
||||
{
|
||||
void OnNonMhw2Traffic(int sourcePid, int sectionTableId, byte trafficType);
|
||||
void OnMhw2Channels(int sourcePid, MediaHighway2ChannelSection channelSection);
|
||||
void OnMhw2Categories(int sourcePid, MediaHighway2CategorySection categorySection);
|
||||
void OnMhw2Titles(int sourcePid, MediaHighway2TitleSection titleSection);
|
||||
void OnMhw2Summary(int sourcePid, MediaHighway2SummarySection summarySection);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DVBServices;
|
||||
using skyscraper5.Mpeg2;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2
|
||||
{
|
||||
internal class Mhw2Parser : IPsiProcessor
|
||||
{
|
||||
private Mhw2EventHandler eventHandler;
|
||||
|
||||
public Mhw2Parser(Mhw2EventHandler eventHandler)
|
||||
{
|
||||
this.eventHandler = eventHandler;
|
||||
}
|
||||
|
||||
public void GatherPsi(PsiSection section, int sourcePid)
|
||||
{
|
||||
if (section.TableId == 0xc8)
|
||||
{
|
||||
byte[] bytes = section.GetData();
|
||||
switch (bytes[3])
|
||||
{
|
||||
case 0:
|
||||
try
|
||||
{
|
||||
MediaHighway2ChannelSection channelSection = MediaHighway2ChannelSection.ProcessMediaHighwayChannelTable(bytes);
|
||||
eventHandler.OnMhw2Channels(sourcePid, channelSection);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
return;
|
||||
case 1:
|
||||
try
|
||||
{
|
||||
MediaHighway2CategorySection categorySection = MediaHighway2CategorySection.ProcessMediaHighwayCategoryTable(bytes);
|
||||
eventHandler.OnMhw2Categories(sourcePid, categorySection);
|
||||
}
|
||||
catch (NotImplementedException e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
return;
|
||||
case 2:
|
||||
//Unknown
|
||||
break;
|
||||
case 3:
|
||||
//Unknown
|
||||
break;
|
||||
case 4:
|
||||
//Channel Name String Table, uninteresting.
|
||||
return;
|
||||
default:
|
||||
eventHandler.OnNonMhw2Traffic(sourcePid, section.TableId, bytes[3]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (section.TableId == 0xe6)
|
||||
{
|
||||
byte[] bytes = section.GetData();
|
||||
try
|
||||
{
|
||||
MediaHighway2TitleSection titleSection = MediaHighway2TitleSection.ProcessMediaHighwayTitleTable(bytes);
|
||||
if (titleSection != null)
|
||||
{
|
||||
eventHandler.OnMhw2Titles(sourcePid, titleSection);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
else if (section.TableId == 0x96)
|
||||
{
|
||||
byte[] bytes = section.GetData();
|
||||
MediaHighway2SummarySection summarySection = MediaHighway2SummarySection.ProcessMediaHighwaySummaryTable(bytes);
|
||||
eventHandler.OnMhw2Summary(sourcePid,summarySection);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventHandler.OnNonMhw2Traffic(sourcePid, section.TableId, section.GetData()[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,153 @@
|
||||
using DVBServices;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper8.Skyscraper.Plugins;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2
|
||||
{
|
||||
internal class Mhw2Scraper : Mhw2EventHandler
|
||||
{
|
||||
private readonly SkyscraperContext _skyscraperContext;
|
||||
private readonly IMhw2Storage storage;
|
||||
|
||||
public Mhw2Scraper(SkyscraperContext skyscraperContext)
|
||||
{
|
||||
_skyscraperContext = skyscraperContext;
|
||||
storage = new Mhw2StorageImpl(skyscraperContext.DataStorage.GetPluginConnector());
|
||||
_logger = PluginLogManager.GetLogger(GetType());
|
||||
}
|
||||
|
||||
public void OnNonMhw2Traffic(int sourcePid, int sectionTableId, byte mhwType)
|
||||
{
|
||||
}
|
||||
|
||||
private bool hasChannels;
|
||||
public void OnMhw2Channels(int sourcePid, MediaHighway2ChannelSection channelSection)
|
||||
{
|
||||
if (hasChannels)
|
||||
return;
|
||||
if (channelSection == null)
|
||||
return;
|
||||
if (!_skyscraperContext.CurrentNetworkId.HasValue)
|
||||
return;
|
||||
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
|
||||
return;
|
||||
|
||||
storage.InsertChannels(_skyscraperContext.CurrentNetworkId.Value, _skyscraperContext.CurrentTransportStreamId.Value, channelSection);
|
||||
_logger.Log(PluginLogLevel.Info, "Found {0} channels", channelSection.Channels.Count);
|
||||
hasChannels = true;
|
||||
}
|
||||
|
||||
private bool hasCategories;
|
||||
public void OnMhw2Categories(int sourcePid, MediaHighway2CategorySection categorySection)
|
||||
{
|
||||
if (hasCategories)
|
||||
return;
|
||||
if (!_skyscraperContext.CurrentNetworkId.HasValue)
|
||||
return;
|
||||
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
|
||||
return;
|
||||
|
||||
storage.InsertCategories(_skyscraperContext.CurrentNetworkId.Value, _skyscraperContext.CurrentTransportStreamId.Value, categorySection);
|
||||
_logger.Log(PluginLogLevel.Info, "Found {0} categories", categorySection.Categories.Count);
|
||||
hasCategories = true;
|
||||
}
|
||||
|
||||
public void OnMhw2Titles(int sourcePid, MediaHighway2TitleSection titleSection)
|
||||
{
|
||||
if (_binders == null)
|
||||
_binders = new Dictionary<int, Mhw2EventBinder>();
|
||||
|
||||
foreach (MediaHighway2TitleData titleData in titleSection.Titles)
|
||||
{
|
||||
Mhw2EventBinder currentBinder;
|
||||
if (_binders.ContainsKey(titleData.EventID))
|
||||
{
|
||||
currentBinder = _binders[titleData.EventID];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBinder = new Mhw2EventBinder(titleData.EventID);
|
||||
_binders.Add(titleData.EventID, currentBinder);
|
||||
}
|
||||
|
||||
if (!currentBinder.TitleDataSeen)
|
||||
{
|
||||
currentBinder.EventName = titleData.EventName;
|
||||
currentBinder.CategoryID = titleData.CategoryID;
|
||||
currentBinder.ChannelID = titleData.ChannelID;
|
||||
currentBinder.Duration = titleData.Duration;
|
||||
currentBinder.MainCategory = titleData.MainCategory;
|
||||
currentBinder.StartTime = titleData.StartTime;
|
||||
currentBinder.SubCategory = titleData.SubCategory;
|
||||
currentBinder.TitleDataSeen = true;
|
||||
}
|
||||
|
||||
if (IsBinderComplete(currentBinder))
|
||||
{
|
||||
StoreBinder(currentBinder);
|
||||
_binders.Remove(titleData.EventID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnMhw2Summary(int sourcePid, MediaHighway2SummarySection summarySection)
|
||||
{
|
||||
if (_binders == null)
|
||||
_binders = new Dictionary<int, Mhw2EventBinder>();
|
||||
|
||||
Mhw2EventBinder currentBinder;
|
||||
if (_binders.ContainsKey(summarySection.SummaryData.EventID))
|
||||
{
|
||||
currentBinder = _binders[summarySection.SummaryData.EventID];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBinder = new Mhw2EventBinder(summarySection.SummaryData.EventID);
|
||||
_binders.Add(summarySection.SummaryData.EventID, currentBinder);
|
||||
}
|
||||
|
||||
currentBinder.ShortDescription = summarySection.SummaryData.ShortDescription;
|
||||
currentBinder.ShortDescriptionSeen = true;
|
||||
if (IsBinderComplete(currentBinder))
|
||||
{
|
||||
StoreBinder(currentBinder);
|
||||
_binders.Remove(summarySection.SummaryData.EventID);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<int,Mhw2EventBinder> _binders;
|
||||
private readonly PluginLogger _logger;
|
||||
|
||||
|
||||
private bool IsBinderComplete(Mhw2EventBinder binder)
|
||||
{
|
||||
if (!_skyscraperContext.CurrentNetworkId.HasValue)
|
||||
return false;
|
||||
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
|
||||
return false;
|
||||
if (!hasCategories)
|
||||
return false;
|
||||
if (!hasChannels)
|
||||
return false;
|
||||
if (!binder.ShortDescriptionSeen)
|
||||
return false;
|
||||
if (!binder.TitleDataSeen)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void StoreBinder(Mhw2EventBinder binder)
|
||||
{
|
||||
if (!storage.TestForEvent(_skyscraperContext.CurrentNetworkId.Value, _skyscraperContext.CurrentTransportStreamId.Value, binder))
|
||||
{
|
||||
_logger.Log(PluginLogLevel.Info, "Event: {0}", binder.EventName);
|
||||
storage.InsertEvent(_skyscraperContext.CurrentNetworkId.Value, _skyscraperContext.CurrentTransportStreamId.Value, binder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,297 @@
|
||||
using DVBServices;
|
||||
using skyscraper5.Data.PostgreSql;
|
||||
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
|
||||
using skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Npgsql;
|
||||
using NpgsqlTypes;
|
||||
|
||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2
|
||||
{
|
||||
internal interface IMhw2Storage
|
||||
{
|
||||
void InsertCategories(int networkId, int transportStreamId, MediaHighway2CategorySection categorySection);
|
||||
void InsertChannels(int networkId, int transportStreamId, MediaHighway2ChannelSection channelSection);
|
||||
bool TestForEvent(int networkId, int transportStreamId, Mhw2EventBinder binder);
|
||||
void InsertEvent(int networkId, int transportStreamId, Mhw2EventBinder binder);
|
||||
}
|
||||
internal class Mhw2StorageImpl : IMhw2Storage
|
||||
{
|
||||
private readonly IMhw2Storage _storageEngine;
|
||||
|
||||
public Mhw2StorageImpl(object[] getPluginConnector)
|
||||
{
|
||||
object o = getPluginConnector[0];
|
||||
switch (o)
|
||||
{
|
||||
case InMemoryPluginToken t1:
|
||||
_storageEngine = new Mhw2StorageInMemory();
|
||||
break;
|
||||
case PostgresqlToken t2:
|
||||
_storageEngine = new Mhw2StoragePostgresql(t2);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(o.GetType().FullName);
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertCategories(int networkId, int transportStreamId, MediaHighway2CategorySection categorySection)
|
||||
{
|
||||
_storageEngine.InsertCategories(networkId, transportStreamId, categorySection);
|
||||
}
|
||||
|
||||
public void InsertChannels(int networkId, int transportStreamId, MediaHighway2ChannelSection channelSection)
|
||||
{
|
||||
_storageEngine.InsertChannels(networkId, transportStreamId, channelSection);
|
||||
}
|
||||
|
||||
public bool TestForEvent(int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
return _storageEngine.TestForEvent(networkId, transportStreamId, binder);
|
||||
}
|
||||
|
||||
public void InsertEvent(int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
_storageEngine.InsertEvent(networkId, transportStreamId, binder);
|
||||
}
|
||||
}
|
||||
|
||||
internal class Mhw2StorageInMemory : IMhw2Storage
|
||||
{
|
||||
private Dictionary<Tuple<int, int>, MediaHighway2CategorySection> _categories;
|
||||
public void InsertCategories(int networkId, int transportStreamId, MediaHighway2CategorySection categorySection)
|
||||
{
|
||||
if (_categories == null)
|
||||
_categories = new Dictionary<Tuple<int, int>, MediaHighway2CategorySection>();
|
||||
|
||||
Tuple<int, int> x = new Tuple<int, int>(networkId, transportStreamId);
|
||||
if (!_categories.ContainsKey(x))
|
||||
{
|
||||
_categories.Add(x, categorySection);
|
||||
}
|
||||
}
|
||||
|
||||
private Dictionary<Tuple<int, int>, MediaHighway2ChannelSection> _channels;
|
||||
public void InsertChannels(int networkId, int transportStreamId, MediaHighway2ChannelSection channelSection)
|
||||
{
|
||||
if (_channels == null)
|
||||
_channels = new Dictionary<Tuple<int, int>, MediaHighway2ChannelSection>();
|
||||
|
||||
Tuple<int, int> x = new Tuple<int, int>(networkId, transportStreamId);
|
||||
if (!_categories.ContainsKey(x))
|
||||
{
|
||||
_channels.Add(x, channelSection);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Dictionary<Tuple<int, int, int, DateTime>, Mhw2EventBinder> _events;
|
||||
public bool TestForEvent(int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
if (_events == null)
|
||||
return false;
|
||||
|
||||
Tuple<int, int, int, DateTime> coordinates = new Tuple<int, int, int, DateTime>(networkId, transportStreamId, binder.EventId, binder.StartTime);
|
||||
return _events.ContainsKey(coordinates);
|
||||
}
|
||||
|
||||
public void InsertEvent(int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
if (_events == null)
|
||||
_events = new Dictionary<Tuple<int, int, int, DateTime>, Mhw2EventBinder>();
|
||||
|
||||
|
||||
Tuple<int, int, int, DateTime> coordinates = new Tuple<int, int, int, DateTime>(networkId, transportStreamId, binder.EventId, binder.StartTime);
|
||||
if (!_events.ContainsKey(coordinates))
|
||||
{
|
||||
_events.Add(coordinates, binder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class Mhw2StoragePostgresql : IMhw2Storage
|
||||
{
|
||||
private readonly PostgresqlToken _postgresqlToken;
|
||||
|
||||
public Mhw2StoragePostgresql(PostgresqlToken postgresqlToken)
|
||||
{
|
||||
_postgresqlToken = postgresqlToken;
|
||||
}
|
||||
|
||||
private HashSet<Tuple<int, int, int>> _knownCategories;
|
||||
public void InsertCategories(int networkId, int transportStreamId, MediaHighway2CategorySection categorySection)
|
||||
{
|
||||
if (_knownCategories == null)
|
||||
_knownCategories = new HashSet<Tuple<int, int, int>>();
|
||||
|
||||
foreach (MediaHighwayCategoryEntry category in categorySection.Categories)
|
||||
{
|
||||
Tuple<int, int, int> coordinate = new Tuple<int, int, int>(networkId, transportStreamId, category.Number);
|
||||
if (!_knownCategories.Contains(coordinate))
|
||||
{
|
||||
_postgresqlToken.EnqueueTask(x => InsertCategory(x,networkId, transportStreamId, category));
|
||||
_knownCategories.Add(coordinate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<Tuple<int, int, int, int, int>> _knownChannels;
|
||||
public void InsertChannels(int networkId, int transportStreamId, MediaHighway2ChannelSection channelSection)
|
||||
{
|
||||
if (channelSection == null)
|
||||
return;
|
||||
|
||||
if (_knownChannels == null)
|
||||
_knownChannels = new HashSet<Tuple<int, int, int, int, int>>();
|
||||
|
||||
foreach (MediaHighwayChannelInfoEntry channel in channelSection.Channels)
|
||||
{
|
||||
Tuple<int, int, int, int, int> coordinate = new Tuple<int, int, int, int, int>(networkId, transportStreamId, channel.OriginalNetworkID, channel.TransportStreamID, channel.ServiceID);
|
||||
if (!_knownChannels.Contains(coordinate))
|
||||
{
|
||||
_postgresqlToken.EnqueueTask(x => InsertChannel(x, networkId, transportStreamId, channel));
|
||||
_knownChannels.Add(coordinate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private HashSet<Tuple<int, int, int, DateTime>> _knownEvents;
|
||||
|
||||
public bool TestForEvent(int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
if (_knownEvents == null)
|
||||
_knownEvents = new HashSet<Tuple<int, int, int, DateTime>>();
|
||||
|
||||
Tuple<int, int, int, DateTime> coordinates = new Tuple<int, int, int, DateTime>(networkId, transportStreamId, binder.EventId, binder.StartTime);
|
||||
if (_knownEvents.Contains(coordinates))
|
||||
return true;
|
||||
|
||||
NpgsqlConnection connection = _postgresqlToken.GetConnection();
|
||||
connection.Open();
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT dateadded FROM mediahighway2_events WHERE nid = @nid AND tsid = @tsid AND eid = @eid AND start_time = @stime";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, networkId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, transportStreamId);
|
||||
command.Parameters.AddWithValue("@eid", NpgsqlDbType.Integer, binder.EventId);
|
||||
command.Parameters.AddWithValue("@stime", NpgsqlDbType.Timestamp, binder.StartTime);
|
||||
NpgsqlDataReader dataReader = command.ExecuteReader();
|
||||
bool result = dataReader.Read();
|
||||
if (result)
|
||||
{
|
||||
_knownEvents.Add(coordinates);
|
||||
}
|
||||
dataReader.Close();
|
||||
command.Dispose();
|
||||
connection.Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
public void InsertEvent(int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
_postgresqlToken.EnqueueTask(x => InsertEventEx(x, networkId, transportStreamId, binder));
|
||||
Tuple<int, int, int, DateTime> coordinates = new Tuple<int, int, int, DateTime>(networkId, transportStreamId, binder.EventId, binder.StartTime);
|
||||
_knownEvents.Add(coordinates);
|
||||
}
|
||||
|
||||
private void InsertEventEx(NpgsqlConnection connection, int networkId, int transportStreamId, Mhw2EventBinder binder)
|
||||
{
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText =
|
||||
"INSERT INTO mediahighway2_events VALUES (@nid,@tsid,@eid,@stime,DEFAULT,@ename,@category,@channel,@duration,@mcategory,@scategory,@description)";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, networkId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, transportStreamId);
|
||||
command.Parameters.AddWithValue("@eid", NpgsqlDbType.Integer, binder.EventId);
|
||||
command.Parameters.AddWithValue("@stime", NpgsqlDbType.Timestamp, binder.StartTime);
|
||||
command.Parameters.AddWithValue("@ename", NpgsqlDbType.Text, SanitizeString(binder.EventName));
|
||||
command.Parameters.AddWithValue("@category", NpgsqlDbType.Integer, binder.CategoryID);
|
||||
command.Parameters.AddWithValue("@channel", NpgsqlDbType.Integer, binder.ChannelID);
|
||||
command.Parameters.AddWithValue("@duration", NpgsqlDbType.Integer, Convert.ToInt32(binder.Duration.TotalSeconds));
|
||||
command.Parameters.AddWithValue("@mcategory", NpgsqlDbType.Integer, binder.MainCategory);
|
||||
command.Parameters.AddWithValue("@scategory", NpgsqlDbType.Integer, binder.SubCategory);
|
||||
command.Parameters.AddWithValue("@description", NpgsqlDbType.Text, binder.ShortDescription);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private string SanitizeString(string ename)
|
||||
{
|
||||
if (ename.Contains("\0"))
|
||||
{
|
||||
int indexOf = ename.IndexOf("\0");
|
||||
ename = ename.Substring(0, indexOf);
|
||||
return ename;
|
||||
}
|
||||
|
||||
return ename;
|
||||
}
|
||||
|
||||
|
||||
private void InsertChannel(NpgsqlConnection connection, int networkId, int transportStreamId, MediaHighwayChannelInfoEntry channel)
|
||||
{
|
||||
if (TestChannel(connection, networkId, transportStreamId, channel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText = "INSERT INTO mediahighway2_channels VALUES (@snid,@stsid,@tonid,@ttsid,@tsid,@name,DEFAULT)";
|
||||
command.Parameters.AddWithValue("@snid", NpgsqlDbType.Integer, networkId);
|
||||
command.Parameters.AddWithValue("@stsid", NpgsqlDbType.Integer, transportStreamId);
|
||||
command.Parameters.AddWithValue("@tonid", NpgsqlDbType.Integer, channel.OriginalNetworkID);
|
||||
command.Parameters.AddWithValue("@ttsid", NpgsqlDbType.Integer, channel.TransportStreamID);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, channel.ServiceID);
|
||||
command.Parameters.AddWithValue("@name", NpgsqlDbType.Text, channel.Name);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private bool TestChannel(NpgsqlConnection connection, int networkId, int transportStreamId, MediaHighwayChannelInfoEntry channel)
|
||||
{
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT dateadded FROM mediahighway2_channels WHERE src_nid = @snid AND src_tsid = @stsid AND tgt_onid = @tonid AND tgt_tsid = @ttsid AND tgt_sid = @tsid";
|
||||
command.Parameters.AddWithValue("@snid", NpgsqlDbType.Integer, networkId);
|
||||
command.Parameters.AddWithValue("@stsid", NpgsqlDbType.Integer, transportStreamId);
|
||||
command.Parameters.AddWithValue("@tonid", NpgsqlDbType.Integer, channel.OriginalNetworkID);
|
||||
command.Parameters.AddWithValue("@ttsid", NpgsqlDbType.Integer, channel.TransportStreamID);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, channel.ServiceID);
|
||||
NpgsqlDataReader dataReader = command.ExecuteReader();
|
||||
bool result = dataReader.Read();
|
||||
dataReader.Close();
|
||||
command.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void InsertCategory(NpgsqlConnection connection, int networkId, int transportStreamId, MediaHighwayCategoryEntry category)
|
||||
{
|
||||
if (TestCategory(connection, networkId, transportStreamId, category))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText = "INSERT INTO mediahighway2_categories VALUES (@nid,@tsid,@number,@description,DEFAULT)";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, networkId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, transportStreamId);
|
||||
command.Parameters.AddWithValue("@number", NpgsqlDbType.Integer, category.Number);
|
||||
command.Parameters.AddWithValue("@description", NpgsqlDbType.Text, category.Description);
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
private bool TestCategory(NpgsqlConnection connection, int networkId, int transportStreamId, MediaHighwayCategoryEntry category)
|
||||
{
|
||||
NpgsqlCommand command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT dateadded FROM mediahighway2_categories WHERE nid = @nid AND tsid = @tsid AND number = @number";
|
||||
command.Parameters.AddWithValue("@nid", NpgsqlDbType.Integer, networkId);
|
||||
command.Parameters.AddWithValue("@tsid", NpgsqlDbType.Integer, transportStreamId);
|
||||
command.Parameters.AddWithValue("@number", NpgsqlDbType.Integer, category.Number);
|
||||
NpgsqlDataReader dataReader = command.ExecuteReader();
|
||||
bool result = dataReader.Read();
|
||||
dataReader.Close();
|
||||
command.Dispose();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\DataTableStorages\skyscraper5.Data.PostgreSql\skyscraper5.Data.PostgreSql.csproj" />
|
||||
<ProjectReference Include="..\..\skyscraper8\skyscraper8.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ using skyscraper5.T2MI;
|
||||
using skyscraper5.src.Mpeg2.PacketFilter;
|
||||
using skyscraper8.Skyscraper.IO;
|
||||
using log4net;
|
||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||
using skyscraper8.Skyscraper.Scraper.Storage;
|
||||
|
||||
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")]
|
||||
@ -37,9 +38,15 @@ namespace skyscraper5
|
||||
{
|
||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||
|
||||
private static void IntegrationTest()
|
||||
{
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
logger.Info("Hello!");
|
||||
{
|
||||
IntegrationTest();
|
||||
|
||||
logger.Info("Hello!");
|
||||
ffmpegFrameGrabber.CanStart();
|
||||
logger.DebugFormat("Found {0}-bit Operating system.", Environment.Is64BitOperatingSystem ? 64 : 32);
|
||||
logger.DebugFormat("I'm a {0}-bit Process.", Environment.Is64BitProcess ? 64 : 32);
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"profiles": {
|
||||
"skyscraper8": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "\"Z:\\Freebies\\Datasets\\SkyscraperLibrarian\\DVB-S August 2024\\Astra28\\skyscraper_20240829_0651_0283E_10714_H_21999.ts\"",
|
||||
"commandLineArgs": "cscan-live tcp://tetsuro:6969",
|
||||
"remoteDebugEnabled": false
|
||||
},
|
||||
"Container (Dockerfile)": {
|
||||
|
||||
17
skyscraper8/Skyscraper/Plugins/ExperimentalPlugin.cs
Normal file
17
skyscraper8/Skyscraper/Plugins/ExperimentalPlugin.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.Skyscraper.Plugins
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
|
||||
public sealed class ExperimentalAttribute : Attribute
|
||||
{
|
||||
public ExperimentalAttribute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,10 +16,13 @@ namespace skyscraper8.Skyscraper.Plugins
|
||||
private PluginAppenderEx _finalOutput;
|
||||
protected override void Append(LoggingEvent loggingEvent)
|
||||
{
|
||||
object? messageObject = loggingEvent.MessageObject;
|
||||
if (messageObject == null)
|
||||
messageObject = "";
|
||||
PluginLogLevel mappedLevel = MapLevel(loggingEvent.Level);
|
||||
DateTime mappedTime = DateTime.Now;
|
||||
string mappedLoggerName = loggingEvent.LoggerName;
|
||||
string mappedMessage = loggingEvent.MessageObject.ToString();
|
||||
string mappedMessage = messageObject.ToString();
|
||||
_finalOutput.Log(mappedTime, mappedLevel, mappedLoggerName, mappedMessage);
|
||||
}
|
||||
|
||||
|
||||
@ -2698,5 +2698,10 @@ namespace skyscraper5.Skyscraper.Scraper
|
||||
return _pluginContexts;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPluginEvent()
|
||||
{
|
||||
lastEventTimestamp = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs
Normal file
73
skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs;
|
||||
using skyscraper8.DvbNip;
|
||||
using skyscraper8.Ietf.FLUTE;
|
||||
|
||||
namespace skyscraper8.Skyscraper.Scraper.Storage
|
||||
{
|
||||
internal class NullObjectStorage : ObjectStorage
|
||||
{
|
||||
public bool ObjectCarouselFileArrival(VfsFile vfsFile, int transportStreamId, int networkId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void DataCarouselModuleArrival(int currentNetworkId, int currentTransportStreamId, int elementaryPid,
|
||||
ushort moduleModuleId, byte moduleModuleVersion, Stream result)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsDsmCcModuleWanted(int currentNetworkId, int currentTransportStreamId, int elementaryPid, ushort moduleId,
|
||||
byte moduleVersion)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TestForFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber,
|
||||
int mappingStreamElementaryPid)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void StoreFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, ushort pid,
|
||||
byte[] imageData)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void WaitForCompletion()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void UiSetVersion(int version)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public object[] GetPluginConnector()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Ping()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool DvbNipTestForFile(string announcedFileContentLocation)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void DvbNipFileArrival(NipActualCarrierInformation carrier, FluteListener listener)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,7 +167,7 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection
|
||||
if (Scoreboard[i].Score <= -10)
|
||||
{
|
||||
//Console.WriteLine("PID 0x{0:X4} is probably not for {1}", Pid, Scoreboard[i].GetType().Name);
|
||||
EventHandler.AutodetectionRuleOut(Pid, Scoreboard[i], ProgramContext);
|
||||
//EventHandler.AutodetectionRuleOut(Pid, Scoreboard[i], ProgramContext);
|
||||
Scoreboard[i] = new DisqualifiedContestant(Scoreboard[i].Pid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace skyscraper5.Skyscraper.Scraper.Utils
|
||||
{
|
||||
class PacketDiscarder : ITsPacketProcessor
|
||||
public class PacketDiscarder : ITsPacketProcessor
|
||||
{
|
||||
public void PushPacket(TsPacket packet)
|
||||
{
|
||||
|
||||
@ -14,6 +14,7 @@ namespace skyscraper5.Skyscraper.Text
|
||||
{
|
||||
case 0x00: resultBuilder.Append('\0'); break; //Null
|
||||
case 0x01: break; //Start of Header?
|
||||
case 0x02: break; //Start of text
|
||||
case 0x03: break; //End of text
|
||||
case 0x04: break; //End of transmission? Sure doesn't look like it.
|
||||
case 0x05: break; //Enquiry?
|
||||
@ -25,6 +26,7 @@ namespace skyscraper5.Skyscraper.Text
|
||||
case 0x0b: resultBuilder.Append('\v'); break; //Vertical Tab
|
||||
case 0x0c: resultBuilder.Append('\f'); break; //Form Feed
|
||||
case 0x0d: resultBuilder.Append('\r'); break; //Carriage Return
|
||||
case 0x0e: break; //Shift Out?
|
||||
case 0x0f: break; //Shift in?
|
||||
case 0x10: break; //Data Link Escape?
|
||||
case 0x11: break; // XON / XOFF
|
||||
|
||||
33
skyscraper8/Skyscraper/Text/Encodings/dvb-big5.cs
Normal file
33
skyscraper8/Skyscraper/Text/Encodings/dvb-big5.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using skyscraper5.Skyscraper.Text;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
|
||||
namespace skyscraper8.Skyscraper.Text.Encodings
|
||||
{
|
||||
[SkyscraperEncoding("dvb-big5")]
|
||||
internal class dvb_big5 : SkyscraperBaseEncoding16
|
||||
{
|
||||
protected override char[] Decrypt(byte[] preprocessed)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
MemoryStream ms = new MemoryStream(preprocessed, false);
|
||||
while (ms.Position < ms.Length)
|
||||
{
|
||||
byte leadByte = ms.ReadUInt8();
|
||||
if (leadByte <= 0x7e)
|
||||
{
|
||||
AsciiTable.GetAsciiChar(leadByte, sb);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
return sb.ToString().ToCharArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,8 +6,8 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
{
|
||||
[SkyscraperEncoding("dvb-iso-8859-10")]
|
||||
class dvb_iso_8859_10 : SkyscraperBaseEncoding8
|
||||
[SkyscraperEncoding("dvb-iso-8859-11")]
|
||||
class dvb_iso_8859_11 : SkyscraperBaseEncoding8
|
||||
{
|
||||
protected override char[] Decrypt(byte[] preprocessed)
|
||||
{
|
||||
@ -21,60 +21,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
}
|
||||
switch (preprocessed[i])
|
||||
{
|
||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
||||
case 0xa9: resultBuilder.Append('Đ'); break;
|
||||
case 0xaa: resultBuilder.Append('Š'); break;
|
||||
case 0xac: resultBuilder.Append('Ž'); break;
|
||||
case 0xae: resultBuilder.Append('Ū'); break;
|
||||
case 0xb0: resultBuilder.Append('°'); break;
|
||||
case 0xb1: resultBuilder.Append('ą'); break;
|
||||
case 0xb9: resultBuilder.Append('đ'); break;
|
||||
case 0xba: resultBuilder.Append('š'); break;
|
||||
case 0xbc: resultBuilder.Append('ž'); break;
|
||||
case 0xbe: resultBuilder.Append('ū'); break;
|
||||
case 0xc1: resultBuilder.Append('Á'); break;
|
||||
case 0xc2: resultBuilder.Append('Â'); break;
|
||||
case 0xc4: resultBuilder.Append('Ä'); break;
|
||||
case 0xc5: resultBuilder.Append('Å'); break;
|
||||
case 0xc6: resultBuilder.Append('Æ'); break;
|
||||
case 0xc8: resultBuilder.Append('Č'); break;
|
||||
case 0xc9: resultBuilder.Append('É'); break;
|
||||
case 0xcd: resultBuilder.Append('Í'); break;
|
||||
case 0xcf: resultBuilder.Append('Ï'); break;
|
||||
case 0xd0: resultBuilder.Append('Ð'); break;
|
||||
case 0xd3: resultBuilder.Append('Ó'); break;
|
||||
case 0xd6: resultBuilder.Append('Ö'); break;
|
||||
case 0xda: resultBuilder.Append('Ú'); break;
|
||||
case 0xdc: resultBuilder.Append('Ü'); break;
|
||||
case 0xdd: resultBuilder.Append('Ý'); break;
|
||||
case 0xdf: resultBuilder.Append('ß'); break;
|
||||
case 0xe0: resultBuilder.Append('ā'); break;
|
||||
case 0xe1: resultBuilder.Append('á'); break;
|
||||
case 0xe2: resultBuilder.Append('â'); break;
|
||||
case 0xe3: resultBuilder.Append('ã'); break;
|
||||
case 0xe4: resultBuilder.Append('ä'); break;
|
||||
case 0xe5: resultBuilder.Append('å'); break;
|
||||
case 0xe6: resultBuilder.Append('æ'); break;
|
||||
case 0xe8: resultBuilder.Append('č'); break;
|
||||
case 0xe9: resultBuilder.Append('é'); break;
|
||||
case 0xea: resultBuilder.Append('ę'); break;
|
||||
case 0xeb: resultBuilder.Append('ë'); break;
|
||||
case 0xed: resultBuilder.Append('í'); break;
|
||||
case 0xee: resultBuilder.Append('î'); break;
|
||||
case 0xef: resultBuilder.Append('ï'); break;
|
||||
case 0xf0: resultBuilder.Append('ð'); break;
|
||||
case 0xf1: resultBuilder.Append('ņ'); break;
|
||||
case 0xf2: resultBuilder.Append('ō'); break;
|
||||
case 0xf3: resultBuilder.Append('ó'); break;
|
||||
case 0xf4: resultBuilder.Append('ô'); break;
|
||||
case 0xf5: resultBuilder.Append('õ'); break;
|
||||
case 0xf6: resultBuilder.Append('ö'); break;
|
||||
case 0xf8: resultBuilder.Append('ø'); break;
|
||||
case 0xfa: resultBuilder.Append('ú'); break;
|
||||
case 0xfb: resultBuilder.Append('û'); break;
|
||||
case 0xfd: resultBuilder.Append('ý'); break;
|
||||
case 0xfc: resultBuilder.Append('ü'); break;
|
||||
default:
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i]));
|
||||
}
|
||||
}
|
||||
|
||||
86
skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-11.cs
Normal file
86
skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-11.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
{
|
||||
[SkyscraperEncoding("dvb-iso-8859-10")]
|
||||
class dvb_iso_8859_10 : SkyscraperBaseEncoding8
|
||||
{
|
||||
protected override char[] Decrypt(byte[] preprocessed)
|
||||
{
|
||||
StringBuilder resultBuilder = new StringBuilder();
|
||||
for (int i = 0; i < preprocessed.Length; i++)
|
||||
{
|
||||
if (preprocessed[i] <= 0x7e)
|
||||
{
|
||||
AsciiTable.GetAsciiChar(preprocessed[i], resultBuilder);
|
||||
continue;
|
||||
}
|
||||
switch (preprocessed[i])
|
||||
{
|
||||
case 0x7f: break;
|
||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
||||
case 0xa9: resultBuilder.Append('Đ'); break;
|
||||
case 0xaa: resultBuilder.Append('Š'); break;
|
||||
case 0xac: resultBuilder.Append('Ž'); break;
|
||||
case 0xae: resultBuilder.Append('Ū'); break;
|
||||
case 0xb0: resultBuilder.Append('°'); break;
|
||||
case 0xb1: resultBuilder.Append('ą'); break;
|
||||
case 0xb9: resultBuilder.Append('đ'); break;
|
||||
case 0xba: resultBuilder.Append('š'); break;
|
||||
case 0xbc: resultBuilder.Append('ž'); break;
|
||||
case 0xbe: resultBuilder.Append('ū'); break;
|
||||
case 0xc1: resultBuilder.Append('Á'); break;
|
||||
case 0xc2: resultBuilder.Append('Â'); break;
|
||||
case 0xc4: resultBuilder.Append('Ä'); break;
|
||||
case 0xc5: resultBuilder.Append('Å'); break;
|
||||
case 0xc6: resultBuilder.Append('Æ'); break;
|
||||
case 0xc8: resultBuilder.Append('Č'); break;
|
||||
case 0xc9: resultBuilder.Append('É'); break;
|
||||
case 0xcd: resultBuilder.Append('Í'); break;
|
||||
case 0xcf: resultBuilder.Append('Ï'); break;
|
||||
case 0xd0: resultBuilder.Append('Ð'); break;
|
||||
case 0xd3: resultBuilder.Append('Ó'); break;
|
||||
case 0xd6: resultBuilder.Append('Ö'); break;
|
||||
case 0xda: resultBuilder.Append('Ú'); break;
|
||||
case 0xdc: resultBuilder.Append('Ü'); break;
|
||||
case 0xdd: resultBuilder.Append('Ý'); break;
|
||||
case 0xdf: resultBuilder.Append('ß'); break;
|
||||
case 0xe0: resultBuilder.Append('ā'); break;
|
||||
case 0xe1: resultBuilder.Append('á'); break;
|
||||
case 0xe2: resultBuilder.Append('â'); break;
|
||||
case 0xe3: resultBuilder.Append('ã'); break;
|
||||
case 0xe4: resultBuilder.Append('ä'); break;
|
||||
case 0xe5: resultBuilder.Append('å'); break;
|
||||
case 0xe6: resultBuilder.Append('æ'); break;
|
||||
case 0xe8: resultBuilder.Append('č'); break;
|
||||
case 0xe9: resultBuilder.Append('é'); break;
|
||||
case 0xea: resultBuilder.Append('ę'); break;
|
||||
case 0xeb: resultBuilder.Append('ë'); break;
|
||||
case 0xed: resultBuilder.Append('í'); break;
|
||||
case 0xee: resultBuilder.Append('î'); break;
|
||||
case 0xef: resultBuilder.Append('ï'); break;
|
||||
case 0xf0: resultBuilder.Append('ð'); break;
|
||||
case 0xf1: resultBuilder.Append('ņ'); break;
|
||||
case 0xf2: resultBuilder.Append('ō'); break;
|
||||
case 0xf3: resultBuilder.Append('ó'); break;
|
||||
case 0xf4: resultBuilder.Append('ô'); break;
|
||||
case 0xf5: resultBuilder.Append('õ'); break;
|
||||
case 0xf6: resultBuilder.Append('ö'); break;
|
||||
case 0xf8: resultBuilder.Append('ø'); break;
|
||||
case 0xfa: resultBuilder.Append('ú'); break;
|
||||
case 0xfb: resultBuilder.Append('û'); break;
|
||||
case 0xfd: resultBuilder.Append('ý'); break;
|
||||
case 0xfc: resultBuilder.Append('ü'); break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return resultBuilder.ToString().ToCharArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -25,21 +25,29 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0xa1: resultBuilder.Append('”'); break;
|
||||
case 0xa3: resultBuilder.Append('£'); break;
|
||||
case 0xa5: resultBuilder.Append('„'); break;
|
||||
case 0xa7: resultBuilder.Append('§'); break;
|
||||
case 0xa8: resultBuilder.Append('Ø'); break;
|
||||
case 0xab: resultBuilder.Append('«'); break;
|
||||
case 0xac: resultBuilder.Append('¬'); break;
|
||||
case 0xad: resultBuilder.Append('\u00ad'); break;
|
||||
case 0xae: resultBuilder.Append('®'); break;
|
||||
case 0xb0: resultBuilder.Append('°'); break;
|
||||
case 0xb4: resultBuilder.Append('“'); break;
|
||||
case 0xb8: resultBuilder.Append('ø'); break;
|
||||
case 0xb9: resultBuilder.Append('¹'); break;
|
||||
case 0xbb: resultBuilder.Append('»'); break;
|
||||
case 0xbf: resultBuilder.Append('æ'); break;
|
||||
case 0xc3: resultBuilder.Append('Ć'); break;
|
||||
case 0xc4: resultBuilder.Append('Ä'); break;
|
||||
case 0xc5: resultBuilder.Append('Å'); break;
|
||||
case 0xc7: resultBuilder.Append('Ē'); break;
|
||||
case 0xc8: resultBuilder.Append('Č'); break;
|
||||
case 0xc9: resultBuilder.Append('É'); break;
|
||||
case 0xca: resultBuilder.Append('Ź'); break;
|
||||
case 0xce: resultBuilder.Append('Ī'); break;
|
||||
case 0xcf: resultBuilder.Append('Ļ'); break;
|
||||
case 0xd0: resultBuilder.Append('Š'); break;
|
||||
case 0xd1: resultBuilder.Append('Ń'); break;
|
||||
case 0xd3: resultBuilder.Append('Ó'); break;
|
||||
case 0xd6: resultBuilder.Append('Ö'); break;
|
||||
case 0xd9: resultBuilder.Append('Ł'); break;
|
||||
@ -58,6 +66,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0xe9: resultBuilder.Append('é'); break;
|
||||
case 0xea: resultBuilder.Append('ź'); break;
|
||||
case 0xeb: resultBuilder.Append('ė'); break;
|
||||
case 0xed: resultBuilder.Append('ķ'); break;
|
||||
case 0xee: resultBuilder.Append('ī'); break;
|
||||
case 0xf0: resultBuilder.Append('š'); break;
|
||||
case 0xf1: resultBuilder.Append('ń'); break;
|
||||
|
||||
@ -22,20 +22,38 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
switch (preprocessed[i])
|
||||
{
|
||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
||||
case 0xa1: resultBuilder.Append('Ḃ'); break;
|
||||
case 0xaf: resultBuilder.Append('Ÿ'); break;
|
||||
case 0xa3: resultBuilder.Append('£'); break;
|
||||
case 0xb4: resultBuilder.Append('Ṁ'); break;
|
||||
case 0xb5: resultBuilder.Append('ṁ'); break;
|
||||
case 0xb7: resultBuilder.Append('Ṗ'); break;
|
||||
case 0xb8: resultBuilder.Append('ẁ'); break;
|
||||
case 0xba: resultBuilder.Append('ẃ'); break;
|
||||
case 0xbd: resultBuilder.Append('Ẅ'); break;
|
||||
case 0xc1: resultBuilder.Append('Á'); break;
|
||||
case 0xc2: resultBuilder.Append('Â'); break;
|
||||
case 0xc3: resultBuilder.Append('Ã'); break;
|
||||
case 0xc7: resultBuilder.Append('Ç'); break;
|
||||
case 0xc8: resultBuilder.Append('È'); break;
|
||||
case 0xcb: resultBuilder.Append('Ë'); break;
|
||||
case 0xcf: resultBuilder.Append('Ï'); break;
|
||||
case 0xd2: resultBuilder.Append('Ò'); break;
|
||||
case 0xd6: resultBuilder.Append('Ö'); break;
|
||||
case 0xd8: resultBuilder.Append('Ø'); break;
|
||||
case 0xd9: resultBuilder.Append('Ù'); break;
|
||||
case 0xda: resultBuilder.Append('Ú'); break;
|
||||
case 0xe0: resultBuilder.Append('à'); break;
|
||||
case 0xe1: resultBuilder.Append('á'); break;
|
||||
case 0xe3: resultBuilder.Append('ã'); break;
|
||||
case 0xe4: resultBuilder.Append('ä'); break;
|
||||
case 0xe7: resultBuilder.Append('ç'); break;
|
||||
case 0xe8: resultBuilder.Append('è'); break;
|
||||
case 0xe9: resultBuilder.Append('é'); break;
|
||||
case 0xea: resultBuilder.Append('ê'); break;
|
||||
case 0xed: resultBuilder.Append('í'); break;
|
||||
case 0xf0: resultBuilder.Append('ŵ'); break;
|
||||
case 0xf2: resultBuilder.Append('ò'); break;
|
||||
case 0xf3: resultBuilder.Append('ó'); break;
|
||||
case 0xfa: resultBuilder.Append('ú'); break;
|
||||
case 0xfc: resultBuilder.Append('ü'); break;
|
||||
|
||||
@ -92,6 +92,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0xf4: resultBuilder.Append('ô'); break;
|
||||
case 0xf5: resultBuilder.Append('õ'); break;
|
||||
case 0xf6: resultBuilder.Append('ö'); break;
|
||||
case 0xf7: resultBuilder.Append('÷'); break;
|
||||
case 0xf8: resultBuilder.Append('ø'); break;
|
||||
case 0xf9: resultBuilder.Append('ù'); break;
|
||||
case 0xfa: resultBuilder.Append('ú'); break;
|
||||
|
||||
@ -20,6 +20,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0x00: break; //Null
|
||||
case 0x0a: resultBuilder.Append('\n'); break;
|
||||
case 0x10: break; //Data Link Escape
|
||||
case 0x12: break; //Device Control 2
|
||||
case 0x13: break; //Device Control 3
|
||||
case 0x20: resultBuilder.Append(' '); break;
|
||||
case 0x21: resultBuilder.Append('!'); break;
|
||||
@ -104,6 +105,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0x7a: resultBuilder.Append('z'); arabMode = false; break;
|
||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
||||
case 0xac: resultBuilder.Append('،'); arabMode = true; break;
|
||||
case 0xb2: break;
|
||||
case 0xbb: resultBuilder.Append('؛'); arabMode = true; break;
|
||||
case 0xbf: resultBuilder.Append('؟'); arabMode = true; break;
|
||||
case 0xc1: resultBuilder.Append('ء'); arabMode = true; break;
|
||||
@ -132,6 +134,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0xd8: resultBuilder.Append('ظ'); arabMode = true; break;
|
||||
case 0xd9: resultBuilder.Append('ع'); arabMode = true; break;
|
||||
case 0xda: resultBuilder.Append('غ'); arabMode = true; break;
|
||||
case 0xdb: resultBuilder.Append('؛'); arabMode = true; break;
|
||||
case 0xe0: resultBuilder.Append('ـ'); arabMode = true; break;
|
||||
case 0xe1: resultBuilder.Append('ف'); arabMode = true; break;
|
||||
case 0xe2: resultBuilder.Append('ق'); arabMode = true; break;
|
||||
|
||||
@ -36,6 +36,9 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
||||
case 0xad: resultBuilder.Append('\u00ad'); break;
|
||||
case 0xae: resultBuilder.Append('®'); break;
|
||||
case 0xaf: resultBuilder.Append('¯'); break;
|
||||
case 0xcd: break;
|
||||
case 0xb4: resultBuilder.Append('´'); break;
|
||||
case 0xd0: break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i]));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user