diff --git a/src/DirectPlay8Address.cpp b/src/DirectPlay8Address.cpp index 549ab76..743d6ba 100644 --- a/src/DirectPlay8Address.cpp +++ b/src/DirectPlay8Address.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include "DirectPlay8Address.hpp" @@ -17,6 +19,41 @@ DirectPlay8Address::DirectPlay8Address(std::atomic *global_refcoun AddRef(); } +DirectPlay8Address::DirectPlay8Address(const DirectPlay8Address &src): + global_refcount(src.global_refcount), + local_refcount(0), + user_data(src.user_data) +{ + replace_components(src.components); + AddRef(); +} + +DirectPlay8Address::~DirectPlay8Address() +{ + clear_components(); +} + +void DirectPlay8Address::clear_components() +{ + for(auto c = components.begin(); c != components.end(); ++c) + { + delete *c; + } + + components.clear(); +} + +void DirectPlay8Address::replace_components(const std::vector src) +{ + clear_components(); + + components.reserve(src.size()); + for(auto c = src.begin(); c != src.end(); ++c) + { + components.push_back((*c)->clone()); + } +} + HRESULT DirectPlay8Address::QueryInterface(REFIID riid, void **ppvObject) { if(riid == IID_IDirectPlay8Address || riid == IID_IUnknown) @@ -71,12 +108,16 @@ HRESULT DirectPlay8Address::BuildFromURLA(CHAR* pszSourceURL) HRESULT DirectPlay8Address::Duplicate(PDIRECTPLAY8ADDRESS* ppdpaNewAddress) { - UNIMPLEMENTED("DirectPlay8Address::Duplicate"); + *ppdpaNewAddress = new DirectPlay8Address(*this); + return S_OK; } HRESULT DirectPlay8Address::SetEqual(PDIRECTPLAY8ADDRESS pdpaAddress) { - UNIMPLEMENTED("DirectPlay8Address::SetEqual"); + replace_components(((DirectPlay8Address*)(pdpaAddress))->components); + user_data = ((DirectPlay8Address*)(pdpaAddress))->user_data; + + return S_OK; } HRESULT DirectPlay8Address::IsEqual(PDIRECTPLAY8ADDRESS pdpaAddress) @@ -86,7 +127,10 @@ HRESULT DirectPlay8Address::IsEqual(PDIRECTPLAY8ADDRESS pdpaAddress) HRESULT DirectPlay8Address::Clear() { - UNIMPLEMENTED("DirectPlay8Address::Clear"); + clear_components(); + user_data.clear(); + + return S_OK; } HRESULT DirectPlay8Address::GetURLW(WCHAR* pwszURL, PDWORD pdwNumChars) @@ -101,55 +145,292 @@ HRESULT DirectPlay8Address::GetURLA(CHAR* pszURL, PDWORD pdwNumChars) HRESULT DirectPlay8Address::GetSP(GUID* pguidSP) { - UNIMPLEMENTED("DirectPlay8Address::GetSP"); + GUID buf; + DWORD buf_size = sizeof(buf); + DWORD type; + + HRESULT res = GetComponentByName(DPNA_KEY_PROVIDER, &buf, &buf_size, &type); + + if(res == S_OK && type == DPNA_DATATYPE_GUID) + { + *pguidSP = buf; + return S_OK; + } + else if(res == S_OK) + { + return DPNERR_GENERIC; + } + else{ + return res; + } } HRESULT DirectPlay8Address::GetUserData(LPVOID pvUserData, PDWORD pdwBufferSize) { - UNIMPLEMENTED("DirectPlay8Address::GetUserData"); + if(user_data.empty()) + { + return DPNERR_DOESNOTEXIST; + } + + if(pvUserData != NULL && *pdwBufferSize >= user_data.size()) + { + memcpy(pvUserData, user_data.data(), user_data.size()); + *pdwBufferSize = user_data.size(); + return S_OK; + } + else{ + *pdwBufferSize = user_data.size(); + return DPNERR_BUFFERTOOSMALL; + } } HRESULT DirectPlay8Address::SetSP(CONST GUID* CONST pguidSP) { - UNIMPLEMENTED("DirectPlay8Address::SetSP"); + return AddComponent(DPNA_KEY_PROVIDER, pguidSP, sizeof(*pguidSP), DPNA_DATATYPE_GUID); } HRESULT DirectPlay8Address::SetUserData(CONST void* CONST pvUserData, CONST DWORD dwDataSize) { - UNIMPLEMENTED("DirectPlay8Address::SetUserData"); + user_data.clear(); + + if(pvUserData != NULL && dwDataSize > 0) + { + user_data.insert(user_data.end(), (unsigned char*)(pvUserData),(unsigned char*)(pvUserData) + dwDataSize); + } + + return S_OK; } HRESULT DirectPlay8Address::GetNumComponents(PDWORD pdwNumComponents) { - UNIMPLEMENTED("DirectPlay8Address::GetNumComponents"); + return components.size(); } HRESULT DirectPlay8Address::GetComponentByName(CONST WCHAR* CONST pwszName, LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) { - UNIMPLEMENTED("DirectPlay8Address::GetComponentByName"); + for(auto c = components.begin(); c != components.end(); ++c) + { + if((*c)->name == pwszName) + { + return (*c)->get_component(pvBuffer, pdwBufferSize, pdwDataType); + } + } + + return DPNERR_DOESNOTEXIST; } HRESULT DirectPlay8Address::GetComponentByIndex(CONST DWORD dwComponentID, WCHAR* pwszName, PDWORD pdwNameLen, void* pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) { - UNIMPLEMENTED("DirectPlay8Address::GetComponentByIndex"); + if(dwComponentID >= components.size()) + { + return DPNERR_DOESNOTEXIST; + } + + Component *c = components[dwComponentID]; + + HRESULT res = c->get_component(pvBuffer, pdwBufferSize, pdwDataType); + + if(*pdwNameLen > c->name.length() && pwszName != NULL) + { + wcscpy(pwszName, c->name.c_str()); + *pdwNameLen = c->name.length() + 1; + } + else{ + *pdwNameLen = c->name.length() + 1; + res = DPNERR_BUFFERTOOSMALL; + } + + return res; } HRESULT DirectPlay8Address::AddComponent(CONST WCHAR* CONST pwszName, CONST void* CONST lpvData, CONST DWORD dwDataSize, CONST DWORD dwDataType) { - UNIMPLEMENTED("DirectPlay8Address::AddComponent"); + auto existing_component = components.begin(); + for(; existing_component != components.end(); ++existing_component) + { + if((*existing_component)->name == pwszName) + { + break; + } + } + + Component *new_component; + + switch(dwDataType) + { + case DPNA_DATATYPE_STRING: + new_component = new StringComponentW(pwszName, (const wchar_t*)(lpvData), dwDataSize); + break; + + case DPNA_DATATYPE_STRING_ANSI: + new_component = new StringComponentA(pwszName, (const char*)(lpvData), dwDataSize); + break; + + case DPNA_DATATYPE_DWORD: + if(dwDataSize != sizeof(DWORD)) + { + return DPNERR_INVALIDPARAM; + } + + new_component = new DWORDComponent(pwszName, *((DWORD*)(lpvData))); + break; + + case DPNA_DATATYPE_GUID: + if(dwDataSize != sizeof(GUID)) + { + return DPNERR_INVALIDPARAM; + } + + new_component = new GUIDComponent(pwszName, *((GUID*)(lpvData))); + break; + + default: + UNIMPLEMENTED("DirectPlay8Address::AddComponent() with dwDataType %u", (unsigned)(dwDataType)); + } + + if(existing_component != components.end()) + { + delete *existing_component; + *existing_component = new_component; + } + else{ + components.push_back(new_component); + } + + return S_OK; } HRESULT DirectPlay8Address::GetDevice(GUID* pDevGuid) { - UNIMPLEMENTED("DirectPlay8Address::GetDevice"); + GUID buf; + DWORD buf_size = sizeof(buf); + DWORD type; + + HRESULT res = GetComponentByName(DPNA_KEY_DEVICE, &buf, &buf_size, &type); + + if(res == S_OK && type == DPNA_DATATYPE_GUID) + { + *pDevGuid = buf; + return S_OK; + } + else if(res == S_OK) + { + return DPNERR_GENERIC; + } + else{ + return res; + } } HRESULT DirectPlay8Address::SetDevice(CONST GUID* CONST devGuid) { - UNIMPLEMENTED("DirectPlay8Address::SetDevice"); + return AddComponent(DPNA_KEY_DEVICE, devGuid, sizeof(*devGuid), DPNA_DATATYPE_GUID); } HRESULT DirectPlay8Address::BuildFromDirectPlay4Address(LPVOID pvAddress, DWORD dwDataSize) { UNIMPLEMENTED("DirectPlay8Address::BuildFromDirectPlay4Address"); } + +DirectPlay8Address::Component::Component(const std::wstring &name, DWORD type): + name(name), + type(type) {} + +DirectPlay8Address::Component::~Component() {} + +DirectPlay8Address::StringComponentW::StringComponentW(const std::wstring &name, const wchar_t *lpvData, DWORD dwDataSize): + Component(name, DPNA_DATATYPE_STRING), value(lpvData, dwDataSize) {} + +DirectPlay8Address::Component *DirectPlay8Address::StringComponentW::clone() +{ + return new DirectPlay8Address::StringComponentW(name, value.data(), value.length()); +} + +HRESULT DirectPlay8Address::StringComponentW::get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) +{ + *pdwDataType = DPNA_DATATYPE_STRING; + + if(*pdwBufferSize > value.length() && pvBuffer != NULL) + { + wcscpy((wchar_t*)(pvBuffer), value.c_str()); + *pdwBufferSize = value.length() + 1; + return S_OK; + } + else{ + *pdwBufferSize = value.length() + 1; + return DPNERR_BUFFERTOOSMALL; + } +} + +DirectPlay8Address::StringComponentA::StringComponentA(const std::wstring &name, const char *lpvData, DWORD dwDataSize): + Component(name, DPNA_DATATYPE_STRING_ANSI), value(lpvData, dwDataSize) {} + +HRESULT DirectPlay8Address::StringComponentA::get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) +{ + *pdwDataType = DPNA_DATATYPE_STRING_ANSI; + + if(*pdwBufferSize > value.length() && pvBuffer != NULL) + { + strcpy((char*)(pvBuffer), value.c_str()); + *pdwBufferSize = value.length() + 1; + return S_OK; + } + else{ + *pdwBufferSize = value.length() + 1; + return DPNERR_BUFFERTOOSMALL; + } +} + +DirectPlay8Address::Component *DirectPlay8Address::StringComponentA::clone() +{ + return new DirectPlay8Address::StringComponentA(name, value.data(), value.length()); +} + +DirectPlay8Address::DWORDComponent::DWORDComponent(const std::wstring &name, DWORD value): + Component(name, DPNA_DATATYPE_DWORD), value(value) {} + +DirectPlay8Address::Component *DirectPlay8Address::DWORDComponent::clone() +{ + return new DirectPlay8Address::DWORDComponent(name, value); +} + +HRESULT DirectPlay8Address::DWORDComponent::get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) +{ + *pdwDataType = DPNA_DATATYPE_DWORD; + + if(*pdwBufferSize >= sizeof(DWORD) && pvBuffer != NULL) + { + *((DWORD*)(pvBuffer)) = value; + *pdwBufferSize = sizeof(DWORD); + return S_OK; + } + else{ + *pdwBufferSize = sizeof(DWORD); + return DPNERR_BUFFERTOOSMALL; + } +} + +DirectPlay8Address::GUIDComponent::GUIDComponent(const std::wstring &name, GUID value): + Component(name, DPNA_DATATYPE_GUID), value(value) {} + + +DirectPlay8Address::Component *DirectPlay8Address::GUIDComponent::clone() +{ + return new DirectPlay8Address::GUIDComponent(name, value); +} + +HRESULT DirectPlay8Address::GUIDComponent::get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) +{ + *pdwDataType = DPNA_DATATYPE_GUID; + + if(*pdwBufferSize >= sizeof(GUID) && pvBuffer != NULL) + { + *((GUID*)(pvBuffer)) = value; + *pdwBufferSize = sizeof(GUID); + return S_OK; + } + else{ + *pdwBufferSize = sizeof(GUID); + return DPNERR_BUFFERTOOSMALL; + } +} diff --git a/src/DirectPlay8Address.hpp b/src/DirectPlay8Address.hpp index 07a010e..d35da98 100644 --- a/src/DirectPlay8Address.hpp +++ b/src/DirectPlay8Address.hpp @@ -4,16 +4,80 @@ #include #include #include +#include +#include class DirectPlay8Address: public IDirectPlay8Address { private: + class Component + { + public: + const std::wstring name; + const DWORD type; + + virtual ~Component(); + + virtual Component *clone() = 0; + virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType) = 0; + + protected: + Component(const std::wstring &name, DWORD type); + }; + + class StringComponentW: public Component + { + public: + const std::wstring value; + + StringComponentW(const std::wstring &name, const wchar_t *lpvData, DWORD dwDataSize); + virtual Component *clone(); + virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); + }; + + class StringComponentA: public Component + { + public: + const std::string value; + + StringComponentA(const std::wstring &name, const char *lpvData, DWORD dwDataSize); + virtual Component *clone(); + virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); + }; + + class DWORDComponent: public Component + { + public: + const DWORD value; + + DWORDComponent(const std::wstring &name, DWORD value); + virtual Component *clone(); + virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); + }; + + class GUIDComponent: public Component + { + public: + const GUID value; + + GUIDComponent(const std::wstring &name, GUID value); + virtual Component *clone(); + virtual HRESULT get_component(LPVOID pvBuffer, PDWORD pdwBufferSize, PDWORD pdwDataType); + }; + std::atomic * const global_refcount; ULONG local_refcount; - + + std::vector components; + std::vector user_data; + + void clear_components(); + void replace_components(const std::vector src); + public: DirectPlay8Address(std::atomic *global_refcount); - virtual ~DirectPlay8Address() {} + DirectPlay8Address(const DirectPlay8Address &src); + virtual ~DirectPlay8Address(); /* IUnknown */ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;