mirror of
https://github.com/Team-Resurgent/XBMC4Xbox.git
synced 2026-08-15 11:18:13 -07:00
If ever adding the XBMC4Xbox source to GitHub use "git add -f -A" or it wont add all the files.
1580 lines
51 KiB
C++
1580 lines
51 KiB
C++
#pragma code_seg( "RTV_TEXT" )
|
|
#pragma data_seg( "RTV_DATA" )
|
|
#pragma bss_seg( "RTV_BSS" )
|
|
#pragma const_seg( "RTV_RD" )
|
|
|
|
/*
|
|
** ReplayTV 5000
|
|
** Guide Parser
|
|
** by Lee Thompson <thompsonl@logh.net> Dan Frumin <rtv@frumin.com>, Todd Larason <jtl@molehill.org>
|
|
**
|
|
** 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.
|
|
**
|
|
** If you distribute a modified version of this program, the program MUST tell the user
|
|
** in the usage summary how the program has been modified, and who performed the modification.
|
|
** Modified source code MUST be distributed with the modified program.
|
|
**
|
|
** For additional detail on the Replay 4000/4500/5000 internals, protocols and structures I highly recommend
|
|
** visiting Todd's site: http://www.molehill.org/twiki/bin/view/Replay/WebHome
|
|
**
|
|
***************************************************************************************************************
|
|
**
|
|
** IMPORTANT NOTE: This is the last version of GuideParser with this codebase.
|
|
**
|
|
** GuideParser was originally just a research project to learn the Guide Snapshot format. This research
|
|
** phase is pretty much at a close and this code is very ugly.
|
|
**
|
|
** Others wishing to continue development of GuideParser with this code are welcome to do so under the above
|
|
** limitations.
|
|
**
|
|
***************************************************************************************************************
|
|
**
|
|
** Revision History:
|
|
**
|
|
** 1.02 - LT Updated for 5.0 Software
|
|
** 1.01 - LT ReplayTV 5000
|
|
** 1.0 - LT Final version with this codebase.
|
|
** Organized the structures a bit better.
|
|
** Fixed some annoying bugs.
|
|
** Added -combined option which does a mini replayChannel lookup, best used with -ls
|
|
** .11 - LT Whoops! ReplayChannel had the wrong number for szThemeInfo, should've been 64 not 60! (Thanks Clem!)
|
|
** Todd corrected a mis-assigned bitmask for TV rating "TV-G"
|
|
** Todd's been knocking himself out with research... as a result no more unknowns in tagProgramInfo!
|
|
** Added Genre lookups
|
|
** .10 - LT Works on FreeBSD now (thanks Andy!)
|
|
** Fixed a minor display bug.
|
|
** Supports MPAA "G" ratings.
|
|
** Added -d option for dumping unknowns as numbers.
|
|
** Added -x (Xtra) option for displaying TMSIDs and so forth.
|
|
** Added -nowrap to supress word wrap.
|
|
** Added STDIN support!
|
|
** Added Input Source lookup.
|
|
** Better organized sub-structures.
|
|
** Channel/Show Output now uses the word wrapper for everything.
|
|
** Some minor tweaks.
|
|
** Less unknowns. (Thanks in large part to Todd)
|
|
** Released on Mar 10th 2002
|
|
** .09 - LT Wrote an int64 Big->Small Endian converter.
|
|
** UNIX/WIN32 stuff sorted out.
|
|
** Cleaned up some code.
|
|
** Dependency on stdafx.h removed.
|
|
** Improved Word Wrapper.
|
|
** Fixed some bugs.
|
|
** Less unknowns.
|
|
** Released on Jan 13th 2002
|
|
** .08 - LT More fixes!
|
|
** Better wordwrapping!
|
|
** Less unknowns!
|
|
** Released on Jan 10th 2002
|
|
** .07 - LT Categories :)
|
|
** Dan added the extraction command line switches and code.
|
|
** Released on Jan 8th 2002
|
|
** .06 - LT Timezone fixes
|
|
** Released on Jan 5th 2002
|
|
** .05 - LT Checking to see if guide file is damaged (some versions of ReplayPC have a problem in this area)
|
|
** Found a case where GuideHeader.replayshows is not accurate!
|
|
** Lots of other fixes.
|
|
** Released on Jan 4th 2002
|
|
** .04 - LT Day of Week implemented.
|
|
** Categories are loaded but lookup isn't working.
|
|
** .03 - LT Private build.
|
|
** .02 - LT Private build.
|
|
** .01 - LT Private build.
|
|
** Initial Version
|
|
** 01/03/2002
|
|
**
|
|
**
|
|
***************************************************************************************************************
|
|
**
|
|
** TO DO:
|
|
**
|
|
** 1. Rewrite!
|
|
**
|
|
**
|
|
** BUGS
|
|
** Piping from replaypc to guideparser gets a few replaychannels in and somehow loses it's alignment -- looks
|
|
** like the 'file' is being truncated.
|
|
**
|
|
***************************************************************************************************************
|
|
** FreeBSD fixes by Andrew Tulloch <andrew@biliskner.demon.co.uk>
|
|
***************************************************************************************************************
|
|
*/
|
|
|
|
#ifdef _XBOX
|
|
#include <Xtl.h>
|
|
#pragma pack(1) // don't use byte alignments on the structs
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#if !defined(AFX_STDAFX_H__11AD8D81_EA54_4CD0_9A74_44F7170DE43F__INCLUDED_)
|
|
#define AFX_STDAFX_H__11AD8D81_EA54_4CD0_9A74_44F7170DE43F__INCLUDED_
|
|
#endif
|
|
|
|
#if _MSC_VER > 1000
|
|
#pragma once
|
|
#endif // _MSC_VER > 1000
|
|
|
|
#pragma pack(1) // don't use byte alignments on the structs
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#if defined (_WIN32) && !defined(_XBOX)
|
|
#include <winsock2.h>
|
|
#endif
|
|
|
|
#include <winnt.h>
|
|
#include <winbase.h>
|
|
#endif
|
|
|
|
#if defined(__unix__) && !defined(__FreeBSD__)
|
|
#include <netinet/in.h>
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
|
|
#if defined (_WIN32) && !defined(_XBOX)
|
|
#pragma comment(lib, "ws2_32.lib") // load winsock2 (we only use it for endian conversion)
|
|
#define FILEPOS fpos_t
|
|
#endif
|
|
|
|
#ifdef __unix__
|
|
typedef unsigned char BYTE;
|
|
typedef unsigned long long DWORD64;
|
|
typedef unsigned long DWORD;
|
|
typedef unsigned short WORD;
|
|
#define FILEPOS unsigned long
|
|
#define _tzset() tzset()
|
|
#define _tzname tzname
|
|
#define _timezone timezone
|
|
#define MoveMemory(dst,src,len) memmove(dst,src,len)
|
|
#define HIWORD(x) (WORD)(x >> 16)
|
|
#endif
|
|
|
|
extern int _daylight;
|
|
extern long _timezone;
|
|
extern char *_tzname[2];
|
|
|
|
#define SHOWSTRUCTURESIZES 1 // this is for debugging...
|
|
#undef SHOWSTRUCTURESIZES // ...uncomment this line for structure sizes to be shown
|
|
|
|
// 5.0
|
|
#define REPLAYSHOW 512 // needed size of replayshow structure
|
|
#define GUIDEHEADER 840 // needed size of guideheader structure
|
|
#define PROGRAMINFO 272 // needed size of programinfo structure
|
|
#define CHANNELINFO 80 // needed size of channelinfo structure
|
|
|
|
// 4.5
|
|
#define GUIDEHEADER45 808 // needed size of guideheader structure
|
|
|
|
// 4.3
|
|
#define GUIDEHEADER43 808 // needed size of guideheader structure
|
|
#define REPLAYSHOW43 444 // needed size of replayshow structure
|
|
|
|
#define MAXCHANNELS 99
|
|
|
|
#define lpszTitle "ReplayTV 5000 (Alpha) GuideParser v1.02 (Build 17)"
|
|
#define lpszCopyright "(C) 2002 Lee Thompson, Dan Frumin, Todd Larason, and Andrew Tulloch"
|
|
#define lpszComment ""
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Data Structures
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
//******************** COMMENTS *******************************************
|
|
//-------------------------------------------------------------------------
|
|
/*
|
|
** General ReplayTV Notes
|
|
**
|
|
** The RTV4K/5K platforms are capable of supporting NTSC, PAL and SECAM so
|
|
** in theory there may be one or more bytes always set a certain way as they
|
|
** reflect NTSC.
|
|
**
|
|
** On the subject of recorded time: The ReplayTV units appear to
|
|
** automatically pad shows by 3 seconds. e.g. If you schedule a show that
|
|
** airs at 6:00 PM, the recording will actually begin at 5:59:57 PM.
|
|
** Because of this, even an unpadded show will have a 3 second discrepency
|
|
** between ReplayShow.recorded and ReplayShow.eventtime.
|
|
**
|
|
**
|
|
** Categories
|
|
**
|
|
** There appears to be an *internal* maximum of 32 but the units appear
|
|
** to only use 17 total.
|
|
**
|
|
** Secondary Offset (GuideHeader)
|
|
**
|
|
** If you jump to this absolute location this repeats the first 12 bytes of
|
|
** this header, null terminates and then 4 unknown DWORDs.
|
|
**
|
|
** You will then be at the first byte of the first ReplayChannel record.
|
|
**
|
|
**
|
|
** Genre Codes
|
|
** Todd Larason's been slowly figuring these out, you can see the list at
|
|
** http://www.molehill.org/twiki/bin/view/Replay/RnsGetCG2
|
|
**
|
|
*/
|
|
|
|
/**************************************************************************
|
|
**
|
|
** GUIDE HEADER
|
|
**
|
|
**
|
|
** Most of the unknowns in the GuideHeader are garbage/junk. Why
|
|
** these aren't initialized to null I have no idea.
|
|
**
|
|
** They may also be a memory structure that has no meaning on a 'remote unit'.
|
|
**
|
|
**************************************************************************/
|
|
|
|
// 5000 OS Version 5.0
|
|
typedef struct tagGuideSnapshotHeader {
|
|
WORD osversion; // OS Version (5 for 4.5, 3 for 4.3, 0 on 5.0)
|
|
WORD snapshotversion; // Snapshot Version (1) (2 on 5.0) This might be better termed as snapshot version
|
|
DWORD structuresize; // Should always be 64
|
|
DWORD unknown1; // 0x00000002
|
|
DWORD unknown2; // 0x00000005
|
|
DWORD channelcount; // Number of Replay Channels
|
|
DWORD channelcountcheck; // Should always be equal to channelcount, it's incremented as the snapshot is built.
|
|
DWORD unknown3; // 0x00000000
|
|
DWORD groupdataoffset; // Offset of Group Data
|
|
DWORD channeloffset; // Offset of First Replay Channel (If you don't care about categories, jump to this)
|
|
DWORD showoffset; // Offset of First Replay Show (If you don't care about ReplayChannels, jump to this)
|
|
DWORD snapshotsize; // Total Size of the Snapshot
|
|
DWORD unknown4; // 0x00000001
|
|
DWORD unknown5; // 0x00000004
|
|
DWORD flags; // Careful, this is uninitialized, ignore invalid bits
|
|
DWORD unknown6; // 0x00000002
|
|
DWORD unknown7; // 0x00000000
|
|
} GuideSnapshotHeader;
|
|
|
|
typedef struct tagGroupData {
|
|
DWORD structuresize; // Should always be 776
|
|
DWORD categories; // Number of Categories (MAX: 32 [ 0 - 31 ] )
|
|
DWORD category[32]; // category lookup 2 ^ number, position order = text
|
|
DWORD categoryoffset[32]; // Offsets for the GuideHeader.catbuffer
|
|
char catbuffer[512]; // GuideHeader.categoryoffset contains the starting position of each category.
|
|
} GroupData;
|
|
|
|
typedef struct tagGuideHeader {
|
|
struct tagGuideSnapshotHeader GuideSnapshotHeader;
|
|
struct tagGroupData GroupData;
|
|
} GuideHeader;
|
|
|
|
// 4000 OS Version 4.3 / 5000 OS Version 4.5
|
|
typedef struct tagGuideSnapshotHeader45 {
|
|
WORD osversion; // Major Revision (5 for Replay5000s, 3 for Replay 4000/4500s)
|
|
WORD snapshotversion; // Minor Revision (1)
|
|
DWORD structuresize; // Should always be 32
|
|
DWORD channelcount; // Number of Replay Channels
|
|
DWORD channelcountcheck; // Number of Replay Channels (Copy 2; should always match)
|
|
DWORD groupdataoffset; // Offset of Group Data
|
|
DWORD channeloffset; // Offset of First Replay Channel (If you don't care about categories, jump to this)
|
|
DWORD showoffset; // Offset of First Replay Show (If you don't care about ReplayChannels, jump to this)
|
|
DWORD flags; // Careful, this is uninitialized, ignore invalid bits
|
|
} GuideSnapshotHeader45;
|
|
|
|
// GroupData structure is the same for 4.3/4.5 and 5.0
|
|
|
|
typedef struct tagGuideHeader45 {
|
|
struct tagGuideSnapshotHeader45 GuideSnapshotHeader;
|
|
struct tagGroupData GroupData;
|
|
} GuideHeader45;
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** SUB-STRUCTURES
|
|
**
|
|
*******************************************************************************/
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Movie Extended Info Structure
|
|
|
|
typedef struct tagMovieInfo {
|
|
WORD mpaa; // MPAA Rating
|
|
WORD stars; // Star Rating * 10 (i.e. value of 20 = 2 stars)
|
|
WORD year; // Release Year
|
|
WORD runtime; // Strange HH:MM format
|
|
} MovieInfo;
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Has Parts Info Structure
|
|
|
|
typedef struct tagPartsInfo {
|
|
WORD partnumber; // Part X [Of Y]
|
|
WORD maxparts; // [Part X] Of Y
|
|
} PartsInfo;
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Program Info Structure
|
|
|
|
typedef struct tagProgramInfo {
|
|
DWORD structuresize; // Should always be 272 (0x0110)
|
|
DWORD autorecord; // If non-zero it is an automatic recording, otherwise it is a manual recording.
|
|
DWORD isvalid; // Not sure what it actually means! (should always be 1 in exported guide)
|
|
DWORD tuning; // Tuning (Channel Number) for the Program
|
|
DWORD flags; // Program Flags
|
|
DWORD eventtime; // Scheduled Time of the Show
|
|
DWORD tmsID; // Tribune Media Services ID (inherited from ChannelInfo)
|
|
WORD minutes; // Minutes (add with show padding for total)
|
|
BYTE genre1; // Genre Code 1
|
|
BYTE genre2; // Genre Code 2
|
|
BYTE genre3; // Genre Code 3
|
|
BYTE genre4; // Genre Code 4
|
|
WORD recLen; // Record Length of Description Block
|
|
BYTE titleLen; // Length of Title
|
|
BYTE episodeLen; // Length of Episode
|
|
BYTE descriptionLen; // Length of Description
|
|
BYTE actorLen; // Length of Actors
|
|
BYTE guestLen; // Length of Guest
|
|
BYTE suzukiLen; // Length of Suzuki String (Newer genre tags)
|
|
BYTE producerLen; // Length of Producer
|
|
BYTE directorLen; // Length of Director
|
|
char szDescription[228]; // This can have parts/movie sub-structure
|
|
} ProgramInfo;
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Channel Info Structure
|
|
|
|
typedef struct tagChannelInfo {
|
|
DWORD structuresize; // Should always be 80 (0x50)
|
|
DWORD usetuner; // If non-zero the tuner is used, otherwise it's a direct input.
|
|
DWORD isvalid; // Record valid if non-zero
|
|
DWORD tmsID; // Tribune Media Services ID
|
|
WORD channel; // Channel Number
|
|
BYTE device; // Device
|
|
BYTE tier; // Cable/Satellite Service Tier
|
|
char szChannelName[16]; // Channel Name
|
|
char szChannelLabel[32]; // Channel Description
|
|
char cablesystem[8]; // Cable system ID
|
|
DWORD channelindex; // Channel Index (USUALLY tagChannelinfo.channel repeated)
|
|
} ChannelInfo;
|
|
|
|
|
|
/*******************************************************************************
|
|
**
|
|
** REPLAY SHOW
|
|
**
|
|
*******************************************************************************/
|
|
|
|
typedef struct tagReplayShow {
|
|
DWORD created; // ReplayChannel ID (tagReplayChannel.created)
|
|
DWORD recorded; // Filename/Time of Recording (aka ShowID)
|
|
DWORD inputsource; // Replay Input Source
|
|
DWORD quality; // Recording Quality Level
|
|
DWORD guaranteed; // (0xFFFFFFFF if guaranteed)
|
|
DWORD playbackflags; // Not well understood yet.
|
|
struct tagChannelInfo ChannelInfo;
|
|
struct tagProgramInfo ProgramInfo;
|
|
DWORD ivsstatus; // Always 1 in a snapshot outside of a tagReplayChannel
|
|
DWORD guideid; // The show_id on the original ReplayTV for IVS shows. Otherwise 0
|
|
DWORD downloadid; // Valid only during actual transfer of index or mpeg file; format/meaning still unknown
|
|
DWORD timessent; // Times sent using IVS
|
|
DWORD seconds; // Show Duration in Seconds (this is the exact actual length of the recording)
|
|
DWORD GOP_count; // MPEG Group of Picture Count
|
|
DWORD GOP_highest; // Highest GOP number seen, 0 on a snapshot.
|
|
DWORD GOP_last; // Last GOP number seen, 0 on a snapshot.
|
|
DWORD checkpointed; // 0 in possibly-out-of-date in-memory copies; always -1 in snapshots
|
|
DWORD intact; // 0xffffffff in a snapshot; 0 means a deleted show
|
|
DWORD upgradeflag; // Always 0 in a snapshot
|
|
DWORD instance; // Episode Instance Counter (0 offset)
|
|
WORD unused; // Not preserved when padding values are set, presumably not used
|
|
BYTE beforepadding; // Before Show Padding
|
|
BYTE afterpadding; // After Show Padding
|
|
DWORD64 indexsize; // Size of NDX file (IVS Shows Only)
|
|
DWORD64 mpegsize; // Size of MPG file (IVS Shows Only)
|
|
char szReserved[68]; // Show Label (NOT PRESENT in 4k 4.3 version, work around it)
|
|
} ReplayShow;
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// WIN32 Functions
|
|
//-------------------------------------------------------------------------
|
|
|
|
#ifdef _WIN32
|
|
|
|
//-------------------------------------------------------------------------
|
|
void UnixTimeToFileTime(time_t t, LPFILETIME pft)
|
|
{
|
|
LONGLONG ll;
|
|
|
|
ll = Int32x32To64(t, 10000000) + 116444736000000000;
|
|
pft->dwLowDateTime = (DWORD)ll;
|
|
pft->dwHighDateTime = (DWORD)(ll >> 32);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
void UnixTimeToSystemTime(time_t t, LPSYSTEMTIME pst)
|
|
{
|
|
FILETIME ft;
|
|
|
|
UnixTimeToFileTime(t, &ft);
|
|
FileTimeToSystemTime(&ft, pst);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
char * UnixTimeToString(time_t t)
|
|
{
|
|
static char sbuf[17];
|
|
char szTimeZone[32];
|
|
SYSTEMTIME st;
|
|
int tzbias;
|
|
|
|
_tzset();
|
|
|
|
memset(szTimeZone,0,sizeof(szTimeZone));
|
|
|
|
MoveMemory(szTimeZone,_tzname[0],1);
|
|
strcat(szTimeZone,"T");
|
|
|
|
tzbias = _timezone;
|
|
|
|
UnixTimeToSystemTime(t - tzbias, &st);
|
|
sprintf(sbuf, "%d-%.2d-%.2d %.2d:%.2d:%.2d",
|
|
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
|
return sbuf;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------
|
|
// UNIX Functions
|
|
//-------------------------------------------------------------------------
|
|
|
|
#ifdef __unix__
|
|
char * UnixTimeToString(time_t t)
|
|
{
|
|
static char sbuf[17];
|
|
struct tm * tm;
|
|
|
|
tm = localtime(&t);
|
|
strftime(sbuf, sizeof(sbuf), "%Y-%m-%d %H:%M:%S", tm);
|
|
return sbuf;
|
|
}
|
|
#endif
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Common Functions
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Lookup Tables
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
void DisplayQuality(int quality, char *szQuality)
|
|
{
|
|
switch( quality )
|
|
{
|
|
case 0:
|
|
strcpy( szQuality, "High" );
|
|
break;
|
|
case 1:
|
|
strcpy( szQuality, "Medium" );
|
|
break;
|
|
case 2:
|
|
strcpy( szQuality, "Standard" );
|
|
break;
|
|
default:
|
|
strcpy( szQuality, "" );
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void DisplayExtendedTVRating(int tvrating, char *szRating, bool append)
|
|
{
|
|
|
|
if (append == false)
|
|
{
|
|
strcpy( szRating, "");
|
|
}
|
|
|
|
if (tvrating & 0x00020000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
|
|
strcat( szRating, "S" ); // Sex
|
|
}
|
|
|
|
if (tvrating & 0x00040000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
|
|
strcat( szRating, "V" ); // Violence
|
|
}
|
|
|
|
if (tvrating & 0x00080000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
|
|
strcat( szRating, "L" ); // Language
|
|
}
|
|
|
|
if (tvrating & 0x00100000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
|
|
strcat( szRating, "D" ); // Drug Use
|
|
}
|
|
|
|
if (tvrating & 0x00200000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
|
|
strcat( szRating, "F" ); // Fantasy Violence
|
|
}
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void DisplayTVRating(int tvrating, char *szRating)
|
|
{
|
|
strcpy( szRating, "");
|
|
|
|
if (tvrating & 0x00008000)
|
|
{
|
|
strcpy( szRating, "TV-Y" );
|
|
}
|
|
|
|
if (tvrating & 0x00010000)
|
|
{
|
|
strcpy( szRating, "TV-Y7" );
|
|
}
|
|
|
|
if (tvrating & 0x00001000)
|
|
{
|
|
strcpy( szRating, "TV-G" );
|
|
}
|
|
|
|
if (tvrating & 0x00004000)
|
|
{
|
|
strcpy( szRating, "TV-PG" );
|
|
}
|
|
|
|
if (tvrating & 0x00002000)
|
|
{
|
|
strcpy( szRating, "TV-MA" );
|
|
}
|
|
|
|
if (tvrating & 0x00000800)
|
|
{
|
|
strcpy( szRating, "TV-14" );
|
|
}
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void DisplayExtendedMPAARating(int mpaarating, char *szRating, bool append)
|
|
{
|
|
if (append == false)
|
|
{
|
|
strcpy( szRating, "");
|
|
}
|
|
|
|
if (mpaarating & 0x00400000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "AC" ); // Adult Content
|
|
}
|
|
|
|
if (mpaarating & 0x00800000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "BN" ); // Brief Nudity
|
|
}
|
|
|
|
if (mpaarating & 0x01000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "GL" ); // Graphic Language
|
|
}
|
|
|
|
if (mpaarating & 0x02000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "GV" ); // Graphic Violence
|
|
}
|
|
|
|
if (mpaarating & 0x04000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "AL" ); // Adult Language
|
|
}
|
|
|
|
if (mpaarating & 0x08000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "MV" ); // Mild Violence
|
|
}
|
|
|
|
if (mpaarating & 0x10000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "N" ); // Nudity
|
|
}
|
|
|
|
if (mpaarating & 0x20000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "RP" ); // Rape
|
|
}
|
|
|
|
if (mpaarating & 0x40000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "SC " ); // Sexual Content
|
|
}
|
|
|
|
if (mpaarating & 0x80000000)
|
|
{
|
|
if (strlen(szRating) > 0)
|
|
{
|
|
strcat( szRating, " ");
|
|
}
|
|
|
|
strcat( szRating, "V" ); // Violence
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
void DisplayMPAARating(int mpaarating, char *szRating)
|
|
{
|
|
strcpy( szRating, "");
|
|
|
|
if (mpaarating & 0x00000001)
|
|
{
|
|
strcat( szRating, "AO" ); // unverified
|
|
}
|
|
|
|
if (mpaarating & 0x00000002)
|
|
{
|
|
strcat( szRating, "G" );
|
|
}
|
|
|
|
if (mpaarating & 0x00000004)
|
|
{
|
|
strcat( szRating, "NC-17" );
|
|
}
|
|
|
|
if (mpaarating & 0x00000008)
|
|
{
|
|
strcat( szRating, "NR" );
|
|
}
|
|
|
|
if (mpaarating & 0x00000010)
|
|
{
|
|
strcat( szRating, "PG" );
|
|
}
|
|
|
|
if (mpaarating & 0x00000020)
|
|
{
|
|
strcat( szRating, "PG-13" );
|
|
}
|
|
|
|
if (mpaarating & 0x00000040)
|
|
{
|
|
strcat( szRating, "R" );
|
|
}
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Data Presentation Functions
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
void ConvertCodepage(char *szString)
|
|
{
|
|
bool exitloop = false;
|
|
unsigned int i = 0;
|
|
char ch;
|
|
|
|
if (szString[0] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for( i = 0; i < strlen(szString); ++i )
|
|
{
|
|
ch = szString[i];
|
|
|
|
// Windows Codepage Translation to DOS/UNIX etc
|
|
|
|
if (ch == (char)146)
|
|
{
|
|
szString[i] = '\'';
|
|
}
|
|
|
|
if (ch == (char)147)
|
|
{
|
|
szString[i] = '\"';
|
|
}
|
|
|
|
if (ch == (char)148)
|
|
{
|
|
szString[i] = '\"';
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
// Windows (Console) specific translations
|
|
#endif
|
|
|
|
#ifdef __unix__
|
|
// UNIX specific translations
|
|
#endif
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Misc. Functions
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
int CalculateMinutes( int seconds )
|
|
{
|
|
int original = seconds;
|
|
int retval = 0;
|
|
double result1 = 0.0;
|
|
double result2 = 0.0;
|
|
|
|
if (seconds < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
result1 = seconds / 60;
|
|
result2 = seconds % 60;
|
|
|
|
if (result2 > .0) // this will round up if there's any remainder,
|
|
// could also make this .5 etc
|
|
{
|
|
retval = (int)result1 + 1;
|
|
}
|
|
else
|
|
{
|
|
retval = (int)result1;
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// ENDIAN CONVERSION FUNCTIONS
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
// LONGLONG/INT64 Endian Conversion
|
|
//-------------------------------------------------------------------------
|
|
|
|
//-------------------------------------------------------------------------
|
|
DWORD64 ntohll(DWORD64 llValue)
|
|
{
|
|
DWORD64 retval = 0;
|
|
|
|
// This is really cheesy but it works so that's all that matters
|
|
// If someone out there wants to replace this with something cooler,
|
|
// please feel free to do so!
|
|
|
|
char szBuffer[17];
|
|
char szInt64[17];
|
|
|
|
memset(szBuffer,0,sizeof(szBuffer));
|
|
memset(szInt64,0,sizeof(szInt64));
|
|
|
|
MoveMemory(szBuffer,&llValue,sizeof(llValue));
|
|
|
|
int cc = sizeof(llValue) - 1;
|
|
int i = 0;
|
|
|
|
for( i = 0; i < sizeof(llValue); ++i )
|
|
{
|
|
szInt64[i] = szBuffer[cc];
|
|
--cc;
|
|
}
|
|
|
|
MoveMemory(&retval,szInt64,sizeof(retval));
|
|
|
|
return retval;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void ConvertProgramInfoEndian(struct tagProgramInfo * strProgramInfo)
|
|
{
|
|
|
|
strProgramInfo->autorecord = ntohl(strProgramInfo->autorecord);
|
|
strProgramInfo->eventtime = ntohl(strProgramInfo->eventtime);
|
|
strProgramInfo->flags = ntohl(strProgramInfo->flags);
|
|
strProgramInfo->isvalid = ntohl(strProgramInfo->isvalid);
|
|
strProgramInfo->minutes = ntohs(strProgramInfo->minutes);
|
|
strProgramInfo->recLen = ntohs(strProgramInfo->recLen);
|
|
strProgramInfo->structuresize = ntohl(strProgramInfo->structuresize);
|
|
strProgramInfo->tuning = ntohl(strProgramInfo->tuning);
|
|
strProgramInfo->tmsID = ntohl(strProgramInfo->tmsID);
|
|
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void ConvertMovieInfoEndian(struct tagMovieInfo * strMovieInfo)
|
|
{
|
|
strMovieInfo->mpaa = ntohs(strMovieInfo->mpaa);
|
|
strMovieInfo->runtime = ntohs(strMovieInfo->runtime);
|
|
strMovieInfo->stars = ntohs(strMovieInfo->stars);
|
|
strMovieInfo->year = ntohs(strMovieInfo->year);
|
|
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void ConvertPartsInfoEndian(struct tagPartsInfo * strPartsInfo)
|
|
{
|
|
strPartsInfo->maxparts = ntohs(strPartsInfo->maxparts);
|
|
strPartsInfo->partnumber = ntohs(strPartsInfo->partnumber);
|
|
|
|
return;
|
|
}
|
|
//-------------------------------------------------------------------------
|
|
void ConvertReplayShowEndian(struct tagReplayShow * strReplayShow)
|
|
{
|
|
strReplayShow->checkpointed = ntohl(strReplayShow->checkpointed);
|
|
strReplayShow->created = ntohl(strReplayShow->created);
|
|
strReplayShow->downloadid = ntohl(strReplayShow->downloadid);
|
|
strReplayShow->GOP_count = ntohl(strReplayShow->GOP_count);
|
|
strReplayShow->GOP_highest = ntohl(strReplayShow->GOP_highest);
|
|
strReplayShow->GOP_last = ntohl(strReplayShow->GOP_last);
|
|
strReplayShow->guaranteed = ntohl(strReplayShow->guaranteed);
|
|
strReplayShow->guideid = ntohl(strReplayShow->guideid);
|
|
strReplayShow->indexsize = ntohll(strReplayShow->indexsize);
|
|
strReplayShow->inputsource = ntohl(strReplayShow->inputsource);
|
|
strReplayShow->instance = ntohl(strReplayShow->instance);
|
|
strReplayShow->intact = ntohl(strReplayShow->intact);
|
|
strReplayShow->ivsstatus = ntohl(strReplayShow->ivsstatus);
|
|
strReplayShow->mpegsize = ntohll(strReplayShow->mpegsize);
|
|
strReplayShow->playbackflags = ntohl(strReplayShow->playbackflags);
|
|
strReplayShow->quality = ntohl(strReplayShow->quality);
|
|
strReplayShow->recorded = ntohl(strReplayShow->recorded);
|
|
strReplayShow->seconds = ntohl(strReplayShow->seconds);
|
|
strReplayShow->timessent = ntohl(strReplayShow->timessent);
|
|
strReplayShow->upgradeflag = ntohl(strReplayShow->upgradeflag);
|
|
strReplayShow->unused = ntohs(strReplayShow->unused);
|
|
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void ConvertReplayGuideEndian(struct tagGuideHeader * strGuideHeader)
|
|
{
|
|
|
|
strGuideHeader->GroupData.categories = ntohl(strGuideHeader->GroupData.categories);
|
|
strGuideHeader->GroupData.structuresize = ntohl(strGuideHeader->GroupData.structuresize);
|
|
|
|
strGuideHeader->GuideSnapshotHeader.snapshotsize = ntohl(strGuideHeader->GuideSnapshotHeader.snapshotsize);
|
|
strGuideHeader->GuideSnapshotHeader.channeloffset = ntohl(strGuideHeader->GuideSnapshotHeader.channeloffset);
|
|
strGuideHeader->GuideSnapshotHeader.flags = ntohl(strGuideHeader->GuideSnapshotHeader.flags);
|
|
strGuideHeader->GuideSnapshotHeader.groupdataoffset = ntohl(strGuideHeader->GuideSnapshotHeader.groupdataoffset);
|
|
strGuideHeader->GuideSnapshotHeader.osversion = ntohs(strGuideHeader->GuideSnapshotHeader.osversion);
|
|
strGuideHeader->GuideSnapshotHeader.snapshotversion = ntohs(strGuideHeader->GuideSnapshotHeader.snapshotversion);
|
|
strGuideHeader->GuideSnapshotHeader.channelcount = ntohl(strGuideHeader->GuideSnapshotHeader.channelcount);
|
|
strGuideHeader->GuideSnapshotHeader.channelcountcheck = ntohl(strGuideHeader->GuideSnapshotHeader.channelcountcheck);
|
|
strGuideHeader->GuideSnapshotHeader.showoffset = ntohl(strGuideHeader->GuideSnapshotHeader.showoffset);
|
|
|
|
strGuideHeader->GuideSnapshotHeader.unknown1 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown1);
|
|
strGuideHeader->GuideSnapshotHeader.unknown2 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown2);
|
|
strGuideHeader->GuideSnapshotHeader.unknown3 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown3);
|
|
strGuideHeader->GuideSnapshotHeader.unknown4 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown4);
|
|
strGuideHeader->GuideSnapshotHeader.unknown5 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown5);
|
|
strGuideHeader->GuideSnapshotHeader.unknown6 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown6);
|
|
strGuideHeader->GuideSnapshotHeader.unknown7 = ntohl(strGuideHeader->GuideSnapshotHeader.unknown7);
|
|
|
|
for( unsigned int cc = 0; cc < strGuideHeader->GroupData.categories; ++cc )
|
|
{
|
|
strGuideHeader->GroupData.category[cc] = ntohl(strGuideHeader->GroupData.category[cc]);
|
|
strGuideHeader->GroupData.categoryoffset[cc] = ntohl(strGuideHeader->GroupData.categoryoffset[cc]);
|
|
}
|
|
|
|
|
|
{
|
|
strGuideHeader->GuideSnapshotHeader.structuresize = ntohl(strGuideHeader->GuideSnapshotHeader.structuresize);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void ConvertReplayGuide45To50Endian(struct tagGuideHeader45 * strGuideHeader45, struct tagGuideHeader * strGuideHeader)
|
|
{
|
|
|
|
strGuideHeader->GroupData.categories = ntohl(strGuideHeader45->GroupData.categories);
|
|
strGuideHeader->GroupData.structuresize = ntohl(strGuideHeader45->GroupData.structuresize);
|
|
|
|
strGuideHeader->GuideSnapshotHeader.snapshotsize = 0;
|
|
strGuideHeader->GuideSnapshotHeader.channeloffset = ntohl(strGuideHeader45->GuideSnapshotHeader.channeloffset);
|
|
strGuideHeader->GuideSnapshotHeader.flags = ntohl(strGuideHeader45->GuideSnapshotHeader.flags);
|
|
strGuideHeader->GuideSnapshotHeader.groupdataoffset = ntohl(strGuideHeader45->GuideSnapshotHeader.groupdataoffset);
|
|
strGuideHeader->GuideSnapshotHeader.osversion = ntohs(strGuideHeader45->GuideSnapshotHeader.osversion);
|
|
strGuideHeader->GuideSnapshotHeader.snapshotversion = ntohs(strGuideHeader45->GuideSnapshotHeader.snapshotversion);
|
|
strGuideHeader->GuideSnapshotHeader.channelcount = ntohl(strGuideHeader45->GuideSnapshotHeader.channelcount);
|
|
strGuideHeader->GuideSnapshotHeader.channelcountcheck = ntohl(strGuideHeader45->GuideSnapshotHeader.channelcountcheck);
|
|
strGuideHeader->GuideSnapshotHeader.showoffset = ntohl(strGuideHeader45->GuideSnapshotHeader.showoffset);
|
|
|
|
strGuideHeader->GuideSnapshotHeader.unknown1 = 0;
|
|
strGuideHeader->GuideSnapshotHeader.unknown2 = 0;
|
|
strGuideHeader->GuideSnapshotHeader.unknown3 = 0;
|
|
strGuideHeader->GuideSnapshotHeader.unknown4 = 0;
|
|
strGuideHeader->GuideSnapshotHeader.unknown5 = 0;
|
|
strGuideHeader->GuideSnapshotHeader.unknown6 = 0;
|
|
strGuideHeader->GuideSnapshotHeader.unknown7 = 0;
|
|
|
|
for( unsigned int cc = 0; cc < strGuideHeader->GroupData.categories; ++cc )
|
|
{
|
|
strGuideHeader->GroupData.category[cc] = ntohl(strGuideHeader45->GroupData.category[cc]);
|
|
strGuideHeader->GroupData.categoryoffset[cc] = ntohl(strGuideHeader45->GroupData.categoryoffset[cc]);
|
|
}
|
|
|
|
|
|
{
|
|
strGuideHeader->GuideSnapshotHeader.structuresize = ntohl(strGuideHeader45->GuideSnapshotHeader.structuresize);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
// GuideParser
|
|
//-------------------------------------------------------------------------
|
|
|
|
extern "C" {
|
|
int GuideParser(char * szOutputBuffer, const char * szInput, const size_t InputSize)
|
|
{
|
|
const char * fptr, * junkptr;
|
|
bool moreshows, receivedshow;
|
|
bool isguaranteed, isrepeat, isletterbox, ismovie, hasparts, iscc, isppv, isstereo, issap;
|
|
char szBuffer[1024], szQuality[16];
|
|
char szEpisodeTitle[128];
|
|
char szStarRating[6], szMPAARating[10], szOriginalDescriptionBuffer[226];
|
|
char szTVRating[32];
|
|
char szShowTitle[128];
|
|
char szExtTV[64];
|
|
char szExtMPAA[64];
|
|
int i, curshow, cc;
|
|
size_t readsize;
|
|
ReplayShow strReplayShow;
|
|
GuideHeader strGuideHeader;
|
|
GuideHeader45 strGuideHeader45;
|
|
MovieInfo strMovieInfo;
|
|
PartsInfo strPartsInfo;
|
|
|
|
// Initialize
|
|
|
|
memset(szBuffer,0,sizeof(szBuffer));
|
|
memset(szQuality,0,sizeof(szQuality));
|
|
memset(szEpisodeTitle,0,sizeof(szEpisodeTitle));
|
|
memset(szOriginalDescriptionBuffer,0,sizeof(szOriginalDescriptionBuffer));
|
|
memset(szStarRating,0,sizeof(szStarRating));
|
|
memset(szMPAARating,0,sizeof(szMPAARating));
|
|
memset(szExtTV,0,sizeof(szExtTV));
|
|
memset(szExtMPAA,0,sizeof(szExtMPAA));
|
|
sprintf(szOutputBuffer,"");
|
|
|
|
// Display Initial Header
|
|
|
|
//printf("%s\n",lpszTitle);
|
|
//printf("%s\n\n",lpszCopyright);
|
|
//printf("%s\n",lpszComment);
|
|
|
|
// Structure Sizes
|
|
|
|
#ifdef SHOWSTRUCTURESIZES
|
|
|
|
//printf("struct strGuideHeader is %d bytes\n",sizeof(tagGuideHeader));
|
|
//printf("struct strMovieInfo is %d bytes\n",sizeof(tagMovieInfo));
|
|
//printf("struct strPartsInfo is %d bytes\n",sizeof(tagPartsInfo));
|
|
//printf("struct strProgramInfo is %d bytes\n",sizeof(tagProgramInfo));
|
|
//printf("struct strChannelInfo is %d bytes\n",sizeof(tagChannelInfo));
|
|
//printf("struct strReplayShow is %d bytes\n",sizeof(tagReplayShow));
|
|
//printf("\n");
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
// Check to make sure structures are required sizes, this is mostly for those of you tinkering with this
|
|
// and - of course - me :).
|
|
|
|
if (sizeof(ProgramInfo) != PROGRAMINFO)
|
|
{
|
|
//printf("Error in ProgramInfo structure, needs to be %u instead of %u\n",PROGRAMINFO,sizeof(ProgramInfo));
|
|
}
|
|
|
|
if (sizeof(ChannelInfo) != CHANNELINFO)
|
|
{
|
|
//printf("Error in ChannelInfo structure, needs to be %u instead of %u\n",CHANNELINFO,sizeof(ChannelInfo));
|
|
}
|
|
|
|
|
|
if (sizeof(ReplayShow) != REPLAYSHOW)
|
|
{
|
|
//printf("Error in ReplayShow structure, needs to be %u instead of %u\n",REPLAYSHOW,sizeof(ReplayShow));
|
|
}
|
|
|
|
if (sizeof(GuideHeader) != GUIDEHEADER)
|
|
{
|
|
//printf("Error in GuideHeader structure, needs to be %u instead of %u\n",GUIDEHEADER,sizeof(GuideHeader));
|
|
}
|
|
|
|
// 4.5
|
|
if (sizeof(GuideHeader45) != GUIDEHEADER45)
|
|
{
|
|
//printf("Error in GuideHeader45 structure, needs to be %u instead of %u\n",GUIDEHEADER45,sizeof(GuideHeader45));
|
|
}
|
|
#endif
|
|
|
|
curshow = 0;
|
|
i = 0;
|
|
junkptr = szInput;
|
|
fptr = szInput;
|
|
|
|
DWORD ver;
|
|
|
|
memcpy(&ver, fptr, sizeof(ver));
|
|
ver = ntohl(ver);
|
|
//printf("V %d.%d!\n", HIWORD(ver), LOWORD(ver));
|
|
|
|
//-------------------------------------------------------------------------
|
|
// Replay Header
|
|
//-------------------------------------------------------------------------
|
|
|
|
//printf("Reading ReplayTV Guide Header\n");
|
|
|
|
switch(HIWORD(ver))
|
|
{
|
|
case 0: // 5k 5.0
|
|
memcpy( &strGuideHeader, fptr, sizeof(strGuideHeader) );
|
|
ConvertReplayGuideEndian(&strGuideHeader);
|
|
break;
|
|
case 3: // 4k 4.3
|
|
case 5: // 5k 4.5
|
|
memcpy( &strGuideHeader45, fptr, sizeof(strGuideHeader45) );
|
|
ConvertReplayGuide45To50Endian(&strGuideHeader45, &strGuideHeader);
|
|
break;
|
|
default: // Unknown: try 5k 5.0
|
|
//printf("Unknown ReplayTV version: %d.%d!\n", HIWORD(ver), LOWORD(ver));
|
|
memcpy( &strGuideHeader, fptr, sizeof(strGuideHeader) );
|
|
ConvertReplayGuideEndian(&strGuideHeader);
|
|
break;
|
|
}
|
|
|
|
if (strGuideHeader.GuideSnapshotHeader.channelcount != strGuideHeader.GuideSnapshotHeader.channelcountcheck)
|
|
{
|
|
//printf("Guide Snapshot might be damaged. (%u/%u)\n",strGuideHeader.GuideSnapshotHeader.channelcount,strGuideHeader.GuideSnapshotHeader.channelcountcheck);
|
|
}
|
|
|
|
// jump to the first show record
|
|
|
|
// fptr = (long)strGuideHeader.GuideSnapshotHeader.showoffset + junkptr;
|
|
fptr = (long)strGuideHeader.GuideSnapshotHeader.showoffset + junkptr;
|
|
|
|
//-------------------------------------------------------------------------
|
|
// ReplayShows
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
//printf("\n\nReading ReplayShows\n\n");
|
|
|
|
moreshows = true;
|
|
curshow = 0;
|
|
|
|
strcat(szOutputBuffer, "<REPLAYGUIDE>\n");
|
|
do
|
|
{
|
|
readsize = sizeof(strReplayShow);
|
|
// 4k 4.3 doesn't have the extra bytes for szReserved at the end of the struct
|
|
if ( HIWORD( ver ) == 3 ) readsize -= sizeof(strReplayShow.szReserved);
|
|
|
|
// Need to check if ptr is at, beyond or near end of input (i.e. within sizeof(strReplayshow))
|
|
if ( (InputSize - (fptr - szInput) ) < readsize)
|
|
{
|
|
moreshows = false;
|
|
}
|
|
else
|
|
{
|
|
memcpy( &strReplayShow, fptr, readsize);
|
|
|
|
curshow++;
|
|
|
|
memset(szTVRating,0,sizeof(szTVRating));
|
|
memset(szBuffer,0,sizeof(szBuffer));
|
|
memset(szEpisodeTitle,0,sizeof(szEpisodeTitle));
|
|
memset(szShowTitle,0,sizeof(szShowTitle));
|
|
memset(szMPAARating,0,sizeof(szMPAARating));
|
|
memset(szOriginalDescriptionBuffer,0,sizeof(szOriginalDescriptionBuffer));
|
|
strcpy(szStarRating,"*****");
|
|
memset(szExtTV,0,sizeof(szExtTV));
|
|
memset(szExtMPAA,0,sizeof(szExtMPAA));
|
|
|
|
// Convert Endian
|
|
|
|
ConvertReplayShowEndian(&strReplayShow);
|
|
ConvertProgramInfoEndian(&strReplayShow.ProgramInfo);
|
|
|
|
/*
|
|
// this is for this hack, this seems to be no longer used so copy it from eventtime
|
|
|
|
if (strReplayShow.recorded == 0) {
|
|
strReplayShow.recorded = strReplayShow.ProgramInfo.eventtime;
|
|
}
|
|
*/
|
|
|
|
// Process ProgramInfo
|
|
|
|
MoveMemory(szOriginalDescriptionBuffer,strReplayShow.ProgramInfo.szDescription,sizeof(szOriginalDescriptionBuffer));
|
|
|
|
// Process Flags
|
|
|
|
iscc = false;
|
|
issap = false;
|
|
isstereo = false;
|
|
ismovie = false;
|
|
isppv = false;
|
|
hasparts = false;
|
|
isletterbox = false;
|
|
isrepeat = false;
|
|
receivedshow = false;
|
|
isguaranteed = false;
|
|
cc = 0; // Offset for Extended Data
|
|
|
|
if (strReplayShow.guaranteed == 0xFFFFFFFF)
|
|
{
|
|
isguaranteed = true;
|
|
}
|
|
|
|
if (strReplayShow.guideid != 0)
|
|
{
|
|
receivedshow = true;
|
|
}
|
|
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000001)
|
|
{
|
|
iscc = true;
|
|
}
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000002)
|
|
{
|
|
isstereo = true;
|
|
}
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000004)
|
|
{
|
|
isrepeat = true;
|
|
}
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000008)
|
|
{
|
|
issap = true;
|
|
}
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000010)
|
|
{
|
|
isletterbox = true;
|
|
}
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000020)
|
|
{
|
|
// Movie, load extra 8 bytes into MovieInfo structure.
|
|
|
|
ismovie = true;
|
|
MoveMemory(&strMovieInfo,szOriginalDescriptionBuffer + cc,sizeof(strMovieInfo));
|
|
ConvertMovieInfoEndian(&strMovieInfo);
|
|
|
|
memset(szBuffer,0,sizeof(szBuffer));
|
|
cc = cc + sizeof(strMovieInfo);
|
|
MoveMemory(szBuffer,szOriginalDescriptionBuffer + cc,sizeof(szOriginalDescriptionBuffer) - cc);
|
|
|
|
// this won't do the half stars, it's too cheesy for that!
|
|
|
|
i = strMovieInfo.stars / 10;
|
|
szStarRating[i] = 0;
|
|
|
|
// MPAA Rating
|
|
|
|
DisplayMPAARating(strMovieInfo.mpaa,szMPAARating);
|
|
DisplayExtendedMPAARating(strMovieInfo.mpaa,szExtMPAA,false);
|
|
|
|
if (strlen(szMPAARating) > 0)
|
|
{
|
|
if (strlen(szExtMPAA) > 0)
|
|
{
|
|
strcat( szMPAARating, " (" );
|
|
strcat( szMPAARating, szExtMPAA );
|
|
strcat( szMPAARating, ")" );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000040)
|
|
{
|
|
|
|
// Multiple Parts
|
|
|
|
hasparts = true;
|
|
MoveMemory(&strPartsInfo,szOriginalDescriptionBuffer + cc,sizeof(strPartsInfo));
|
|
ConvertPartsInfoEndian(&strPartsInfo);
|
|
|
|
memset(szBuffer,0,sizeof(szBuffer));
|
|
|
|
cc = cc + sizeof(strPartsInfo);
|
|
MoveMemory(szBuffer,szOriginalDescriptionBuffer + cc,sizeof(szOriginalDescriptionBuffer) - cc);
|
|
}
|
|
|
|
if (strReplayShow.ProgramInfo.flags & 0x00000080)
|
|
{
|
|
isppv = true;
|
|
}
|
|
|
|
if (!ismovie)
|
|
{
|
|
/*
|
|
**
|
|
** NOTE:
|
|
** This is what the Replay does. However, the TMS data does support a mix
|
|
** so, if you want, you can remove "if (!ismovie)".
|
|
*/
|
|
|
|
DisplayTVRating(strReplayShow.ProgramInfo.flags,szTVRating);
|
|
DisplayExtendedTVRating(strReplayShow.ProgramInfo.flags,szExtTV,false);
|
|
}
|
|
|
|
if (strlen(szTVRating) > 0)
|
|
{
|
|
if (strlen(szExtTV) > 0)
|
|
{
|
|
strcat( szTVRating, " (" );
|
|
strcat( szTVRating, szExtTV );
|
|
strcat( szTVRating, ")" );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
i = cc; // set offset (needed if it's been mangled by HasParts or IsMovie)
|
|
|
|
strncpy(szShowTitle,strReplayShow.ProgramInfo.szDescription + i,strReplayShow.ProgramInfo.titleLen);
|
|
i = i + strReplayShow.ProgramInfo.titleLen;
|
|
|
|
strncpy(szEpisodeTitle,strReplayShow.ProgramInfo.szDescription + i,strReplayShow.ProgramInfo.episodeLen);
|
|
i = i + strReplayShow.ProgramInfo.episodeLen;
|
|
|
|
// Convert Codepages
|
|
|
|
ConvertCodepage(strReplayShow.ProgramInfo.szDescription);
|
|
ConvertCodepage(szShowTitle);
|
|
ConvertCodepage(szEpisodeTitle);
|
|
|
|
// Build Strings
|
|
|
|
DisplayQuality(strReplayShow.quality,szQuality);
|
|
|
|
// Display Record
|
|
|
|
strcat(szOutputBuffer, "<ITEM>\n");
|
|
strcat(szOutputBuffer,"\t<DISPLAYNAME>");
|
|
|
|
if (szEpisodeTitle[0] > 31)
|
|
{
|
|
sprintf(szBuffer,"%s \"%s\"",szShowTitle,szEpisodeTitle);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
}
|
|
else
|
|
{
|
|
if (ismovie)
|
|
{
|
|
|
|
if (szStarRating[0] != 0)
|
|
{
|
|
if (strMovieInfo.stars % 10)
|
|
{
|
|
sprintf(szBuffer,"%s (%s1/2, %s, %d",szShowTitle,szStarRating,szMPAARating,strMovieInfo.year);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szBuffer,"%s (%s, %s, %d",szShowTitle,szStarRating,szMPAARating,strMovieInfo.year);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(szBuffer,"%s (%s, %d",szShowTitle,szMPAARating,strMovieInfo.year);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcat(szOutputBuffer, szShowTitle);
|
|
}
|
|
}
|
|
|
|
// display flags
|
|
|
|
cc = 0;
|
|
i = 0;
|
|
|
|
if (iscc)
|
|
{
|
|
cc++;
|
|
}
|
|
if (isstereo)
|
|
{
|
|
cc++;
|
|
}
|
|
if (isrepeat)
|
|
{
|
|
cc++;
|
|
}
|
|
if (issap)
|
|
{
|
|
cc++;
|
|
}
|
|
if (isppv)
|
|
{
|
|
cc++;
|
|
}
|
|
|
|
if (szTVRating[0] > 31)
|
|
{
|
|
cc++;
|
|
}
|
|
|
|
if (isletterbox)
|
|
{
|
|
cc++;
|
|
}
|
|
|
|
if (cc > 0)
|
|
{
|
|
if (ismovie)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
else
|
|
{
|
|
strcat(szOutputBuffer," (");
|
|
}
|
|
i = 1;
|
|
}
|
|
else
|
|
{
|
|
if (ismovie)
|
|
{
|
|
strcat(szOutputBuffer,")");
|
|
}
|
|
}
|
|
|
|
if (szTVRating[0] > 31)
|
|
{
|
|
strcat(szOutputBuffer,szTVRating);
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (iscc)
|
|
{
|
|
strcat(szOutputBuffer,"CC");
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (isstereo)
|
|
{
|
|
strcat(szOutputBuffer,"Stereo");
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (isrepeat)
|
|
{
|
|
strcat(szOutputBuffer,"Repeat");
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (issap)
|
|
{
|
|
strcat(szOutputBuffer,"SAP");
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (isppv)
|
|
{
|
|
strcat(szOutputBuffer,"PPV");
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (isletterbox)
|
|
{
|
|
strcat(szOutputBuffer,"Letterboxed");
|
|
cc--;
|
|
if (cc)
|
|
{
|
|
strcat(szOutputBuffer,", ");
|
|
}
|
|
}
|
|
|
|
if (i > 0)
|
|
{
|
|
strcat(szOutputBuffer,")");
|
|
}
|
|
|
|
if (hasparts)
|
|
{
|
|
sprintf(szBuffer,"Part %d of %d",strPartsInfo.partnumber,strPartsInfo.maxparts);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
}
|
|
|
|
strcat(szOutputBuffer,"</DISPLAYNAME>\n");
|
|
|
|
sprintf(szBuffer,"\t<QUALITY>%s</QUALITY>\n",szQuality);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
|
|
sprintf(szBuffer,"\t<RECORDED>%s</RECORDED>\n",UnixTimeToString(strReplayShow.recorded));
|
|
strcat(szOutputBuffer, szBuffer);
|
|
|
|
sprintf(szBuffer,"\t<PATH>Video/%u.mpg</PATH>\n",strReplayShow.recorded);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
|
|
strcat(szOutputBuffer,"\t<DURATION>");
|
|
i = strReplayShow.ProgramInfo.minutes + strReplayShow.afterpadding + strReplayShow.beforepadding;
|
|
cc = CalculateMinutes(strReplayShow.seconds);
|
|
if (cc != i)
|
|
{
|
|
// This can happen if the cable goes out during recording or if you hit STOP etc.
|
|
sprintf(szBuffer,"%d minutes ( %d scheduled )",cc,i);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szBuffer,"%d minutes",cc);
|
|
}
|
|
strcat(szOutputBuffer, szBuffer);
|
|
strcat(szOutputBuffer,"</DURATION>\n");
|
|
|
|
sprintf(szBuffer,"\t<SIZE>%d</SIZE>\n",cc);
|
|
strcat(szOutputBuffer, szBuffer);
|
|
|
|
strcat(szOutputBuffer,"</ITEM>\n");
|
|
|
|
fptr += readsize;
|
|
}
|
|
}
|
|
while ( moreshows == true );
|
|
strcat(szOutputBuffer, "</REPLAYGUIDE>\n");
|
|
|
|
// Done, shut it down
|
|
|
|
//printf("Done! %u ReplayShows parsed!\n", curshow);
|
|
|
|
return 0;
|
|
|
|
}
|
|
}
|
|
|