From: Anton Baskanov baskanov@gmail.com
--- dlls/dplayx/dplay.c | 2 +- dlls/dplayx/dplay_global.h | 3 + dlls/dplayx/dplayx_messages.c | 214 +++++++++++++++++++++++++++++++++- dlls/dplayx/dplayx_messages.h | 46 ++++++++ dlls/dplayx/tests/dplayx.c | 16 +-- 5 files changed, 271 insertions(+), 10 deletions(-)
diff --git a/dlls/dplayx/dplay.c b/dlls/dplayx/dplay.c index 057003ec8d9..5f0ba3bdcb3 100644 --- a/dlls/dplayx/dplay.c +++ b/dlls/dplayx/dplay.c @@ -1413,7 +1413,7 @@ static HRESULT DP_CreateSPPlayer( IDirectPlayImpl *This, DPID dpid, DWORD flags, return DP_OK; }
-static HRESULT DP_CreatePlayer( IDirectPlayImpl *This, void *msgHeader, DPID *lpid, DPNAME *lpName, +HRESULT DP_CreatePlayer( IDirectPlayImpl *This, void *msgHeader, DPID *lpid, DPNAME *lpName, void *data, DWORD dataSize, void *spData, DWORD spDataSize, DWORD dwFlags, HANDLE hEvent, BOOL bAnsi ) { diff --git a/dlls/dplayx/dplay_global.h b/dlls/dplayx/dplay_global.h index cc3385569ec..b946c078ec6 100644 --- a/dlls/dplayx/dplay_global.h +++ b/dlls/dplayx/dplay_global.h @@ -201,6 +201,9 @@ HRESULT DP_HandleMessage( IDirectPlayImpl *This, const void *lpMessageBody, DWORD dwMessageBodySize, const void *lpMessageHeader, WORD wCommandId, WORD wVersion, void **lplpReply, DWORD *lpdwMsgSize ); DPSESSIONDESC2 *DP_DuplicateSessionDesc( const DPSESSIONDESC2 *src, BOOL dstAnsi, BOOL srcAnsi ); +HRESULT DP_CreatePlayer( IDirectPlayImpl *This, void *msgHeader, DPID *lpid, DPNAME *lpName, + void *data, DWORD dataSize, void *spData, DWORD spDataSize, DWORD dwFlags, + HANDLE hEvent, BOOL bAnsi );
/* DP SP external interfaces into DirectPlay */ extern HRESULT DP_GetSPPlayerData( IDirectPlayImpl *lpDP, DPID idPlayer, void **lplpData ); diff --git a/dlls/dplayx/dplayx_messages.c b/dlls/dplayx/dplayx_messages.c index 8df2cf4e7a4..371caebb893 100644 --- a/dlls/dplayx/dplayx_messages.c +++ b/dlls/dplayx/dplayx_messages.c @@ -295,6 +295,160 @@ HRESULT DP_MSG_SendRequestPlayerId( IDirectPlayImpl *This, DWORD dwFlags, DPID * return hr; }
+static HRESULT DP_MSG_ReadString( char *data, DWORD *inoutOffset, DWORD maxSize, WCHAR **string ) +{ + DWORD offset = *inoutOffset; + DWORD maxLength; + DWORD length; + + if( maxSize - offset < sizeof( WCHAR ) ) + return DPERR_GENERIC; + + maxLength = (maxSize - offset) / sizeof( WCHAR ); + length = wcsnlen( (WCHAR *) &data[ offset ], maxLength ); + if( length == maxLength ) + return DPERR_GENERIC; + + *string = (WCHAR *) &data[ offset ]; + *inoutOffset = offset + (length + 1) * sizeof( WCHAR ); + + return DP_OK; +} + +static HRESULT DP_MSG_ReadInteger( char *data, DWORD *inoutOffset, DWORD maxSize, DWORD size, + DWORD *value ) +{ + DWORD offset = *inoutOffset; + + switch ( size ) + { + case 0: + *value = 0; + break; + case 1: + if( maxSize - offset < 1 ) + return DPERR_GENERIC; + *value = *(BYTE *) &data[ offset ]; + *inoutOffset = offset + 1; + break; + case 2: + if( maxSize - offset < 2 ) + return DPERR_GENERIC; + *value = *(WORD *) &data[ offset ]; + *inoutOffset = offset + 2; + break; + case 3: + if( maxSize - offset < 4 ) + return DPERR_GENERIC; + *value = *(DWORD *) &data[ offset ]; + *inoutOffset = offset + 4; + break; + } + + return DP_OK; +} + +static HRESULT DP_MSG_ReadSuperPackedPlayer( char *data, DWORD *inoutOffset, DWORD maxSize, + DPPLAYERINFO *playerInfo ) +{ + DPLAYI_SUPERPACKEDPLAYER *packedPlayer; + DWORD offset = *inoutOffset; + HRESULT hr; + + memset( playerInfo, 0, sizeof( DPPLAYERINFO ) ); + + if( maxSize - offset < sizeof( DPLAYI_SUPERPACKEDPLAYER ) ) + return DPERR_GENERIC; + packedPlayer = (DPLAYI_SUPERPACKEDPLAYER *) &data[ offset ]; + offset += sizeof( DPLAYI_SUPERPACKEDPLAYER ); + + playerInfo->flags = packedPlayer->flags; + playerInfo->id = packedPlayer->id; + playerInfo->versionOrSystemPlayerId = packedPlayer->versionOrSystemPlayerId; + + if( packedPlayer->infoMask & DPLAYI_SUPERPACKEDPLAYER_SHORT_NAME_PRESENT ) + { + hr = DP_MSG_ReadString( data, &offset, maxSize, &playerInfo->name.lpszShortName ); + if ( FAILED( hr ) ) + return hr; + } + + if( packedPlayer->infoMask & DPLAYI_SUPERPACKEDPLAYER_LONG_NAME_PRESENT ) + { + hr = DP_MSG_ReadString( data, &offset, maxSize, &playerInfo->name.lpszLongName ); + if ( FAILED( hr ) ) + return hr; + } + + hr = DP_MSG_ReadInteger( data, &offset, maxSize, + DPLAYI_SUPERPACKEDPLAYER_PLAYER_DATA_LENGTH_SIZE( packedPlayer->infoMask ), + &playerInfo->playerDataLength ); + if ( FAILED( hr ) ) + return hr; + + if( playerInfo->playerDataLength ) + { + if( maxSize - offset < playerInfo->playerDataLength ) + return DPERR_GENERIC; + playerInfo->playerData = &data[ offset ]; + offset += playerInfo->playerDataLength; + } + + hr = DP_MSG_ReadInteger( data, &offset, maxSize, + DPLAYI_SUPERPACKEDPLAYER_SP_DATA_LENGTH_SIZE( packedPlayer->infoMask ), + &playerInfo->spDataLength ); + if ( FAILED( hr ) ) + return hr; + + if( playerInfo->spDataLength ) + { + if( maxSize - offset < playerInfo->spDataLength ) + return DPERR_GENERIC; + playerInfo->spData = &data[ offset ]; + offset += playerInfo->spDataLength; + } + + hr = DP_MSG_ReadInteger( data, &offset, maxSize, + DPLAYI_SUPERPACKEDPLAYER_PLAYER_COUNT_SIZE( packedPlayer->infoMask ), + &playerInfo->playerCount ); + if ( FAILED( hr ) ) + return hr; + + if( playerInfo->playerCount ) + { + if( maxSize - offset < playerInfo->playerCount * sizeof( DPID ) ) + return DPERR_GENERIC; + playerInfo->playerIds = (DPID *) &data[ offset ]; + offset += playerInfo->playerCount * sizeof( DPID ); + } + + if( packedPlayer->infoMask & DPLAYI_SUPERPACKEDPLAYER_PARENT_ID_PRESENT ) + { + if( maxSize - offset < sizeof( DPID ) ) + return DPERR_GENERIC; + playerInfo->parentId = *(DPID *) &data[ offset ]; + offset += sizeof( DPID ); + } + + hr = DP_MSG_ReadInteger( data, &offset, maxSize, + DPLAYI_SUPERPACKEDPLAYER_SHORTCUT_COUNT_SIZE( packedPlayer->infoMask ), + &playerInfo->shortcutCount ); + if ( FAILED( hr ) ) + return hr; + + if( playerInfo->shortcutCount ) + { + if( maxSize - offset < playerInfo->shortcutCount * sizeof( DPID ) ) + return DPERR_GENERIC; + playerInfo->shortcutIds = (DPID *) &data[ offset ]; + offset += playerInfo->shortcutCount * sizeof( DPID ); + } + + *inoutOffset = offset; + + return S_OK; +} + HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlayImpl *This, DPID dpidServer ) { LPVOID lpMsg; @@ -372,7 +526,65 @@ HRESULT DP_MSG_ForwardPlayerCreation( IDirectPlayImpl *This, DPID dpidServer ) /* Need to examine the data and extract the new player id */ if( lpMsg != NULL ) { - FIXME( "Name Table reply received: stub\n" ); + DPMSG_SENDENVELOPE *envelope; + + if( dwMsgSize < sizeof( DPMSG_SENDENVELOPE ) ) + { + free( msgHeader ); + free( lpMsg ); + return DPERR_GENERIC; + } + envelope = (DPMSG_SENDENVELOPE *) lpMsg; + + if( envelope->wCommandId == DPMSGCMD_SUPERENUMPLAYERSREPLY ) + { + DPSP_MSG_SUPERENUMPLAYERSREPLY *enumPlayersReply; + DWORD offset; + int i; + + if( dwMsgSize < sizeof( DPSP_MSG_SUPERENUMPLAYERSREPLY ) ) + { + free( msgHeader ); + free( lpMsg ); + return DPERR_GENERIC; + } + enumPlayersReply = (DPSP_MSG_SUPERENUMPLAYERSREPLY *) envelope; + + offset = enumPlayersReply->packedOffset; + for( i = 0; i < enumPlayersReply->playerCount; ++i ) + { + DPPLAYERINFO playerInfo; + + hr = DP_MSG_ReadSuperPackedPlayer( (char *) enumPlayersReply, &offset, dwMsgSize, + &playerInfo ); + if( FAILED( hr ) ) + { + free( msgHeader ); + free( lpMsg ); + return hr; + } + + if ( playerInfo.id == dpidServer ) + continue; + + hr = DP_CreatePlayer( This, msgHeader, &playerInfo.id, &playerInfo.name, + playerInfo.playerData, playerInfo.playerDataLength, playerInfo.spData, + playerInfo.spDataLength, playerInfo.flags & ~DPLAYI_PLAYER_PLAYERLOCAL, NULL, + FALSE ); + if( FAILED( hr ) ) + { + free( msgHeader ); + free( lpMsg ); + return hr; + } + } + } + else if( envelope->wCommandId == DPMSGCMD_GETNAMETABLEREPLY ) + { + FIXME( "Name Table reply received: stub\n" ); + } + free( msgHeader ); + free( lpMsg ); }
return hr; diff --git a/dlls/dplayx/dplayx_messages.h b/dlls/dplayx/dplayx_messages.h index 09526085d5a..09a0ffb03d9 100644 --- a/dlls/dplayx/dplayx_messages.h +++ b/dlls/dplayx/dplayx_messages.h @@ -28,6 +28,23 @@
#include "dplay_global.h"
+typedef struct +{ + DWORD flags; + DPID id; + DWORD versionOrSystemPlayerId; + DPNAME name; + DWORD playerDataLength; + void *playerData; + DWORD spDataLength; + void *spData; + DWORD playerCount; + DPID *playerIds; + DPID parentId; + DWORD shortcutCount; + DPID *shortcutIds; +} DPPLAYERINFO; + DWORD CreateLobbyMessageReceptionThread( HANDLE hNotifyEvent, HANDLE hStart, HANDLE hDeath, HANDLE hConnRead );
@@ -221,6 +238,35 @@ typedef struct tagDPMSG_FORWARDADDPLAYERNACK } DPMSG_FORWARDADDPLAYERNACK, *LPDPMSG_FORWARDADDPLAYERNACK; typedef const DPMSG_FORWARDADDPLAYERNACK* LPCDPMSG_FORWARDADDPLAYERNACK;
+typedef struct +{ + DWORD size; + DWORD flags; + DPID id; + DWORD infoMask; + DWORD versionOrSystemPlayerId; +} DPLAYI_SUPERPACKEDPLAYER; + +#define DPLAYI_SUPERPACKEDPLAYER_SHORT_NAME_PRESENT 0x001 +#define DPLAYI_SUPERPACKEDPLAYER_LONG_NAME_PRESENT 0x002 +#define DPLAYI_SUPERPACKEDPLAYER_SP_DATA_LENGTH_SIZE( mask ) (((mask) >> 2) & 0x3) +#define DPLAYI_SUPERPACKEDPLAYER_PLAYER_DATA_LENGTH_SIZE( mask ) (((mask) >> 4) & 0x3) +#define DPLAYI_SUPERPACKEDPLAYER_PLAYER_COUNT_SIZE( mask ) (((mask) >> 6) & 0x3) +#define DPLAYI_SUPERPACKEDPLAYER_PARENT_ID_PRESENT 0x100 +#define DPLAYI_SUPERPACKEDPLAYER_SHORTCUT_COUNT_SIZE( mask ) (((mask) >> 9) & 0x3) + +typedef struct +{ + DPMSG_SENDENVELOPE envelope; + DWORD playerCount; + DWORD groupCount; + DWORD packedOffset; + DWORD shortcutCount; + DWORD descriptionOffset; + DWORD nameOffset; + DWORD passwordOffset; +} DPSP_MSG_SUPERENUMPLAYERSREPLY; + #include "poppack.h"
#endif diff --git a/dlls/dplayx/tests/dplayx.c b/dlls/dplayx/tests/dplayx.c index 1c2b9bcbd19..dcf0e4f2c4d 100644 --- a/dlls/dplayx/tests/dplayx.c +++ b/dlls/dplayx/tests/dplayx.c @@ -2029,8 +2029,8 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const playerType ); if ( player->expectedShortName ) { - ok_( __FILE__, data->line )( name->lpszShortNameA && !strcmp( name->lpszShortNameA, player->expectedShortName ), - "got short name %s.\n", wine_dbgstr_a( name->lpszShortNameA ) ); + todo_wine ok_( __FILE__, data->line )( name->lpszShortNameA && !strcmp( name->lpszShortNameA, player->expectedShortName ), + "got short name %s.\n", wine_dbgstr_a( name->lpszShortNameA ) ); } else { @@ -2039,8 +2039,8 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const } if ( player->expectedLongName ) { - ok_( __FILE__, data->line )( name->lpszLongNameA && !strcmp( name->lpszLongNameA, player->expectedLongName ), - "got long name %s.\n", wine_dbgstr_a( name->lpszLongNameA ) ); + todo_wine ok_( __FILE__, data->line )( name->lpszLongNameA && !strcmp( name->lpszLongNameA, player->expectedLongName ), + "got long name %s.\n", wine_dbgstr_a( name->lpszLongNameA ) ); } else { @@ -2053,8 +2053,8 @@ static BOOL CALLBACK checkPlayerListCallback( DPID dpid, DWORD playerType, const playerDataSize = sizeof( playerData ); hr = IDirectPlayX_GetPlayerData( data->dp, dpid, playerData, &playerDataSize, DPGET_REMOTE ); ok_( __FILE__, data->line )( hr == DP_OK, "GetPlayerData() returned %#lx.\n", hr ); - ok_( __FILE__, data->line )( playerDataSize == player->expectedPlayerDataSize, - "got player data size %lu.\n", playerDataSize ); + todo_wine ok_( __FILE__, data->line )( playerDataSize == player->expectedPlayerDataSize, + "got player data size %lu.\n", playerDataSize ); ok_( __FILE__, data->line )( !memcmp( playerData, player->expectedPlayerData, player->expectedPlayerDataSize ), "player data doesn't match.\n" );
@@ -2085,8 +2085,8 @@ static void checkPlayerList_( int line, IDirectPlay4 *dp, ExpectedPlayer *expect
hr = IDirectPlayX_EnumPlayers( dp, NULL, checkPlayerListCallback, &data, 0 ); ok_( __FILE__, line )( hr == DP_OK, "EnumPlayers() returned %#lx.\n", hr ); - todo_wine ok_( __FILE__, line )( data.actualPlayerCount == data.expectedPlayerCount, "got player count %d.\n", - data.actualPlayerCount ); + ok_( __FILE__, line )( data.actualPlayerCount == data.expectedPlayerCount, "got player count %d.\n", + data.actualPlayerCount ); }
#define check_Open( dp, dpsd, serverDpsd, requestExpected, port, expectedPassword, expectedHr ) check_Open_( __LINE__, dp, dpsd, serverDpsd, requestExpected, port, expectedPassword, expectedHr )