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/bin/Debug/net8.0
|
||||||
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj/Debug/net8.0
|
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj/Debug/net8.0
|
||||||
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj
|
/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/obj
|
||||||
|
/.vs/skyscraper8/CopilotIndices/17.14.827.52834
|
||||||
|
|||||||
@ -178,7 +178,22 @@ namespace skyscraper5.Data.PostgreSql
|
|||||||
|
|
||||||
private void UpdateDvbNipPrivateDataSpecifier(NpgsqlConnection connection, Tuple<ushort, ushort, ushort, ushort, uint> coordinates, DateTime versionUpdate, List<string> privateDataSessions)
|
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;
|
private bool[] _dvbNipKnownNetworks;
|
||||||
|
|||||||
@ -182,7 +182,7 @@ namespace skyscraper5.Data.PostgreSql
|
|||||||
private void AddDvbiServiceToServiceList(NpgsqlConnection x, string id, string serviceListId)
|
private void AddDvbiServiceToServiceList(NpgsqlConnection x, string id, string serviceListId)
|
||||||
{
|
{
|
||||||
NpgsqlCommand checkCommand = x.CreateCommand();
|
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("@service", NpgsqlDbType.Text, id);
|
||||||
checkCommand.Parameters.AddWithValue("@servicelist", NpgsqlDbType.Text, serviceListId);
|
checkCommand.Parameters.AddWithValue("@servicelist", NpgsqlDbType.Text, serviceListId);
|
||||||
NpgsqlDataReader dataReader = checkCommand.ExecuteReader();
|
NpgsqlDataReader dataReader = checkCommand.ExecuteReader();
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace skyscraper5.Data.PostgreSql
|
|||||||
connectionStringBuilder = stringBuilder;
|
connectionStringBuilder = stringBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NpgsqlConnectionStringBuilder connectionStringBuilder;
|
internal NpgsqlConnectionStringBuilder connectionStringBuilder;
|
||||||
|
|
||||||
|
|
||||||
public bool TestForRelatedContent(EitEvent lEvent, RctLinkInfo rctLinkInfo)
|
public bool TestForRelatedContent(EitEvent lEvent, RctLinkInfo rctLinkInfo)
|
||||||
@ -158,9 +158,14 @@ namespace skyscraper5.Data.PostgreSql
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PostgresqlToken pluginToken;
|
||||||
public object[] GetPluginConnector()
|
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
|
namespace skyscraper5.Data.PostgreSql
|
||||||
{
|
{
|
||||||
public partial class PostgresqlDataStore
|
public delegate void WriterTask(NpgsqlConnection connection);
|
||||||
|
|
||||||
|
public partial class PostgresqlDataStore
|
||||||
{
|
{
|
||||||
private Thread _writerThread;
|
private Thread _writerThread;
|
||||||
|
|
||||||
private delegate void WriterTask(NpgsqlConnection connection);
|
|
||||||
|
|
||||||
private Queue<WriterTask> _writerTasks;
|
private Queue<WriterTask> _writerTasks;
|
||||||
|
|
||||||
private void EnqueueTask(WriterTask task)
|
internal void EnqueueTask(WriterTask task)
|
||||||
{
|
{
|
||||||
if (_writerTasks == null)
|
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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using skyscraper5.Skyscraper.Text;
|
||||||
|
|
||||||
namespace DVBServices
|
namespace DVBServices
|
||||||
{
|
{
|
||||||
@ -63,5 +66,77 @@ namespace DVBServices
|
|||||||
|
|
||||||
return ((char)('a' + (value - 10)));
|
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
|
private class EPGCollector
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -47,5 +55,90 @@ namespace DomainObjects
|
|||||||
Write("============================ " + identity + " ==============================");
|
Write("============================ " + identity + " ==============================");
|
||||||
Write("");
|
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.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||||
|
|
||||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||||
{
|
{
|
||||||
[SkyscraperPlugin]
|
[SkyscraperPlugin]
|
||||||
internal class FreesatBatSdtContestant : Contestant
|
internal class FreesatBatSdtContestant : Contestant
|
||||||
{
|
{
|
||||||
public FreesatBatSdtContestant(int pid) : base("Freesat BAT/SDT", pid)
|
public FreesatBatSdtContestant(int pid) : base("Freesat BAT/SDT", pid)
|
||||||
{
|
{
|
||||||
|
PacketProcessor = new PacketDiscarder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
@ -29,7 +31,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
if (freesatScraper == null)
|
if (freesatScraper == null)
|
||||||
{
|
{
|
||||||
freesatScraper = new FreesatTunnelScraper();
|
freesatScraper = new FreesatTunnelScraper();
|
||||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4,13 +4,14 @@ using skyscraper5.Mpeg2.Descriptors;
|
|||||||
using skyscraper5.Skyscraper.Plugins;
|
using skyscraper5.Skyscraper.Plugins;
|
||||||
using skyscraper5.Skyscraper.Scraper;
|
using skyscraper5.Skyscraper.Scraper;
|
||||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||||
|
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||||
{
|
{
|
||||||
[SkyscraperPlugin]
|
[SkyscraperPlugin]
|
||||||
internal class FreesatEpgContestant : Contestant
|
internal class FreesatEpgContestant : Contestant
|
||||||
@ -18,6 +19,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
public FreesatEpgContestant(int pid)
|
public FreesatEpgContestant(int pid)
|
||||||
: base("Freesat EPG", pid)
|
: base("Freesat EPG", pid)
|
||||||
{
|
{
|
||||||
|
PacketProcessor = new PacketDiscarder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
@ -30,7 +32,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
if (freesatScraper == null)
|
if (freesatScraper == null)
|
||||||
{
|
{
|
||||||
freesatScraper = new FreesatTunnelScraper();
|
freesatScraper = new FreesatTunnelScraper();
|
||||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4,13 +4,14 @@ using skyscraper5.Mpeg2.Descriptors;
|
|||||||
using skyscraper5.Skyscraper.Plugins;
|
using skyscraper5.Skyscraper.Plugins;
|
||||||
using skyscraper5.Skyscraper.Scraper;
|
using skyscraper5.Skyscraper.Scraper;
|
||||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||||
|
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||||
{
|
{
|
||||||
[SkyscraperPlugin]
|
[SkyscraperPlugin]
|
||||||
internal class FreesatNitContestant : Contestant
|
internal class FreesatNitContestant : Contestant
|
||||||
@ -18,6 +19,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
public FreesatNitContestant(int pid)
|
public FreesatNitContestant(int pid)
|
||||||
: base("Freesat Network Information", pid)
|
: base("Freesat Network Information", pid)
|
||||||
{
|
{
|
||||||
|
PacketProcessor = new PacketDiscarder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
@ -30,7 +32,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
if (freesatScraper == null)
|
if (freesatScraper == null)
|
||||||
{
|
{
|
||||||
freesatScraper = new FreesatTunnelScraper();
|
freesatScraper = new FreesatTunnelScraper();
|
||||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
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;
|
||||||
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||||
|
using skyscraper5.Skyscraper.Scraper.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
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]
|
[SkyscraperPlugin]
|
||||||
internal class FreesatTdtContestant : Contestant
|
internal class FreesatTdtContestant : Contestant
|
||||||
@ -18,6 +19,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
public FreesatTdtContestant(int pid)
|
public FreesatTdtContestant(int pid)
|
||||||
: base("Freesat Timestamp", pid)
|
: base("Freesat Timestamp", pid)
|
||||||
{
|
{
|
||||||
|
PacketProcessor = new PacketDiscarder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
@ -30,7 +32,7 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
if (freesatScraper == null)
|
if (freesatScraper == null)
|
||||||
{
|
{
|
||||||
freesatScraper = new FreesatTunnelScraper();
|
freesatScraper = new FreesatTunnelScraper();
|
||||||
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector());
|
freesatScraper.ConnectToStorage(skyscraperContext.DataStorage.GetPluginConnector(), skyscraperContext.OnPluginEvent);
|
||||||
skyscraperContext.PluginContext.Add(freesatScraper);
|
skyscraperContext.PluginContext.Add(freesatScraper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ using skyscraper5.Skyscraper.Plugins;
|
|||||||
using skyscraper8.EPGCollectorPort.Properties;
|
using skyscraper8.EPGCollectorPort.Properties;
|
||||||
using skyscraper8.Skyscraper.Text;
|
using skyscraper8.Skyscraper.Text;
|
||||||
|
|
||||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||||
{
|
{
|
||||||
[SkyscraperPlugin]
|
[SkyscraperPlugin]
|
||||||
[EncodingTypeId(0x01)]
|
[EncodingTypeId(0x01)]
|
||||||
@ -3,11 +3,12 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using skyscraper5.Data.PostgreSql;
|
||||||
using skyscraper5.Dvb.Psi.Model;
|
using skyscraper5.Dvb.Psi.Model;
|
||||||
using skyscraper5.Ietf.Rfc971;
|
using skyscraper5.Ietf.Rfc971;
|
||||||
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
|
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
|
||||||
|
|
||||||
namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||||
{
|
{
|
||||||
internal interface IFreesatTunnelDataStorage
|
internal interface IFreesatTunnelDataStorage
|
||||||
{
|
{
|
||||||
@ -28,6 +29,9 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide
|
|||||||
case InMemoryPluginToken t1:
|
case InMemoryPluginToken t1:
|
||||||
_storageEngine = new FreesatTunnelDataStorageInMemory();
|
_storageEngine = new FreesatTunnelDataStorageInMemory();
|
||||||
break;
|
break;
|
||||||
|
case PostgresqlToken t2:
|
||||||
|
_storageEngine = new FreesatTunnelDataStoragePostgresql(t2);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException(o.GetType().FullName);
|
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.Descriptors;
|
||||||
using skyscraper5.Dvb.Psi;
|
using skyscraper5.Dvb.Psi;
|
||||||
using skyscraper5.Dvb.Psi.Model;
|
using skyscraper5.Dvb.Psi.Model;
|
||||||
using skyscraper8.EPGCollectorPort.SkyscraperSide;
|
|
||||||
using skyscraper8.Skyscraper.Scraper.Storage;
|
using skyscraper8.Skyscraper.Scraper.Storage;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -10,7 +9,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using skyscraper8.Skyscraper.Plugins;
|
using skyscraper8.Skyscraper.Plugins;
|
||||||
|
|
||||||
namespace skyscraper5.Skyscraper.Scraper
|
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.Freesat
|
||||||
{
|
{
|
||||||
internal class FreesatTunnelScraper : IBatEventHandler, ISdtEventHandler, ITdtEventHandler, ITotEventHandler, IEitEventHandler, INitEventHandler
|
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);
|
_logger.Log(PluginLogLevel.Info, "NIT Network {0} Transport Stream {1}", networkId, transportStream.TransportStreamId);
|
||||||
_dataStorage.StoreNitTransportStream(networkId, transportStream);
|
_dataStorage.StoreNitTransportStream(networkId, transportStream);
|
||||||
}
|
_hostNotification.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnNitNetwork(NitNetwork nitNetwork)
|
public void OnNitNetwork(NitNetwork nitNetwork)
|
||||||
@ -81,7 +81,8 @@ namespace skyscraper5.Skyscraper.Scraper
|
|||||||
{
|
{
|
||||||
_logger.Log(PluginLogLevel.Info, "NIT Network {0}", nitNetwork.NetworkId);
|
_logger.Log(PluginLogLevel.Info, "NIT Network {0}", nitNetwork.NetworkId);
|
||||||
_dataStorage.StoreNitNetwork(nitNetwork);
|
_dataStorage.StoreNitNetwork(nitNetwork);
|
||||||
}
|
_hostNotification.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private EitEvent[] runningEvents;
|
private EitEvent[] runningEvents;
|
||||||
@ -90,26 +91,25 @@ namespace skyscraper5.Skyscraper.Scraper
|
|||||||
if (_dataStorage.StoreEitEvent(eitEvent))
|
if (_dataStorage.StoreEitEvent(eitEvent))
|
||||||
{
|
{
|
||||||
_logger.Log(PluginLogLevel.Info, "EIT Event: {0}", eitEvent.EventName);
|
_logger.Log(PluginLogLevel.Info, "EIT Event: {0}", eitEvent.EventName);
|
||||||
|
_hostNotification.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eitEvent.RunningStatus == RunningStatus.Running)
|
if (eitEvent.RunningStatus == RunningStatus.Running)
|
||||||
{
|
{
|
||||||
if (runningEvents == null)
|
if (runningEvents == null)
|
||||||
runningEvents = new EitEvent[UInt16.MaxValue];
|
runningEvents = new EitEvent[ushort.MaxValue];
|
||||||
runningEvents[eitEvent.ServiceId] = eitEvent;
|
runningEvents[eitEvent.ServiceId] = eitEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PluginLogger _logger;
|
private PluginLogger _logger;
|
||||||
private IFreesatTunnelDataStorage _dataStorage;
|
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(GetType());
|
||||||
_dataStorage = new FreesatTunnelDataStorage(getPluginConnector);
|
_hostNotification = onPluginEvent;
|
||||||
}
|
|
||||||
|
|
||||||
_logger = PluginLogManager.GetLogger(this.GetType());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\DataTableStorages\skyscraper5.Data.PostgreSql\skyscraper5.Data.PostgreSql.csproj" />
|
||||||
<ProjectReference Include="..\..\skyscraper8\skyscraper8.csproj" />
|
<ProjectReference Include="..\..\skyscraper8\skyscraper8.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -28,6 +28,7 @@ using skyscraper5.T2MI;
|
|||||||
using skyscraper5.src.Mpeg2.PacketFilter;
|
using skyscraper5.src.Mpeg2.PacketFilter;
|
||||||
using skyscraper8.Skyscraper.IO;
|
using skyscraper8.Skyscraper.IO;
|
||||||
using log4net;
|
using log4net;
|
||||||
|
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
|
||||||
using skyscraper8.Skyscraper.Scraper.Storage;
|
using skyscraper8.Skyscraper.Scraper.Storage;
|
||||||
|
|
||||||
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config")]
|
[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 readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||||
|
|
||||||
|
private static void IntegrationTest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
logger.Info("Hello!");
|
IntegrationTest();
|
||||||
|
|
||||||
|
logger.Info("Hello!");
|
||||||
ffmpegFrameGrabber.CanStart();
|
ffmpegFrameGrabber.CanStart();
|
||||||
logger.DebugFormat("Found {0}-bit Operating system.", Environment.Is64BitOperatingSystem ? 64 : 32);
|
logger.DebugFormat("Found {0}-bit Operating system.", Environment.Is64BitOperatingSystem ? 64 : 32);
|
||||||
logger.DebugFormat("I'm a {0}-bit Process.", Environment.Is64BitProcess ? 64 : 32);
|
logger.DebugFormat("I'm a {0}-bit Process.", Environment.Is64BitProcess ? 64 : 32);
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"skyscraper8": {
|
"skyscraper8": {
|
||||||
"commandName": "Project",
|
"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
|
"remoteDebugEnabled": false
|
||||||
},
|
},
|
||||||
"Container (Dockerfile)": {
|
"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;
|
private PluginAppenderEx _finalOutput;
|
||||||
protected override void Append(LoggingEvent loggingEvent)
|
protected override void Append(LoggingEvent loggingEvent)
|
||||||
{
|
{
|
||||||
|
object? messageObject = loggingEvent.MessageObject;
|
||||||
|
if (messageObject == null)
|
||||||
|
messageObject = "";
|
||||||
PluginLogLevel mappedLevel = MapLevel(loggingEvent.Level);
|
PluginLogLevel mappedLevel = MapLevel(loggingEvent.Level);
|
||||||
DateTime mappedTime = DateTime.Now;
|
DateTime mappedTime = DateTime.Now;
|
||||||
string mappedLoggerName = loggingEvent.LoggerName;
|
string mappedLoggerName = loggingEvent.LoggerName;
|
||||||
string mappedMessage = loggingEvent.MessageObject.ToString();
|
string mappedMessage = messageObject.ToString();
|
||||||
_finalOutput.Log(mappedTime, mappedLevel, mappedLoggerName, mappedMessage);
|
_finalOutput.Log(mappedTime, mappedLevel, mappedLoggerName, mappedMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2698,5 +2698,10 @@ namespace skyscraper5.Skyscraper.Scraper
|
|||||||
return _pluginContexts;
|
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)
|
if (Scoreboard[i].Score <= -10)
|
||||||
{
|
{
|
||||||
//Console.WriteLine("PID 0x{0:X4} is probably not for {1}", Pid, Scoreboard[i].GetType().Name);
|
//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);
|
Scoreboard[i] = new DisqualifiedContestant(Scoreboard[i].Pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace skyscraper5.Skyscraper.Scraper.Utils
|
namespace skyscraper5.Skyscraper.Scraper.Utils
|
||||||
{
|
{
|
||||||
class PacketDiscarder : ITsPacketProcessor
|
public class PacketDiscarder : ITsPacketProcessor
|
||||||
{
|
{
|
||||||
public void PushPacket(TsPacket packet)
|
public void PushPacket(TsPacket packet)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -14,6 +14,7 @@ namespace skyscraper5.Skyscraper.Text
|
|||||||
{
|
{
|
||||||
case 0x00: resultBuilder.Append('\0'); break; //Null
|
case 0x00: resultBuilder.Append('\0'); break; //Null
|
||||||
case 0x01: break; //Start of Header?
|
case 0x01: break; //Start of Header?
|
||||||
|
case 0x02: break; //Start of text
|
||||||
case 0x03: break; //End of text
|
case 0x03: break; //End of text
|
||||||
case 0x04: break; //End of transmission? Sure doesn't look like it.
|
case 0x04: break; //End of transmission? Sure doesn't look like it.
|
||||||
case 0x05: break; //Enquiry?
|
case 0x05: break; //Enquiry?
|
||||||
@ -25,6 +26,7 @@ namespace skyscraper5.Skyscraper.Text
|
|||||||
case 0x0b: resultBuilder.Append('\v'); break; //Vertical Tab
|
case 0x0b: resultBuilder.Append('\v'); break; //Vertical Tab
|
||||||
case 0x0c: resultBuilder.Append('\f'); break; //Form Feed
|
case 0x0c: resultBuilder.Append('\f'); break; //Form Feed
|
||||||
case 0x0d: resultBuilder.Append('\r'); break; //Carriage Return
|
case 0x0d: resultBuilder.Append('\r'); break; //Carriage Return
|
||||||
|
case 0x0e: break; //Shift Out?
|
||||||
case 0x0f: break; //Shift in?
|
case 0x0f: break; //Shift in?
|
||||||
case 0x10: break; //Data Link Escape?
|
case 0x10: break; //Data Link Escape?
|
||||||
case 0x11: break; // XON / XOFF
|
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
|
namespace skyscraper5.Skyscraper.Text.Encodings
|
||||||
{
|
{
|
||||||
[SkyscraperEncoding("dvb-iso-8859-10")]
|
[SkyscraperEncoding("dvb-iso-8859-11")]
|
||||||
class dvb_iso_8859_10 : SkyscraperBaseEncoding8
|
class dvb_iso_8859_11 : SkyscraperBaseEncoding8
|
||||||
{
|
{
|
||||||
protected override char[] Decrypt(byte[] preprocessed)
|
protected override char[] Decrypt(byte[] preprocessed)
|
||||||
{
|
{
|
||||||
@ -21,60 +21,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
|||||||
}
|
}
|
||||||
switch (preprocessed[i])
|
switch (preprocessed[i])
|
||||||
{
|
{
|
||||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
default:
|
||||||
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]));
|
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 0xa1: resultBuilder.Append('”'); break;
|
||||||
case 0xa3: resultBuilder.Append('£'); break;
|
case 0xa3: resultBuilder.Append('£'); break;
|
||||||
case 0xa5: resultBuilder.Append('„'); break;
|
case 0xa5: resultBuilder.Append('„'); break;
|
||||||
|
case 0xa7: resultBuilder.Append('§'); break;
|
||||||
case 0xa8: resultBuilder.Append('Ø'); break;
|
case 0xa8: resultBuilder.Append('Ø'); break;
|
||||||
case 0xab: resultBuilder.Append('«'); break;
|
case 0xab: resultBuilder.Append('«'); break;
|
||||||
|
case 0xac: resultBuilder.Append('¬'); break;
|
||||||
case 0xad: resultBuilder.Append('\u00ad'); break;
|
case 0xad: resultBuilder.Append('\u00ad'); break;
|
||||||
case 0xae: resultBuilder.Append('®'); break;
|
case 0xae: resultBuilder.Append('®'); break;
|
||||||
case 0xb0: resultBuilder.Append('°'); break;
|
case 0xb0: resultBuilder.Append('°'); break;
|
||||||
case 0xb4: resultBuilder.Append('“'); break;
|
case 0xb4: resultBuilder.Append('“'); break;
|
||||||
case 0xb8: resultBuilder.Append('ø'); break;
|
case 0xb8: resultBuilder.Append('ø'); break;
|
||||||
|
case 0xb9: resultBuilder.Append('¹'); break;
|
||||||
case 0xbb: resultBuilder.Append('»'); break;
|
case 0xbb: resultBuilder.Append('»'); break;
|
||||||
case 0xbf: resultBuilder.Append('æ'); break;
|
case 0xbf: resultBuilder.Append('æ'); break;
|
||||||
case 0xc3: resultBuilder.Append('Ć'); break;
|
case 0xc3: resultBuilder.Append('Ć'); break;
|
||||||
case 0xc4: resultBuilder.Append('Ä'); break;
|
case 0xc4: resultBuilder.Append('Ä'); break;
|
||||||
case 0xc5: resultBuilder.Append('Å'); break;
|
case 0xc5: resultBuilder.Append('Å'); break;
|
||||||
|
case 0xc7: resultBuilder.Append('Ē'); break;
|
||||||
case 0xc8: resultBuilder.Append('Č'); break;
|
case 0xc8: resultBuilder.Append('Č'); break;
|
||||||
case 0xc9: 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 0xd0: resultBuilder.Append('Š'); break;
|
||||||
|
case 0xd1: resultBuilder.Append('Ń'); break;
|
||||||
case 0xd3: resultBuilder.Append('Ó'); break;
|
case 0xd3: resultBuilder.Append('Ó'); break;
|
||||||
case 0xd6: resultBuilder.Append('Ö'); break;
|
case 0xd6: resultBuilder.Append('Ö'); break;
|
||||||
case 0xd9: resultBuilder.Append('Ł'); break;
|
case 0xd9: resultBuilder.Append('Ł'); break;
|
||||||
@ -58,6 +66,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
|||||||
case 0xe9: resultBuilder.Append('é'); break;
|
case 0xe9: resultBuilder.Append('é'); break;
|
||||||
case 0xea: resultBuilder.Append('ź'); break;
|
case 0xea: resultBuilder.Append('ź'); break;
|
||||||
case 0xeb: resultBuilder.Append('ė'); break;
|
case 0xeb: resultBuilder.Append('ė'); break;
|
||||||
|
case 0xed: resultBuilder.Append('ķ'); break;
|
||||||
case 0xee: resultBuilder.Append('ī'); break;
|
case 0xee: resultBuilder.Append('ī'); break;
|
||||||
case 0xf0: resultBuilder.Append('š'); break;
|
case 0xf0: resultBuilder.Append('š'); break;
|
||||||
case 0xf1: resultBuilder.Append('ń'); break;
|
case 0xf1: resultBuilder.Append('ń'); break;
|
||||||
|
|||||||
@ -22,20 +22,38 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
|||||||
switch (preprocessed[i])
|
switch (preprocessed[i])
|
||||||
{
|
{
|
||||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
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 0xc1: resultBuilder.Append('Á'); break;
|
||||||
case 0xc2: resultBuilder.Append('Â'); break;
|
case 0xc2: resultBuilder.Append('Â'); break;
|
||||||
case 0xc3: resultBuilder.Append('Ã'); break;
|
case 0xc3: resultBuilder.Append('Ã'); break;
|
||||||
case 0xc7: resultBuilder.Append('Ç'); break;
|
case 0xc7: resultBuilder.Append('Ç'); break;
|
||||||
case 0xc8: resultBuilder.Append('È'); break;
|
case 0xc8: resultBuilder.Append('È'); break;
|
||||||
|
case 0xcb: resultBuilder.Append('Ë'); break;
|
||||||
case 0xcf: resultBuilder.Append('Ï'); break;
|
case 0xcf: resultBuilder.Append('Ï'); break;
|
||||||
|
case 0xd2: resultBuilder.Append('Ò'); break;
|
||||||
case 0xd6: 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 0xe1: resultBuilder.Append('á'); break;
|
||||||
|
case 0xe3: resultBuilder.Append('ã'); break;
|
||||||
case 0xe4: resultBuilder.Append('ä'); break;
|
case 0xe4: resultBuilder.Append('ä'); break;
|
||||||
case 0xe7: resultBuilder.Append('ç'); break;
|
case 0xe7: resultBuilder.Append('ç'); break;
|
||||||
case 0xe8: resultBuilder.Append('è'); break;
|
case 0xe8: resultBuilder.Append('è'); break;
|
||||||
case 0xe9: resultBuilder.Append('é'); break;
|
case 0xe9: resultBuilder.Append('é'); break;
|
||||||
case 0xea: resultBuilder.Append('ê'); break;
|
case 0xea: resultBuilder.Append('ê'); break;
|
||||||
case 0xed: resultBuilder.Append('í'); break;
|
case 0xed: resultBuilder.Append('í'); break;
|
||||||
|
case 0xf0: resultBuilder.Append('ŵ'); break;
|
||||||
|
case 0xf2: resultBuilder.Append('ò'); break;
|
||||||
case 0xf3: resultBuilder.Append('ó'); break;
|
case 0xf3: resultBuilder.Append('ó'); break;
|
||||||
case 0xfa: resultBuilder.Append('ú'); break;
|
case 0xfa: resultBuilder.Append('ú'); break;
|
||||||
case 0xfc: resultBuilder.Append('ü'); break;
|
case 0xfc: resultBuilder.Append('ü'); break;
|
||||||
|
|||||||
@ -92,6 +92,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
|||||||
case 0xf4: resultBuilder.Append('ô'); break;
|
case 0xf4: resultBuilder.Append('ô'); break;
|
||||||
case 0xf5: resultBuilder.Append('õ'); break;
|
case 0xf5: resultBuilder.Append('õ'); break;
|
||||||
case 0xf6: resultBuilder.Append('ö'); break;
|
case 0xf6: resultBuilder.Append('ö'); break;
|
||||||
|
case 0xf7: resultBuilder.Append('÷'); break;
|
||||||
case 0xf8: resultBuilder.Append('ø'); break;
|
case 0xf8: resultBuilder.Append('ø'); break;
|
||||||
case 0xf9: resultBuilder.Append('ù'); break;
|
case 0xf9: resultBuilder.Append('ù'); break;
|
||||||
case 0xfa: resultBuilder.Append('ú'); break;
|
case 0xfa: resultBuilder.Append('ú'); break;
|
||||||
|
|||||||
@ -20,6 +20,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings
|
|||||||
case 0x00: break; //Null
|
case 0x00: break; //Null
|
||||||
case 0x0a: resultBuilder.Append('\n'); break;
|
case 0x0a: resultBuilder.Append('\n'); break;
|
||||||
case 0x10: break; //Data Link Escape
|
case 0x10: break; //Data Link Escape
|
||||||
|
case 0x12: break; //Device Control 2
|
||||||
case 0x13: break; //Device Control 3
|
case 0x13: break; //Device Control 3
|
||||||
case 0x20: resultBuilder.Append(' '); break;
|
case 0x20: resultBuilder.Append(' '); break;
|
||||||
case 0x21: 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 0x7a: resultBuilder.Append('z'); arabMode = false; break;
|
||||||
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
case 0xa0: resultBuilder.Append('\u00a0'); break;
|
||||||
case 0xac: resultBuilder.Append('،'); arabMode = true; break;
|
case 0xac: resultBuilder.Append('،'); arabMode = true; break;
|
||||||
|
case 0xb2: break;
|
||||||
case 0xbb: resultBuilder.Append('؛'); arabMode = true; break;
|
case 0xbb: resultBuilder.Append('؛'); arabMode = true; break;
|
||||||
case 0xbf: resultBuilder.Append('؟'); arabMode = true; break;
|
case 0xbf: resultBuilder.Append('؟'); arabMode = true; break;
|
||||||
case 0xc1: 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 0xd8: resultBuilder.Append('ظ'); arabMode = true; break;
|
||||||
case 0xd9: resultBuilder.Append('ع'); arabMode = true; break;
|
case 0xd9: resultBuilder.Append('ع'); arabMode = true; break;
|
||||||
case 0xda: 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 0xe0: resultBuilder.Append('ـ'); arabMode = true; break;
|
||||||
case 0xe1: resultBuilder.Append('ف'); arabMode = true; break;
|
case 0xe1: resultBuilder.Append('ف'); arabMode = true; break;
|
||||||
case 0xe2: 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 0xad: resultBuilder.Append('\u00ad'); break;
|
||||||
case 0xae: resultBuilder.Append('®'); break;
|
case 0xae: resultBuilder.Append('®'); break;
|
||||||
case 0xaf: resultBuilder.Append('¯'); break;
|
case 0xaf: resultBuilder.Append('¯'); break;
|
||||||
|
case 0xcd: break;
|
||||||
|
case 0xb4: resultBuilder.Append('´'); break;
|
||||||
|
case 0xd0: break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i]));
|
throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i]));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user