aboutsummaryrefslogtreecommitdiff
path: root/lib/libRTV
diff options
context:
space:
mode:
authortheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
committertheuni <theuni-nospam-@xbmc.org>2011-01-24 16:05:21 -0500
commitc51b1189e3d5353e842991f5859ddcea0f73e426 (patch)
treeef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/libRTV
parentbe61ebdc9e897fe40c6f371111724de79ddee8d5 (diff)
Merged cptspiff's code-reshuffle branch.
Squashed commit due to build breakage during code-reshuffle history. Conflicts: xbmc/Util.cpp xbmc/cdrip/CDDARipper.cpp xbmc/filesystem/Directory.cpp xbmc/filesystem/File.cpp
Diffstat (limited to 'lib/libRTV')
-rw-r--r--lib/libRTV/GuideParser.cpp1593
-rw-r--r--lib/libRTV/GuideParser.h7
-rw-r--r--lib/libRTV/Makefile.in9
-rw-r--r--lib/libRTV/crypt.c215
-rw-r--r--lib/libRTV/crypt.h29
-rw-r--r--lib/libRTV/guideclient.c128
-rw-r--r--lib/libRTV/guideclient.h27
-rw-r--r--lib/libRTV/httpclient.c494
-rw-r--r--lib/libRTV/httpclient.h95
-rw-r--r--lib/libRTV/httpfsclient.c401
-rw-r--r--lib/libRTV/httpfsclient.h79
-rw-r--r--lib/libRTV/interface.c363
-rw-r--r--lib/libRTV/interface.h39
-rwxr-xr-xlib/libRTV/libRTV.libbin0 -> 62010 bytes
-rw-r--r--lib/libRTV/libRTV.sln30
-rw-r--r--lib/libRTV/libRTV.vcproj483
-rw-r--r--lib/libRTV/libRTV.vcxproj229
-rw-r--r--lib/libRTV/libRTV.vcxproj.filters77
-rwxr-xr-xlib/libRTV/libRTVd.libbin0 -> 152314 bytes
-rw-r--r--lib/libRTV/md5.c337
-rw-r--r--lib/libRTV/md5.h24
-rw-r--r--lib/libRTV/netclient.c316
-rw-r--r--lib/libRTV/netclient.h29
-rw-r--r--lib/libRTV/rtv.c222
-rw-r--r--lib/libRTV/rtv.h85
-rw-r--r--lib/libRTV/sleep.c44
-rw-r--r--lib/libRTV/sleep.h22
27 files changed, 5377 insertions, 0 deletions
diff --git a/lib/libRTV/GuideParser.cpp b/lib/libRTV/GuideParser.cpp
new file mode 100644
index 0000000000..5006bc60ab
--- /dev/null
+++ b/lib/libRTV/GuideParser.cpp
@@ -0,0 +1,1593 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+** 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(__APPLE__)) && !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 __APPLE__
+#include <AvailabilityMacros.h>
+#endif
+
+#if defined(__unix__) || defined(__APPLE__)
+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;
+#if defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED > 1040)
+extern long _timezone;
+#endif
+#ifndef _WIN32
+extern char *_tzname[2];
+#endif
+
+#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");
+
+#if (MAC_OS_X_VERSION_MAX_ALLOWED <= 1040) && !defined(_WIN32)
+ struct timezone tz;
+ gettimeofday(NULL, &tz);
+ tzbias = tz.tz_minuteswest;
+#else
+ tzbias = _timezone;
+#endif
+
+ 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
+//-------------------------------------------------------------------------
+
+#if defined(__unix__) || defined(__APPLE__)
+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)
+{
+ 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
+
+#if defined(__unix__) || defined(__APPLE__)
+ // UNIX specific translations
+#endif
+
+ }
+
+ return;
+
+}
+
+//-------------------------------------------------------------------------
+// Misc. Functions
+//-------------------------------------------------------------------------
+
+//-------------------------------------------------------------------------
+int CalculateMinutes( int 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));
+
+ size_t cc = sizeof(llValue) - 1;
+ size_t 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,"%s", "");
+
+ // 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/%ld.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;
+
+}
+}
+
diff --git a/lib/libRTV/GuideParser.h b/lib/libRTV/GuideParser.h
new file mode 100644
index 0000000000..16f990c5ea
--- /dev/null
+++ b/lib/libRTV/GuideParser.h
@@ -0,0 +1,7 @@
+#ifndef GUIDEPARSER_H
+#define GUIDEPARSER_H
+
+extern int GuideParser(char * szOutputBuffer, const char * szInput, const size_t InputSize);
+
+#endif
+
diff --git a/lib/libRTV/Makefile.in b/lib/libRTV/Makefile.in
new file mode 100644
index 0000000000..697573b1b8
--- /dev/null
+++ b/lib/libRTV/Makefile.in
@@ -0,0 +1,9 @@
+SRCS=crypt.c guideclient.c GuideParser.c httpclient.c httpfsclient.c interface.c md5.c netclient.c rtv.c sleep.c
+
+CFLAGS += -D_LINUX
+CXXFLAGS += -D_LINUX
+
+LIB= librtv-@ARCH@.a
+
+include ../../Makefile.include
+
diff --git a/lib/libRTV/crypt.c b/lib/libRTV/crypt.c
new file mode 100644
index 0000000000..62251331a6
--- /dev/null
+++ b/lib/libRTV/crypt.c
@@ -0,0 +1,215 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#include "crypt.h"
+#include "md5.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+static void checksum(unsigned char * dest, unsigned const char * src, u32 len,
+ int checksum_num)
+{
+
+ static unsigned char extradata[][64] = {{
+ 0x41,0x47,0xc8,0x09, 0xba,0x3c,0x99,0x6a,
+ 0xda,0x09,0x9a,0x0f, 0xc0,0xd3,0x47,0xca,
+ 0xd1,0x95,0x81,0x19, 0xab,0x17,0xc6,0x5f,
+ 0xad,0xea,0xe5,0x75, 0x9c,0x49,0x18,0xa5,
+ 0xdf,0x35,0x46,0x5b, 0x78,0x0e,0xcb,0xc7,
+ 0x8c,0x3e,0xf4,0x90, 0xa2,0xb7,0x8e,0x00,
+ 0x53,0x8d,0x4c,0xab, 0x13,0xa5,0x16,0x00,
+ 0xff,0xb8,0x4b,0x20, 0x29,0x22,0x9d,0xee,
+ }, {
+ 0xda,0x76,0x5c,0xd4, 0x34,0xc3,0xd7,0x2c,
+ 0xac,0x40,0xb8,0xd8, 0x59,0xbc,0x59,0x34,
+ 0xaa,0xbf,0x89,0xbd, 0x85,0xe8,0x40,0x27,
+ 0x78,0x2b,0x18,0x6e, 0xa6,0x6e,0x5a,0xc6,
+ 0xda,0xe3,0x86,0x84, 0x40,0x14,0x2a,0x23,
+ 0x4f,0x5d,0x38,0x5e, 0x7f,0xd9,0x73,0x7d,
+ 0xe4,0x80,0x3d,0x21, 0x28,0x41,0xf1,0xb2,
+ 0x96,0x43,0x2b,0xcc, 0x0c,0x9d,0x26,0xb9,
+ }};
+
+ md5_context c;
+ md5_starts(&c);
+ md5_update(&c, src, len);
+ md5_update(&c, extradata[checksum_num], sizeof extradata[checksum_num]);
+ md5_finish(&c, dest);
+}
+
+static u32 cryptblock(u32 k, char * buf, u32 size)
+{
+ u32 i;
+
+ for (i = 0; i < size; i++) {
+ k = k * 0xb8f7 + 0x15bb9;
+ buf[i] ^= k;
+ }
+ return k;
+}
+
+/* cyphertext bytes:
+ *
+ * 2, 4, 1, 7 -- key material block 1
+ * 0, 3, 5, 6 -- unknown/unused
+ * 8..23 -- checksum(24..end)
+ * 24..27 -- crypt(0x42ffdfa9)
+ * 28..31 -- crypt(time_t)
+ * 32..end -- crypt(text)
+ *
+ * it looks like you should be able to decrypt 24..end in one step, after
+ * getting the key material, if you don't want to do the sanity check first
+ * and don't mind it all in one buffer
+ */
+
+int rtv_decrypt(const char * cyphertext, u32 cyphertext_len,
+ char * plainbuf, u32 plainbuf_len,
+ u32 * p_time, u32 * p_plain_len,
+ int checksum_num)
+{
+ unsigned char key_buf[4];
+ unsigned char sanity_buf[4];
+ unsigned char time_buf[4];
+ unsigned char csum_buf[16];
+ unsigned char * p;
+ u32 key;
+ u32 sanity;
+#if VERBOSE_OBFUSC
+ unsigned char obfusc_buf[4];
+ u32 obfusc;
+#endif
+
+ if (plainbuf_len < cyphertext_len - 32)
+ return -1;
+
+ /* unshuffle the key and unxor it */
+ key_buf[0] = cyphertext[2];
+ key_buf[1] = cyphertext[4];
+ key_buf[2] = cyphertext[1];
+ key_buf[3] = cyphertext[7];
+ p = key_buf;
+ key = rtv_to_u32(&p) ^ 0xcb0baf47;
+
+#if VERBOSE_OBFUSC
+ obfusc_buf[0] = cyphertext[0];
+ obfusc_buf[1] = cyphertext[3];
+ obfusc_buf[2] = cyphertext[5];
+ obfusc_buf[3] = cyphertext[6];
+ p = key_buf;
+ obfusc = rtv_to_u32(&p);
+ //fprintf(stderr, "Key: %ld (0x%lx)\n", (unsigned long)key, (unsigned long)key);
+ //fprintf(stderr, "Obfusc: %ld (0x%lx)\n", (unsigned long)obfusc, (unsigned long)obfusc);
+#endif
+
+ /* check the sanity field */
+ memcpy(sanity_buf, cyphertext + 24, 4);
+ key = cryptblock(key, (char*)sanity_buf, 4);
+ p = sanity_buf;
+ sanity = rtv_to_u32(&p);
+ if (sanity != 0x42ffdfa9)
+ return -1;
+
+ /* decrypt the time field */
+ memcpy(time_buf, cyphertext + 28, 4);
+ key = cryptblock(key, (char*)time_buf, 4);
+
+ /* decrypt the actual text */
+ memcpy(plainbuf, cyphertext + 32, cyphertext_len - 32);
+ cryptblock(key, (char*)plainbuf, cyphertext_len - 32);
+
+ /* check the checksum */
+ checksum(csum_buf, (unsigned const char*)(cyphertext + 24), cyphertext_len - 24, checksum_num);
+ if (memcmp(csum_buf, cyphertext + 8, 16) != 0)
+ return -2;
+
+ if (p_plain_len) {
+ *p_plain_len = cyphertext_len - 32;
+ }
+ if (p_time) {
+ p = time_buf;
+ *p_time = rtv_to_u32(&p);
+#if VERBOSE_OBFUSC
+// fprintf(stderr, "Time: %ld (0x%lx)\n", (unsigned long)*p_time, (unsigned long)*p_time);
+#endif
+ }
+ return 0;
+}
+
+int rtv_encrypt(const char * plaintext, u32 plaintext_len,
+ char * cyphertext, u32 buffer_len, u32 * cyphertext_len,
+ int checksum_num)
+{
+ u32 key;
+ u32 t;
+ u32 obfusc;
+ unsigned char key_buf[4];
+ unsigned char obfusc_buf[4];
+ unsigned char * p;
+
+ if (buffer_len < plaintext_len + 32)
+ return -1;
+
+ /* make up a key and obfuscatory material; get the time */
+ key = rand();
+ obfusc = rand();
+ t = (u32)time(NULL);
+
+ p = NULL;//getenv("TIMEOFF");
+ if (p)
+ t += atoi((char*)p);
+
+ /* encrypt the key */
+ p = key_buf;
+ rtv_from_u32(&p, key ^ 0xcb0baf47);
+
+ p = obfusc_buf;
+ rtv_from_u32(&p, obfusc);
+
+ /* scramble the key and obfusc material */
+ cyphertext[0] = obfusc_buf[3];
+ cyphertext[1] = key_buf[2];
+ cyphertext[2] = key_buf[0];
+ cyphertext[3] = obfusc_buf[2];
+ cyphertext[4] = key_buf[1];
+ cyphertext[5] = obfusc_buf[1];
+ cyphertext[6] = obfusc_buf[0];
+ cyphertext[7] = key_buf[3];
+
+ /* store the sanity check & time */
+ p = (unsigned char*)(cyphertext + 24);
+ rtv_from_u32(&p, 0x42ffdfa9);
+ rtv_from_u32(&p, t);
+
+ /* copy the plaintext */
+ memcpy(p, plaintext, plaintext_len);
+
+ /* encrypt the whole thing */
+ cryptblock(key, cyphertext+24, plaintext_len+8);
+
+ /* fill in the checksum */
+ checksum((unsigned char*)(cyphertext + 8), (unsigned const char*)(cyphertext + 24), plaintext_len + 8, checksum_num);
+
+ /* and we're done */
+ *cyphertext_len = plaintext_len + 32;
+ return 0;
+}
diff --git a/lib/libRTV/crypt.h b/lib/libRTV/crypt.h
new file mode 100644
index 0000000000..497d180881
--- /dev/null
+++ b/lib/libRTV/crypt.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#ifndef CRYPT_H
+#define CRYPT_H
+
+#include "rtv.h"
+
+int rtv_decrypt(const char * cyphertext, u32 cypherlength,
+ char * plainbuf, u32 plainbuflength,
+ u32 * time, u32 * plainlen,
+ int checksum_num);
+int rtv_encrypt(const char * plaintext, u32 plaintext_len,
+ char * cyphertext, u32 buffer_len, u32 * cyphertext_len,
+ int checksum_num);
+#endif
+
+
diff --git a/lib/libRTV/guideclient.c b/lib/libRTV/guideclient.c
new file mode 100644
index 0000000000..e21cdd8789
--- /dev/null
+++ b/lib/libRTV/guideclient.c
@@ -0,0 +1,128 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#include "rtv.h"
+#include "guideclient.h"
+#include "httpclient.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+struct snapshot_data
+{
+ int firsttime;
+ int filesize;
+ int bytes_read;
+ char * timestamp;
+ char * buf;
+ u32 status;
+};
+
+static void get_snapshot_callback(unsigned char * buf, size_t len, void * vd)
+{
+ struct snapshot_data * data = vd;
+ unsigned char * buf_data_start;
+ unsigned long bytes_to_read;
+
+ if (data->firsttime) {
+ unsigned char * end, * equal, * cur;
+
+ data->firsttime = 0;
+
+ /* First line: error code */
+ cur = buf;
+ end = (unsigned char*)strchr((char*)cur, '\n');
+ if (end) *end = '\0';
+ data->status = strtoul((char*)cur, NULL, 16);
+ if (!end) return;
+ do {
+ cur = end + 1;
+ if (*cur == '#') {
+ end = (unsigned char*)strchr((char*)cur, '\0');
+ len -= (end - buf);
+ buf_data_start = end;
+ break;
+ }
+ end = (unsigned char*)strchr((char*)cur, '\n');
+ if (!end) return;
+ *end = '\0';
+ equal = (unsigned char*)strchr((char*)cur, '=');
+ if (!equal) return;
+ if (strncmp((char*)cur, "guide_file_name=", (int)(equal-cur+1)) == 0) {
+ data->timestamp = malloc(strlen((const char*)(equal+1))+1);
+ strcpy((char*)data->timestamp, (const char*)(equal+1));
+ } else if (strncmp((char*)cur, "FileLength=", (int)(equal-cur+1)) == 0) {
+ data->filesize = strtoul((char*)equal+1, NULL, 0);
+ data->buf = malloc(data->filesize);
+ } /* also "RemoteFileName", but we don't expose it */
+ } while (1);
+ } else {
+ buf_data_start = buf;
+ }
+
+ bytes_to_read = MIN(len, (unsigned)(data->filesize - data->bytes_read));
+ memcpy(data->buf + data->bytes_read, buf_data_start, bytes_to_read);
+ data->bytes_read += bytes_to_read;
+
+ free(buf);
+}
+
+unsigned long guide_client_get_snapshot(unsigned char ** presult,
+ unsigned char ** ptimestamp,
+ unsigned long * psize,
+ const char * address,
+ const char * cur_timestamp)
+{
+ struct snapshot_data data;
+ char url[512];
+ struct hc * hc;
+
+ memset(&data, 0, sizeof data);
+ data.firsttime = 1;
+ data.status = -1;
+
+ sprintf(url, "http://%s/http_replay_guide-get_snapshot?"
+ "guide_file_name=%s&serial_no=RTV4080K0000000000",
+ address,
+ cur_timestamp);
+
+ hc = hc_start_request(url);
+ if (!hc) {
+ perror("Error: guide_client_get_snapshot(): hc_start_request()");
+ goto exit;
+ }
+
+
+ hc_send_request(hc);
+ hc_read_pieces(hc, get_snapshot_callback, &data);
+
+ hc_free(hc);
+
+ *ptimestamp = (unsigned char*)data.timestamp;
+ *presult = (unsigned char*)data.buf;
+ *psize = data.filesize;
+
+exit:
+ return data.status;
+}
+
diff --git a/lib/libRTV/guideclient.h b/lib/libRTV/guideclient.h
new file mode 100644
index 0000000000..b448783376
--- /dev/null
+++ b/lib/libRTV/guideclient.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#ifndef GUIDECLIENT_H
+#define GUIDECLIENT_H
+
+#include "httpclient.h"
+
+unsigned long guide_client_get_snapshot(unsigned char ** presult,
+ unsigned char ** ptimestamp,
+ unsigned long * psize,
+ const char * address,
+ const char * cur_timestamp);
+
+/* XXX should also have is_show_in_use and delete_show */
+#endif
diff --git a/lib/libRTV/httpclient.c b/lib/libRTV/httpclient.c
new file mode 100644
index 0000000000..26a4946faf
--- /dev/null
+++ b/lib/libRTV/httpclient.c
@@ -0,0 +1,494 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#include "httpclient.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MAX_CHUNK 32768
+
+struct hc_headers
+{
+ char * tag;
+ char * value;
+ struct hc_headers * next;
+};
+
+struct hc
+{
+ struct nc * nc;
+ char * hostname;
+ short port;
+ char * localpart;
+ char * status;
+ struct hc_headers * req_headers;
+ struct hc_headers * rsp_headers;
+ size_t curr_chunk_len;
+};
+
+static void hc_h_free(struct hc_headers * hh)
+{
+ free(hh->tag);
+ free(hh->value);
+ free(hh);
+}
+
+static struct hc_headers * hc_h_make(const char * tag, const char * value)
+{
+ struct hc_headers * h;
+
+ h = malloc(sizeof *h);
+ if (!h)
+ goto error;
+ memset(h, 0, sizeof *h);
+
+ h->tag = strdup(tag);
+ if (!h->tag)
+ goto error;
+
+ h->value = strdup(value);
+ if (!h->value)
+ goto error;
+
+ return h;
+error:
+ if (h)
+ hc_h_free(h);
+ return NULL;
+}
+
+void hc_free(struct hc * hc)
+{
+ struct hc_headers * n;
+
+ if (hc) {
+ free(hc->hostname);
+ free(hc->localpart);
+ free(hc->status);
+ while (hc->req_headers) {
+ n = hc->req_headers->next;
+ hc_h_free(hc->req_headers);
+ hc->req_headers = n;
+ }
+ while (hc->rsp_headers) {
+ n = hc->rsp_headers->next;
+ hc_h_free(hc->rsp_headers);
+ hc->rsp_headers = n;
+ }
+ if (hc->nc)
+ nc_close(hc->nc);
+ free(hc);
+ }
+}
+
+int hc_add_req_header(struct hc * hc, const char * tag, const char * value)
+{
+ struct hc_headers * h;
+
+ h = hc_h_make(tag, value);
+ if (!h)
+ goto error;
+ h->next = hc->req_headers;
+ hc->req_headers = h;
+ return 0;
+error:
+ return -1;
+}
+
+struct hc * hc_start_request(char * url)
+{
+ struct hc * hc;
+ char * e;
+
+ hc = malloc(sizeof *hc);
+ memset(hc, 0, sizeof *hc);
+
+ if (strncmp(url, "http://", 7) != 0) {
+ goto error;
+ }
+ url += 7;
+ e = strchr(url, '/');
+ if (!e) {
+ hc->hostname = strdup(url);
+ hc->localpart = strdup("/");
+ } else {
+ hc->hostname = malloc(e - url + 1);
+ if (!hc->hostname) goto error;
+ memcpy(hc->hostname, url, e - url);
+ hc->hostname[e-url] = '\0';
+ hc->localpart = strdup(e);
+ if (!hc->localpart) goto error;
+ }
+
+ if (hc_add_req_header(hc, "Host", hc->hostname) < 0)
+ goto error;
+
+ e = strchr(hc->hostname, ':');
+ if (e) {
+ *e = '\0';
+ hc->port = (short)strtoul(e+1, NULL, 10);
+ } else {
+ hc->port = 80;
+ }
+
+ hc->nc = nc_open(hc->hostname, hc->port);
+ if (!hc->nc)
+ goto error;
+
+ return hc;
+error:
+ if (hc)
+ hc_free(hc);
+ return NULL;
+}
+
+int hc_send_request(struct hc * hc)
+{
+ char buffer[1024];
+ size_t l;
+ struct hc_headers * h;
+
+ l = strlen(hc->localpart) + strlen("GET HTTP/1.1\r\n");
+ for (h = hc->req_headers; h; h = h->next)
+ l += strlen(h->tag) + strlen(h->value) + 4;
+ l += 3;
+ if (l > sizeof buffer) {
+ //fprintf(stderr, "ERROR: hc_send_request: buffer too small; need %lu\n",(unsigned long)l);
+ return -1;
+ }
+
+ l = sprintf(buffer, "GET %s HTTP/1.1\r\n", hc->localpart);
+ for (h = hc->req_headers; h; h = h->next)
+ l += sprintf(buffer+l, "%s: %s\r\n", h->tag, h->value);
+ l += sprintf(buffer+l, "\r\n");
+ nc_write(hc->nc, (unsigned char*)buffer, l);
+
+ if (nc_read_line(hc->nc, (unsigned char*)buffer, sizeof buffer) <= 0) {
+ perror("ERROR: hc_send_request nc_read_line");
+ return -1;
+ }
+
+ hc->status = strdup(buffer);
+ while (nc_read_line(hc->nc, (unsigned char*)buffer, sizeof buffer) > 0) {
+ char * e;
+ e = strchr(buffer, ':');
+ if (e) {
+ *e = '\0';
+ e++;
+ while (isspace(*e))
+ e++;
+ h = hc_h_make(buffer, e);
+ h->next = hc->rsp_headers;
+ hc->rsp_headers = h;
+ } else {
+ //fprintf(stderr, "ERROR: hc_send_request got invalid header line :%s:\n", buffer);
+ }
+ }
+
+ return 0;
+}
+
+int hc_post_request(struct hc * hc,
+ int (*callback)(unsigned char *, size_t, void *),
+ void * v)
+{
+ char buffer[1024];
+ size_t l;
+ struct hc_headers * h;
+
+ l = strlen(hc->localpart) + strlen("POST HTTP/1.0\r\n");
+ for (h = hc->req_headers; h; h = h->next)
+ l += strlen(h->tag) + strlen(h->value) + 4;
+ l += 3;
+ if (l > sizeof buffer) {
+ //fprintf(stderr, "ERROR: hc_post_request: buffer too small; need %lu\n",(unsigned long)l);
+ return -1;
+ }
+
+ l = sprintf(buffer, "POST %s HTTP/1.0\r\n", hc->localpart);
+ for (h = hc->req_headers; h; h = h->next)
+ l += sprintf(buffer+l, "%s: %s\r\n", h->tag, h->value);
+ l += sprintf(buffer+l, "\r\n");
+ nc_write(hc->nc, (unsigned char*)buffer, l);
+
+ while ((l = callback((unsigned char*)buffer, sizeof buffer, v)) != 0) {
+ int r;
+ r = nc_write(hc->nc, (unsigned char*)buffer, l);
+// fprintf(stderr, "%d\n", r);
+
+ }
+
+ if (nc_read_line(hc->nc, (unsigned char*)buffer, sizeof buffer) <= 0) {
+ perror("ERROR: hc_post_request nc_read_line");
+ return -1;
+ }
+ hc->status = strdup(buffer);
+ while (nc_read_line(hc->nc, (unsigned char*)buffer, sizeof buffer) > 0) {
+ char * e;
+ e = strchr(buffer, ':');
+ if (e) {
+ *e = '\0';
+ e++;
+ while (isspace(*e))
+ e++;
+ h = hc_h_make(buffer, e);
+ h->next = hc->rsp_headers;
+ hc->rsp_headers = h;
+ } else {
+ //fprintf(stderr, "ERROR: hc_post_request got invalid header line :%s:\n", buffer);
+ }
+ }
+
+ return 0;
+}
+
+int hc_get_status(struct hc * hc)
+{
+ return strtoul(hc->status + 9, NULL, 10);
+}
+
+char * hc_lookup_rsp_header(struct hc * hc, const char * tag)
+{
+ struct hc_headers * h;
+
+ for (h = hc->rsp_headers; h; h = h->next)
+ if (strcasecmp(tag, h->tag) == 0)
+ return h->value;
+ return NULL;
+}
+
+extern int hc_read_pieces(struct hc * hc,
+ void (*callback)(unsigned char *, size_t, void *),
+ void * v)
+{
+ char * te;
+ int chunked = 0;
+ int done = 0;
+ char * buf;
+ size_t len, len_read, octets_to_go;
+ char * cl;
+
+ cl = hc_lookup_rsp_header(hc, "Content-Length");
+ if (cl) {
+ octets_to_go = strtoul(cl, NULL, 10);
+ } else {
+ octets_to_go = 0;
+ }
+
+ te = hc_lookup_rsp_header(hc, "Transfer-Encoding");
+ if (te && strcmp(te, "chunked") == 0) {
+ chunked = 1;
+ }
+ while (!done) {
+ if (chunked) {
+ char lenstr[32];
+
+ nc_read_line(hc->nc, (unsigned char*)lenstr, sizeof lenstr);
+ len = strtoul(lenstr, NULL, 16);
+ } else {
+ if (cl) {
+ len = octets_to_go;
+ if (len > MAX_CHUNK)
+ len = MAX_CHUNK;
+ } else {
+ len = MAX_CHUNK;
+ }
+ }
+ if (len) {
+ buf = malloc(len+1);
+ len_read = nc_read(hc->nc, (unsigned char*)buf, len);
+ if (len_read < len)
+ done = 1;
+ buf[len_read] = '\0';
+ callback((unsigned char*)buf, len_read, v);
+ if (cl) {
+ octets_to_go -= len_read;
+ if (octets_to_go == 0 && !chunked) {
+ done = 1;
+ }
+ }
+ } else {
+ done = 1;
+ }
+ if (chunked) {
+ char linebuf[80];
+ /* if done, then any non-blank lines read here are
+ supposed to be treated as HTTP header lines, but since
+ we didn't say we could accept trailers, the server's
+ only allowed to send them if it's happy with us
+ discarding them. (2616 3.7b). The Replay doesn't use
+ trailers anyway */
+ while (nc_read_line(hc->nc, (unsigned char*)linebuf, sizeof linebuf) > 0)
+ ;
+ }
+ }
+ return 0;
+}
+
+struct chunk
+{
+ char * buf;
+ size_t len;
+ struct chunk * next;
+};
+
+struct read_all_data
+{
+ struct chunk * start;
+ struct chunk * end;
+ size_t total;
+};
+
+static void read_all_callback(unsigned char * buf, size_t len, void * vd)
+{
+ struct read_all_data * data = vd;
+ struct chunk * chunk;
+
+ chunk = malloc(sizeof *chunk);
+ chunk->buf = (char*)buf;
+ chunk->len = len;
+ chunk->next = NULL;
+
+ if (data->end) {
+ data->end->next = chunk;
+ data->end = chunk;
+ } else {
+ data->start = data->end = chunk;
+ }
+
+ data->total += len;
+}
+
+unsigned char * hc_read_all_len(struct hc * hc, size_t * plen)
+{
+ struct read_all_data data;
+ struct chunk * chunk, * next;
+ size_t cur;
+ unsigned char * r;
+
+ data.start = data.end = NULL;
+ data.total = 0;
+
+ hc_read_pieces(hc, read_all_callback, &data);
+
+ r = malloc(data.total + 1);
+ cur = 0;
+ for (chunk = data.start; chunk; chunk = next) {
+ memcpy(r+cur, chunk->buf, chunk->len);
+ cur += chunk->len;
+ free(chunk->buf);
+ next = chunk->next;
+ free(chunk);
+ }
+
+ r[data.total] = '\0';
+ if (plen)
+ *plen = data.total;
+
+ return r;
+}
+
+unsigned char * hc_read_all(struct hc * hc)
+{
+ return hc_read_all_len(hc, NULL);
+}
+
+
+extern int hc_read_pieces_len(struct hc * hc,
+ void (*callback)(unsigned char *, size_t, void *),
+ void * v, size_t len_to_read)
+{
+ char * te;
+ int chunked = 0;
+ int done = 0;
+ char * buf;
+ size_t len, len_read, octets_to_go;
+ char * cl;
+
+ // NOTE: len_to_read is not currently implemented for non-chunked content.
+ // The ReplayTV only sends chunked content so this doesn't matter here.
+ cl = hc_lookup_rsp_header(hc, "Content-Length");
+ if (cl) {
+ octets_to_go = strtoul(cl, NULL, 10);
+ } else {
+ octets_to_go = 0;
+ }
+
+ te = hc_lookup_rsp_header(hc, "Transfer-Encoding");
+ if (te && strcmp(te, "chunked") == 0) {
+ chunked = 1;
+ }
+ while (!done) {
+ if (chunked) {
+ char lenstr[32];
+
+ if (!hc->curr_chunk_len) {
+ nc_read_line(hc->nc, (unsigned char*)lenstr, sizeof lenstr);
+ hc->curr_chunk_len = strtoul(lenstr, NULL, 16);
+ }
+ if (len_to_read > hc->curr_chunk_len) {
+ len = hc->curr_chunk_len;
+ } else {
+ len = len_to_read;
+ }
+ } else {
+ if (cl) {
+ len = octets_to_go;
+ if (len > MAX_CHUNK)
+ len = MAX_CHUNK;
+ } else {
+ len = MAX_CHUNK;
+ }
+ }
+ if (len) {
+ buf = malloc(len+1);
+ len_read = nc_read(hc->nc, (unsigned char*)buf, len);
+ if (len_read <= len)
+ done = 1;
+ buf[len_read] = '\0';
+ callback((unsigned char*)buf, len_read, v);
+ if (cl) {
+ octets_to_go -= len_read;
+ if (octets_to_go == 0 && !chunked) {
+ done = 1;
+ }
+ }
+ hc->curr_chunk_len -= len_read;
+ } else {
+ done = 1;
+ }
+ if (chunked && !hc->curr_chunk_len) {
+ char linebuf[80];
+ /* if done, then any non-blank lines read here are
+ supposed to be treated as HTTP header lines, but since
+ we didn't say we could accept trailers, the server's
+ only allowed to send them if it's happy with us
+ discarding them. (2616 3.7b). The Replay doesn't use
+ trailers anyway */
+ while (nc_read_line(hc->nc, (unsigned char*)linebuf, sizeof linebuf) > 0)
+ ;
+ }
+ }
+ return 0;
+}
+
diff --git a/lib/libRTV/httpclient.h b/lib/libRTV/httpclient.h
new file mode 100644
index 0000000000..7f2da0e585
--- /dev/null
+++ b/lib/libRTV/httpclient.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+/*
+ * Overview of an HTTP request:
+ *
+ * 1. call hc_start_request() with an URL
+ *
+ * hc = hc_start_request("http://192.168.117.3/index.html");
+ * if (!hc) {error}
+ *
+ * Right now the address in the URL must be given as an IP address, not
+ * a hostname. That's a bug, not a feature.
+ *
+ * 2. add any necessary headers with hc_add_req_header; the Host header is
+ * created automatically; any others, including User-Agent, must be
+ * explicitely set
+ *
+ * if (!hc_add_req_header(hc, "User-Agent", "Mozilla/4.0 (Isn't everything?)") != 0) {error}
+ *
+ * 3. send the request; hc_send_request() uses GET, hc_post_request() uses
+ * POST, with the callback function called repeatedly for the data. It
+ * should return the number of bytes filled in, and signal end of data by
+ * returning 0.
+ *
+ * if (!hc_send_request(hc)) {error}
+ *
+ * 4. check the returned status; 200 is the normal success code, any 2.. code
+ * is a success of some sort. 3.. codes are redirects, 4.. are errors; see
+ * the HTTP specs for more information
+ *
+ * if (hc_get_status(hc)/100 != 2) {exception of some sort}
+ *
+ * 5. Check any response headers you're interested in.
+ *
+ * last_modified = hc_lookup_rsp_header(hc, "Last-Modified");
+ * if (!last_modified) {header wasn't supplied}
+ *
+ * 6. read the data; if the item is known to be short, you have the memory for
+ * it (2x the data length; half of that as a contiguous block), and don't
+ * mind waiting for all of it, get it all with hc_read_all(). If one of
+ * conditions doesn't hold, call hc_read_pieces(). The callback function
+ * is given a buffer to a chunk of data, the amount of data there, and
+ * a pointer you supply, usually to a structure where it can store state,
+ * get parameters from the original caller and return information to the
+ * original caller
+ *
+ * if (!(data = hc_read_all(hc))) {error}
+ *
+ * Either way, you own the data chunk -- free() it when you're done with it
+ *
+ * 7. Clean up
+ *
+ * hc_free(hc);
+ */
+#ifndef HTTPCLIENT_H
+#define HTTPCLIENT_H
+
+#include "netclient.h"
+
+#ifdef _WIN32
+# define strcasecmp(a, b) strcmp(a, b)
+#endif
+
+struct hc;
+
+extern struct hc * hc_start_request(char * url);
+extern int hc_add_req_header(struct hc * hc, const char * tag, const char * value);
+extern int hc_send_request(struct hc * hc);
+extern int hc_post_request(struct hc * hc,
+ int (*callback)(unsigned char *, size_t, void *),
+ void * v);
+extern int hc_get_status(struct hc * hc);
+extern char * hc_lookup_rsp_header(struct hc * hc, const char * tag);
+extern unsigned char * hc_read_all_len(struct hc * hc, size_t * plen);
+extern unsigned char * hc_read_all(struct hc * hc);
+extern int hc_read_pieces(struct hc * hc,
+ void (*)(unsigned char *, size_t, void *),
+ void *);
+extern int hc_read_pieces_len(struct hc * hc,
+ void (*)(unsigned char *, size_t, void *),
+ void *, size_t);
+extern void hc_free(struct hc * hc);
+#endif
diff --git a/lib/libRTV/httpfsclient.c b/lib/libRTV/httpfsclient.c
new file mode 100644
index 0000000000..c53ad6a9b1
--- /dev/null
+++ b/lib/libRTV/httpfsclient.c
@@ -0,0 +1,401 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * Parts based on ReplayPC 0.3 by Matthew T. Linehan and others
+ *
+ * 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 of the License, 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.
+ */
+
+#include "httpfsclient.h"
+#include "sleep.h"
+#include "crypt.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+int hfs_output_errors = 1;
+
+#define ARGBUFSIZE 2048
+static int make_httpfs_url(char * dst, size_t size,
+ const char * address, const char * command,
+ va_list args)
+{
+ char * d, * tag, * value, *argp;
+ int argno = 0;
+ size_t l, argl;
+ char argbuf[ARGBUFSIZE]; /* XXX bad, should fix this */
+
+ (void) size;
+
+ l = strlen(address) + strlen(command) + strlen("http:///httpfs-?");
+ if (l >= size) {
+ //if (hfs_output_errors)
+ //fprintf(stderr, "Error: make_httpfs_url: address + command too long for buffer\n");
+ return -1;
+ }
+
+ d = dst;
+ d += sprintf(d, "http://%s/httpfs-%s?", address, command);
+
+ argp = argbuf;
+ argl = 0;
+ while ((tag = va_arg(args, char *)) != NULL) {
+ value = va_arg(args, char *);
+ if (value == NULL) {
+ continue;
+ }
+ if (argno)
+ argl++;
+ argl += strlen(tag)+1+strlen(value);
+ if (argl >= sizeof(argbuf)) {
+ //if (hfs_output_errors)
+ //fprintf(stderr, "Error: make_httpfs_url: with arg %s, argbuf too small\n", tag);
+ return -1;
+ }
+ if (argno)
+ *argp++ = '&';
+ argp += sprintf(argp, "%s=%s", tag, value);
+ argno++;
+ }
+
+ if (replaytv_version.major >= 5 ||
+ (replaytv_version.major == 4 && replaytv_version.minor >= 3)) {
+ unsigned char ctext[ARGBUFSIZE+32] ;
+ u32 ctextlen;
+ unsigned int i;
+
+ if (l + strlen("__Q_=") + 2*argl + 32 >= size) {
+ //if (hfs_output_errors)
+ // fprintf(stderr, "Error: make_httpfs_url: encrypted args too large for buffer\n");
+ return -1;
+ }
+
+ strcpy(d, "__Q_=");
+ d += strlen(d);
+ rtv_encrypt(argbuf, argl, (char*)ctext, sizeof ctext, &ctextlen, 1);
+ for (i = 0; i < ctextlen; i++)
+ d += sprintf(d, "%02x", ctext[i]);
+ } else {
+ if (l + argl >= size) {
+ //if (hfs_output_errors)
+ //fprintf(stderr, "Error: make_httpfs_url: args too large for buffer\n");
+ return -1;
+ }
+ strcpy(d, argbuf);
+ }
+
+ return 0;
+}
+
+static int add_httpfs_headers(struct hc * hc)
+{
+ hc_add_req_header(hc, "Authorization", "Basic Uk5TQmFzaWM6QTd4KjgtUXQ=" );
+ hc_add_req_header(hc, "User-Agent", "Replay-HTTPFS/1");
+ hc_add_req_header(hc, "Accept-Encoding", "text/plain");
+
+ return 0;
+}
+
+static struct hc * make_request(const char * address, const char * command,
+ va_list ap)
+{
+ struct hc * hc = NULL;
+ char url[URLSIZE];
+ int http_status;
+
+ if (make_httpfs_url(url, sizeof url, address, command, ap) < 0)
+ goto exit;
+
+ hc = hc_start_request(url);
+ if (!hc) {
+ if (hfs_output_errors)
+ perror("Error: make_request(): hc_start_request()");
+ if (errno == 0) {
+// fprintf(stderr, "Check your clock.\n"
+ // "The system clock must be within 40 seconds of the Replay's.");
+ }
+ goto exit;
+ }
+
+ if (add_httpfs_headers(hc)) {
+ goto exit;
+ }
+
+ hc_send_request(hc);
+
+ http_status = hc_get_status(hc);
+ if (http_status/100 != 2) {
+ //if (hfs_output_errors)
+ //fprintf(stderr, "Error: http status %d\n", http_status);
+ goto exit;
+ }
+
+ return hc;
+
+exit:
+ if (hc)
+ hc_free(hc);
+ return NULL;
+}
+
+
+unsigned long hfs_do_simple(char ** presult, const char * address,
+ const char * command, ...)
+{
+ va_list ap;
+ struct hc * hc;
+ char * tmp, * e;
+ int http_status;
+ unsigned long rtv_status;
+
+ va_start(ap, command);
+ hc = make_request(address, command, ap);
+ va_end(ap);
+
+ if (!hc)
+ return -1;
+
+ http_status = hc_get_status(hc);
+ if (http_status/100 != 2) {
+ //if (hfs_output_errors)
+ // fprintf(stderr, "Error: http status %d\n", http_status);
+ hc_free(hc);
+ return http_status;
+ }
+
+ tmp = (char*)hc_read_all(hc);
+ hc_free(hc);
+
+ e = strchr(tmp, '\n');
+ if (e) {
+ *presult = strdup(e+1);
+ rtv_status = strtoul(tmp, NULL, 10);
+ free(tmp);
+ return rtv_status;
+ } else if (http_status == 204) {
+ *presult = NULL;
+ free(tmp);
+ return 0;
+ } else {
+ //if (hfs_output_errors)
+ // fprintf(stderr, "Error: end of httpfs status line not found\n");
+ return -1;
+ }
+}
+
+struct hfs_data
+{
+ void (*fn)(unsigned char *, size_t, void *);
+ void * v;
+ unsigned long status;
+ u16 msec_delay;
+ u8 firsttime;
+ char * buffer;
+ size_t bufLen;
+};
+
+/* XXX should this free the buf, or make a new one on the first block
+ * and let our caller free them if it wants? */
+static void hfs_callback(unsigned char * buf, size_t len, void * vd)
+{
+ struct hfs_data * data = vd;
+ unsigned char * buf_data_start;
+
+ if (data->firsttime) {
+ unsigned char * e;
+
+ data->firsttime = 0;
+
+ /* First line: error code */
+ e = (unsigned char*)strchr((char*)buf, '\n');
+ if (e)
+ *e = '\0';
+ data->status = strtoul((char*)buf, NULL, 16);
+
+ e++;
+ len -= (e - buf);
+ buf_data_start = e;
+ } else {
+ buf_data_start = buf;
+ }
+
+ data->fn(buf_data_start, len, data->v);
+ free(buf);
+
+ if (data->msec_delay)
+ rtv_sleep(data->msec_delay);
+}
+
+unsigned long hfs_do_chunked(void (*fn)(unsigned char *, size_t, void *),
+ void *v,
+ const char * address,
+ u16 msec_delay,
+ const char * command,
+ ...)
+{
+ struct hfs_data data;
+ struct hc * hc;
+ va_list ap;
+
+ va_start(ap, command);
+ hc = make_request(address, command, ap);
+ va_end(ap);
+
+ if (!hc)
+ return -1;
+
+ memset(&data, 0, sizeof data);
+ data.fn = fn;
+ data.v = v;
+ data.firsttime = 1;
+ data.msec_delay = msec_delay;
+
+ hc_read_pieces(hc, hfs_callback, &data);
+ hc_free(hc);
+
+ return data.status;
+}
+
+unsigned long hfs_do_post_simple(char ** presult, const char * address,
+ int (*fn)(unsigned char *, size_t, void *),
+ void *v,
+ unsigned long size,
+ const char * command, ...)
+{
+ char buf[URLSIZE];
+ va_list ap;
+ struct hc * hc;
+ char * tmp, * e;
+ int http_status;
+ unsigned long rtv_status;
+
+ va_start(ap, command);
+ if (make_httpfs_url(buf, sizeof buf, address, command, ap) < 0)
+ return -1;
+ va_end(ap);
+
+ errno = 0;
+ hc = hc_start_request(buf);
+ if (!hc) {
+ if (hfs_output_errors)
+ perror("Error: hfs_do_simple(): hc_start_request()");
+ if (errno == 0) {
+ //fprintf(stderr, "Check your clock.\n"
+ // "The system clock must be within 40 seconds of the Replay's.");
+ }
+ return -1;
+ }
+ sprintf(buf, "%lu", size);
+ if (add_httpfs_headers(hc) != 0)
+ return -1;
+
+ hc_add_req_header(hc, "Content-Length", buf);
+
+ hc_post_request(hc, fn, v);
+
+ http_status = hc_get_status(hc);
+ if (http_status/100 != 2) {
+ //if (hfs_output_errors)
+ // fprintf(stderr, "Error: http status %d\n", http_status);
+ hc_free(hc);
+ return http_status;
+ }
+
+ tmp = (char*)hc_read_all(hc);
+ hc_free(hc);
+
+ e = strchr(tmp, '\n');
+ if (e) {
+ *presult = strdup(e+1);
+ rtv_status = strtoul(tmp, NULL, 10);
+ free(tmp);
+ return rtv_status;
+ } else if (http_status == 204) {
+ *presult = NULL;
+ free(tmp);
+ return 0;
+ } else {
+ //if (hfs_output_errors)
+ //fprintf(stderr, "Error: end of httpfs status line not found\n");
+ return -1;
+ }
+}
+
+
+static void hfs_callback2(unsigned char * buf, size_t len, void * vd)
+{
+ struct hfs_data * data = vd;
+ unsigned char * buf_data_start;
+
+ if (data->firsttime) {
+ unsigned char * e;
+
+ data->firsttime = 0;
+
+ /* First line: error code */
+ e = (unsigned char*)strchr((char*)buf, '\n');
+ if (e)
+ *e = '\0';
+ data->status = strtoul((char*)buf, NULL, 16);
+
+ e++;
+ len -= (e - buf);
+ buf_data_start = e;
+ } else {
+ buf_data_start = buf;
+ }
+
+ /* append to buffer, this may be called multiple times */
+ memcpy(data->buffer+data->bufLen, buf_data_start, len);
+ data->bufLen += len;
+ free(buf);
+}
+
+struct hc * hfs_do_chunked_open(const char * address, const char * command, ...)
+{
+ struct hc * hc;
+ va_list ap;
+
+ va_start(ap, command);
+ hc = make_request(address, command, ap);
+ va_end(ap);
+
+ return hc;
+}
+
+size_t hfs_do_chunked_read(struct hc * hc, char * buf, size_t pos, size_t len)
+{
+ struct hfs_data data;
+
+ memset(&data, 0, sizeof data);
+ data.buffer = buf;
+ if (!pos)
+ data.firsttime = 1;
+
+ hc_read_pieces_len(hc, hfs_callback2, &data, len);
+
+ return data.bufLen;
+}
+
+void hfs_do_chunked_close(struct hc * hc)
+{
+ hc_free(hc);
+}
+
diff --git a/lib/libRTV/httpfsclient.h b/lib/libRTV/httpfsclient.h
new file mode 100644
index 0000000000..a949b86158
--- /dev/null
+++ b/lib/libRTV/httpfsclient.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * Parts based on ReplayPC 0.3 by Matthew T. Linehan and others
+ *
+ * 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 of the License, 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.
+ */
+
+/*
+ * These all return:
+ * 0 for complete success
+ * -1 for a miscellaneous client error
+ * an HTTP error code if the server returned one (300-499 range)
+ * an httpfs error code if the httpfs provider returned one (8082xxxx range,
+ * it seems)
+ *
+ * hfs_do_simple: makes a request, collects all the data, gives it back
+ * hfs_do_chunked: makes a request, gives it to a callback function in chunks
+ * the callback does *not* own the data, and must not free it
+ * or keep a pointer to it; copy it if you want to keep it.
+ * This difference from the httpclient layer is ugly and may
+ * change at some point, even though that will cause a memory
+ * leak in all existing clients
+ * hfs_do_post_simple: POSTs a request, using a callback function to get chunks
+ * of data. The size must be known beforehand, an apparent
+ * unfortunate limitation of the ReplayTV httpfs server.
+ * writefile is the only (current/known) httpfs command that
+ * needs POST
+ *
+ * command: the httpfs command, one of: ls fstat volinfo cp mv rm create
+ * mkdir readfile writefile
+ * arguments are passed as tag/value pairs, NULL terminated.
+ * args for cp: src dest
+ * arg for create, fstat, ls, mkdir, rm, volinfo: name
+ * args for mv: old new
+ * args for readfile, writefile: name pos size
+ */
+
+#ifndef HTTPFSCLIENT_H
+#define HTTPFSCLIENT_H
+
+#include "httpclient.h"
+#include "rtv.h"
+
+#define URLSIZE 512
+
+extern int hfs_output_errors;
+
+extern unsigned long hfs_do_simple(char ** presult,
+ const char * address, const char * command,
+ ...);
+extern unsigned long hfs_do_chunked(void (*)(unsigned char *, size_t, void *),
+ void *,
+ const char * address, u16 msec_delay,
+ const char * command,
+ ...);
+extern unsigned long hfs_do_post_simple(char ** presult, const char * address,
+ int (*fn)(unsigned char *, size_t, void *),
+ void *v,
+ unsigned long size,
+ const char * command,
+ ...);
+extern struct hc * hfs_do_chunked_open(const char * address, const char * command, ...);
+extern size_t hfs_do_chunked_read(struct hc * hc, char * buf, size_t pos, size_t len);
+extern void hfs_do_chunked_close(struct hc * hc);
+
+
+#define RTV_ENOFILE 80820005
+#define RTV_EEXIST 80820018
+#define RTV_EPERM 80820024
+#endif
diff --git a/lib/libRTV/interface.c b/lib/libRTV/interface.c
new file mode 100644
index 0000000000..0aa0e54013
--- /dev/null
+++ b/lib/libRTV/interface.c
@@ -0,0 +1,363 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * libRTV
+ * by rtvguy
+ * A library encapsulating most of the functionality of John Todd Larason's
+ * ReplayPC project and Lee Thompson's GuideParser project.
+ *
+ * libRTV includes much of the original source code by the authors of the
+ * ReplayPC and GuideParser projects. GuideParser was modified under the
+ * terms of its license to remove support for parsing ReplayChannels and
+ * add support for parsing all current versions of ReplayGuide data. ReplayPC
+ * was modified under the terms of its license to improve efficiency of the
+ * network code for the purposes of streaming video to a calling program, as
+ * well as to remove reliance on the OpenSSL library for MD5 functions.
+ *
+ * ReplayPC Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ * GuideParser Copyright (C) 2002-2003 Lee Thompson <thompsonl@logh.net>,
+ * Dan Frumin <rtv@frumin.com>, Todd Larason <jtl@molehill.org>
+ * libRTV Copyright (C) 2003-2004 rtvguy
+ *
+ * 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 of the License, 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "httpfsclient.h"
+#include "guideclient.h"
+#include "GuideParser.h"
+#include "interface.h"
+
+#ifdef _XBOX
+#include <Xtl.h>
+typedef SOCKET socket_fd;
+#elif defined _WIN32
+#include <WS2tcpip.h>
+typedef SOCKET socket_fd;
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <stdlib.h>
+#define closesocket(fd) close(fd)
+typedef int socket_fd;
+typedef socket_fd SOCKET;
+#define INVALID_SOCKET (-1)
+#endif
+
+//*********************************************************************************************
+u64 rtv_get_filesize(const char* strHostName, const char* strFileName)
+{
+ char * data = NULL;
+ char ** lines;
+ int num_lines;
+ int i;
+ u64 size;
+ unsigned long status;
+
+ status = hfs_do_simple(&data, strHostName,
+ "fstat",
+ "name", strFileName,
+ NULL);
+ if (status != 0) {
+ //fprintf(stderr, "Error fstat %ld\n", status);
+ free(data);
+ return 0;
+ }
+
+ num_lines = rtv_split_lines(data, &lines);
+ for (i = 0; i < num_lines; i++) {
+ if (strncmp(lines[i], "size=", 5) == 0) {
+ sscanf(lines[i]+5, "%llu", &size);
+ break;
+ }
+ }
+
+ rtv_free_lines(num_lines, lines);
+ free(data);
+ return size;
+}
+//*********************************************************************************************
+unsigned long rtv_get_guide(unsigned char ** result, const char * address)
+{
+ char * orig_timestamp = "0";
+ unsigned char * timestamp = NULL;
+ unsigned long size;
+ unsigned long status;
+
+ status = guide_client_get_snapshot(result, &timestamp, &size,
+ address, orig_timestamp);
+ if (timestamp)
+ free(timestamp);
+ if (status != 0) {
+ //fprintf(stderr, "Error get_snapshot %ld\n", status);
+ return 0;
+ }
+
+ return size;
+}
+//*********************************************************************************************
+int rtv_parse_guide(char * szOutputBuffer, const char * szInput, const size_t InputSize)
+{
+ return(GuideParser(szOutputBuffer, szInput, InputSize));
+}
+//*********************************************************************************************
+int rtv_get_guide_xml(unsigned char ** result, const char * address)
+{
+ unsigned long gsize;
+ unsigned char * lresult = NULL;
+
+ gsize = rtv_get_guide(&lresult, address);
+ if (!gsize)
+ {
+ if (lresult)
+ free (lresult);
+ return 0;
+ }
+
+ *result = malloc(gsize * 1.5);
+ if (!*result)
+ {
+ if (lresult)
+ free (lresult);
+ return 0;
+ }
+
+ rtv_parse_guide((char*)*result, (char*)lresult, gsize);
+
+ if (lresult)
+ free (lresult);
+ return 1;
+}
+//*********************************************************************************************
+int rtv_list_files(unsigned char ** result, const char * address, const char * path)
+{
+ unsigned long status;
+
+ status = hfs_do_simple((char **)result, address,
+ "ls",
+ "name", path,
+ NULL);
+ if (status != 0) {
+ //fprintf(stderr, "Error %ld\n", status);
+ if (result)
+ free(result);
+ return 0;
+ }
+
+ return 1;
+}
+//*********************************************************************************************
+RTVD rtv_open_file(const char * address, const char * strFileName, u64 filePos)
+{
+ RTVD rtvd;
+ char szOffset[32];
+
+ rtvd = malloc(sizeof *rtvd);
+
+ rtvd->firstReadDone = 0;
+#ifdef _LINUX
+ sprintf(szOffset,"%llu",filePos);
+#else
+ _i64toa(filePos,szOffset,10);
+#endif
+
+ rtvd->hc = hfs_do_chunked_open( address,
+ "readfile",
+ "pos", szOffset,
+ "name", strFileName,
+ NULL);
+ return rtvd;
+}
+//*********************************************************************************************
+size_t rtv_read_file(RTVD rtvd, char * lpBuf, size_t uiBufSize)
+{
+ size_t lenread;
+
+ lenread = hfs_do_chunked_read(rtvd->hc, (char *) lpBuf, rtvd->firstReadDone, uiBufSize);
+ rtvd->firstReadDone = 1;
+
+ return lenread;
+}
+//*********************************************************************************************
+void rtv_close_file(RTVD rtvd)
+{
+ hfs_do_chunked_close(rtvd->hc);
+ free(rtvd);
+}
+//*********************************************************************************************
+int rtv_discovery(struct RTV ** result, unsigned long msTimeout)
+{
+ const char upnpQuery[] = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nST: urn:replaytv-com:device:ReplayDevice:1\r\nMX: 3\r\n\r\n";
+ const char httpQuery[] = "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n";
+ char sendBuf[128];
+ char upnpFile[32];
+ char * p1, * p2;
+ char msg[2048];
+ int opt;
+ int r, len, numRTV;
+ SOCKET s1, s2;
+ struct timeval tv;
+ struct RTV * rtv = NULL;
+ fd_set fds1, fds2;
+ struct sockaddr_in sin; /* send address structure */
+ struct sockaddr_in sin2; /* receive address structure */
+
+ // Need to initialize Winsock on Win32
+#if defined(_WIN32) && !defined(_XBOX)
+ WSADATA wd;
+ if (WSAStartup(MAKEWORD(2,2), &wd) == -1)
+ {
+ goto error;
+ }
+#endif
+ s1 = 0;
+ s2 = 0;
+
+ // Set up the information for the UPNP port connection
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(1900);
+
+ // For some reason, the UPNP address doesn't work on Xbox; so we
+ // use the broadcast address, which seems to work.
+#if defined(_XBOX) || defined(_WIN32)
+ sin.sin_addr.S_un.S_addr = htonl(INADDR_BROADCAST);
+#else
+ inet_aton("239.255.255.250",(struct in_addr*)&sin.sin_addr.s_addr);
+#endif
+
+ if ((s1 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ {
+ //fprintf(stderr,"error: socket(): %d\n", errno);
+ goto error;
+ }
+
+ opt = 1;
+ if ((setsockopt(s1, SOL_SOCKET, SO_BROADCAST, (const void*)&opt, sizeof(opt))) < 0) {
+ goto error;
+ }
+
+ // Send the UPNP query
+ r = sendto(s1, upnpQuery, (int) strlen(upnpQuery), 0, (struct sockaddr *)&sin, sizeof(sin));
+
+ // Initialize variables in preparation to receive responses from the ReplayTV(s)
+ numRTV = 0;
+ rtv = calloc(1, sizeof(struct RTV));
+ if (!rtv) goto error;
+ //memset(rtv,0,sizeof(struct RTV));
+ tv.tv_sec = msTimeout / 1000;
+ tv.tv_usec = (msTimeout % 1000) * 1000;
+ FD_ZERO(&fds1);
+ FD_SET(s1, &fds1);
+
+ // Read the response from a ReplayTV, loop while there are more responses waiting
+ while (select((int) s1 + 1, &fds1, NULL, NULL, &tv))
+ {
+ len = sizeof(struct sockaddr);
+ r = recvfrom(s1, msg, sizeof(msg), 0, (struct sockaddr *)&sin2, (socklen_t*)&len);
+ if (r < 0)
+ {
+ //fprintf(stderr, "recvfrom error: %d\n", errno);
+ } else {
+ numRTV++;
+
+ // Reallocate memory to accomodate the additional ReplayTVs found
+ if (numRTV > 1)
+ {
+ rtv = realloc(rtv, sizeof(struct RTV) * numRTV);
+ if (!rtv) goto error;
+ }
+ //printf("ip: %s\n", inet_ntoa(sin2.sin_addr));
+
+ // Extract IP part and copy to hostname
+ p1 = strstr(msg, "LOCATION: http://") + 17;
+ p2 = strchr(p1, '/');
+ *p2 = '\0';
+ strcpy(rtv[numRTV-1].hostname, p1);
+
+ // Extract UPNP device description file part and copy to upnpFile
+ p1 = p2 + 1;
+ p2 = strchr(p1, '\r');
+ *p2 = '\0';
+ strcpy(upnpFile, p1);
+
+ strcpy(rtv[numRTV-1].friendlyName, rtv[numRTV-1].hostname);
+
+ // Open socket for connecting to ReplayTV to get its friendlyName
+ if ((s2 = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
+ // Connect to ReplayTV
+ sin2.sin_port = htons(80);
+ r = connect(s2, (struct sockaddr *)&sin2, sizeof(sin2));
+ sprintf(sendBuf, httpQuery, upnpFile, rtv[numRTV-1].hostname);
+ r = send(s2, sendBuf, (int) strlen(sendBuf), 0);
+ FD_ZERO(&fds2);
+ FD_SET(s2, &fds2);
+ // Read response if there is one
+ if (select((int) s2 + 1, &fds2, NULL, NULL, &tv)) {
+ p1 = msg;
+ p2 = p1 + sizeof(msg);
+ r = 0;
+ do {
+ p1+=r;
+ r = recv(s2, p1, p2-p1, 0);
+ } while(r>0 && (p2-p1) > 0);
+ msg[sizeof(msg)-1] = 0;
+
+ p1 = strstr(msg, "<friendlyName>");
+ if(p1) {
+ p1 += 14;
+ p2 = strchr(p1, '<');
+ if(p2)
+ {
+ *p2 = '\0';
+ strcpy(rtv[numRTV-1].friendlyName, p1);
+ }
+ }
+ }
+
+ r = closesocket(s2);
+ s2 = 0;
+ }
+ }
+ }
+ r = closesocket(s1);
+ s1 = 0;
+
+ //Need to clean up the Winsock on Win32
+#if defined(_WIN32) && !defined(_XBOX)
+ WSACleanup();
+#endif
+
+ // Pass back the pointer to the array of rtv and return number of ReplayTV(s) found
+ *result = rtv;
+ return numRTV;
+
+ // Clean up and return error
+error:
+ if (rtv) free(rtv);
+ if (s1) closesocket(s1);
+ if (s2) closesocket(s2);
+#if defined(_WIN32) && !defined(_XBOX)
+ WSACleanup();
+#endif
+ return -1;
+}
+//*********************************************************************************************
+
diff --git a/lib/libRTV/interface.h b/lib/libRTV/interface.h
new file mode 100644
index 0000000000..dac5cec489
--- /dev/null
+++ b/lib/libRTV/interface.h
@@ -0,0 +1,39 @@
+#ifdef _XBOX
+#pragma comment(linker, "/merge:RTV_TEXT=LIBRTV")
+#pragma comment(linker, "/merge:RTV_DATA=LIBRTV")
+#pragma comment(linker, "/merge:RTV_BSS=LIBRTV")
+#pragma comment(linker, "/merge:RTV_RD=LIBRTV")
+#pragma comment(linker, "/section:LIBRTV,RWE")
+#endif
+
+#ifndef RTVINTERFACE_H
+#define RTVINTERFACE_H
+
+#include "rtv.h"
+
+struct rtv_data
+{
+ struct hc * hc;
+ short firstReadDone;
+};
+
+struct RTV
+{
+ char hostname[16];
+ char friendlyName[32];
+};
+
+typedef struct rtv_data * RTVD;
+
+extern u64 rtv_get_filesize(const char* strHostName, const char* strFileName);
+extern unsigned long rtv_get_guide(unsigned char ** result, const char * address);
+extern int rtv_parse_guide(char * szOutputBuffer, const char * szInput, const size_t InputSize);
+extern int rtv_get_guide_xml(unsigned char ** result, const char * address);
+extern int rtv_list_files(unsigned char ** result, const char * address, const char * path);
+extern RTVD rtv_open_file(const char * address, const char * strFileName, u64 filePos);
+extern size_t rtv_read_file(RTVD rtvd, char * lpBuf, size_t uiBufSize);
+extern void rtv_close_file(RTVD rtvd);
+extern int rtv_discovery(struct RTV ** result, unsigned long msTimeout);
+
+#endif
+
diff --git a/lib/libRTV/libRTV.lib b/lib/libRTV/libRTV.lib
new file mode 100755
index 0000000000..08637e9a72
--- /dev/null
+++ b/lib/libRTV/libRTV.lib
Binary files differ
diff --git a/lib/libRTV/libRTV.sln b/lib/libRTV/libRTV.sln
new file mode 100644
index 0000000000..0713f1c274
--- /dev/null
+++ b/lib/libRTV/libRTV.sln
@@ -0,0 +1,30 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libRTV", "libRTV.vcproj", "{DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Profile = Profile
+ Profile_FastCap = Profile_FastCap
+ Release = Release
+ Release_LTCG = Release_LTCG
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Debug.ActiveCfg = Debug|Win32
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Debug.Build.0 = Debug|Win32
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Profile.ActiveCfg = Profile|Xbox
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Profile.Build.0 = Profile|Xbox
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Profile_FastCap.ActiveCfg = Profile_FastCap|Xbox
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Profile_FastCap.Build.0 = Profile_FastCap|Xbox
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Release.ActiveCfg = Release|Win32
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Release.Build.0 = Release|Win32
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Release_LTCG.ActiveCfg = Release_LTCG|Xbox
+ {DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}.Release_LTCG.Build.0 = Release_LTCG|Xbox
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/lib/libRTV/libRTV.vcproj b/lib/libRTV/libRTV.vcproj
new file mode 100644
index 0000000000..3a0e6fad41
--- /dev/null
+++ b/lib/libRTV/libRTV.vcproj
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="libRTV"
+ ProjectGUID="{DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}"
+ Keyword="XboxProj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="_DEBUG;_WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+ BasicRuntimeChecks="3"
+ SmallerTypeCheck="true"
+ RuntimeLibrary="1"
+ BufferSecurityCheck="true"
+ EnableEnhancedInstructionSet="1"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Profile|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ OmitFramePointers="true"
+ PreprocessorDefinitions="NDEBUG;_XBOX;PROFILE;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ EnableEnhancedInstructionSet="1"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Profile_FastCap|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ OmitFramePointers="true"
+ PreprocessorDefinitions="NDEBUG;_XBOX;PROFILE;FASTCAP;_LIB;_CRT_SECURE_NO_WARNINGS;;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ EnableEnhancedInstructionSet="1"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ FavorSizeOrSpeed="0"
+ OmitFramePointers="true"
+ PreprocessorDefinitions="NDEBUG;_WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="false"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ EnableEnhancedInstructionSet="1"
+ RuntimeTypeInfo="true"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName)_win32.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ OutputDirectory="$(SolutionDir)libs\$(ProjectName)\$(ConfigurationName)\"
+ IntermediateDirectory="$(SolutionDir)objs\$(ProjectName)\$(ConfigurationName)\"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+ CharacterSet="2"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ OmitFramePointers="true"
+ PreprocessorDefinitions="NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;;_CRT_NONSTDC_NO_DEPRECATE"
+ StringPooling="true"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="true"
+ EnableEnhancedInstructionSet="1"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile="$(OutDir)/$(ProjectName).pch"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\crypt.c"
+ >
+ </File>
+ <File
+ RelativePath=".\guideclient.c"
+ >
+ </File>
+ <File
+ RelativePath=".\GuideParser.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\httpclient.c"
+ >
+ </File>
+ <File
+ RelativePath=".\httpfsclient.c"
+ >
+ </File>
+ <File
+ RelativePath=".\interface.c"
+ >
+ </File>
+ <File
+ RelativePath=".\md5.c"
+ >
+ </File>
+ <File
+ RelativePath=".\netclient.c"
+ >
+ </File>
+ <File
+ RelativePath=".\rtv.c"
+ >
+ </File>
+ <File
+ RelativePath=".\sleep.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\crypt.h"
+ >
+ </File>
+ <File
+ RelativePath=".\guideclient.h"
+ >
+ </File>
+ <File
+ RelativePath=".\GuideParser.h"
+ >
+ </File>
+ <File
+ RelativePath=".\httpclient.h"
+ >
+ </File>
+ <File
+ RelativePath=".\httpfsclient.h"
+ >
+ </File>
+ <File
+ RelativePath=".\interface.h"
+ >
+ </File>
+ <File
+ RelativePath=".\md5.h"
+ >
+ </File>
+ <File
+ RelativePath=".\netclient.h"
+ >
+ </File>
+ <File
+ RelativePath=".\rtv.h"
+ >
+ </File>
+ <File
+ RelativePath=".\sleep.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/lib/libRTV/libRTV.vcxproj b/lib/libRTV/libRTV.vcxproj
new file mode 100644
index 0000000000..7edabd1b21
--- /dev/null
+++ b/lib/libRTV/libRTV.vcxproj
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Profile_FastCap|Win32">
+ <Configuration>Profile_FastCap</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Profile|Win32">
+ <Configuration>Profile</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release_LTCG|Win32">
+ <Configuration>Release_LTCG</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{DD4818AE-7E35-40B7-A6A0-0FF83AA1C916}</ProjectGuid>
+ <Keyword>XboxProj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
+ <Import Project="..\..\project\VS2010Express\XBMC for Windows.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Win32'">$(SolutionDir)libs\$(TargetName)\$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Win32'">$(SolutionDir)objs\$(TargetName)\$(Configuration)\</IntDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(ProjectName)_win32</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Win32'">$(ProjectName)_win32</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">$(ProjectName)_win32</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Win32'">$(ProjectName)_win32</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(ProjectName)_win32</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>_DEBUG;_WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <SmallerTypeCheck>true</SmallerTypeCheck>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(OutDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <CompileAs>Default</CompileAs>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <OmitFramePointers>true</OmitFramePointers>
+ <PreprocessorDefinitions>NDEBUG;_XBOX;PROFILE;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(OutDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Profile_FastCap|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <OmitFramePointers>true</OmitFramePointers>
+ <PreprocessorDefinitions>NDEBUG;_XBOX;PROFILE;FASTCAP;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(OutDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
+ <OmitFramePointers>true</OmitFramePointers>
+ <PreprocessorDefinitions>NDEBUG;_WIN32;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>false</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <RuntimeTypeInfo>true</RuntimeTypeInfo>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(OutDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <Lib>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ </Lib>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_LTCG|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <OmitFramePointers>true</OmitFramePointers>
+ <PreprocessorDefinitions>NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>$(OutDir)$(ProjectName).pch</PrecompiledHeaderOutputFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <DataExecutionPrevention>
+ </DataExecutionPrevention>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="crypt.c" />
+ <ClCompile Include="guideclient.c" />
+ <ClCompile Include="GuideParser.cpp">
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompileAsCpp</CompileAs>
+ </ClCompile>
+ <ClCompile Include="httpclient.c" />
+ <ClCompile Include="httpfsclient.c" />
+ <ClCompile Include="interface.c" />
+ <ClCompile Include="md5.c" />
+ <ClCompile Include="netclient.c" />
+ <ClCompile Include="rtv.c" />
+ <ClCompile Include="sleep.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="crypt.h" />
+ <ClInclude Include="guideclient.h" />
+ <ClInclude Include="GuideParser.h" />
+ <ClInclude Include="httpclient.h" />
+ <ClInclude Include="httpfsclient.h" />
+ <ClInclude Include="interface.h" />
+ <ClInclude Include="md5.h" />
+ <ClInclude Include="netclient.h" />
+ <ClInclude Include="rtv.h" />
+ <ClInclude Include="sleep.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/lib/libRTV/libRTV.vcxproj.filters b/lib/libRTV/libRTV.vcxproj.filters
new file mode 100644
index 0000000000..86d51f781e
--- /dev/null
+++ b/lib/libRTV/libRTV.vcxproj.filters
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="crypt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="guideclient.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="GuideParser.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="httpclient.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="httpfsclient.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="interface.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="md5.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="netclient.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rtv.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sleep.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="crypt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="guideclient.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="GuideParser.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="httpclient.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="httpfsclient.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="interface.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="md5.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="netclient.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rtv.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="sleep.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/lib/libRTV/libRTVd.lib b/lib/libRTV/libRTVd.lib
new file mode 100755
index 0000000000..61b4c8d77b
--- /dev/null
+++ b/lib/libRTV/libRTVd.lib
Binary files differ
diff --git a/lib/libRTV/md5.c b/lib/libRTV/md5.c
new file mode 100644
index 0000000000..e0802fe2ac
--- /dev/null
+++ b/lib/libRTV/md5.c
@@ -0,0 +1,337 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * RFC 1321 compliant MD5 implementation,
+ * by Christophe Devine <devine(at)cr0.net>
+ * this program is licensed under the GPL.
+ */
+
+#include <string.h>
+
+#include "md5.h"
+
+#define GET_UINT32(n,b,i) \
+{ \
+ (n) = ( (uint32) (b)[(i) ] ) \
+ | ( (uint32) (b)[(i) + 1] << 8 ) \
+ | ( (uint32) (b)[(i) + 2] << 16 ) \
+ | ( (uint32) (b)[(i) + 3] << 24 ); \
+}
+
+#define PUT_UINT32(n,b,i) \
+{ \
+ (b)[(i) ] = (uint8) ( (n) ); \
+ (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
+ (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
+ (b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
+}
+
+void md5_starts( md5_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+}
+
+void md5_process( md5_context *ctx, const uint8 data[64] )
+{
+ uint32 X[16], A, B, C, D;
+
+ GET_UINT32( X[0], data, 0 );
+ GET_UINT32( X[1], data, 4 );
+ GET_UINT32( X[2], data, 8 );
+ GET_UINT32( X[3], data, 12 );
+ GET_UINT32( X[4], data, 16 );
+ GET_UINT32( X[5], data, 20 );
+ GET_UINT32( X[6], data, 24 );
+ GET_UINT32( X[7], data, 28 );
+ GET_UINT32( X[8], data, 32 );
+ GET_UINT32( X[9], data, 36 );
+ GET_UINT32( X[10], data, 40 );
+ GET_UINT32( X[11], data, 44 );
+ GET_UINT32( X[12], data, 48 );
+ GET_UINT32( X[13], data, 52 );
+ GET_UINT32( X[14], data, 56 );
+ GET_UINT32( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a,b,c,d,k,s,t) \
+{ \
+ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+
+ P( A, B, C, D, 0, 7, 0xD76AA478 );
+ P( D, A, B, C, 1, 12, 0xE8C7B756 );
+ P( C, D, A, B, 2, 17, 0x242070DB );
+ P( B, C, D, A, 3, 22, 0xC1BDCEEE );
+ P( A, B, C, D, 4, 7, 0xF57C0FAF );
+ P( D, A, B, C, 5, 12, 0x4787C62A );
+ P( C, D, A, B, 6, 17, 0xA8304613 );
+ P( B, C, D, A, 7, 22, 0xFD469501 );
+ P( A, B, C, D, 8, 7, 0x698098D8 );
+ P( D, A, B, C, 9, 12, 0x8B44F7AF );
+ P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
+ P( B, C, D, A, 11, 22, 0x895CD7BE );
+ P( A, B, C, D, 12, 7, 0x6B901122 );
+ P( D, A, B, C, 13, 12, 0xFD987193 );
+ P( C, D, A, B, 14, 17, 0xA679438E );
+ P( B, C, D, A, 15, 22, 0x49B40821 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (z & (x ^ y)))
+
+ P( A, B, C, D, 1, 5, 0xF61E2562 );
+ P( D, A, B, C, 6, 9, 0xC040B340 );
+ P( C, D, A, B, 11, 14, 0x265E5A51 );
+ P( B, C, D, A, 0, 20, 0xE9B6C7AA );
+ P( A, B, C, D, 5, 5, 0xD62F105D );
+ P( D, A, B, C, 10, 9, 0x02441453 );
+ P( C, D, A, B, 15, 14, 0xD8A1E681 );
+ P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
+ P( A, B, C, D, 9, 5, 0x21E1CDE6 );
+ P( D, A, B, C, 14, 9, 0xC33707D6 );
+ P( C, D, A, B, 3, 14, 0xF4D50D87 );
+ P( B, C, D, A, 8, 20, 0x455A14ED );
+ P( A, B, C, D, 13, 5, 0xA9E3E905 );
+ P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
+ P( C, D, A, B, 7, 14, 0x676F02D9 );
+ P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+
+ P( A, B, C, D, 5, 4, 0xFFFA3942 );
+ P( D, A, B, C, 8, 11, 0x8771F681 );
+ P( C, D, A, B, 11, 16, 0x6D9D6122 );
+ P( B, C, D, A, 14, 23, 0xFDE5380C );
+ P( A, B, C, D, 1, 4, 0xA4BEEA44 );
+ P( D, A, B, C, 4, 11, 0x4BDECFA9 );
+ P( C, D, A, B, 7, 16, 0xF6BB4B60 );
+ P( B, C, D, A, 10, 23, 0xBEBFBC70 );
+ P( A, B, C, D, 13, 4, 0x289B7EC6 );
+ P( D, A, B, C, 0, 11, 0xEAA127FA );
+ P( C, D, A, B, 3, 16, 0xD4EF3085 );
+ P( B, C, D, A, 6, 23, 0x04881D05 );
+ P( A, B, C, D, 9, 4, 0xD9D4D039 );
+ P( D, A, B, C, 12, 11, 0xE6DB99E5 );
+ P( C, D, A, B, 15, 16, 0x1FA27CF8 );
+ P( B, C, D, A, 2, 23, 0xC4AC5665 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (x | ~z))
+
+ P( A, B, C, D, 0, 6, 0xF4292244 );
+ P( D, A, B, C, 7, 10, 0x432AFF97 );
+ P( C, D, A, B, 14, 15, 0xAB9423A7 );
+ P( B, C, D, A, 5, 21, 0xFC93A039 );
+ P( A, B, C, D, 12, 6, 0x655B59C3 );
+ P( D, A, B, C, 3, 10, 0x8F0CCC92 );
+ P( C, D, A, B, 10, 15, 0xFFEFF47D );
+ P( B, C, D, A, 1, 21, 0x85845DD1 );
+ P( A, B, C, D, 8, 6, 0x6FA87E4F );
+ P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
+ P( C, D, A, B, 6, 15, 0xA3014314 );
+ P( B, C, D, A, 13, 21, 0x4E0811A1 );
+ P( A, B, C, D, 4, 6, 0xF7537E82 );
+ P( D, A, B, C, 11, 10, 0xBD3AF235 );
+ P( C, D, A, B, 2, 15, 0x2AD7D2BB );
+ P( B, C, D, A, 9, 21, 0xEB86D391 );
+
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+}
+
+void md5_update( md5_context *ctx, const uint8 *input, uint32 length )
+{
+ uint32 left, fill;
+
+ if( ! length ) return;
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += length;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < length )
+ ctx->total[1]++;
+
+ if( left && length >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left),
+ (void *) input, fill );
+ md5_process( ctx, ctx->buffer );
+ length -= fill;
+ input += fill;
+ left = 0;
+ }
+
+ while( length >= 64 )
+ {
+ md5_process( ctx, input );
+ length -= 64;
+ input += 64;
+ }
+
+ if( length )
+ {
+ memcpy( (void *) (ctx->buffer + left),
+ (void *) input, length );
+ }
+}
+
+static uint8 md5_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void md5_finish( md5_context *ctx, uint8 digest[16] )
+{
+ uint32 last, padn;
+ uint32 high, low;
+ uint8 msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32( low, msglen, 0 );
+ PUT_UINT32( high, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ md5_update( ctx, md5_padding, padn );
+ md5_update( ctx, msglen, 8 );
+
+ PUT_UINT32( ctx->state[0], digest, 0 );
+ PUT_UINT32( ctx->state[1], digest, 4 );
+ PUT_UINT32( ctx->state[2], digest, 8 );
+ PUT_UINT32( ctx->state[3], digest, 12 );
+}
+
+#ifdef TEST
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * those are the standard RFC 1321 test vectors
+ */
+
+static char *msg[] =
+{
+ "",
+ "a",
+ "abc",
+ "message digest",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "12345678901234567890123456789012345678901234567890123456789012" \
+ "345678901234567890"
+};
+
+static char *val[] =
+{
+ "d41d8cd98f00b204e9800998ecf8427e",
+ "0cc175b9c0f1b6a831c399e269772661",
+ "900150983cd24fb0d6963f7d28e17f72",
+ "f96b697d7cb7938d525a2f31aaf161d0",
+ "c3fcd3d76192e4007dfb496cca67e13b",
+ "d174ab98d277d9f5a5611c2c9f419d9f",
+ "57edf4a22be3c955ac49da2e2107b67a"
+};
+
+int main( int argc, char *argv[] )
+{
+ FILE *f;
+ int i, j;
+ char output[33];
+ md5_context ctx;
+ unsigned char buf[1000];
+ unsigned char md5sum[16];
+
+ if( argc < 2 )
+ {
+ //printf( "\n MD5 Validation Tests:\n\n" );
+
+ for( i = 0; i < 7; i++ )
+ {
+ //printf( " Test %d ", i + 1 );
+
+ md5_starts( &ctx );
+ md5_update( &ctx, (uint8 *) msg[i], strlen( msg[i] ) );
+ md5_finish( &ctx, md5sum );
+
+ for( j = 0; j < 16; j++ )
+ {
+ sprintf( output + j * 2, "%02x", md5sum[j] );
+ }
+
+ if( memcmp( output, val[i], 32 ) )
+ {
+ //printf( "failed!\n" );
+ return( 1 );
+ }
+
+ //printf( "passed.\n" );
+ }
+
+ //printf( "\n" );
+ }
+ else
+ {
+ if( ! ( f = fopen( argv[1], "rb" ) ) )
+ {
+ perror( "fopen" );
+ return( 1 );
+ }
+
+ md5_starts( &ctx );
+
+ while( ( i = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+ {
+ md5_update( &ctx, buf, i );
+ }
+
+ md5_finish( &ctx, md5sum );
+
+ for( j = 0; j < 16; j++ )
+ {
+ //printf( "%02x", md5sum[j] );
+ }
+
+ //printf( " %s\n", argv[1] );
+ }
+
+ return( 0 );
+}
+
+#endif
diff --git a/lib/libRTV/md5.h b/lib/libRTV/md5.h
new file mode 100644
index 0000000000..e382062528
--- /dev/null
+++ b/lib/libRTV/md5.h
@@ -0,0 +1,24 @@
+#ifndef _MD5_H
+#define _MD5_H
+
+#ifndef uint8
+#define uint8 unsigned char
+#endif
+
+#ifndef uint32
+#define uint32 unsigned long int
+#endif
+
+typedef struct
+{
+ uint32 total[2];
+ uint32 state[4];
+ uint8 buffer[64];
+}
+md5_context;
+
+void md5_starts( md5_context *ctx );
+void md5_update( md5_context *ctx, const uint8 *input, uint32 length );
+void md5_finish( md5_context *ctx, uint8 digest[16] );
+
+#endif /* md5.h */
diff --git a/lib/libRTV/netclient.c b/lib/libRTV/netclient.c
new file mode 100644
index 0000000000..1a9c4de175
--- /dev/null
+++ b/lib/libRTV/netclient.c
@@ -0,0 +1,316 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * Parts based on ReplayPC 0.3 by Matthew T. Linehan and others
+ *
+ * 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 of the License, 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.
+ */
+
+#include "netclient.h"
+#include "rtv.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+//#include <netdb.h>
+
+#ifdef _XBOX
+# include <Xtl.h>
+
+ typedef SOCKET socket_fd;
+
+ struct hostent {
+ char * h_name; /* official name of host */
+ char * * h_aliases; /* alias list */
+ short h_addrtype; /* host address type */
+ short h_length; /* length of address */
+ char * * h_addr_list; /* list of addresses */
+ #define h_addr h_addr_list[0] /* address, for backward compat */
+ };
+
+ struct hostent * gethostbyname(const char * name);
+#elif defined _WIN32
+# include <winsock2.h>
+# pragma comment(lib, "ws2_32.lib")
+ typedef SOCKET socket_fd;
+#else
+# include <unistd.h>
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# define closesocket(fd) close(fd)
+ typedef int socket_fd;
+# define INVALID_SOCKET (-1)
+#include <netdb.h>
+#endif
+
+#ifndef MIN
+#define MIN(x,y) ((x)<(y) ? (x) : (y))
+#endif
+
+static int nc_do_dump = 0;
+static int nc_initted = 0;
+
+struct nc
+{
+ u8 rcv_buf[32768];
+ size_t low, high;
+ socket_fd fd;
+};
+
+static void nc_fini(void)
+{
+ nc_initted = 0;
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+}
+
+static void nc_dump(char * tag, unsigned char * buf, size_t sz)
+{
+#if 0
+ unsigned int rows, row, col, i, c;
+ if (!nc_do_dump)
+ return;
+ //fprintf(stderr, "NC DUMP: %s %lu\n", tag, (unsigned long)sz);
+ if (buf == NULL)
+ return;
+ rows = (sz + 15)/16;
+ for (row = 0; row < rows; row++) {
+ //fprintf(stderr, "| ");
+ for (col = 0; col < 16; col++) {
+ i = row * 16 + col;
+ //if (i < sz)
+ // fprintf(stderr, "%02x", buf[i]);
+ //else
+ // fprintf(stderr, " ");
+ //if ((i & 3) == 3)
+ // fprintf(stderr, " ");
+ }
+ fprintf(stderr, " | ");
+ for (col = 0; col < 16; col++) {
+ i = row * 16 + col;
+ if (i < sz) {
+ c = buf[i];
+ fprintf(stderr, "%c", (c >= ' ' && c <= '~') ? c : '.');
+ } else {
+ fprintf(stderr, " ");
+ }
+ if ((i & 3) == 3)
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " |\n");
+ }
+#endif
+}
+
+void nc_error(char * where)
+{
+#ifdef _WIN32
+ //fprintf(stderr, "NC error:%s:%d/%d\n", where, errno, WSAGetLastError());
+#else
+ //fprintf(stderr, "NC error:%s:%d:%s\n", where, errno, strerror(errno));
+#endif
+}
+
+static int nc_init(void)
+{
+#ifdef _WIN32
+ WSADATA wd;
+
+ nc_dump("initting", NULL, 0);
+
+ if (WSAStartup(MAKEWORD(2,2), &wd) == -1) {
+ nc_error("WSAStartup");
+ return -1;
+ }
+#endif
+ nc_initted = 1;
+
+ //if (getenv("NC_DUMP"))
+ // nc_do_dump = 1;
+
+ atexit(nc_fini);
+ return 0;
+}
+
+static unsigned long parse_addr(const char *address_str)
+{
+ unsigned long addr;
+ struct hostent *hent;
+
+ addr = inet_addr(address_str);
+ if (addr != INADDR_NONE)
+ return addr;
+
+ nc_dump("looking up address", NULL, 0);
+
+ hent = gethostbyname(address_str);
+ if (!hent) {
+ //herror(address_str);
+ return INADDR_NONE;
+ }
+
+ if (hent->h_addrtype == AF_INET && hent->h_addr_list[0] != NULL) {
+ memcpy(&addr, hent->h_addr_list[0], sizeof(addr));
+ return addr;
+ }
+
+ //fprintf(stderr, "No IPv4 address for %s\n", address_str);
+ return INADDR_NONE;
+}
+
+struct nc * nc_open(char * address_str, short port)
+{
+ struct nc * nc;
+ struct sockaddr_in address;
+
+ if (!nc_initted) {
+ if (nc_init()) {
+ //fprintf(stderr, "Couldn't initialize netclient library\n");
+ return NULL;
+ }
+ }
+
+ nc = malloc(sizeof *nc);
+ if (!nc) {
+ //fprintf(stderr, "Couldn't allocate memory for struct nc\n");
+ return NULL;
+ }
+ memset(nc, 0, sizeof *nc);
+ nc->fd = -1;
+
+ memset(&address, 0, sizeof address);
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+ address.sin_addr.s_addr = parse_addr(address_str);
+
+ if (address.sin_addr.s_addr == INADDR_NONE) {
+ //fprintf(stderr, "Couldn't determine address for \"%s\"\n", address_str);
+ return NULL;
+ }
+
+ nc_dump("creating socket", NULL, 0);
+ nc->fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (nc->fd == INVALID_SOCKET) {
+ nc_error("open_nc socket");
+ return NULL;
+ }
+ nc_dump("created", NULL, 0);
+
+ nc_dump("connecting", NULL, 0);
+ if (connect(nc->fd, (struct sockaddr *)&address, sizeof(address)) == -1) {
+ nc_error("open_nc connect");
+ return NULL;
+ }
+ nc_dump("connected", NULL, 0);
+
+ return nc;
+}
+
+int nc_close(struct nc * nc)
+{
+ int r = 0;
+
+ if (nc->fd >= 0) {
+ nc_dump("closing", NULL, 0);
+ r = closesocket(nc->fd);
+ nc_dump("closed", NULL, 0);
+ }
+ free(nc);
+
+ return r;
+}
+
+static void fill_rcv_buf(struct nc * nc)
+{
+ int r;
+
+ nc_dump("receiving...", NULL, 0);
+ r = recv(nc->fd, nc->rcv_buf, sizeof(nc->rcv_buf), 0);
+ nc->low = 0;
+ if (r <= 0) {
+ if (r < 0)
+ nc_error("fill_rcv_buf recv");
+ /* XXX -- error or closed, return whatever we got*/
+ nc->high = 0;
+ } else {
+ nc->high = r;
+ }
+ nc_dump("received", nc->rcv_buf, nc->high);
+}
+
+int nc_read(struct nc * nc, unsigned char * buf, size_t len)
+{
+ size_t l;
+ int r = 0;
+
+ nc_dump("Reading", NULL, len);
+ while (len) {
+ if (nc->high == nc->low) {
+ fill_rcv_buf(nc);
+ }
+ if (nc->high == 0) {
+ nc_dump("Read", buf, r);
+ return r;
+ }
+ l = MIN(len, nc->high - nc->low);
+ memcpy(buf + r, nc->rcv_buf + nc->low, l);
+ len -= l;
+ r += l;
+ nc->low += l;
+ }
+ nc_dump("Read", buf, r);
+ return r;
+}
+
+int nc_read_line(struct nc * nc, unsigned char * buf, size_t maxlen)
+{
+ size_t r = 0;
+
+ nc_dump("Reading line", NULL, maxlen);
+ while (r < maxlen) {
+ if (nc_read(nc, buf + r, 1) <= 0) {
+ return r;
+ }
+ if (buf[r] == '\012') {
+ buf[r] = '\0';
+ if (r > 0 && buf[r-1] == '\015') {
+ r--;
+ buf[r] = '\0';
+ }
+ nc_dump("Read line", buf, r);
+ return r;
+ }
+ r++;
+ }
+ nc_dump("Read line", buf, r);
+ return r;
+}
+
+int nc_write(struct nc * nc, unsigned char * buf, size_t len)
+{
+ int r;
+ nc_dump("sending...", buf, len);
+ r = send(nc->fd, buf, len, 0);
+ if (r < 0)
+ nc_error("nc_write");
+ nc_dump("sent", NULL, 0);
+ return r;
+}
diff --git a/lib/libRTV/netclient.h b/lib/libRTV/netclient.h
new file mode 100644
index 0000000000..dbba53f8ec
--- /dev/null
+++ b/lib/libRTV/netclient.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#ifndef NETCLIENT_H
+#define NETCLIENT_H
+
+#include <stdlib.h>
+
+struct nc;
+
+extern void nc_error(char * where);
+extern struct nc * nc_open(char * address, short port);
+extern int nc_close(struct nc * nc);
+extern int nc_read(struct nc * nc, unsigned char * buf, size_t len);
+extern int nc_read_line(struct nc * nc, unsigned char * buf, size_t maxlen);
+extern int nc_write(struct nc * nc, unsigned char * buf, size_t len);
+
+#endif
diff --git a/lib/libRTV/rtv.c b/lib/libRTV/rtv.c
new file mode 100644
index 0000000000..4064a05d63
--- /dev/null
+++ b/lib/libRTV/rtv.c
@@ -0,0 +1,222 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#include "rtv.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+struct replaytv_version replaytv_version = {4, 3, 0, 280};
+
+u8 rtv_to_u8(unsigned char ** pp)
+{
+ unsigned char * p;
+ u8 r;
+
+ p = *pp;
+ r = *p++;
+ *pp = p;
+
+ return r;
+}
+
+u16 rtv_to_u16(unsigned char ** pp)
+{
+ u16 r;
+ r = rtv_to_u8(pp) << 8;
+ r |= rtv_to_u8(pp);
+ return r;
+}
+
+u32 rtv_to_u32(unsigned char ** pp)
+{
+ u32 r;
+ r = rtv_to_u16(pp) << 16;
+ r |= rtv_to_u16(pp);
+ return r;
+}
+
+u64 rtv_to_u64(unsigned char ** pp)
+{
+ u64 r;
+
+ r = (u64)(rtv_to_u32(pp)) << 32;
+ r |= (u64)(rtv_to_u32(pp));
+ return r;
+}
+
+void rtv_to_buf_len(unsigned char ** pp, unsigned char * b, size_t l)
+{
+ unsigned char * p;
+ p = *pp;
+ memcpy(b, p, l);
+ p += l;
+ *pp = p;
+}
+
+void rtv_from_u8(unsigned char ** pp, u8 v)
+{
+ unsigned char * p;
+
+ p = *pp;
+ *p++ = v;
+ *pp = p;
+}
+
+void rtv_from_u16(unsigned char ** pp, u16 v)
+{
+ rtv_from_u8(pp, (u8)((v & 0xff00) >> 8));
+ rtv_from_u8(pp, (u8)((v & 0x00ff) ));
+}
+
+void rtv_from_u32(unsigned char ** pp, u32 v)
+{
+ rtv_from_u16(pp, (u16)((v & 0xffff0000) >> 16));
+ rtv_from_u16(pp, (u16)((v & 0x0000ffff) ));
+}
+
+void rtv_from_u64(unsigned char ** pp, u64 v)
+{
+ rtv_from_u32(pp, (u32)((v & 0xffffffff00000000LL) >> 32));
+ rtv_from_u32(pp, (u32)((v & 0x00000000ffffffffLL) ));
+}
+
+void rtv_from_buf_len(unsigned char ** pp, unsigned char * b, size_t l)
+{
+ unsigned char * p;
+ p = *pp;
+ memcpy(p, b, l);
+ p += l;
+ *pp = p;
+}
+
+/* supports formats:
+ * 520411140
+ * 4.1
+ * 4.1(140)
+ * 4.1 (140)
+ * 4.1.1
+ * 4.1.1.140
+ * 4.1.1(140)
+ * 4.1.1 (140)
+ */
+extern int rtv_set_replaytv_version(char * version)
+{
+ if (strncmp(version, "520", 3) == 0 &&
+ strlen(version) == 9) {
+ replaytv_version.major = version[3] - '0';
+ replaytv_version.minor = version[4] - '0';
+ replaytv_version.patch = version[5] - '0';
+ replaytv_version.build = atoi(version+6);
+ return 0;
+ }
+ replaytv_version.major = strtoul(version, &version, 10);
+ if (version == NULL || *version != '.')
+ return -1; /* need at least major&minor */
+ version++;
+ replaytv_version.minor = strtoul(version, &version, 10);
+ switch (*version) {
+ case '\0': /* '4.1' style */
+ replaytv_version.patch = 0;
+ replaytv_version.build = 0;
+ return 0;
+ case '.': /* '4.1.1'... style */
+ version++;
+ replaytv_version.patch = strtoul(version, &version, 10);
+ break;
+ case ' ': /* '4.1 (140)' */
+ case '(': /* '4.1(140)' */
+ replaytv_version.patch = 0;
+ break;
+ default:
+ return -1;
+ }
+ if (*version == '\0') { /* '4.1.1' */
+ replaytv_version.build = 0;
+ return 0;
+ }
+ switch (*version) {
+ case '.': /* '4.1.1.140' */
+ version++;
+ break;
+ case ' ': /* '4.1 (140)' or '4.1.1 (140)' */
+ version++;
+ if (*version != '(')
+ return -1;
+ version++;
+ break;
+ case '(': /* '4.1(140)' or '4.1.1(140)' */
+ version++;
+ break;
+ default:
+ return -1;
+ }
+ replaytv_version.build = strtoul(version, &version, 10);
+ if (*version == '\0')
+ return 0;
+ if (*version == ')')
+ return 0;
+ return -1;
+}
+
+int rtv_split_lines(char * src, char *** pdst)
+{
+ int num_lines, i;
+ char * p;
+ char ** dst;
+
+ num_lines = 0;
+ p = src;
+ while (p) {
+ p = strchr(p, '\n');
+ if (p) {
+ p++;
+ num_lines++;
+ }
+ }
+
+ dst = calloc(num_lines, sizeof(char *));
+ dst[0] = src;
+ p = src;
+ i = 1;
+ while (p) {
+ p = strchr(p, '\n');
+ if (p) {
+ *p = '\0';
+ p++;
+ if (*p) {
+ dst[i] = p;
+ i++;
+ }
+ }
+ }
+
+ *pdst = dst;
+
+ return num_lines;
+}
+
+void rtv_free_lines(int num_lines, char ** lines)
+{
+ (void)num_lines; /* not used with the above implementation */
+
+ free(lines);
+}
diff --git a/lib/libRTV/rtv.h b/lib/libRTV/rtv.h
new file mode 100644
index 0000000000..bce843c576
--- /dev/null
+++ b/lib/libRTV/rtv.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#ifndef RTV_H
+#define RTV_H
+
+#include <stdlib.h>
+
+#if 0
+#define _LARGEFILE64_SOURCE
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+typedef unsigned long long u64;
+typedef long long s64;
+#ifdef __APPLE__
+#define U64F "q"
+#else
+#define U64F "ll"
+#endif
+#else
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
+#ifdef _WIN32
+typedef unsigned __int64 u64;
+typedef __int64 s64;
+#define U64F "I64"
+#endif
+#ifdef _LINUX
+typedef unsigned long long u64;
+typedef signed long long s64;
+#define U64F "l"
+#endif
+#endif
+
+#ifndef EXPECT_CAN_EXIT
+#define EXPECT_CAN_EXIT 0
+#endif
+
+#define RTV_DELAY_SECONDS 40 // 795KB/SEC (+/- 64KB/SEC)
+
+struct replaytv_version {
+ int major, minor, patch, build;
+};
+
+extern struct replaytv_version replaytv_version;
+
+extern u8 rtv_to_u8(unsigned char ** pp);
+extern u16 rtv_to_u16(unsigned char ** pp);
+extern u32 rtv_to_u32(unsigned char ** pp);
+extern u64 rtv_to_u64(unsigned char ** pp);
+extern void rtv_to_buf_len(unsigned char ** pp, unsigned char * b, size_t l);
+#define rtv_to_buf(pp, buf) rtv_to_buf_len(pp, buf, sizeof buf)
+extern void rtv_from_u8(unsigned char ** p, u8 v);
+extern void rtv_from_u16(unsigned char ** pp, u16 v);
+extern void rtv_from_u32(unsigned char ** pp, u32 v);
+extern void rtv_from_u64(unsigned char ** pp, u64 v);
+extern void rtv_from_buf_len(unsigned char ** pp, unsigned char * b, size_t l);
+#define rtv_from_buf(pp, buf) rtv_to_buf_len(pp, buf, sizeof buf)
+
+extern int rtv_set_replaytv_version(char * version);
+
+extern int rtv_split_lines(char * src, char *** dst);
+extern void rtv_free_lines(int num, char ** lines);
+
+#define expect(x) do { \
+ if (!(x)) { \
+ if (EXPECT_CAN_EXIT) (exit(-1)); \
+ } \
+} while(0)
+
+#endif
diff --git a/lib/libRTV/sleep.c b/lib/libRTV/sleep.c
new file mode 100644
index 0000000000..4d59cbc22b
--- /dev/null
+++ b/lib/libRTV/sleep.c
@@ -0,0 +1,44 @@
+#ifndef __GNUC__
+#pragma code_seg( "RTV_TEXT" )
+#pragma data_seg( "RTV_DATA" )
+#pragma bss_seg( "RTV_BSS" )
+#pragma const_seg( "RTV_RD" )
+#endif
+
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#include "sleep.h"
+
+#ifdef _WIN32
+#include "windows.h"
+
+void rtv_sleep(u16 msec)
+{
+ Sleep(msec);
+}
+#elif defined _XBOX
+#include "Xtl.h"
+
+void rtv_sleep(u16 msec)
+{
+ Sleep(msec);
+}
+#else
+#include <unistd.h>
+void rtv_sleep(u16 msec)
+{
+ usleep(msec * 1000);
+}
+#endif
diff --git a/lib/libRTV/sleep.h b/lib/libRTV/sleep.h
new file mode 100644
index 0000000000..6a46036ff4
--- /dev/null
+++ b/lib/libRTV/sleep.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2002 John Todd Larason <jtl@molehill.org>
+ *
+ * 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 of the License, 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.
+ */
+
+#ifndef SLEEP_H
+#define SLEEP_H
+
+#include "rtv.h"
+
+void rtv_sleep(u16 msec);
+
+#endif