//===== Copyright © 1996-2010, Valve Corporation, All rights reserved. ======// // // Purpose: Utility class for discovering and caching path info on the PS3. // // $NoKeywords: $ //===========================================================================// #ifndef SN_TARGET_PS3 #error You're compiling this file on the wrong platform! #endif #include #include #include #include "../public/ps3_pathinfo.h" #include #include "errorrenderloop.h" #include // statically defined because not available in LauncherMain: #ifndef DBG_H static void LocalError( const char *fmt, ... ) { va_list args; va_start(args, fmt); vprintf( fmt, args ); ErrorRenderLoop loop; loop.Run(); exit(1); } static void AssertMsg( bool cond, const char *complaint ) { if (!cond) { LocalError(complaint); } } #else #define LocalError Error #endif #define CheckError( x, str ) if ( x < 0 ) { LocalError( "%s: %s\n", str, GetSonyErrorString( x ) ); return x; } #ifndef _CERT #define DiagnosticStringMode 1 #define DiagnosticString( x ) do { unsigned int dummy; sys_tty_write( SYS_TTYP15, x, strlen( x ), &dummy ); } while(0) #else #define DiagnosticString( x ) ((void)0) #endif CPs3ContentPathInfo g_Ps3GameDataPathInfo; CPs3ContentPathInfo::CPs3ContentPathInfo() : m_bInitialized(false), m_nHDDFreeSizeKb( 0 ), m_nBootType( 0 ), m_nBootAttribs( 0 ), m_gameParentalLevel( 0 ), m_gameResolution( 0 ), m_gameSoundFormat( 0 ) { #define GAME_INIT( x ) memset( x, 0, sizeof( x ) ) GAME_INIT( m_gameTitle ); GAME_INIT( m_gameTitleID ); GAME_INIT( m_gameAppVer ); GAME_INIT( m_gamePatchAppVer ); GAME_INIT( m_gameContentPath ); GAME_INIT( m_gamePatchContentPath ); GAME_INIT( m_gameBasePath ); GAME_INIT( m_gamePatchBasePath ); GAME_INIT( m_gameExesPath ); GAME_INIT( m_gameHDDataPath ); GAME_INIT( m_gameImageDataPath ); GAME_INIT( m_gameSystemCachePath ); GAME_INIT( m_gameSavesShadowPath ); #undef GAME_INIT } const char *GetSonyErrorString( int errorcode ) ; /// return a description for a CELL_GAME_ERROR code int CPs3ContentPathInfo::Init( unsigned int uiFlagsMask ) { AssertMsg( !m_bInitialized, "CPs3ContentPathInfo is being initialized twice!\n" ); ///////////////////////////////////////////////////////////////////////// // // load sysutil NP // ////////////////////////////////////////////////////////////////////////// // we'll need to haul libsysutil into memory ( CELL_SYSMODULE_SYSUTIL_NP ) { int suc = cellSysmoduleLoadModule( CELL_SYSMODULE_SYSUTIL_NP ); if ( suc != CELL_OK ) { LocalError( "Failed to load sysutil_np: %s\n", GetSonyErrorString(suc) ); return suc; } } ///////////////////////////////////////////////////////////////////////// // // load sysutil GAME // ////////////////////////////////////////////////////////////////////////// // we'll need to haul libsysutil into memory ( CELL_SYSMODULE_SYSUTIL_GAME ) bool bSysModuleIsLoaded = cellSysmoduleIsLoaded( CELL_SYSMODULE_SYSUTIL_GAME ) == CELL_SYSMODULE_LOADED ; // if this assert trips, then: // 1) look at where the sysutil_game module is loaded to make sure it still needs to be loaded at this point (maybe you can dump it to save memory) // 2) if it's being taken care of somewhere else, we don't need to load the module here. AssertMsg( !bSysModuleIsLoaded, "The SYSUTIL_GAME module is already loaded -- revist load order logic in CPs3ContentPathInfo::Init()\n"); if ( !bSysModuleIsLoaded ) { int suc = cellSysmoduleLoadModule( CELL_SYSMODULE_SYSUTIL_GAME ); if ( suc != CELL_OK ) { LocalError( "Failed to load sysutil_game: %s\n", GetSonyErrorString(suc) ); return suc; } } ////////////////////////////////////////////////////////////////////////// // // cellGameBootCheck // ////////////////////////////////////////////////////////////////////////// // get the base to the content directory. CellGameContentSize size; // For game content of a disc boot game, sizeKB and sysSizeKB take no meaning – please do not use them memset(&size, 0, sizeof(CellGameContentSize)); char bootdir[CELL_GAME_DIRNAME_SIZE] = {0}; int success = cellGameBootCheck( &m_nBootType, &m_nBootAttribs, &size, bootdir ); if ( success != CELL_GAME_RET_OK ) { LocalError("cellGameBootCheck failed (line %d, code %d): %s\n", __LINE__, success, GetSonyErrorString(success) ); return success; } #if DiagnosticStringMode if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_DEBUG ) { DiagnosticString( "GAME BOOT: DEBUG MODE\n" ); } if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_APP_HOME ) { DiagnosticString( "GAME BOOT: HOSTFS MODE (app_home)\n" ); } if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_PATCH ) { DiagnosticString( "GAME BOOT: PATCH MODE\n" ); } if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_INVITE_MESSAGE ) { DiagnosticString( "GAME BOOT: INVITE MESSAGE\n" ); } if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_CUSTOM_DATA_MESSAGE ) { DiagnosticString( "GAME BOOT: CUSTOM DATA MESSAGE\n" ); } DiagnosticString( "BOOT DIR " ); DiagnosticString( bootdir ); DiagnosticString( "\n" ); #endif m_bInitialized = true; m_nHDDFreeSizeKb = size.hddFreeSizeKB; ////////////////////////////////////////////////////////////////////////// // // cellGameContentPermit // ////////////////////////////////////////////////////////////////////////// if ( !( uiFlagsMask & INIT_RETAIL_MODE ) ) { DiagnosticString( "BOOT INFO USING NON-RETAIL BOOT\n" ); // // BOOT MODE required: PARAM.SFO // success = cellGameGetParamString( CELL_GAME_PARAMID_TITLE, m_gameTitle, sizeof( m_gameTitle ) ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_TITLE )" ); success = cellGameGetParamString( CELL_GAME_PARAMID_TITLE_ID, m_gameTitleID, sizeof( m_gameTitleID ) ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_TITLE_ID )" ); success = cellGameGetParamString( CELL_GAME_PARAMID_APP_VER, m_gameAppVer, sizeof( m_gameAppVer ) ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_APP_VER )" ); success = cellGameGetParamInt( CELL_GAME_PARAMID_PARENTAL_LEVEL, &m_gameParentalLevel ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_PARENTAL_LEVEL )" ); success = cellGameGetParamInt( CELL_GAME_PARAMID_RESOLUTION, &m_gameResolution ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_RESOLUTION )" ); success = cellGameGetParamInt( CELL_GAME_PARAMID_SOUND_FORMAT, &m_gameSoundFormat ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_SOUND_FORMAT )" ); // Access /app_home/... success = cellGameContentPermit( m_gameContentPath, m_gameBasePath ) ; DiagnosticString( "BOOT ROOT " ); DiagnosticString( m_gameContentPath ); DiagnosticString( "\n" ); DiagnosticString( "BOOT USR " ); DiagnosticString( m_gameBasePath ); DiagnosticString( "\n" ); // when running the game from the debugger, the data path returned by ContentPermit contains // HOSTFS formatted path like /app_home/D:\perforce\... // Perform the fixup to conform to disk image layout if ( (m_nBootAttribs & CELL_GAME_ATTRIBUTE_DEBUG) && !strncmp( m_gameBasePath, "/app_home", sizeof( "/app_home" ) - 1 ) ) { snprintf( m_gameContentPath, sizeof( m_gameContentPath ) - 1, "/app_home/PS3_GAME" ); snprintf( m_gameBasePath, sizeof( m_gameBasePath ) - 1, "/app_home/PS3_GAME/USRDIR" ); DiagnosticString( "BOOT ROOT/ " ); DiagnosticString( m_gameContentPath ); DiagnosticString( "\n" ); DiagnosticString( "BOOT USR// " ); DiagnosticString( m_gameBasePath ); DiagnosticString( "\n" ); } } else { if ( m_nBootType != CELL_GAME_GAMETYPE_DISC ) { LocalError("Only disk boot is supported in RETAIL mode! (bootmode=%d)\n", m_nBootType ); return -1; } // Finish access to boot executable { char tmp_contentInfoPath[CELL_GAME_PATH_MAX] = {0}; char tmp_usrdirPath[CELL_GAME_PATH_MAX] = {0}; success = cellGameContentPermit( tmp_contentInfoPath, tmp_usrdirPath ); // must call this to allow mounting of BDVD DiagnosticString( "BOOT ROOT " ); DiagnosticString( tmp_contentInfoPath ); DiagnosticString( "\n" ); DiagnosticString( "BOOT USR " ); DiagnosticString( tmp_usrdirPath ); DiagnosticString( "\n" ); } // in RETAIL mode we always have our assets on BDVD success = cellGameDataCheck( m_nBootType, NULL, &size); if ( success == CELL_GAME_RET_OK ) { // // BOOT MODE required: PARAM.SFO // success = cellGameGetParamString( CELL_GAME_PARAMID_TITLE, m_gameTitle, sizeof( m_gameTitle ) ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_TITLE )" ); success = cellGameGetParamString( CELL_GAME_PARAMID_TITLE_ID, m_gameTitleID, sizeof( m_gameTitleID ) ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_TITLE_ID )" ); success = cellGameGetParamString( CELL_GAME_PARAMID_APP_VER, m_gameAppVer, sizeof( m_gameAppVer ) ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_APP_VER )" ); success = cellGameGetParamInt( CELL_GAME_PARAMID_PARENTAL_LEVEL, &m_gameParentalLevel ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_PARENTAL_LEVEL )" ); success = cellGameGetParamInt( CELL_GAME_PARAMID_RESOLUTION, &m_gameResolution ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_RESOLUTION )" ); success = cellGameGetParamInt( CELL_GAME_PARAMID_SOUND_FORMAT, &m_gameSoundFormat ); CheckError( success, "PARAM.SFO getParam( CELL_GAME_PARAMID_SOUND_FORMAT )" ); // Access BDVD: success = cellGameContentPermit( m_gameContentPath, m_gameBasePath ) ; } else { LocalError("cellGameDataCheck failed (line %d, code %d): %s\n", __LINE__, success, GetSonyErrorString(success) ); return success; } } DiagnosticString( "-----------PARAM.SFO----------" ); DiagnosticString( "\nTITLE " ); DiagnosticString( m_gameTitle ); DiagnosticString( "\nTITLE ID " ); DiagnosticString( m_gameTitleID ); DiagnosticString( "\nAPP_VER " ); DiagnosticString( m_gameAppVer ); if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_PATCH ) { CellGameContentSize cgcs; memset( &cgcs, 0, sizeof(CellGameContentSize) ); success = cellGamePatchCheck( &cgcs, NULL ); if ( success == CELL_GAME_RET_OK ) { success = cellGameGetParamString( CELL_GAME_PARAMID_APP_VER, m_gamePatchAppVer, sizeof( m_gamePatchAppVer ) ); CheckError( success, "PARAM.SFO PATCH getParam( CELL_GAME_PARAMID_APP_VER )" ); DiagnosticString( "\nAPP_VER****" ); DiagnosticString( m_gamePatchAppVer ); success = cellGameContentPermit( m_gamePatchContentPath, m_gamePatchBasePath ) ; } else { LocalError("cellGamePatchCheck failed (line %d, code %d): %s\n", __LINE__, success, GetSonyErrorString(success) ); return success; } } DiagnosticString( "\n------------------------------\n" ); ////////////////////////////////////////////////////////////////////////// // // filesystem path setup // ////////////////////////////////////////////////////////////////////////// DiagnosticString( "----------FILESYSTEM----------" ); DiagnosticString( "\nPS3_GAME " ); DiagnosticString( m_gameContentPath ); DiagnosticString( "\nUSRDIR " ); DiagnosticString( m_gameBasePath ); if ( m_nBootAttribs & CELL_GAME_ATTRIBUTE_PATCH ) { DiagnosticString( "\nPS3_GAME***" ); DiagnosticString( m_gamePatchContentPath ); DiagnosticString( "\nUSRDIR*****" ); DiagnosticString( m_gamePatchBasePath ); } #if 0 // Get the game data directory on the hard disk. success = cellGameDataCheck( CELL_GAME_GAMETYPE_GAMEDATA, m_gameTitleID, &size ); if ( success == CELL_GAME_RET_NONE ) { CellGameSetInitParams init; memset( &init, 0, sizeof( init ) ); memcpy( init.title, m_gameTitle, sizeof( m_gameTitle ) ); memcpy( init.titleId, m_gameTitleID, sizeof( m_gameTitleID ) ); memcpy( init.version, m_gameAppVer, sizeof( m_gameAppVer ) ); char tmp_contentInfoPath[CELL_GAME_PATH_MAX] = {0}; char tmp_usrdirPath[CELL_GAME_PATH_MAX] = {0}; success = cellGameCreateGameData( &init, tmp_contentInfoPath, tmp_usrdirPath ); DiagnosticString( "\nTMP_GAME " ); DiagnosticString( tmp_contentInfoPath ); DiagnosticString( "\nTMP_USRD " ); DiagnosticString( tmp_usrdirPath ); } char contentInfoPath[256]; if ( success == CELL_GAME_RET_OK ) { success = cellGameContentPermit( contentInfoPath, m_gameHDDataPath ); } #else snprintf( m_gameHDDataPath, sizeof( m_gameHDDataPath ), "/dev_hdd0/game/NPUB30589/USRDIR" ); //snprintf( m_gameHDDataPath, sizeof( m_gameHDDataPath ), "/dev_hdd0/game/BLUS30732/USRDIR" ); #endif DiagnosticString( "\nHDD_PATH " ); DiagnosticString( m_gameHDDataPath ); // Mount system cache if ( success >= CELL_GAME_RET_OK ) { CellSysCacheParam sysCacheParams; memset( &sysCacheParams, 0, sizeof( CellSysCacheParam ) ); memcpy( sysCacheParams.cacheId, GetWWMASTER_TitleID(), 10 ); success = cellSysCacheMount( &sysCacheParams ); if ( success >= CELL_GAME_RET_OK ) { memcpy( m_gameSystemCachePath, sysCacheParams.getCachePath, sizeof( m_gameSystemCachePath ) ); if ( uiFlagsMask & INIT_SYS_CACHE_CLEAR ) cellSysCacheClear(); } } DiagnosticString( "\nSYS_CACH " ); DiagnosticString( m_gameSystemCachePath ); // Determine where image files (maps, zips, etc.) are located: snprintf( m_gameImageDataPath, sizeof( m_gameImageDataPath ), m_gameBasePath ); if ( uiFlagsMask & INIT_IMAGE_APP_HOME ) snprintf( m_gameImageDataPath, sizeof( m_gameImageDataPath ), "/app_home/PS3_GAME/USRDIR" ); else if ( uiFlagsMask & INIT_IMAGE_ON_HDD ) snprintf( m_gameImageDataPath, sizeof( m_gameImageDataPath ), m_gameHDDataPath ); else if ( uiFlagsMask & INIT_IMAGE_ON_BDVD ) snprintf( m_gameImageDataPath, sizeof( m_gameImageDataPath ), "/dev_bdvd/PS3_GAME/USRDIR" ); DiagnosticString( "\nIMAGE_PATH " ); DiagnosticString( m_gameImageDataPath ); // Determine where PRX files are located: snprintf( m_gameExesPath, sizeof( m_gameExesPath ), "%s/bin", m_gameBasePath ); if ( uiFlagsMask & INIT_PRX_APP_HOME ) snprintf( m_gameExesPath, sizeof( m_gameExesPath ), "/app_home/PS3_GAME/USRDIR/bin" ); else if ( uiFlagsMask & INIT_PRX_ON_HDD ) snprintf( m_gameExesPath, sizeof( m_gameExesPath ), "%s/bin", m_gameHDDataPath ); else if ( uiFlagsMask & INIT_PRX_ON_BDVD ) snprintf( m_gameExesPath, sizeof( m_gameExesPath ), "/dev_bdvd/PS3_GAME/USRDIR/bin" ); DiagnosticString( "\nPRX_PATH " ); DiagnosticString( m_gameExesPath ); DiagnosticString( "\n------------------------------\n" ); // we cache the saves to a local directory -- keep that info here so it's in a uniform // place accessible from everywhere. strncpy( m_gameSavesShadowPath, m_gameSystemCachePath, sizeof(m_gameSavesShadowPath) ); strncat( m_gameSavesShadowPath, "/tempsave/", sizeof(m_gameSavesShadowPath) ); ////////////////////////////////////////////////////////////////////////// // // finished // ////////////////////////////////////////////////////////////////////////// if ( !bSysModuleIsLoaded ) // actually this means it wasn't loaded when we got into the function { cellSysmoduleUnloadModule( CELL_SYSMODULE_SYSUTIL_GAME ); } return success; } const char *GetSonyErrorString( int errorcode ) { switch( errorcode ) { case CELL_GAME_RET_OK: return "CELL_GAME_RET_OK"; case CELL_GAME_ERROR_ACCESS_ERROR: return "HDD access error"; case CELL_GAME_ERROR_BUSY: return "The call of an access preparing function was repeated"; case CELL_GAME_ERROR_IN_SHUTDOWN: return "Processing cannot be executed because application termination is being processed"; case CELL_GAME_ERROR_INTERNAL: return "Fatal error occurred in the utility"; case CELL_GAME_ERROR_PARAM: return "There is an error in the argument (application bug)"; case CELL_GAME_ERROR_BOOTPATH: return "Pathname of booted program file is too long" ; case CELL_SYSMODULE_ERROR_UNKNOWN: return "Tried to load an unknown PRX"; case CELL_SYSMODULE_ERROR_FATAL: return "Sysmodule PRX load failed"; case CELL_GAME_ERROR_BROKEN: return "The specified game content is corrupted"; default: return "Unknown error code"; } } /* The boot attributes member of CPs3ContentPathInfo is some combination of: CELL_GAME_ATTRIBUTE_PATCH Booted from a patch (only for a disc boot game) CELL_GAME_ATTRIBUTE_APP_HOME Booted from the host machine (development machine only) CELL_GAME_ATTRIBUTE_DEBUG Booted from the debugger (development machine only) CELL_GAME_ATTRIBUTE_XMBBUY Rebooted from the game purchasing feature of the NP DRM utility CELL_GAME_ATTRIBUTE_COMMERCE2_BROWSER Rebooted from the store browsing feature of the NP IN-GAME commerce 2 utility CELL_GAME_ATTRIBUTE_INVITE_MESSAGE Booted from the game boot invitation message of the NP basic utility CELL_GAME_ATTRIBUTE_CUSTOM_DATA_MESSAGE Booted from a message with a custom data attachment of the NP basic utility CELL_GAME_ATTRIBUTE_WEB_BROWSER Booted from the full browser feature of the web browser utility */