From 748aff99ccd28a7b6d183fcea19b6a0f3a587389 Mon Sep 17 00:00:00 2001 From: Zorua Date: Sat, 24 Sep 2022 03:00:21 -0400 Subject: [PATCH] un-screw steamshim on Windows again --- steamshim/steamshim_child.c | 925 ++++++++++++++++++------------------ 1 file changed, 456 insertions(+), 469 deletions(-) diff --git a/steamshim/steamshim_child.c b/steamshim/steamshim_child.c index 71a99f9..70861e4 100644 --- a/steamshim/steamshim_child.c +++ b/steamshim/steamshim_child.c @@ -1,469 +1,456 @@ - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN 1 -#include -#include -#include -#include -typedef int PipeType; -#define NULLPIPE 0 -typedef unsigned __int8 uint8; -typedef __int32 int32; -typedef unsigned __int64 uint64; -#else -#include -#include -#include -#include -#include -#include -#include -typedef uint8_t uint8; -typedef int32_t int32; -typedef uint64_t uint64; -typedef int PipeType; -#define NULLPIPE -1 -#endif -#include - -#include "steamshim_child.h" - -#ifdef STEAMSHIM_DEBUG -#define dbgpipe printf -#else -static inline void dbgpipe(const char *fmt, ...) { - (void)fmt; -} -#endif - -static int writePipe(PipeType fd, const void *buf, const unsigned int _len); -static int readPipe(PipeType fd, void *buf, const unsigned int _len); -static void closePipe(PipeType fd); -static char *getEnvVar(const char *key, char *buf, const size_t buflen); -static int pipeReady(PipeType fd); - - -#ifdef _WIN32 - -static int pipeReady(PipeType fd) -{ - return 1; - DWORD avail = 0; - return (PeekNamedPipe(fd, NULL, 0, NULL, &avail, NULL) && (avail > 0)); -} /* pipeReady */ - -static int writePipe(PipeType fd, const void *buf, const unsigned int _len) -{ - const ssize_t len = (ssize_t) _len; - ssize_t bw; - while (((bw = _write(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ } - return (bw == len); -} /* writePipe */ - -static int readPipe(PipeType fd, void *buf, const unsigned int _len) -{ - const ssize_t len = (ssize_t) _len; - ssize_t br; - while (((br = _read(fd, buf, len)) == 0)) { /*spin*/ } - return (int) br; -} /* readPipe */ - -static void closePipe(PipeType fd) -{ - _close(fd); -} /* closePipe */ - -static char *getEnvVar(const char *key, char *buf, const size_t buflen) -{ - const DWORD rc = GetEnvironmentVariableA(key, buf, buflen); - /* rc doesn't count null char, hence "<". */ - return ((rc > 0) && (rc < buflen)) ? buf : NULL; -} /* getEnvVar */ - -#else - -static int pipeReady(PipeType fd) -{ - int rc; - struct pollfd pfd = { fd, POLLIN | POLLERR | POLLHUP, 0 }; - while (((rc = poll(&pfd, 1, 0)) == -1) && (errno == EINTR)) { /*spin*/ } - return (rc == 1); -} /* pipeReady */ - -static int writePipe(PipeType fd, const void *buf, const unsigned int _len) -{ - const ssize_t len = (ssize_t) _len; - ssize_t bw; - while (((bw = write(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ } - return (bw == len); -} /* writePipe */ - -static int readPipe(PipeType fd, void *buf, const unsigned int _len) -{ - const ssize_t len = (ssize_t) _len; - ssize_t br; - while (((br = read(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ } - return (int) br; -} /* readPipe */ - -static void closePipe(PipeType fd) -{ - close(fd); -} /* closePipe */ - -static char *getEnvVar(const char *key, char *buf, const size_t buflen) -{ - const char *envr = getenv(key); - if (!envr || (strlen(envr) >= buflen)) - return NULL; - strcpy(buf, envr); - return buf; -} /* getEnvVar */ - -#endif - - -static PipeType GPipeRead = NULLPIPE; -static PipeType GPipeWrite = NULLPIPE; - -typedef enum ShimCmd -{ - SHIMCMD_BYE, - SHIMCMD_PUMP, - SHIMCMD_REQUESTSTATS, - SHIMCMD_STORESTATS, - SHIMCMD_SETACHIEVEMENT, - SHIMCMD_GETACHIEVEMENT, - SHIMCMD_RESETSTATS, - SHIMCMD_SETSTATI, - SHIMCMD_GETSTATI, - SHIMCMD_SETSTATF, - SHIMCMD_GETSTATF, - SHIMCMD_GETPERSONANAME, - SHIMCMD_GETCURRENTGAMELANGUAGE, -} ShimCmd; - -static int write1ByteCmd(const uint8 b1) -{ - const uint8 buf[] = { 1, b1 }; - return writePipe(GPipeWrite, buf, sizeof (buf)); -} /* write1ByteCmd */ - -static int write2ByteCmd(const uint8 b1, const uint8 b2) -{ - const uint8 buf[] = { 2, b1, b2 }; - return writePipe(GPipeWrite, buf, sizeof (buf)); -} /* write2ByteCmd */ - -static inline int writeBye(void) -{ - dbgpipe("Child sending SHIMCMD_BYE().\n"); - return write1ByteCmd(SHIMCMD_BYE); -} // writeBye - -static int initPipes(void) -{ - char buf[64]; - - if (!getEnvVar("STEAMSHIM_READHANDLE", buf, sizeof (buf))) - return 0; - GPipeRead = (PipeType) strtoull(buf, 0, 10); - - if (!getEnvVar("STEAMSHIM_WRITEHANDLE", buf, sizeof (buf))) - return 0; - GPipeWrite = (PipeType) strtoull(buf, 0, 10); - - return ((GPipeRead != NULLPIPE) && (GPipeWrite != NULLPIPE)); -} /* initPipes */ - - -int STEAMSHIM_init(void) -{ - dbgpipe("Child init start.\n"); - if (!initPipes()) - { - dbgpipe("Child init failed.\n"); - return 0; - } /* if */ - -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif - - dbgpipe("Child init success!\n"); - return 1; -} /* STEAMSHIM_init */ - -void STEAMSHIM_deinit(void) -{ - dbgpipe("Child deinit.\n"); - if (GPipeWrite != NULLPIPE) - { - writeBye(); - closePipe(GPipeWrite); - } /* if */ - - if (GPipeRead != NULLPIPE) - closePipe(GPipeRead); - - GPipeRead = GPipeWrite = NULLPIPE; - -#ifndef _WIN32 - signal(SIGPIPE, SIG_DFL); -#endif -} /* STEAMSHIM_deinit */ - -static inline int isAlive(void) -{ - return ((GPipeRead != NULLPIPE) && (GPipeWrite != NULLPIPE)); -} /* isAlive */ - -static inline int isDead(void) -{ - return !isAlive(); -} /* isDead */ - -int STEAMSHIM_alive(void) -{ - return isAlive(); -} /* STEAMSHIM_alive */ - -static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) -{ - static STEAMSHIM_Event event; - const STEAMSHIM_EventType type = (STEAMSHIM_EventType) *(buf++); - buflen--; - - memset(&event, '\0', sizeof (event)); - event.type = type; - event.okay = 1; - - #ifdef STEAMSHIM_DEBUG - if (0) {} - #define PRINTGOTEVENT(x) else if (type == x) printf("Child got " #x ".\n") - PRINTGOTEVENT(SHIMEVENT_BYE); - PRINTGOTEVENT(SHIMEVENT_STATSRECEIVED); - PRINTGOTEVENT(SHIMEVENT_STATSSTORED); - PRINTGOTEVENT(SHIMEVENT_SETACHIEVEMENT); - PRINTGOTEVENT(SHIMEVENT_GETACHIEVEMENT); - PRINTGOTEVENT(SHIMEVENT_RESETSTATS); - PRINTGOTEVENT(SHIMEVENT_SETSTATI); - PRINTGOTEVENT(SHIMEVENT_GETSTATI); - PRINTGOTEVENT(SHIMEVENT_SETSTATF); - PRINTGOTEVENT(SHIMEVENT_GETSTATF); - PRINTGOTEVENT(SHIMEVENT_GETPERSONANAME); - PRINTGOTEVENT(SHIMEVENT_GETCURRENTGAMELANGUAGE); - #undef PRINTGOTEVENT - else printf("Child got unknown shimevent %d.\n", (int) type); - #endif - - switch (type) - { - case SHIMEVENT_BYE: - break; - - case SHIMEVENT_STATSRECEIVED: - case SHIMEVENT_STATSSTORED: - if (!buflen) return NULL; - event.okay = *(buf++) ? 1 : 0; - break; - - case SHIMEVENT_SETACHIEVEMENT: - if (buflen < 3) return NULL; - event.ivalue = *(buf++) ? 1 : 0; - event.okay = *(buf++) ? 1 : 0; - strcpy(event.name, (const char *) buf); - break; - - case SHIMEVENT_GETACHIEVEMENT: - if (buflen < 10) return NULL; - event.ivalue = (int) *(buf++); - if (event.ivalue == 2) - event.ivalue = event.okay = 0; - event.epochsecs = (long long unsigned) *((uint64 *) buf); - buf += sizeof (uint64); - strcpy(event.name, (const char *) buf); - break; - - case SHIMEVENT_RESETSTATS: - if (buflen != 2) return NULL; - event.ivalue = *(buf++) ? 1 : 0; - event.okay = *(buf++) ? 1 : 0; - break; - - case SHIMEVENT_SETSTATI: - case SHIMEVENT_GETSTATI: - event.okay = *(buf++) ? 1 : 0; - event.ivalue = (int) *((int32 *) buf); - buf += sizeof (int32); - strcpy(event.name, (const char *) buf); - break; - - case SHIMEVENT_SETSTATF: - case SHIMEVENT_GETSTATF: - event.okay = *(buf++) ? 1 : 0; - event.fvalue = (int) *((float *) buf); - buf += sizeof (float); - strcpy(event.name, (const char *) buf); - break; - - case SHIMEVENT_GETPERSONANAME: - case SHIMEVENT_GETCURRENTGAMELANGUAGE: - strcpy(event.name, (const char *) buf); - break; - - default: /* uh oh */ - return NULL; - } /* switch */ - - return &event; -} /* processEvent */ - -const STEAMSHIM_Event *STEAMSHIM_pump(void) -{ - static uint8 buf[256]; - static int br = 0; - int evlen = (br > 0) ? ((int) buf[0]) : 0; - - if (isDead()) - return NULL; - - if (br <= evlen) /* we have an incomplete commmand. Try to read more. */ - { - if (pipeReady(GPipeRead)) - { - const int morebr = readPipe(GPipeRead, buf + br, sizeof (buf) - br); - if (morebr > 0) - br += morebr; - else /* uh oh */ - { - dbgpipe("Child readPipe failed! Shutting down.\n"); - STEAMSHIM_deinit(); /* kill it all. */ - } /* else */ - } /* if */ - } /* if */ - - if (evlen && (br > evlen)) - { - const STEAMSHIM_Event *retval = processEvent(buf+1, evlen); - br -= evlen + 1; - if (br > 0) - memmove(buf, buf+evlen+1, br); - return retval; - } /* if */ - - /* Run Steam event loop. */ - if (br == 0) - { - dbgpipe("Child sending SHIMCMD_PUMP().\n"); - write1ByteCmd(SHIMCMD_PUMP); - } /* if */ - - return NULL; -} /* STEAMSHIM_pump */ - -void STEAMSHIM_requestStats(void) -{ - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_REQUESTSTATS().\n"); - write1ByteCmd(SHIMCMD_REQUESTSTATS); -} /* STEAMSHIM_requestStats */ - -void STEAMSHIM_storeStats(void) -{ - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_STORESTATS().\n"); - write1ByteCmd(SHIMCMD_STORESTATS); -} /* STEAMSHIM_storeStats */ - -void STEAMSHIM_setAchievement(const char *name, const int enable) -{ - uint8 buf[256]; - uint8 *ptr = buf+1; - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_SETACHIEVEMENT('%s', %senable).\n", name, enable ? "" : "!"); - *(ptr++) = (uint8) SHIMCMD_SETACHIEVEMENT; - *(ptr++) = enable ? 1 : 0; - strcpy((char *) ptr, name); - ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - writePipe(GPipeWrite, buf, buf[0] + 1); -} /* STEAMSHIM_setAchievement */ - -void STEAMSHIM_getAchievement(const char *name) -{ - uint8 buf[256]; - uint8 *ptr = buf+1; - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_GETACHIEVEMENT('%s').\n", name); - *(ptr++) = (uint8) SHIMCMD_GETACHIEVEMENT; - strcpy((char *) ptr, name); - ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - writePipe(GPipeWrite, buf, buf[0] + 1); -} /* STEAMSHIM_getAchievement */ - -void STEAMSHIM_resetStats(const int bAlsoAchievements) -{ - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_RESETSTATS(%salsoAchievements).\n", bAlsoAchievements ? "" : "!"); - write2ByteCmd(SHIMCMD_RESETSTATS, bAlsoAchievements ? 1 : 0); -} /* STEAMSHIM_resetStats */ - -static void writeStatThing(const ShimCmd cmd, const char *name, const void *val, const size_t vallen) -{ - uint8 buf[256]; - uint8 *ptr = buf+1; - if (isDead()) return; - *(ptr++) = (uint8) cmd; - if (vallen) - { - memcpy(ptr, val, vallen); - ptr += vallen; - } /* if */ - strcpy((char *) ptr, name); - ptr += strlen(name) + 1; - buf[0] = (uint8) ((ptr-1) - buf); - writePipe(GPipeWrite, buf, buf[0] + 1); -} /* writeStatThing */ - -void STEAMSHIM_setStatI(const char *name, const int _val) -{ - const int32 val = (int32) _val; - dbgpipe("Child sending SHIMCMD_SETSTATI('%s', val %d).\n", name, val); - writeStatThing(SHIMCMD_SETSTATI, name, &val, sizeof (val)); -} /* STEAMSHIM_setStatI */ - -void STEAMSHIM_getStatI(const char *name) -{ - dbgpipe("Child sending SHIMCMD_GETSTATI('%s').\n", name); - writeStatThing(SHIMCMD_GETSTATI, name, NULL, 0); -} /* STEAMSHIM_getStatI */ - -void STEAMSHIM_setStatF(const char *name, const float val) -{ - dbgpipe("Child sending SHIMCMD_SETSTATF('%s', val %f).\n", name, val); - writeStatThing(SHIMCMD_SETSTATF, name, &val, sizeof (val)); -} /* STEAMSHIM_setStatF */ - -void STEAMSHIM_getStatF(const char *name) -{ - dbgpipe("Child sending SHIMCMD_GETSTATF('%s').\n", name); - writeStatThing(SHIMCMD_GETSTATF, name, NULL, 0); -} /* STEAMSHIM_getStatF */ - -void STEAMSHIM_getPersonaName() -{ - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_GETPERSONANAME().\n"); - write1ByteCmd(SHIMCMD_GETPERSONANAME); -} /* STEAMSHIM_getPersonaName */ - -void STEAMSHIM_getCurrentGameLanguage() -{ - if (isDead()) return; - dbgpipe("Child sending SHIMCMD_GETCURRENTGAMELANGUAGE().\n"); - write1ByteCmd(SHIMCMD_GETCURRENTGAMELANGUAGE); -} /* STEAMSHIM_getCurrentGameLanguage */ - -/* end of steamshim_child.c ... */ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +typedef HANDLE PipeType; +#define NULLPIPE NULL +typedef unsigned __int8 uint8; +typedef __int32 int32; +typedef unsigned __int64 uint64; +#else +#include +#include +#include +#include +#include +#include +#include +typedef uint8_t uint8; +typedef int32_t int32; +typedef uint64_t uint64; +typedef int PipeType; +#define NULLPIPE -1 +#endif +#include + +#include "steamshim_child.h" + +#ifdef STEAMSHIM_DEBUG +#define dbgpipe printf +#else +static inline void dbgpipe(const char *fmt, ...) { + (void)fmt; +} +#endif + +static int writePipe(PipeType fd, const void *buf, const unsigned int _len); +static int readPipe(PipeType fd, void *buf, const unsigned int _len); +static void closePipe(PipeType fd); +static char *getEnvVar(const char *key, char *buf, const size_t buflen); +static int pipeReady(PipeType fd); + + +#ifdef _WIN32 + +static int pipeReady(PipeType fd) +{ + DWORD avail = 0; + return (PeekNamedPipe(fd, NULL, 0, NULL, &avail, NULL) && (avail > 0)); +} /* pipeReady */ + +static int writePipe(PipeType fd, const void *buf, const unsigned int _len) { + const DWORD len = (DWORD)_len; + DWORD bw = 0; + return ((WriteFile(fd, buf, len, &bw, NULL) != 0) && (bw == len)); +} // writePipe + +static int readPipe(PipeType fd, void *buf, const unsigned int _len) { + const DWORD len = (DWORD)_len; + DWORD br = 0; + return ReadFile(fd, buf, len, &br, NULL) ? (int)br : -1; +} // readPipe + +static void closePipe(PipeType fd) +{ + CloseHandle(fd); +} /* closePipe */ + +static char *getEnvVar(const char *key, char *buf, const size_t buflen) +{ + const DWORD rc = GetEnvironmentVariableA(key, buf, buflen); + /* rc doesn't count null char, hence "<". */ + return ((rc > 0) && (rc < buflen)) ? buf : NULL; +} /* getEnvVar */ + +#else + +static int pipeReady(PipeType fd) +{ + int rc; + struct pollfd pfd = { fd, POLLIN | POLLERR | POLLHUP, 0 }; + while (((rc = poll(&pfd, 1, 0)) == -1) && (errno == EINTR)) { /*spin*/ } + return (rc == 1); +} /* pipeReady */ + +static int writePipe(PipeType fd, const void *buf, const unsigned int _len) +{ + const ssize_t len = (ssize_t) _len; + ssize_t bw; + while (((bw = write(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ } + return (bw == len); +} /* writePipe */ + +static int readPipe(PipeType fd, void *buf, const unsigned int _len) +{ + const ssize_t len = (ssize_t) _len; + ssize_t br; + while (((br = read(fd, buf, len)) == -1) && (errno == EINTR)) { /*spin*/ } + return (int) br; +} /* readPipe */ + +static void closePipe(PipeType fd) +{ + close(fd); +} /* closePipe */ + +static char *getEnvVar(const char *key, char *buf, const size_t buflen) +{ + const char *envr = getenv(key); + if (!envr || (strlen(envr) >= buflen)) + return NULL; + strcpy(buf, envr); + return buf; +} /* getEnvVar */ + +#endif + + +static PipeType GPipeRead = NULLPIPE; +static PipeType GPipeWrite = NULLPIPE; + +typedef enum ShimCmd +{ + SHIMCMD_BYE, + SHIMCMD_PUMP, + SHIMCMD_REQUESTSTATS, + SHIMCMD_STORESTATS, + SHIMCMD_SETACHIEVEMENT, + SHIMCMD_GETACHIEVEMENT, + SHIMCMD_RESETSTATS, + SHIMCMD_SETSTATI, + SHIMCMD_GETSTATI, + SHIMCMD_SETSTATF, + SHIMCMD_GETSTATF, + SHIMCMD_GETPERSONANAME, + SHIMCMD_GETCURRENTGAMELANGUAGE, +} ShimCmd; + +static int write1ByteCmd(const uint8 b1) +{ + const uint8 buf[] = { 1, b1 }; + return writePipe(GPipeWrite, buf, sizeof (buf)); +} /* write1ByteCmd */ + +static int write2ByteCmd(const uint8 b1, const uint8 b2) +{ + const uint8 buf[] = { 2, b1, b2 }; + return writePipe(GPipeWrite, buf, sizeof (buf)); +} /* write2ByteCmd */ + +static inline int writeBye(void) +{ + dbgpipe("Child sending SHIMCMD_BYE().\n"); + return write1ByteCmd(SHIMCMD_BYE); +} // writeBye + +static int initPipes(void) +{ + char buf[64]; + + if (!getEnvVar("STEAMSHIM_READHANDLE", buf, sizeof (buf))) + return 0; + GPipeRead = (PipeType) strtoull(buf, 0, 10); + + if (!getEnvVar("STEAMSHIM_WRITEHANDLE", buf, sizeof (buf))) + return 0; + GPipeWrite = (PipeType) strtoull(buf, 0, 10); + + return ((GPipeRead != NULLPIPE) && (GPipeWrite != NULLPIPE)); +} /* initPipes */ + + +int STEAMSHIM_init(void) +{ + dbgpipe("Child init start.\n"); + if (!initPipes()) + { + dbgpipe("Child init failed.\n"); + return 0; + } /* if */ + +#ifndef _WIN32 + signal(SIGPIPE, SIG_IGN); +#endif + + dbgpipe("Child init success!\n"); + return 1; +} /* STEAMSHIM_init */ + +void STEAMSHIM_deinit(void) +{ + dbgpipe("Child deinit.\n"); + if (GPipeWrite != NULLPIPE) + { + writeBye(); + closePipe(GPipeWrite); + } /* if */ + + if (GPipeRead != NULLPIPE) + closePipe(GPipeRead); + + GPipeRead = GPipeWrite = NULLPIPE; + +#ifndef _WIN32 + signal(SIGPIPE, SIG_DFL); +#endif +} /* STEAMSHIM_deinit */ + +static inline int isAlive(void) +{ + return ((GPipeRead != NULLPIPE) && (GPipeWrite != NULLPIPE)); +} /* isAlive */ + +static inline int isDead(void) +{ + return !isAlive(); +} /* isDead */ + +int STEAMSHIM_alive(void) +{ + return isAlive(); +} /* STEAMSHIM_alive */ + +static const STEAMSHIM_Event *processEvent(const uint8 *buf, size_t buflen) +{ + static STEAMSHIM_Event event; + const STEAMSHIM_EventType type = (STEAMSHIM_EventType) *(buf++); + buflen--; + + memset(&event, '\0', sizeof (event)); + event.type = type; + event.okay = 1; + + #ifdef STEAMSHIM_DEBUG + if (0) {} + #define PRINTGOTEVENT(x) else if (type == x) printf("Child got " #x ".\n") + PRINTGOTEVENT(SHIMEVENT_BYE); + PRINTGOTEVENT(SHIMEVENT_STATSRECEIVED); + PRINTGOTEVENT(SHIMEVENT_STATSSTORED); + PRINTGOTEVENT(SHIMEVENT_SETACHIEVEMENT); + PRINTGOTEVENT(SHIMEVENT_GETACHIEVEMENT); + PRINTGOTEVENT(SHIMEVENT_RESETSTATS); + PRINTGOTEVENT(SHIMEVENT_SETSTATI); + PRINTGOTEVENT(SHIMEVENT_GETSTATI); + PRINTGOTEVENT(SHIMEVENT_SETSTATF); + PRINTGOTEVENT(SHIMEVENT_GETSTATF); + PRINTGOTEVENT(SHIMEVENT_GETPERSONANAME); + PRINTGOTEVENT(SHIMEVENT_GETCURRENTGAMELANGUAGE); + #undef PRINTGOTEVENT + else printf("Child got unknown shimevent %d.\n", (int) type); + #endif + + switch (type) + { + case SHIMEVENT_BYE: + break; + + case SHIMEVENT_STATSRECEIVED: + case SHIMEVENT_STATSSTORED: + if (!buflen) return NULL; + event.okay = *(buf++) ? 1 : 0; + break; + + case SHIMEVENT_SETACHIEVEMENT: + if (buflen < 3) return NULL; + event.ivalue = *(buf++) ? 1 : 0; + event.okay = *(buf++) ? 1 : 0; + strcpy(event.name, (const char *) buf); + break; + + case SHIMEVENT_GETACHIEVEMENT: + if (buflen < 10) return NULL; + event.ivalue = (int) *(buf++); + if (event.ivalue == 2) + event.ivalue = event.okay = 0; + event.epochsecs = (long long unsigned) *((uint64 *) buf); + buf += sizeof (uint64); + strcpy(event.name, (const char *) buf); + break; + + case SHIMEVENT_RESETSTATS: + if (buflen != 2) return NULL; + event.ivalue = *(buf++) ? 1 : 0; + event.okay = *(buf++) ? 1 : 0; + break; + + case SHIMEVENT_SETSTATI: + case SHIMEVENT_GETSTATI: + event.okay = *(buf++) ? 1 : 0; + event.ivalue = (int) *((int32 *) buf); + buf += sizeof (int32); + strcpy(event.name, (const char *) buf); + break; + + case SHIMEVENT_SETSTATF: + case SHIMEVENT_GETSTATF: + event.okay = *(buf++) ? 1 : 0; + event.fvalue = (int) *((float *) buf); + buf += sizeof (float); + strcpy(event.name, (const char *) buf); + break; + + case SHIMEVENT_GETPERSONANAME: + case SHIMEVENT_GETCURRENTGAMELANGUAGE: + strcpy(event.name, (const char *) buf); + break; + + default: /* uh oh */ + return NULL; + } /* switch */ + + return &event; +} /* processEvent */ + +const STEAMSHIM_Event *STEAMSHIM_pump(void) +{ + static uint8 buf[256]; + static int br = 0; + int evlen = (br > 0) ? ((int) buf[0]) : 0; + + if (isDead()) + return NULL; + + if (br <= evlen) /* we have an incomplete commmand. Try to read more. */ + { + if (pipeReady(GPipeRead)) + { + const int morebr = readPipe(GPipeRead, buf + br, sizeof (buf) - br); + if (morebr > 0) + br += morebr; + else /* uh oh */ + { + dbgpipe("Child readPipe failed! Shutting down.\n"); + STEAMSHIM_deinit(); /* kill it all. */ + } /* else */ + } /* if */ + } /* if */ + + if (evlen && (br > evlen)) + { + const STEAMSHIM_Event *retval = processEvent(buf+1, evlen); + br -= evlen + 1; + if (br > 0) + memmove(buf, buf+evlen+1, br); + return retval; + } /* if */ + + return NULL; +} /* STEAMSHIM_pump */ + +void STEAMSHIM_requestStats(void) +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_REQUESTSTATS().\n"); + write1ByteCmd(SHIMCMD_REQUESTSTATS); +} /* STEAMSHIM_requestStats */ + +void STEAMSHIM_storeStats(void) +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_STORESTATS().\n"); + write1ByteCmd(SHIMCMD_STORESTATS); +} /* STEAMSHIM_storeStats */ + +void STEAMSHIM_setAchievement(const char *name, const int enable) +{ + uint8 buf[256]; + uint8 *ptr = buf+1; + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_SETACHIEVEMENT('%s', %senable).\n", name, enable ? "" : "!"); + *(ptr++) = (uint8) SHIMCMD_SETACHIEVEMENT; + *(ptr++) = enable ? 1 : 0; + strcpy((char *) ptr, name); + ptr += strlen(name) + 1; + buf[0] = (uint8) ((ptr-1) - buf); + writePipe(GPipeWrite, buf, buf[0] + 1); +} /* STEAMSHIM_setAchievement */ + +void STEAMSHIM_getAchievement(const char *name) +{ + uint8 buf[256]; + uint8 *ptr = buf+1; + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_GETACHIEVEMENT('%s').\n", name); + *(ptr++) = (uint8) SHIMCMD_GETACHIEVEMENT; + strcpy((char *) ptr, name); + ptr += strlen(name) + 1; + buf[0] = (uint8) ((ptr-1) - buf); + writePipe(GPipeWrite, buf, buf[0] + 1); +} /* STEAMSHIM_getAchievement */ + +void STEAMSHIM_resetStats(const int bAlsoAchievements) +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_RESETSTATS(%salsoAchievements).\n", bAlsoAchievements ? "" : "!"); + write2ByteCmd(SHIMCMD_RESETSTATS, bAlsoAchievements ? 1 : 0); +} /* STEAMSHIM_resetStats */ + +static void writeStatThing(const ShimCmd cmd, const char *name, const void *val, const size_t vallen) +{ + uint8 buf[256]; + uint8 *ptr = buf+1; + if (isDead()) return; + *(ptr++) = (uint8) cmd; + if (vallen) + { + memcpy(ptr, val, vallen); + ptr += vallen; + } /* if */ + strcpy((char *) ptr, name); + ptr += strlen(name) + 1; + buf[0] = (uint8) ((ptr-1) - buf); + writePipe(GPipeWrite, buf, buf[0] + 1); +} /* writeStatThing */ + +void STEAMSHIM_setStatI(const char *name, const int _val) +{ + const int32 val = (int32) _val; + dbgpipe("Child sending SHIMCMD_SETSTATI('%s', val %d).\n", name, val); + writeStatThing(SHIMCMD_SETSTATI, name, &val, sizeof (val)); +} /* STEAMSHIM_setStatI */ + +void STEAMSHIM_getStatI(const char *name) +{ + dbgpipe("Child sending SHIMCMD_GETSTATI('%s').\n", name); + writeStatThing(SHIMCMD_GETSTATI, name, NULL, 0); +} /* STEAMSHIM_getStatI */ + +void STEAMSHIM_setStatF(const char *name, const float val) +{ + dbgpipe("Child sending SHIMCMD_SETSTATF('%s', val %f).\n", name, val); + writeStatThing(SHIMCMD_SETSTATF, name, &val, sizeof (val)); +} /* STEAMSHIM_setStatF */ + +void STEAMSHIM_getStatF(const char *name) +{ + dbgpipe("Child sending SHIMCMD_GETSTATF('%s').\n", name); + writeStatThing(SHIMCMD_GETSTATF, name, NULL, 0); +} /* STEAMSHIM_getStatF */ + +void STEAMSHIM_getPersonaName() +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_GETPERSONANAME().\n"); + write1ByteCmd(SHIMCMD_GETPERSONANAME); +} /* STEAMSHIM_getPersonaName */ + +void STEAMSHIM_getCurrentGameLanguage() +{ + if (isDead()) return; + dbgpipe("Child sending SHIMCMD_GETCURRENTGAMELANGUAGE().\n"); + write1ByteCmd(SHIMCMD_GETCURRENTGAMELANGUAGE); +} /* STEAMSHIM_getCurrentGameLanguage */ + +/* end of steamshim_child.c ... */