summaryrefslogtreecommitdiff
path: root/protocols/Steam/src
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Steam/src')
-rw-r--r--protocols/Steam/src/protobuf-c/protobuf-c-text.c501
-rw-r--r--protocols/Steam/src/protobuf-c/protobuf-c-text.h213
-rw-r--r--protocols/Steam/src/stdafx.h5
-rw-r--r--protocols/Steam/src/steam_ws.cpp2
4 files changed, 720 insertions, 1 deletions
diff --git a/protocols/Steam/src/protobuf-c/protobuf-c-text.c b/protocols/Steam/src/protobuf-c/protobuf-c-text.c
new file mode 100644
index 0000000000..6cbc9b46e7
--- /dev/null
+++ b/protocols/Steam/src/protobuf-c/protobuf-c-text.c
@@ -0,0 +1,501 @@
+/** \file
+ * Routines to generate text format protobufs.
+ *
+ * This file contains the internal support functions as well as the
+ * exported functions which are used to generate text format protobufs
+ * from C protobuf data types.
+ *
+ * \author Kevin Lyda <kevin@ie.suberic.net>
+ * \date March 2014
+ */
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "protobuf-c.h"
+#include "protobuf-c-text.h"
+#include "protobuf-c-util.h"
+
+/** A dynamic string struct.
+ *
+ * Used to track additions to a growing string and memory allocation
+ * errors that occur in processing
+ */
+typedef struct _ReturnString {
+ int malloc_err; /**< Set to 1 when there's been a malloc error. */
+ int allocated; /**< Size of allocated string. */
+ int pos; /**< Current end of the string. */
+ char *s; /**< The string. */
+} ReturnString;
+
+/** Append a string to the ReturnString.
+ *
+ * Append the string built from \c format and its args to the \c rs
+ * string. Note that \c malloc_err is checked and if it's true,
+ * this function won't do anything.
+ *
+ * \param[in,out] rs The string to append to.
+ * \param[in] guess A guess at the number of chars being added.
+ * \param[in] allocator allocator functions.
+ * \param[in] format Printf-style format string.
+ * \param[in] ... Variable number of args for \c format.
+ */
+
+static void
+rs_append(ReturnString *rs, int guess,
+ ProtobufCAllocator *allocator,
+ const char *format, ...)
+{
+ va_list args;
+ int added;
+
+ if (rs->malloc_err) {
+ return;
+ }
+
+ if (rs->allocated - rs->pos < guess * 2) {
+ char *tmp;
+
+ tmp = PBC_ALLOC(rs->allocated + guess * 2);
+ if (!tmp) {
+ PBC_FREE(rs->s);
+ rs->s = NULL;
+ rs->malloc_err = 1;
+ return;
+ }
+ memcpy(tmp, rs->s, rs->allocated);
+ PBC_FREE(rs->s);
+ rs->s = tmp;
+ rs->allocated += guess * 2;
+ }
+ va_start(args, format);
+ added = vsnprintf(rs->s + rs->pos, rs->allocated - rs->pos, format, args);
+ va_end(args);
+ rs->pos += added;
+ return;
+}
+
+/** @} */ /* End of utility group. */
+
+
+/** \defgroup generate Functions to generate text format proto bufs
+ * \ingroup internal
+ * @{
+ */
+
+/** Escape string.
+ *
+ * Add escape characters to strings for problematic characters.
+ *
+ * \param[in] src The unescaped string to process.
+ * \param[in] len Length of \c src. Note that \c src might have ASCII
+ * \c NULs so strlen() isn't good enough here.
+ * \param[in] allocator allocator functions.
+ * \return The fully escaped string, or \c NULL if there has been an
+ * allocation error.
+ */
+static char *
+esc_str(char *src, int len, ProtobufCAllocator *allocator)
+{
+ int i, escapes = 0, dst_len = 0;
+ unsigned char *dst;
+
+ for (i = 0; i < len; i++) {
+ if (!isprint(src[i])) {
+ escapes++;
+ }
+ }
+ dst = PBC_ALLOC((escapes * 4) + ((len - escapes) * 2) + 1);
+ if (!dst) {
+ return NULL;
+ }
+
+ for (i = 0; i < len; i++) {
+ switch (src[i]) {
+ /* Special cases. */
+ case '\'':
+ dst[dst_len++] = '\\';
+ dst[dst_len++] = '\'';
+ break;
+ case '\"':
+ dst[dst_len++] = '\\';
+ dst[dst_len++] = '\"';
+ break;
+ case '\\':
+ dst[dst_len++] = '\\';
+ dst[dst_len++] = '\\';
+ break;
+ case '\n':
+ dst[dst_len++] = '\\';
+ dst[dst_len++] = 'n';
+ break;
+ case '\r':
+ dst[dst_len++] = '\\';
+ dst[dst_len++] = 'r';
+ break;
+ case '\t':
+ dst[dst_len++] = '\\';
+ dst[dst_len++] = 't';
+ break;
+
+ /* Escape with octal if !isprint. */
+ default:
+ if (!isprint(src[i])) {
+ dst_len += sprintf(dst + dst_len, "\\%03o", src[i]);
+ } else {
+ dst[dst_len++] = src[i];
+ }
+ break;
+ }
+ }
+ dst[dst_len] = '\0';
+
+ return dst;
+}
+
+/** Internal function to back API function.
+ *
+ * Has a few extra params to better enable recursion. This function gets
+ * called for each nested message as the \c ProtobufCMessage struct is
+ * traversed.
+ *
+ * \param[in,out] rs The string being built up for the text format protobuf.
+ * \param[in] level Indent level - increments in 2's.
+ * \param[in] m The \c ProtobufCMessage being serialised.
+ * \param[in] d The descriptor for the \c ProtobufCMessage.
+ * \param[in] allocator allocator functions.
+ */
+static void
+protobuf_c_text_to_string_internal(ReturnString *rs,
+ int level,
+ ProtobufCMessage *m,
+ const ProtobufCMessageDescriptor *d,
+ ProtobufCAllocator *allocator)
+{
+ int i;
+ size_t j, quantifier_offset;
+ double float_var;
+ const ProtobufCFieldDescriptor *f;
+ ProtobufCEnumDescriptor *enumd;
+ const ProtobufCEnumValue *enumv;
+
+ f = d->fields;
+ for (i = 0; i < d->n_fields; i++) {
+ if (rs->malloc_err) {
+ /* If there's been a malloc error, go die. */
+ return;
+ }
+
+ /* Decide if something needs to be done for this field. */
+ switch (f[i].label) {
+ case PROTOBUF_C_LABEL_OPTIONAL:
+ if (f[i].type == PROTOBUF_C_TYPE_STRING) {
+ if (!STRUCT_MEMBER(char *, m, f[i].offset)
+ || (STRUCT_MEMBER(char *, m, f[i].offset)
+ == (char *)f[i].default_value)) {
+ continue;
+ }
+ } else if (f[i].type == PROTOBUF_C_TYPE_MESSAGE) {
+ if (!STRUCT_MEMBER(char *, m, f[i].offset)) {
+ continue;
+ }
+ } else {
+ if (!STRUCT_MEMBER(protobuf_c_boolean, m, f[i].quantifier_offset)) {
+ continue;
+ }
+ }
+ break;
+ case PROTOBUF_C_LABEL_REPEATED:
+ if (!STRUCT_MEMBER(size_t, m, f[i].quantifier_offset)) {
+ continue;
+ }
+ break;
+ }
+
+ quantifier_offset = STRUCT_MEMBER(size_t, m, f[i].quantifier_offset);
+ /* Field exists and has data, dump it. */
+ switch (f[i].type) {
+ case PROTOBUF_C_TYPE_INT32:
+ case PROTOBUF_C_TYPE_UINT32:
+ case PROTOBUF_C_TYPE_FIXED32:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %u\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(uint32_t *, m, f[i].offset)[j]);
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %u\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(uint32_t, m, f[i].offset));
+ }
+ break;
+ case PROTOBUF_C_TYPE_SINT32:
+ case PROTOBUF_C_TYPE_SFIXED32:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %d\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(int32_t *, m, f[i].offset)[j]);
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %d\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(int32_t, m, f[i].offset));
+ }
+ break;
+ case PROTOBUF_C_TYPE_INT64:
+ case PROTOBUF_C_TYPE_UINT64:
+ case PROTOBUF_C_TYPE_FIXED64:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %lu\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(uint64_t *, m, f[i].offset)[j]);
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %lu\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(uint64_t, m, f[i].offset));
+ }
+ break;
+ case PROTOBUF_C_TYPE_SINT64:
+ case PROTOBUF_C_TYPE_SFIXED64:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %ld\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(int64_t *, m, f[i].offset)[j]);
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %ld\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(int64_t, m, f[i].offset));
+ }
+ break;
+ case PROTOBUF_C_TYPE_FLOAT:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ float_var = STRUCT_MEMBER(float *, m, f[i].offset)[j];
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %g\n",
+ level, "", f[i].name,
+ float_var);
+ }
+ } else {
+ float_var = STRUCT_MEMBER(float, m, f[i].offset);
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %g\n",
+ level, "", f[i].name,
+ float_var);
+ }
+ break;
+ case PROTOBUF_C_TYPE_DOUBLE:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %g\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(double *, m, f[i].offset)[j]);
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %g\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(double, m, f[i].offset));
+ }
+ break;
+ case PROTOBUF_C_TYPE_BOOL:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %s\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(protobuf_c_boolean *, m, f[i].offset)[j]?
+ "true": "false");
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %s\n",
+ level, "", f[i].name,
+ STRUCT_MEMBER(protobuf_c_boolean, m, f[i].offset)?
+ "true": "false");
+ }
+ break;
+ case PROTOBUF_C_TYPE_ENUM:
+ enumd = (ProtobufCEnumDescriptor *)f[i].descriptor;
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ enumv = protobuf_c_enum_descriptor_get_value(
+ enumd, STRUCT_MEMBER(int *, m, f[i].offset)[j]);
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %s\n",
+ level, "", f[i].name,
+ enumv? enumv->name: "unknown");
+ }
+ } else {
+ enumv = protobuf_c_enum_descriptor_get_value(
+ enumd, STRUCT_MEMBER(int, m, f[i].offset));
+ rs_append(rs, level + strlen(f[i].name) + 20,
+ allocator,
+ "%*s%s: %s\n",
+ level, "", f[i].name,
+ enumv? enumv->name: "unknown");
+ }
+ break;
+ case PROTOBUF_C_TYPE_STRING:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ unsigned char *escaped;
+
+ escaped = esc_str(
+ STRUCT_MEMBER(unsigned char **, m, f[i].offset)[j],
+ strlen(STRUCT_MEMBER(unsigned char **, m, f[i].offset)[j]),
+ allocator);
+ if (!escaped) {
+ PBC_FREE(rs->s);
+ rs->s = NULL;
+ rs->malloc_err = 1;
+ return;
+ }
+ rs_append(rs, level + strlen(f[i].name) + strlen(escaped) + 10,
+ allocator,
+ "%*s%s: \"%s\"\n", level, "", f[i].name, escaped);
+ PBC_FREE(escaped);
+ }
+ } else {
+ unsigned char *escaped;
+
+ escaped = esc_str(STRUCT_MEMBER(unsigned char *, m, f[i].offset),
+ strlen(STRUCT_MEMBER(unsigned char *, m, f[i].offset)),
+ allocator);
+ if (!escaped) {
+ PBC_FREE(rs->s);
+ rs->s = NULL;
+ rs->malloc_err = 1;
+ return;
+ }
+ rs_append(rs, level + strlen(f[i].name) + strlen(escaped) + 10,
+ allocator,
+ "%*s%s: \"%s\"\n", level, "", f[i].name, escaped);
+ PBC_FREE(escaped);
+ }
+ break;
+ case PROTOBUF_C_TYPE_BYTES:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0; j < quantifier_offset; j++) {
+ unsigned char *escaped;
+
+ escaped = esc_str(
+ STRUCT_MEMBER(ProtobufCBinaryData *, m, f[i].offset)[j].data,
+ STRUCT_MEMBER(ProtobufCBinaryData *, m, f[i].offset)[j].len,
+ allocator);
+ if (!escaped) {
+ PBC_FREE(rs->s);
+ rs->s = NULL;
+ rs->malloc_err = 1;
+ return;
+ }
+ rs_append(rs, level + strlen(f[i].name) + strlen(escaped) + 10,
+ allocator,
+ "%*s%s: \"%s\"\n", level, "", f[i].name, escaped);
+ PBC_FREE(escaped);
+ }
+ } else {
+ unsigned char *escaped;
+
+ escaped = esc_str(
+ STRUCT_MEMBER(ProtobufCBinaryData, m, f[i].offset).data,
+ STRUCT_MEMBER(ProtobufCBinaryData, m, f[i].offset).len,
+ allocator);
+ if (!escaped) {
+ PBC_FREE(rs->s);
+ rs->s = NULL;
+ rs->malloc_err = 1;
+ return;
+ }
+ rs_append(rs, level + strlen(f[i].name) + strlen(escaped) + 10,
+ allocator,
+ "%*s%s: \"%s\"\n", level, "", f[i].name, escaped);
+ PBC_FREE(escaped);
+ }
+ break;
+
+ case PROTOBUF_C_TYPE_MESSAGE:
+ if (f[i].label == PROTOBUF_C_LABEL_REPEATED) {
+ for (j = 0;
+ j < STRUCT_MEMBER(size_t, m, f[i].quantifier_offset);
+ j++) {
+ rs_append(rs, level + strlen(f[i].name) + 10,
+ allocator,
+ "%*s%s {\n", level, "", f[i].name);
+ protobuf_c_text_to_string_internal(rs, level + 2,
+ STRUCT_MEMBER(ProtobufCMessage **, m, f[i].offset)[j],
+ (ProtobufCMessageDescriptor *)f[i].descriptor,
+ allocator);
+ rs_append(rs, level + 10,
+ allocator,
+ "%*s}\n", level, "");
+ }
+ } else {
+ rs_append(rs, level + strlen(f[i].name) + 10,
+ allocator,
+ "%*s%s {\n", level, "", f[i].name);
+ protobuf_c_text_to_string_internal(rs, level + 2,
+ STRUCT_MEMBER(ProtobufCMessage *, m, f[i].offset),
+ (ProtobufCMessageDescriptor *)f[i].descriptor,
+ allocator);
+ rs_append(rs, level + 10,
+ allocator,
+ "%*s}\n", level, "");
+ }
+ break;
+ default:
+ PBC_FREE(rs->s);
+ rs->s = NULL;
+ return;
+ break;
+ }
+
+ }
+}
+
+/** @} */ /* End of generate group. */
+
+/* See .h file for API docs. */
+
+char *
+protobuf_c_text_to_string(ProtobufCMessage *m,
+ ProtobufCAllocator *allocator)
+{
+ ReturnString rs = { 0, 0, 0, NULL };
+
+ protobuf_c_text_to_string_internal(&rs, 0, m, m->descriptor, allocator);
+
+ return rs.s;
+}
diff --git a/protocols/Steam/src/protobuf-c/protobuf-c-text.h b/protocols/Steam/src/protobuf-c/protobuf-c-text.h
new file mode 100644
index 0000000000..bb3539737d
--- /dev/null
+++ b/protocols/Steam/src/protobuf-c/protobuf-c-text.h
@@ -0,0 +1,213 @@
+#ifndef PROTOBUF_C_TEXT_H
+#define PROTOBUF_C_TEXT_H
+
+/*
+ * \file
+ * Library header file.
+ * This is the header file for the text format protobuf routines.
+ * It contains declarations of all functions and data types exported by
+ * the library.
+ *
+ * \author Kevin Lyda <kevin@ie.suberic.net>
+ * \date March 2014
+ *
+ */
+
+/** \mainpage
+ *
+ * \section description Description
+ *
+ * Google protobufs are an efficient way to serialise and deserialise
+ * data to send across the wire or to store on disk. The Google compiler
+ * and related libraries provide implementations for C++, Java and Python.
+ * A very simple message definition language is used to generate parsers
+ * and generators for this binary format.
+ *
+ * The Protobuf compiler and library for C provide access to this
+ * technology from within C code.
+ *
+ * Besides the efficient binary protobuf format there is also a text mode
+ * format which is accessible to code generated by the Google protobuf
+ * compiler. While the text format has limitations - namely that it lacks
+ * some of the back/forwards-compatibility features of the binary format -
+ * it can be a useful debugging tool and a strict but human readable config
+ * file format.
+ *
+ * The C protobuf implementation is very minimal and lacks this feature.
+ * This library supplements \c libprotobuf-c and provides functions to
+ * generate and consume text format protobuf. They will work fine with
+ * any \c ProtobufCMessage subtype generated by the \c protoc-c
+ * compiler.
+ *
+ * \sa
+ * - Google Protobufs: https://code.google.com/p/protobuf/
+ * - Protobuf docs:
+ * https://developers.google.com/protocol-buffers/docs/overview
+ * - Notes on protobuf compatibility:
+ * https://developers.google.com/protocol-buffers/docs/proto#updating
+ * - Protobuf for C code: https://github.com/protobuf-c/protobuf-c
+ * - Protobuf for C docs:
+ * https://github.com/protobuf-c/protobuf-c/wiki
+ * - Protobuf for C RPC library code:
+ * https://github.com/protobuf-c/protobuf-c-rpc
+ * - Protobuf for C text format code:
+ * https://github.com/protobuf-c/protobuf-c-text
+ * - Protobuf for C text format
+ * <a href=coverage/index.html>test coverage</a>
+ *
+ * \section example Examples
+ *
+ * Both examples use this \c .proto definition:
+ * \verbatim
+message Ponycopter {
+ optional string hair_colour = 1;
+ optional uint32 rotors = 2;
+ optional uint32 awesomeness = 3;
+}
+\endverbatim
+ *
+ * \b Generating
+ *
+ * \verbatim
+#include <protobuf-c/protobuf-c.h>
+#include "ponycopter.pb-c.h"
+
+int main(int argc, char *argv[]) {
+ int len;
+ char *pc_bin, *pc_text;
+ Ponycopter *pc;
+
+ pc_bin = read_a_blob(argv[1], &len);
+ pc = ponycopter__unpack(NULL, len, pc_bin);
+ pc_text = protobuf_c_text_to_string((ProtobufCMessage *)pc, NULL);
+ printf("Ponycopter: %s\n", pc_text);
+}
+\endverbatim
+ *
+ * \b Parsing
+ *
+ * \verbatim
+#include <protobuf-c/protobuf-c.h>
+#include "ponycopter.pb-c.h"
+
+int main(int argc, char *argv[]) {
+ ProtobufCTextError tf_res;
+ Ponycopter *pc;
+
+ pc = (Ponycopter *)protobuf_c_text_from_file(
+ &ponycopter__descriptor, argv[1], &tf_res, NULL);
+}
+\endverbatim
+ */
+
+#include <stdio.h> /* for the FILE * data type. */
+#include "protobuf-c.h"
+
+/** \defgroup api Public API for text format protobufs
+ *
+ * These functions supplement the generated code from \c protoc-c to
+ * allow you to import and export \c ProtobufCMessage structures
+ * from/to the protobuf text mode serialisation.
+ *
+ * These will work with any code generated from \c protoc-c.
+ * @{
+ */
+
+/** Structure for reporting API errors.
+ *
+ * Provides feedback on the success of an API call. Generally if an
+ * API call fails it will return \c NULL. More detail on why it failed
+ * can be found in the parameter with this type.
+ */
+typedef struct _ProtobufCTextError {
+ int *error; /**< Error code. 0 for success, >0 for failure. */
+ char *error_txt; /**< String with error message. */
+ int complete; /**< Reports whether the message is complete
+ (if supported):
+ - -1: Required field check wasn't performed - this
+ happens if your libprotobuf-c is too old.
+ - 0: The message was incomplete.
+ - >0: Message has all required fields set. */
+} ProtobufCTextError;
+
+/** Convert a \c ProtobufCMessage to a string.
+ *
+ * Given a \c ProtobufCMessage serialise it as a text format protobuf.
+ *
+ * \param[in] m The \c ProtobufCMessage to be serialised.
+ * \param[in] allocator This is the same \c ProtobufCAllocator type used
+ * by the \c libprotobuf-c library. You can set it
+ * to \c NULL to accept \c protobuf_c_default_allocator -
+ * the default allocator.
+ * \return The string with the text format serialised \c ProtobufCMessage.
+ * On failure it will return \c NULL. On success, the resulting value
+ * be freed by you with the \c allocator you provided. If you didn't
+ * provide an allocator technically you should do:
+ * \code
+ * protobuf_c_default_allocator.free(
+ * protobuf_c_default_allocator.allocator_data, retval);
+ * \endcode
+ * Though technically \c free(retval); is probably sufficient.
+ */
+extern char *protobuf_c_text_to_string(ProtobufCMessage *m,
+ ProtobufCAllocator *allocator);
+
+/** Import a text format protobuf from a string into a \c ProtobufCMessage.
+ *
+ * Given a string containing a text format protobuf, parse it and return
+ * the corresponding \c ProtobufCMessage struct. On failure, \c NULL is
+ * returned and \c result is updated with why.
+ *
+ * The resulting \c ProtobufCMessage should be freed with
+ * \c protobuf_c_message_free_unpacked() or the generated
+ * \c ..._free_upacked() function. Either is fine, but that's how the
+ * memory should be freed.
+ *
+ * \param[in] descriptor The descriptor from the generated code.
+ * \param[in] msg The string containing the text format protobuf.
+ * \param[out] result This structure contains information on any error
+ * that halted processing.
+ * \param[in] allocator This is the same \c ProtobufCAllocator type used
+ * by the \c libprotobuf-c library. You can set it
+ * to \c NULL to accept \c protobuf_c_default_allocator -
+ * the default allocator.
+ * \return The resulting \c ProtobufCMessage . It returns \c NULL on error.
+ * Check \c result->complete to make sure the message is valid.
+ */
+extern ProtobufCMessage *protobuf_c_text_from_string(
+ const ProtobufCMessageDescriptor *descriptor,
+ char *msg,
+ ProtobufCTextError *result,
+ ProtobufCAllocator *allocator);
+
+/** Import a text format protobuf from a \c FILE into a \c ProtobufCMessage.
+ *
+ * Given a \c FILE containing a text format protobuf, parse it and return
+ * the corresponding \c ProtobufCMessage struct. On failure, \c NULL is
+ * returned and \c result is updated with why.
+ *
+ * The resulting \c ProtobufCMessage should be freed with
+ * \c protobuf_c_message_free_unpacked() or the generated
+ * \c ..._free_upacked() function. Either is fine, but that's how the
+ * memory should be freed.
+ *
+ * \param[in] descriptor The descriptor from the generated code.
+ * \param[in] msg_file The \c FILE containing the text format protobuf.
+ * \param[out] result This structure contains information on any error
+ * that halted processing.
+ * \param[in] allocator This is the same \c ProtobufCAllocator type used
+ * by the \c libprotobuf-c library. You can set it
+ * to \c NULL to accept \c protobuf_c_default_allocator -
+ * the default allocator.
+ * \return The resulting \c ProtobufCMessage . It returns \c NULL on error.
+ * Check \c result->complete to make sure the message is valid.
+ */
+extern ProtobufCMessage *protobuf_c_text_from_file(
+ const ProtobufCMessageDescriptor *descriptor,
+ FILE *msg_file,
+ ProtobufCTextError *result,
+ ProtobufCAllocator *allocator);
+
+/** @} */ /* End of API group. */
+
+#endif /* PROTOBUF_C_TEXT_H */
diff --git a/protocols/Steam/src/stdafx.h b/protocols/Steam/src/stdafx.h
index 2fd47d20f1..11cdbe7e49 100644
--- a/protocols/Steam/src/stdafx.h
+++ b/protocols/Steam/src/stdafx.h
@@ -44,6 +44,11 @@
#include "protobuf-c/steammessages_friendmessages.steamclient.pb-c.h"
#include "proto.h"
+extern "C"
+{
+ #include "protobuf-c/protobuf-c-text.h"
+}
+
#define MODULE "Steam"
#define DB_KEY_LASTMSGTS "LastMessageTS"
diff --git a/protocols/Steam/src/steam_ws.cpp b/protocols/Steam/src/steam_ws.cpp
index 7c7c6f32c1..f22587eca4 100644
--- a/protocols/Steam/src/steam_ws.cpp
+++ b/protocols/Steam/src/steam_ws.cpp
@@ -139,7 +139,7 @@ void CSteamProto::ProcessMessage(const uint8_t *buf, size_t cbLen)
else if (bIsProto) {
uint32_t hdrLen = *(uint32_t *)buf; buf += sizeof(uint32_t); cbLen -= sizeof(uint32_t);
proto::MsgProtoBufHeader tmpHeader(buf, hdrLen);
- if (tmpHeader == nullptr) {
+ if (tmpHeader == nullptr) {
debugLogA("Unable to decode message header, exiting");
return;
}