/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __rpc_h__ #define __rpc_h__ #include #include #include #include #include #include #include "json/json.h" extern void Fail(const char *reason, const char *data); #ifdef INTERPOSE const void* RealGetInterface(const char* interfaceName); void Logging_PP_CompletionCallback(void* user_data, int32_t result); void Logging_PPB_Audio_Callback_1_0(void* sample_buffer, uint32_t buffer_size_in_bytes, void* user_data); struct Logging_PPB_Audio_Callback_1_0_holder { PPB_Audio_Callback_1_0 func; void* user_data; }; struct Logging_PPP_Class_Deprecated_holder { const PPP_Class_Deprecated* _real_PPP_Class_Deprecated; const void* object; }; extern const PPP_Class_Deprecated _interpose_PPP_Class_Deprecated_1_0; #else // INTERPOSE void ToHost(std::stringstream &s, bool abortIfNonMainThread); std::string ToHostWithResult(std::stringstream &s, bool abortIfNonMainThread); enum RPCType { WithResult, NoResult }; enum RPCThread { MainThreadOnly, MaybeNonMainThread }; template void RPC(std::stringstream &s) { return ToHost(s, rpcThread == MainThreadOnly); } template std::string RPCWithResult(std::stringstream &s) { return ToHostWithResult(s, rpcThread == MainThreadOnly); } #endif // INTERPOSE typedef float float_t; typedef double double_t; typedef const void* mem_t; typedef void* const * mem_ptr_t; typedef const char* str_t; typedef const char* cstr_t; typedef int GLint; typedef unsigned int GLuint; typedef unsigned int GLenum; typedef unsigned int GLbitfield; typedef unsigned char GLboolean; typedef float GLclampf; typedef float GLfloat; typedef long int GLintptr; typedef int GLsizei; typedef long int GLsizeiptr; typedef const GLint * GLint_ptr_t; typedef const GLuint * GLuint_ptr_t; typedef const GLenum * GLenum_ptr_t; typedef const GLboolean * GLboolean_ptr_t; typedef const GLfloat * GLfloat_ptr_t; typedef const GLsizei * GLsizei_ptr_t; typedef const GLubyte * GLubyte_ptr_t; #ifdef _WIN32 #include typedef HANDLE PP_FileHandle; #else typedef int PP_FileHandle; #endif struct PPP_MessageHandler_0_2; static void BeginProps(std::stringstream &s) { s << '{'; } static void EndProps(std::stringstream &s) { s << '}'; } static void BeginProp(std::stringstream &s, const std::string &key) { if (s.str().back() != '{') s << ','; s << '"' << key << "\":"; } static void AddProp(std::stringstream &s, const std::string &key, const std::string &value) { BeginProp(s, key); s << value; } static void BeginElements(std::stringstream &s) { s << '['; } static void EndElements(std::stringstream &s) { s << ']'; } static void BeginElement(std::stringstream &s) { if (s.str().back() != '[') s << ','; } static void AddElement(std::stringstream &s, const std::string &value) { BeginElement(s); s << value; } // Define how to send certain primitive types to the browser. template static const std::string ToString(const T *value) { std::stringstream x; x << *value; return x.str(); } static void WriteEscapedChar(std::stringstream& x, const char value) { switch (value) { case '\\': x << "\\\\"; return; case '"': x << "\\" << value; return; } unsigned int v = (unsigned int)value; if (v <= 0x001f) { x << "\\u" << std::setw(4) << std::setfill('0') << std::hex << v; } else { x << value; } } template static void WriteString(std::stringstream& x, const T *value, size_t length) { const char* start = *value; const char* end = start + length; size_t pos = 0; while (start != end) { WriteEscapedChar(x, *(start++)); } } template static const std::string StringToQuotedString(const T *value, size_t length) { std::stringstream x; x << '"'; WriteString(x, value, length); x << '"'; return x.str(); } template static const std::string StringToQuotedString(const T *value) { return StringToQuotedString(value, strlen(*value)); } static const std::string StringToQuotedString(const char *value) { return StringToQuotedString(&value, 1); } template static const std::string PointerToString(T *value) { std::stringstream x; if (!value) { x << "null"; } else { x << (std::intptr_t)value; } return x.str(); } #define DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) \ static const std::string ToString_##T(const T &value) { \ return ToString_##T(&value); \ } #define DEFINE_TOSTRING(T) \ static const std::string ToString_##T(const T *value) { \ return ToString(value); \ } \ DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) #define DEFINE_INT_TOSTRING(T) \ static const std::string ToString_##T(const T *value) { \ std::stringstream x; \ x << std::dec << (int)*value; \ return x.str(); \ } \ DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) #define DEFINE_UNSIGNED_INT_TOSTRING(T) \ static const std::string ToString_##T(const T *value) { \ std::stringstream x; \ x << std::dec << (unsigned int)*value; \ return x.str(); \ } \ DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) #define DEFINE_FLOAT_TOSTRING(T) \ static const std::string ToString_##T(const T *value) { \ switch (std::fpclassify(*value)) { \ case FP_INFINITE: \ case FP_NAN: \ return "null"; \ default: \ return ToString(value); \ } \ } \ DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) #define DEFINE_POINTER_TOSTRING(T) \ static const std::string ToString_##T(const T *value) { \ return PointerToString(*value); \ } \ DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) #define DEFINE_STRING_TOSTRING(T) \ static const std::string ToString_##T(const T *value) { \ return StringToQuotedString(value); \ } \ DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(T) DEFINE_STRING_TOSTRING(char) DEFINE_INT_TOSTRING(int8_t) DEFINE_INT_TOSTRING(int32_t) DEFINE_INT_TOSTRING(int64_t) DEFINE_UNSIGNED_INT_TOSTRING(uint8_t) DEFINE_UNSIGNED_INT_TOSTRING(uint16_t) DEFINE_UNSIGNED_INT_TOSTRING(uint32_t) DEFINE_UNSIGNED_INT_TOSTRING(uint64_t) DEFINE_FLOAT_TOSTRING(float_t) DEFINE_FLOAT_TOSTRING(double_t) DEFINE_POINTER_TOSTRING(mem_t) DEFINE_TOSTRING(mem_ptr_t) DEFINE_STRING_TOSTRING(str_t) static const std::string ToString_str_t(const str_t *value, size_t length) { return StringToQuotedString(value, length); } static const std::string ToString_str_t(const str_t &value, size_t length) { return StringToQuotedString(&value, length); } DEFINE_STRING_TOSTRING(cstr_t) DEFINE_TOSTRING(GLint) DEFINE_TOSTRING(GLuint) DEFINE_TOSTRING(GLenum) DEFINE_TOSTRING(GLbitfield) static const std::string ToString_GLboolean(const GLboolean *value) { std::stringstream x; x << (*value ? "true" : "false"); return x.str(); } DEFINE_TOSTRING_FORWARD_REF_TO_POINTER(GLboolean) DEFINE_TOSTRING(GLfloat) DEFINE_TOSTRING(GLclampf) DEFINE_TOSTRING(GLintptr) DEFINE_TOSTRING(GLsizei) DEFINE_TOSTRING(GLsizeiptr) DEFINE_TOSTRING(GLuint_ptr_t) DEFINE_TOSTRING(GLenum_ptr_t) DEFINE_TOSTRING(GLboolean_ptr_t) DEFINE_POINTER_TOSTRING(GLint_ptr_t) DEFINE_POINTER_TOSTRING(GLfloat_ptr_t) DEFINE_TOSTRING(GLsizei_ptr_t) DEFINE_TOSTRING(PP_FileHandle) #ifdef INTERPOSE static const std::string ToString_GLubyte_ptr_t(const GLubyte *value) { std::stringstream x; x << (const char*)value; return x.str(); } static const std::string ToString_uint16_ptr_t(const uint16_ptr_t value) { return ""; } extern const std::string ToString_PP_DirContents_Dev(const PP_DirContents_Dev *v); static const std::string ToString_PP_DirContents_Dev(PP_DirContents_Dev **value) { if (!value && !*value) { return "{}"; } return ToString_PP_DirContents_Dev(*value); } #endif // Define how to emit client objects that the client sends to the host. We just want // to send a pointer value here, not actually unpack the struct. static const std::string ToString_PPP_MessageHandler(const PPP_MessageHandler_0_2 *value) { std::stringstream x; x << value; return x.str(); } static const std::string ToString_PPP_Class_Deprecated(const PPP_Class_Deprecated *value) { return PointerToString(value); } class JSONIterator { JSON::Parser parser; JSON::Parser::iterator iterator; JSON::Parser::iterator end; public: JSONIterator(const std::string& json) { if (parser.parse(json) <= 0) { Fail("Fatal: failed to parse '%s'\n", json.c_str()); } iterator = parser.begin(); end = parser.end(); } bool isValid() const { return iterator != end; } operator const JSON::Token&() const { return *iterator; } void skip() { ++iterator; } const JSON::Token& getCurrentAndGotoNext() { const JSON::Token& token = *iterator; ++iterator; return token; } const JSON::Token& getCurrentPrimitiveAndGotoNext() { const JSON::Token& token = getCurrentAndGotoNext(); if (!token.isPrimitive()) { Fail("Expected primitive", ""); }; return token; } const JSON::Token& getCurrentStringAndGotoNext() { const JSON::Token& token = getCurrentAndGotoNext(); if (!token.isString()) { Fail("Expected string", ""); }; return token; } const void expectObjectAndGotoFirstProperty() { if (!getCurrentAndGotoNext().isObject()) { Fail("Expected object", ""); } if (!iterator->isString()) { Fail("Expected string", ""); } } const size_t expectArrayAndGotoFirstItem() { const JSON::Token& token = getCurrentAndGotoNext(); if (!token.isArray()) { Fail("Expected array", ""); } return token.children(); } }; template struct OutParam { typedef typename std::conditional::value, typename std::remove_pointer::type, T>::type nopointer; typedef typename std::remove_const::type noconst; typedef typename std::conditional::value, typename std::add_pointer::type, noconst>::type type; }; static void FromJSON_int(JSONIterator& iterator, long int& value) { value = atol(iterator.getCurrentPrimitiveAndGotoNext().value().c_str()); } static void FromJSON_uintptr(JSONIterator& iterator, std::uintptr_t& value) { long long pointer = std::atoll(iterator.getCurrentPrimitiveAndGotoNext().value().c_str()); value = static_cast(pointer); } template static void PointerValueFromJSON(JSONIterator& iterator, T*& value) { std::uintptr_t pointer; FromJSON_uintptr(iterator, pointer); value = (T*)pointer; } static void FromJSON_charArray(JSONIterator& iterator, char* value, size_t count) { const JSON::Token& token = iterator.getCurrentStringAndGotoNext(); std::strncpy(value, token.value().c_str(), count); } // FIXME Check range? #define DEFINE_FROMJSON_INT(T) \ static void FromJSON_##T(JSONIterator& iterator, OutParam::type& value) { \ long int v; \ FromJSON_int(iterator, v); \ value = v; \ } #define DEFINE_FROMJSON_FLOAT(T) \ static void FromJSON_##T(JSONIterator& iterator, OutParam::type& value) \ { \ value = atof(iterator.getCurrentPrimitiveAndGotoNext().value().c_str()); \ } DEFINE_FROMJSON_INT(int8_t) DEFINE_FROMJSON_INT(int32_t) DEFINE_FROMJSON_INT(int64_t) DEFINE_FROMJSON_INT(uint8_t) DEFINE_FROMJSON_INT(uint16_t) DEFINE_FROMJSON_INT(uint32_t) DEFINE_FROMJSON_INT(uint64_t) DEFINE_FROMJSON_FLOAT(float_t) DEFINE_FROMJSON_FLOAT(double_t) static void FromJSON_mem_t(JSONIterator& iterator, OutParam::type& value) { PointerValueFromJSON(iterator, value); } static void FromJSON_mem_ptr_t(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_mem_ptr_t"); } static void FromJSON_str_t(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); if (token.isString()) { size_t length = 0; std::string tokenValue = token.value(); for (std::string::iterator it = tokenValue.begin(); it != tokenValue.cend(); ++it) { ++length; if (*it == '\\' && it + 1 != tokenValue.cend()) { std::string::iterator next = it + 1; switch (*next) { case '\"': case '/': case '\\': tokenValue.erase(it); break; case 'b': tokenValue.replace(it, next + 1, "\b"); break; case 'f': tokenValue.replace(it, next + 1, "\f"); break; case 'r': tokenValue.replace(it, next + 1, "\r"); break; case 'n': tokenValue.replace(it, next + 1, "\n"); break; case 't': tokenValue.replace(it, next + 1, "\t"); break; case 'u': if (tokenValue.cend() - next >= 5) { if (*(next + 1) == '0' && *(next + 2) == '0') { unsigned int v; std::stringstream x; x << *(next + 3) << *(next + 4); x >> std::hex >> v; // Handle Control characters code units // from U+0000 to U+001F. if ( v < 0x0020) { tokenValue.replace(it, next + 5, 1, v); break; } } Fail("Need to handle unicode escapes in strings: %s.", tokenValue.c_str()); } } } } value = (char*) malloc(length + 1); std::memcpy(value, tokenValue.c_str(), length + 1); return; } if (!token.isArray()) { Fail("Expected array", ""); return; } size_t size = token.children(); char* buff = new char[size]; for (size_t i = 0; i < size; ++i) { buff[i] = iterator.getCurrentAndGotoNext().value()[0]; } value = buff; } static void FromJSON_str_t(JSONIterator& iterator, str_t& value) { return FromJSON_str_t(iterator, const_cast::type&>(value)); } static void FromJSON_cstr_t(JSONIterator& iterator, cstr_t& value) { value = strdup(iterator.getCurrentStringAndGotoNext().value().c_str()); } DEFINE_FROMJSON_INT(GLint) DEFINE_FROMJSON_INT(GLuint) static void FromJSON_GLenum(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLenum"); } static void FromJSON_GLbitfield(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLbitfield"); } DEFINE_FROMJSON_INT(GLboolean) static void FromJSON_GLfloat(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLfloat"); } static void FromJSON_GLclampf(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLclampf"); } static void FromJSON_GLintptr(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLintptr"); } DEFINE_FROMJSON_INT(GLsizei) static void FromJSON_GLboolean_ptr_t(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLboolean_ptr_t"); } static void FromJSON_GLenum_ptr_t(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLenum_ptr_t"); } static void FromJSON_GLfloat_ptr_t(JSONIterator& iterator,OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLfloat_ptr_t"); } static void FromJSON_GLint_ptr_t(JSONIterator& iterator, OutParam::type& value) { return FromJSON_GLint(iterator, *value); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLint_ptr_t"); } static void FromJSON_GLsizei_ptr_t(JSONIterator& iterator, OutParam::type& value) { if (!value) { iterator.skip(); } else { FromJSON_GLsizei(iterator, *value); } } static void FromJSON_GLubyte_ptr_t(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentStringAndGotoNext(); std::string tokenValue = token.value(); size_t size = tokenValue.size(); value = new GLubyte[size]; std::memcpy(value, tokenValue.data(), size); } static void FromJSON_GLuint_ptr_t(JSONIterator& iterator, OutParam::type& value) { const JSON::Token& token = iterator.getCurrentAndGotoNext(); Fail("UNIMPLEMENTED: %s\n", "FromJSON_GLuint_ptr_t"); } #ifdef _WIN32 static void FromJSON_PP_FileHandle(JSONIterator& iterator, PP_FileHandle& value) { PointerValueFromJSON(iterator, value); } #else DEFINE_FROMJSON_INT(PP_FileHandle) #endif static void FromJSON_uint16_ptr_t(JSONIterator& iterator, uint16_ptr_t& value) { PointerValueFromJSON(iterator, value); } struct PP_Flash_Menu; void FromJSON_PP_Flash_Menu(JSONIterator& iterator, PP_Flash_Menu &value); void FromJSON_PP_Flash_Menu(JSONIterator& iterator, PP_Flash_Menu *&value); struct PP_DirEntry_Dev; struct PP_DirContents_Dev; void FromJSON_PP_DirEntry_Dev(JSONIterator& iterator, PP_DirEntry_Dev &value); void FromJSON_PP_DirContents_Dev(JSONIterator& iterator, PP_DirContents_Dev *&value); #endif