diff --git a/lsteamclient/gen_wrapper.py b/lsteamclient/gen_wrapper.py index 784a7db9..7bd75f24 100755 --- a/lsteamclient/gen_wrapper.py +++ b/lsteamclient/gen_wrapper.py @@ -211,6 +211,7 @@ UNIX_FUNCS = [ 'steamclient_init', 'steamclient_init_registry', 'steamclient_next_callback', + 'steamclient_get_unix_buffer', 'steamclient_CreateInterface', 'steamclient_Steam_GetAPICallResult', 'steamclient_Steam_BGetCallback', diff --git a/lsteamclient/steamclient_main.c b/lsteamclient/steamclient_main.c index ca028fc8..4302e87b 100644 --- a/lsteamclient/steamclient_main.c +++ b/lsteamclient/steamclient_main.c @@ -325,6 +325,24 @@ done: return ret; } +void *get_unix_buffer( struct u_buffer buf ) +{ + struct steamclient_get_unix_buffer_params params = {.buf = buf}; + void *ret; + + if ((UINT_PTR)buf.ptr == buf.ptr && (UINT_PTR)(buf.ptr + buf.len) == (buf.ptr + buf.len)) + return (void *)(UINT_PTR)buf.ptr; + + if (!(params.ptr = ret = HeapAlloc( GetProcessHeap(), 0, buf.len ))) return NULL; + if (STEAMCLIENT_CALL( steamclient_get_unix_buffer, ¶ms ) || (ret != params.ptr)) + { + HeapFree( GetProcessHeap(), 0, ret ); + ret = params.ptr; + } + + return ret; +} + static BOOL get_env_win(const WCHAR *name, char *value, unsigned int size) { DWORD i, env_size; diff --git a/lsteamclient/steamclient_private.h b/lsteamclient/steamclient_private.h index d88ad63e..b37cb22a 100644 --- a/lsteamclient/steamclient_private.h +++ b/lsteamclient/steamclient_private.h @@ -46,6 +46,7 @@ extern void execute_pending_callbacks(void); struct w_iface *create_win_interface( const char *name, struct u_iface ); void *alloc_mem_for_iface(size_t size, const char *iface_version); void *alloc_vtable(void *vtable, unsigned int method_count, const char *iface_version); +void *get_unix_buffer( struct u_buffer buf ); void init_rtti( char *base ); diff --git a/lsteamclient/steamclient_structs.h b/lsteamclient/steamclient_structs.h index 9bb497c3..8240cc9f 100644 --- a/lsteamclient/steamclient_structs.h +++ b/lsteamclient/steamclient_structs.h @@ -67,4 +67,14 @@ struct u_iface #endif /* __cplusplus */ }; +struct u_buffer +{ + UINT64 ptr; + UINT64 len; +#ifdef __cplusplus + struct u_buffer &operator=(const char* value) { this->ptr = (UINT_PTR)value; this->len = value ? strlen( value ) + 1 : 0; return *this; } + operator char*() const { return (char*)(UINT_PTR)this->ptr; } +#endif /* __cplusplus */ +}; + #endif /* __STEAMCLIENT_STRUCTS_H */ diff --git a/lsteamclient/unix_private.h b/lsteamclient/unix_private.h index 08a31db3..40fdfa29 100644 --- a/lsteamclient/unix_private.h +++ b/lsteamclient/unix_private.h @@ -74,6 +74,7 @@ void convert_callback_utow( int id, void *u_callback, int u_callback_len, void * extern NTSTATUS steamclient_init( void * ); extern NTSTATUS steamclient_init_registry( void * ); extern NTSTATUS steamclient_next_callback( void * ); +extern NTSTATUS steamclient_get_unix_buffer( void * ); extern NTSTATUS steamclient_CreateInterface( void * ); extern NTSTATUS steamclient_Steam_GetAPICallResult( void * ); extern NTSTATUS steamclient_Steam_BGetCallback( void * ); diff --git a/lsteamclient/unixlib.cpp b/lsteamclient/unixlib.cpp index 33e738d5..6b335a48 100644 --- a/lsteamclient/unixlib.cpp +++ b/lsteamclient/unixlib.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #if 0 #pragma makedep unix @@ -683,6 +684,38 @@ NTSTATUS steamclient_init( void *args ) return 0; } +namespace std +{ +template<> struct hash< struct u_buffer > +{ + using argument_type = struct u_buffer; + using result_type = std::size_t; + result_type operator()( argument_type const& buf ) const { return buf.ptr; } +}; +} + +static pthread_mutex_t buffer_cache_lock = PTHREAD_MUTEX_INITIALIZER; +static std::unordered_map< struct u_buffer, void * > buffer_cache; + +NTSTATUS steamclient_get_unix_buffer( void *args ) +{ + struct steamclient_get_unix_buffer_params *params = (struct steamclient_get_unix_buffer_params *)args; + struct cache_entry *entry; + struct rb_entry *ptr; + + pthread_mutex_lock( &buffer_cache_lock ); + auto iter = buffer_cache.find( params->buf ); + if (iter != buffer_cache.end()) params->ptr = iter->second; + else + { + memcpy( params->ptr, (char *)params->buf, params->buf.len ); + buffer_cache[params->buf] = params->ptr; + } + pthread_mutex_unlock( &buffer_cache_lock ); + + return 0; +} + NTSTATUS steamclient_CreateInterface( void *args ) { struct steamclient_CreateInterface_params *params = (struct steamclient_CreateInterface_params *)args; diff --git a/lsteamclient/unixlib.h b/lsteamclient/unixlib.h index 38672867..5a1213ba 100644 --- a/lsteamclient/unixlib.h +++ b/lsteamclient/unixlib.h @@ -32,6 +32,12 @@ struct steamclient_init_params int8_t ignore_child_processes_unset; }; +struct steamclient_get_unix_buffer_params +{ + struct u_buffer buf; + void *ptr; /* client-side ptr */ +}; + enum callback_type { SOCKETS_DEBUG_OUTPUT = 1, diff --git a/lsteamclient/unixlib_generated.cpp b/lsteamclient/unixlib_generated.cpp index ab7eed90..945cac16 100644 --- a/lsteamclient/unixlib_generated.cpp +++ b/lsteamclient/unixlib_generated.cpp @@ -11,6 +11,7 @@ extern "C" const unixlib_entry_t __wine_unix_call_funcs[] = steamclient_init, steamclient_init_registry, steamclient_next_callback, + steamclient_get_unix_buffer, steamclient_CreateInterface, steamclient_Steam_GetAPICallResult, steamclient_Steam_BGetCallback, diff --git a/lsteamclient/unixlib_generated.h b/lsteamclient/unixlib_generated.h index 1bef8572..8c55ea8e 100644 --- a/lsteamclient/unixlib_generated.h +++ b/lsteamclient/unixlib_generated.h @@ -48759,6 +48759,7 @@ enum unix_funcs unix_steamclient_init, unix_steamclient_init_registry, unix_steamclient_next_callback, + unix_steamclient_get_unix_buffer, unix_steamclient_CreateInterface, unix_steamclient_Steam_GetAPICallResult, unix_steamclient_Steam_BGetCallback,