diff options
author | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
---|---|---|
committer | theuni <theuni-nospam-@xbmc.org> | 2011-01-24 16:05:21 -0500 |
commit | c51b1189e3d5353e842991f5859ddcea0f73e426 (patch) | |
tree | ef2cb8a6184699aa614f3655dca4ce661cdc108e /lib/libRTV | |
parent | be61ebdc9e897fe40c6f371111724de79ddee8d5 (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.cpp | 1593 | ||||
-rw-r--r-- | lib/libRTV/GuideParser.h | 7 | ||||
-rw-r--r-- | lib/libRTV/Makefile.in | 9 | ||||
-rw-r--r-- | lib/libRTV/crypt.c | 215 | ||||
-rw-r--r-- | lib/libRTV/crypt.h | 29 | ||||
-rw-r--r-- | lib/libRTV/guideclient.c | 128 | ||||
-rw-r--r-- | lib/libRTV/guideclient.h | 27 | ||||
-rw-r--r-- | lib/libRTV/httpclient.c | 494 | ||||
-rw-r--r-- | lib/libRTV/httpclient.h | 95 | ||||
-rw-r--r-- | lib/libRTV/httpfsclient.c | 401 | ||||
-rw-r--r-- | lib/libRTV/httpfsclient.h | 79 | ||||
-rw-r--r-- | lib/libRTV/interface.c | 363 | ||||
-rw-r--r-- | lib/libRTV/interface.h | 39 | ||||
-rwxr-xr-x | lib/libRTV/libRTV.lib | bin | 0 -> 62010 bytes | |||
-rw-r--r-- | lib/libRTV/libRTV.sln | 30 | ||||
-rw-r--r-- | lib/libRTV/libRTV.vcproj | 483 | ||||
-rw-r--r-- | lib/libRTV/libRTV.vcxproj | 229 | ||||
-rw-r--r-- | lib/libRTV/libRTV.vcxproj.filters | 77 | ||||
-rwxr-xr-x | lib/libRTV/libRTVd.lib | bin | 0 -> 152314 bytes | |||
-rw-r--r-- | lib/libRTV/md5.c | 337 | ||||
-rw-r--r-- | lib/libRTV/md5.h | 24 | ||||
-rw-r--r-- | lib/libRTV/netclient.c | 316 | ||||
-rw-r--r-- | lib/libRTV/netclient.h | 29 | ||||
-rw-r--r-- | lib/libRTV/rtv.c | 222 | ||||
-rw-r--r-- | lib/libRTV/rtv.h | 85 | ||||
-rw-r--r-- | lib/libRTV/sleep.c | 44 | ||||
-rw-r--r-- | lib/libRTV/sleep.h | 22 |
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, ×tamp, &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 Binary files differnew file mode 100755 index 0000000000..08637e9a72 --- /dev/null +++ b/lib/libRTV/libRTV.lib 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 Binary files differnew file mode 100755 index 0000000000..61b4c8d77b --- /dev/null +++ b/lib/libRTV/libRTVd.lib 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 |