1718 lines
45 KiB
C
1718 lines
45 KiB
C
/*
|
|
* npw-rpc.c - Remote Procedure Calls (NPAPI specialisation)
|
|
*
|
|
* nspluginwrapper (C) 2005-2009 Gwenole Beauchesne
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#include "sysdeps.h"
|
|
#include <assert.h>
|
|
|
|
#include "utils.h"
|
|
#include "npw-common.h"
|
|
|
|
#define DEBUG 1
|
|
#include "debug.h"
|
|
|
|
|
|
/*
|
|
* RPC types of NPP/NPN variables
|
|
*/
|
|
|
|
int rpc_type_of_NPNVariable(int variable)
|
|
{
|
|
int type;
|
|
switch (variable) {
|
|
case NPNVjavascriptEnabledBool:
|
|
case NPNVasdEnabledBool:
|
|
case NPNVisOfflineBool:
|
|
case NPNVSupportsXEmbedBool:
|
|
case NPNVSupportsWindowless:
|
|
case NPNVprivateModeBool:
|
|
case NPNVsupportsAdvancedKeyHandling:
|
|
type = RPC_TYPE_BOOLEAN;
|
|
break;
|
|
case NPNVToolkit:
|
|
case NPNVnetscapeWindow:
|
|
type = RPC_TYPE_UINT32;
|
|
break;
|
|
case NPNVdocumentOrigin:
|
|
type = RPC_TYPE_STRING;
|
|
break;
|
|
case NPNVWindowNPObject:
|
|
case NPNVPluginElementNPObject:
|
|
type = RPC_TYPE_NP_OBJECT;
|
|
break;
|
|
default:
|
|
type = RPC_ERROR_GENERIC;
|
|
break;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
int rpc_type_of_NPPVariable(int variable)
|
|
{
|
|
int type;
|
|
switch (variable) {
|
|
case NPPVpluginNameString:
|
|
case NPPVpluginDescriptionString:
|
|
case NPPVformValue: // byte values of 0 does not appear in the UTF-8 encoding but for U+0000
|
|
case NPPVpluginNativeAccessibleAtkPlugId:
|
|
type = RPC_TYPE_STRING;
|
|
break;
|
|
case NPPVpluginWindowSize:
|
|
case NPPVpluginTimerInterval:
|
|
type = RPC_TYPE_INT32;
|
|
break;
|
|
case NPPVpluginNeedsXEmbed:
|
|
case NPPVpluginWindowBool:
|
|
case NPPVpluginTransparentBool:
|
|
case NPPVjavascriptPushCallerBool:
|
|
case NPPVpluginKeepLibraryInMemory:
|
|
case NPPVpluginUrlRequestsDisplayedBool:
|
|
case NPPVpluginWantsAllNetworkStreams:
|
|
case NPPVpluginCancelSrcStream:
|
|
case NPPVsupportsAdvancedKeyHandling:
|
|
case NPPVpluginUsesDOMForCursorBool:
|
|
type = RPC_TYPE_BOOLEAN;
|
|
break;
|
|
case NPPVpluginScriptableNPObject:
|
|
type = RPC_TYPE_NP_OBJECT;
|
|
break;
|
|
default:
|
|
type = RPC_ERROR_GENERIC;
|
|
break;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPW_PluginInstance objects
|
|
*/
|
|
|
|
static int do_send_NPW_PluginInstance(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPW_PluginInstance *plugin = (NPW_PluginInstance *)p_value;
|
|
uint32_t instance_id = 0;
|
|
if (plugin)
|
|
instance_id = plugin->instance_id;
|
|
return rpc_message_send_uint32(message, instance_id);
|
|
}
|
|
|
|
static int do_recv_NPW_PluginInstance(rpc_message_t *message, void *p_value)
|
|
{
|
|
int error;
|
|
uint32_t instance_id;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &instance_id)) < 0)
|
|
return error;
|
|
|
|
NPW_PluginInstance *plugin = id_lookup(instance_id);
|
|
if (instance_id && plugin == NULL)
|
|
npw_printf("ERROR: no valid NPP -> PluginInstance mapping found\n");
|
|
else if (plugin && plugin->instance == NULL)
|
|
npw_printf("ERROR: no valid PluginInstance -> NPP mapping found\n");
|
|
else if (plugin && !npw_plugin_instance_is_valid(plugin))
|
|
npw_printf("ERROR: received PluginInstance was invalidated earlier\n");
|
|
*((NPW_PluginInstance **)p_value) = plugin;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPP objects
|
|
*/
|
|
|
|
static int do_send_NPP(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPP instance = (NPP)p_value;
|
|
NPW_PluginInstance *plugin = NULL;
|
|
if (instance)
|
|
plugin = NPW_PLUGIN_INSTANCE(instance);
|
|
return do_send_NPW_PluginInstance(message, plugin);
|
|
}
|
|
|
|
static int do_recv_NPP(rpc_message_t *message, void *p_value)
|
|
{
|
|
int error;
|
|
NPW_PluginInstance *plugin;
|
|
|
|
if ((error = do_recv_NPW_PluginInstance(message, &plugin)) < 0)
|
|
return error;
|
|
|
|
*((NPP *)p_value) = plugin ? plugin->instance : NULL;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPStream objects
|
|
*/
|
|
|
|
static int do_send_NPStream(rpc_message_t *message, void *p_value)
|
|
{
|
|
uint32_t stream_id = 0;
|
|
NPStream *stream = (NPStream *)p_value;
|
|
if (stream) {
|
|
NPW_StreamInstance *sip = NPW_STREAM_INSTANCE(stream);
|
|
if (sip)
|
|
stream_id = sip->stream_id;
|
|
}
|
|
return rpc_message_send_uint32(message, stream_id);
|
|
}
|
|
|
|
static int do_recv_NPStream(rpc_message_t *message, void *p_value)
|
|
{
|
|
int error;
|
|
uint32_t stream_id;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &stream_id)) < 0)
|
|
return error;
|
|
|
|
NPW_StreamInstance *stream = id_lookup(stream_id);
|
|
*((NPStream **)p_value) = stream ? stream->stream : NULL;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPByteRange objects
|
|
*/
|
|
|
|
static int do_send_NPByteRange(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPByteRange *range = (NPByteRange *)p_value;
|
|
while (range) {
|
|
int error;
|
|
if ((error = rpc_message_send_uint32(message, 1)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, range->offset)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, range->length)) < 0)
|
|
return error;
|
|
range = range->next;
|
|
}
|
|
return rpc_message_send_uint32(message, 0);
|
|
}
|
|
|
|
static int do_recv_NPByteRange(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPByteRange **rangeListPtr = (NPByteRange **)p_value;
|
|
if (rangeListPtr == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
*rangeListPtr = NULL;
|
|
|
|
for (;;) {
|
|
int error;
|
|
uint32_t cont;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &cont)) < 0)
|
|
return error;
|
|
if (!cont)
|
|
break;
|
|
NPByteRange *range = malloc(sizeof(*range));
|
|
if (range == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
range->next = NULL;
|
|
if ((error = rpc_message_recv_int32(message, &range->offset)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &range->length)) < 0)
|
|
return error;
|
|
*rangeListPtr = range;
|
|
rangeListPtr = &range->next;
|
|
}
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPSavedData objects
|
|
*/
|
|
|
|
static int do_send_NPSavedData(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPSavedData *save_area = (NPSavedData *)p_value;
|
|
int error;
|
|
|
|
if (save_area == NULL) {
|
|
if ((error = rpc_message_send_int32(message, 0)) < 0)
|
|
return error;
|
|
}
|
|
else {
|
|
if ((error = rpc_message_send_int32(message, save_area->len)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_bytes(message, save_area->buf, save_area->len)) < 0)
|
|
return error;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPSavedData(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPSavedData *save_area;
|
|
int error;
|
|
int32_t len;
|
|
unsigned char *buf;
|
|
|
|
if ((error = rpc_message_recv_int32(message, &len)) < 0)
|
|
return error;
|
|
if (len == 0)
|
|
save_area = NULL;
|
|
else {
|
|
if ((save_area = NPN_MemAlloc(sizeof(*save_area))) == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
if ((buf = NPN_MemAlloc(len)) == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
if ((error = rpc_message_recv_bytes(message, buf, len)) < 0)
|
|
return error;
|
|
save_area->len = len;
|
|
save_area->buf = buf;
|
|
}
|
|
|
|
if (p_value)
|
|
*((NPSavedData **)p_value) = save_area;
|
|
else if (save_area) {
|
|
NPN_MemFree(save_area->buf);
|
|
NPN_MemFree(save_area);
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NotifyData objects
|
|
*/
|
|
|
|
// Rationale: NotifyData objects are allocated on the plugin side
|
|
// only. IDs are passed through to the browser, and they have no
|
|
// meaning on that side as they are only used to get passed back to
|
|
// the plugin side
|
|
//
|
|
// XXX 64-bit viewers in 32-bit wrappers are not supported
|
|
static int do_send_NotifyData(rpc_message_t *message, void *p_value)
|
|
{
|
|
void *notifyData = (void *)p_value;
|
|
return rpc_message_send_uint64(message, (uintptr_t)notifyData);
|
|
}
|
|
|
|
static int do_recv_NotifyData(rpc_message_t *message, void *p_value)
|
|
{
|
|
int error;
|
|
uint64_t id;
|
|
|
|
if ((error = rpc_message_recv_uint64(message, &id)) < 0)
|
|
return error;
|
|
|
|
if (sizeof(void *) == 4 && ((uint32_t)(id >> 32)) != 0) {
|
|
npw_printf("ERROR: 64-bit viewers in 32-bit wrappers are not supported\n");
|
|
abort();
|
|
}
|
|
|
|
*((void **)p_value) = (void *)(uintptr_t)id;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPRect objects
|
|
*/
|
|
|
|
static int do_send_NPRect(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPRect *rect = (NPRect *)p_value;
|
|
int error;
|
|
|
|
if ((error = rpc_message_send_uint32(message, rect->top)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, rect->left)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, rect->bottom)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, rect->right)) < 0)
|
|
return error;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPRect(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPRect *rect = (NPRect *)p_value;
|
|
uint32_t top, left, bottom, right;
|
|
int error;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &top)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &left)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &bottom)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &right)) < 0)
|
|
return error;
|
|
|
|
rect->top = top;
|
|
rect->left = left;
|
|
rect->bottom = bottom;
|
|
rect->right = right;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPWindow objects
|
|
*/
|
|
|
|
static int do_send_NPSetWindowCallbackStruct(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPSetWindowCallbackStruct *ws_info = (NPSetWindowCallbackStruct *)p_value;
|
|
int error;
|
|
|
|
if (ws_info) {
|
|
if ((error = rpc_message_send_uint32(message, 1)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, ws_info->type)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, ws_info->visual ? XVisualIDFromVisual(ws_info->visual) : 0)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, ws_info->colormap)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, ws_info->depth)) < 0)
|
|
return error;
|
|
}
|
|
else {
|
|
if ((error = rpc_message_send_uint32(message, 0)) < 0)
|
|
return error;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPSetWindowCallbackStruct(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPSetWindowCallbackStruct **ws_info_p = (NPSetWindowCallbackStruct **)p_value;
|
|
NPSetWindowCallbackStruct *ws_info;
|
|
int32_t type;
|
|
uint32_t has_ws_info, visual_id, colormap, depth;
|
|
int error;
|
|
|
|
if (ws_info_p)
|
|
*ws_info_p = NULL;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &has_ws_info)) < 0)
|
|
return error;
|
|
|
|
if (has_ws_info) {
|
|
if ((error = rpc_message_recv_int32(message, &type)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &visual_id)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &colormap)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &depth)) < 0)
|
|
return error;
|
|
|
|
if (ws_info_p) {
|
|
if ((ws_info = calloc(1, sizeof(*ws_info))) == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
ws_info->type = type;
|
|
// display shall be filled in by the plugin
|
|
// visual shall be reconstructed by the plugin based on the visualID
|
|
ws_info->visual = (void *)(uintptr_t)visual_id;
|
|
ws_info->colormap = colormap;
|
|
ws_info->depth = depth;
|
|
*ws_info_p = ws_info;
|
|
}
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_NPWindowData(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPWindow *window = (NPWindow *)p_value;
|
|
int error;
|
|
|
|
if (window == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
|
|
if ((error = rpc_message_send_uint32(message, (Window)window->window)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, window->x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, window->y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, window->width)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, window->height)) < 0)
|
|
return error;
|
|
if ((error = do_send_NPRect(message, &window->clipRect)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, window->type)) < 0)
|
|
return error;
|
|
if ((error = do_send_NPSetWindowCallbackStruct(message, window->ws_info)) < 0)
|
|
return 0;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPWindowData(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPWindow *window = (NPWindow *)p_value;
|
|
NPSetWindowCallbackStruct *ws_info;
|
|
uint32_t window_id;
|
|
int32_t window_type;
|
|
int error;
|
|
|
|
if (window == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &window_id)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &window->x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &window->y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &window->width)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &window->height)) < 0)
|
|
return error;
|
|
if ((error = do_recv_NPRect(message, &window->clipRect)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &window_type)) < 0)
|
|
return error;
|
|
if ((error = do_recv_NPSetWindowCallbackStruct(message, &ws_info)) < 0)
|
|
return error;
|
|
window->type = window_type;
|
|
window->window = (void *)(Window)window_id;
|
|
window->ws_info = ws_info;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_NPWindow(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPWindow *window = (NPWindow *)p_value;
|
|
int error;
|
|
|
|
if (window == NULL) {
|
|
if ((error = rpc_message_send_uint32(message, 0)) < 0)
|
|
return error;
|
|
}
|
|
else {
|
|
if ((error = rpc_message_send_uint32(message, 1)) < 0)
|
|
return error;
|
|
if ((error = do_send_NPWindowData(message, window)) < 0)
|
|
return error;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPWindow(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPWindow **window_p = (NPWindow **)p_value;
|
|
NPWindow *window;
|
|
uint32_t window_valid;
|
|
int error;
|
|
|
|
if (window_p)
|
|
*window_p = NULL;
|
|
if ((error = rpc_message_recv_uint32(message, &window_valid)) < 0)
|
|
return error;
|
|
if (window_valid) {
|
|
if ((window = malloc(sizeof(NPWindow))) == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
if ((error = do_recv_NPWindowData(message, window)) < 0) {
|
|
free(window);
|
|
return error;
|
|
}
|
|
if (window_p)
|
|
*window_p = window;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPEvent objects
|
|
*/
|
|
|
|
// XXX: those are not real XEvent generated by the X server, i.e. some
|
|
// fields can be optimized out, which is what Firefox does
|
|
static bool is_valid_NPEvent_type(NPEvent *event)
|
|
{
|
|
switch (event->type) {
|
|
case GraphicsExpose:
|
|
case FocusIn:
|
|
case FocusOut:
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
case MotionNotify:
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
return true;
|
|
default:
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int do_send_XAnyEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xany.serial)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xany.send_event)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xany.window)) < 0)
|
|
return error;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_XGraphicsExposeEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int error;
|
|
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xgraphicsexpose.x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xgraphicsexpose.y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xgraphicsexpose.width)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xgraphicsexpose.height)) < 0)
|
|
return error;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_XFocusChangeEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_XCrossingEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int error;
|
|
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.mode)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.detail)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.same_screen)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xcrossing.focus)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xcrossing.state)) < 0)
|
|
return error;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_XMotionEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int error;
|
|
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xmotion.root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xmotion.subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xmotion.time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xmotion.x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xmotion.y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xmotion.x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xmotion.y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xmotion.state)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_char(message, xevent->xmotion.is_hint)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xmotion.same_screen)) < 0)
|
|
return error;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_XButtonEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int error;
|
|
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xbutton.root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xbutton.subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xbutton.time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xbutton.x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xbutton.y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xbutton.x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xbutton.y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xbutton.state)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xbutton.button)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xbutton.same_screen)) < 0)
|
|
return error;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_XKeyEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int error;
|
|
if ((error = do_send_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xkey.root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xkey.subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xkey.time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xkey.x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xkey.y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xkey.x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xkey.y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xkey.state)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, xevent->xkey.keycode)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_int32(message, xevent->xkey.same_screen)) < 0)
|
|
return error;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_NPEvent(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPEvent *event = (NPEvent *)p_value;
|
|
int error;
|
|
|
|
if (event == NULL || !is_valid_NPEvent_type(event))
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
|
|
if ((error = rpc_message_send_int32(message, event->type)) < 0)
|
|
return error;
|
|
|
|
switch (event->type) {
|
|
case GraphicsExpose:
|
|
if ((error = do_send_XGraphicsExposeEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case FocusIn:
|
|
case FocusOut:
|
|
if ((error = do_send_XFocusChangeEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
if ((error = do_send_XCrossingEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case MotionNotify:
|
|
if ((error = do_send_XMotionEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
if ((error = do_send_XButtonEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
if ((error = do_send_XKeyEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
default:
|
|
return RPC_ERROR_GENERIC;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XAnyEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
uint32_t serial, send_event, window;
|
|
int error;
|
|
if ((error = rpc_message_recv_uint32(message, &serial)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &send_event)) < 0)
|
|
return error;
|
|
// display shall be filled in by the plugin
|
|
if ((error = rpc_message_recv_uint32(message, &window)) < 0)
|
|
return error;
|
|
xevent->xany.serial = serial;
|
|
xevent->xany.send_event = send_event;
|
|
xevent->xany.window = window;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XGraphicsExposeEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int32_t x, y;
|
|
uint32_t width, height;
|
|
int error;
|
|
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &width)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &height)) < 0)
|
|
return error;
|
|
xevent->xgraphicsexpose.x = x;
|
|
xevent->xgraphicsexpose.y = y;
|
|
xevent->xgraphicsexpose.width = width;
|
|
xevent->xgraphicsexpose.height = height;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XFocusChangeEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XCrossingEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int32_t x, y, x_root, y_root, mode, detail, same_screen, focus;
|
|
uint32_t root, subwindow, time, state;
|
|
int error;
|
|
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &mode)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &detail)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &focus)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
|
return error;
|
|
xevent->xcrossing.root = root;
|
|
xevent->xcrossing.subwindow = subwindow;
|
|
xevent->xcrossing.time = time;
|
|
xevent->xcrossing.x = x;
|
|
xevent->xcrossing.y = y;
|
|
xevent->xcrossing.x_root = x_root;
|
|
xevent->xcrossing.y_root = y_root;
|
|
xevent->xcrossing.mode = mode;
|
|
xevent->xcrossing.detail = detail;
|
|
xevent->xcrossing.same_screen = same_screen;
|
|
xevent->xcrossing.focus = focus;
|
|
xevent->xcrossing.state = state;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XMotionEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
char is_hint;
|
|
int32_t x, y, x_root, y_root, same_screen;
|
|
uint32_t root, subwindow, time, state;
|
|
int error;
|
|
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_char(message, &is_hint)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
|
return error;
|
|
xevent->xmotion.root = root;
|
|
xevent->xmotion.subwindow = subwindow;
|
|
xevent->xmotion.time = time;
|
|
xevent->xmotion.x = x;
|
|
xevent->xmotion.y = y;
|
|
xevent->xmotion.x_root = x_root;
|
|
xevent->xmotion.y_root = y_root;
|
|
xevent->xmotion.state = state;
|
|
xevent->xmotion.is_hint = is_hint;
|
|
xevent->xmotion.same_screen = same_screen;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XButtonEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int32_t x, y, x_root, y_root, same_screen;
|
|
uint32_t root, subwindow, time, state, button;
|
|
int error;
|
|
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &button)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
|
return error;
|
|
xevent->xbutton.root = root;
|
|
xevent->xbutton.subwindow = subwindow;
|
|
xevent->xbutton.time = time;
|
|
xevent->xbutton.x = x;
|
|
xevent->xbutton.y = y;
|
|
xevent->xbutton.x_root = x_root;
|
|
xevent->xbutton.y_root = y_root;
|
|
xevent->xbutton.state = state;
|
|
xevent->xbutton.button = button;
|
|
xevent->xbutton.same_screen = same_screen;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_XKeyEvent(rpc_message_t *message, XEvent *xevent)
|
|
{
|
|
int32_t x, y, x_root, y_root, same_screen;
|
|
uint32_t root, subwindow, time, state, keycode;
|
|
int error;
|
|
if ((error = do_recv_XAnyEvent(message, xevent)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &subwindow)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &time)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &x_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &y_root)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &state)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &keycode)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_int32(message, &same_screen)) < 0)
|
|
return error;
|
|
xevent->xkey.root = root;
|
|
xevent->xkey.subwindow = subwindow;
|
|
xevent->xkey.time = time;
|
|
xevent->xkey.x = x;
|
|
xevent->xkey.y = y;
|
|
xevent->xkey.x_root = x_root;
|
|
xevent->xkey.y_root = y_root;
|
|
xevent->xkey.state = state;
|
|
xevent->xkey.keycode = keycode;
|
|
xevent->xkey.same_screen = same_screen;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPEvent(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPEvent *event = (NPEvent *)p_value;
|
|
int32_t event_type;
|
|
int error;
|
|
|
|
if ((error = rpc_message_recv_int32(message, &event_type)) < 0)
|
|
return error;
|
|
memset(event, 0, sizeof(*event));
|
|
event->type = event_type;
|
|
|
|
switch (event->type) {
|
|
case GraphicsExpose:
|
|
if ((error = do_recv_XGraphicsExposeEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case FocusIn:
|
|
case FocusOut:
|
|
if ((error = do_recv_XFocusChangeEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case EnterNotify:
|
|
case LeaveNotify:
|
|
if ((error = do_recv_XCrossingEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case MotionNotify:
|
|
if ((error = do_recv_XMotionEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case ButtonPress:
|
|
case ButtonRelease:
|
|
if ((error = do_recv_XButtonEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
case KeyPress:
|
|
case KeyRelease:
|
|
if ((error = do_recv_XKeyEvent(message, event)) < 0)
|
|
return error;
|
|
break;
|
|
default:
|
|
return RPC_ERROR_GENERIC;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPFullPrint objects
|
|
*/
|
|
|
|
static int do_send_NPFullPrint(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPFullPrint *fullPrint = (NPFullPrint *)p_value;
|
|
int error;
|
|
|
|
if ((error = rpc_message_send_uint32(message, fullPrint->pluginPrinted)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, fullPrint->printOne)) < 0)
|
|
return error;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPFullPrint(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPFullPrint *fullPrint = (NPFullPrint *)p_value;
|
|
uint32_t pluginPrinted, printOne;
|
|
int error;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &pluginPrinted)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &printOne)) < 0)
|
|
return error;
|
|
|
|
fullPrint->pluginPrinted = pluginPrinted;
|
|
fullPrint->printOne = printOne;
|
|
fullPrint->platformPrint = NULL; // to be filled in by the plugin
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPEmbedPrint objects
|
|
*/
|
|
|
|
static int do_send_NPEmbedPrint(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPEmbedPrint *embedPrint = (NPEmbedPrint *)p_value;
|
|
int error;
|
|
|
|
if ((error = do_send_NPWindowData(message, &embedPrint->window)) < 0)
|
|
return error;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPEmbedPrint(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPEmbedPrint *embedPrint = (NPEmbedPrint *)p_value;
|
|
int error;
|
|
|
|
if ((error = do_recv_NPWindowData(message, &embedPrint->window)) < 0)
|
|
return error;
|
|
|
|
embedPrint->platformPrint = NULL; // to be filled in by the plugin
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPPrint objects
|
|
*/
|
|
|
|
static int do_send_NPPrint(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPPrint *printInfo = (NPPrint *)p_value;
|
|
int error;
|
|
|
|
if ((error = rpc_message_send_uint32(message, printInfo->mode)) < 0)
|
|
return error;
|
|
switch (printInfo->mode) {
|
|
case NP_FULL:
|
|
if ((error = do_send_NPFullPrint(message, &printInfo->print.fullPrint)) < 0)
|
|
return error;
|
|
break;
|
|
case NP_EMBED:
|
|
if ((error = do_send_NPEmbedPrint(message, &printInfo->print.embedPrint)) < 0)
|
|
return error;
|
|
break;
|
|
default:
|
|
return RPC_ERROR_GENERIC;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPPrint(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPPrint *printInfo = (NPPrint *)p_value;
|
|
uint32_t print_mode;
|
|
int error;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &print_mode)) < 0)
|
|
return error;
|
|
switch (print_mode) {
|
|
case NP_FULL:
|
|
if ((error = do_recv_NPFullPrint(message, &printInfo->print.fullPrint)) < 0)
|
|
return error;
|
|
break;
|
|
case NP_EMBED:
|
|
if ((error = do_recv_NPEmbedPrint(message, &printInfo->print.embedPrint)) < 0)
|
|
return error;
|
|
break;
|
|
default:
|
|
return RPC_ERROR_GENERIC;
|
|
}
|
|
|
|
printInfo->mode = print_mode;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPPrintData objects
|
|
*/
|
|
|
|
static int do_send_NPPrintData(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPPrintData *printData = (NPPrintData *)p_value;
|
|
int error;
|
|
|
|
if ((error = rpc_message_send_uint32(message, printData->size)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_bytes(message, printData->data, printData->size)) < 0)
|
|
return error;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPPrintData(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPPrintData *printData = (NPPrintData *)p_value;
|
|
int error;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &printData->size)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_bytes(message, printData->data, printData->size)) < 0)
|
|
return error;
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPObject objects
|
|
*/
|
|
|
|
enum NPObjectType {
|
|
NPOBJECT_NULL = 0,
|
|
NPOBJECT_SENDER_OWNED,
|
|
NPOBJECT_RECEIVER_OWNED
|
|
};
|
|
|
|
static int do_send_NPObject_helper(rpc_message_t *message, void *p_value,
|
|
bool pass_ref)
|
|
{
|
|
NPObject *npobj = (NPObject *)p_value;
|
|
|
|
int error;
|
|
uint32_t type = NPOBJECT_NULL;
|
|
NPW_PluginInstance *plugin = NULL;
|
|
uint32_t npobj_id = 0;
|
|
bool release_stub = false;
|
|
|
|
if (npobj) {
|
|
npobj_id = npobject_get_proxy_id(npobj);
|
|
if (npobj_id == 0) {
|
|
// Sending an object on our side. Allocate a stub so the other
|
|
// side can make a proxy.
|
|
type = NPOBJECT_SENDER_OWNED;
|
|
npobj_id = npobject_create_stub(npobj);
|
|
if (pass_ref) {
|
|
// Release our reference; the stub protects the object from
|
|
// deallocation.
|
|
NPN_ReleaseObject(npobj);
|
|
}
|
|
#if NPW_IS_PLUGIN
|
|
// Get the owning NPP so we can figure out who the owner is.
|
|
plugin = npobject_get_owner(npobj);
|
|
#endif
|
|
} else {
|
|
// This is a proxy for the object on the other side. Just pass
|
|
// the id along.
|
|
type = NPOBJECT_RECEIVER_OWNED;
|
|
if (pass_ref) {
|
|
// As above, we release out reference. If this is not the last
|
|
// reference, we may just do so. Otherwise, we destroy it, but
|
|
// do /not/ send the corresponding RPC. That gets merged into
|
|
// this one.
|
|
if (npobj->referenceCount == 1) {
|
|
npobject_destroy_proxy(npobj, false);
|
|
// Tell the other side to destroy the stub after taking a ref.
|
|
release_stub = true;
|
|
} else {
|
|
NPN_ReleaseObject(npobj);
|
|
}
|
|
}
|
|
}
|
|
assert(npobj_id != 0);
|
|
}
|
|
|
|
// This could be significantly trimmed down, but it really doesn't
|
|
// matter. Latency, not bandwidth, is what we care about.
|
|
if ((error = rpc_message_send_uint32(message, type)) < 0)
|
|
return error;
|
|
if ((error = do_send_NPW_PluginInstance(message, plugin)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_send_uint32(message, npobj_id)) < 0)
|
|
return error;
|
|
if (pass_ref) {
|
|
if ((error = rpc_message_send_uint32(message, release_stub)) < 0)
|
|
return error;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value,
|
|
bool pass_ref)
|
|
{
|
|
int error;
|
|
uint32_t type = NPOBJECT_NULL;
|
|
uint32_t npobj_id = 0;
|
|
NPW_PluginInstance *plugin = NULL;
|
|
uint32_t release_stub = 0;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &type)) < 0)
|
|
return error;
|
|
if ((error = do_recv_NPW_PluginInstance(message, &plugin)) < 0)
|
|
return error;
|
|
if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0)
|
|
return error;
|
|
if (pass_ref) {
|
|
if ((error = rpc_message_recv_uint32(message, &release_stub)) < 0)
|
|
return error;
|
|
}
|
|
|
|
NPObject *npobj = NULL;
|
|
if (type == NPOBJECT_NULL) {
|
|
// Do nothing.
|
|
} else if (type == NPOBJECT_SENDER_OWNED) {
|
|
// We got a newly-created remote stub. Create a matching proxy.
|
|
npobj = npobject_create_proxy(NPW_PLUGIN_INSTANCE_NPP(plugin), npobj_id);
|
|
if (release_stub) {
|
|
npw_printf("ERROR: received release_stub for proxy NPObject.\n");
|
|
return RPC_ERROR_GENERIC;
|
|
}
|
|
} else if (type == NPOBJECT_RECEIVER_OWNED) {
|
|
npobj = npobject_lookup_local(npobj_id);
|
|
assert(npobj != NULL);
|
|
// This is an object on our side. Retain it; receiver must
|
|
// release all received NPObjects.
|
|
NPN_RetainObject(npobj);
|
|
if (release_stub) {
|
|
// We just retained the object, so it won't be destroyed.
|
|
npobject_destroy_stub(npobj_id);
|
|
}
|
|
} else {
|
|
npw_printf("ERROR: unknown NPObject type %d\n", type);
|
|
return RPC_ERROR_GENERIC;
|
|
}
|
|
|
|
*((NPObject **)p_value) = npobj;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_NPObject(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_send_NPObject_helper(message, p_value, false);
|
|
}
|
|
|
|
static int do_recv_NPObject(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_recv_NPObject_helper(message, p_value, false);
|
|
}
|
|
|
|
static int do_send_NPObject_pass_ref(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_send_NPObject_helper(message, p_value, true);
|
|
}
|
|
|
|
static int do_recv_NPObject_pass_ref(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_recv_NPObject_helper(message, p_value, true);
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPIdentifier objects
|
|
*/
|
|
|
|
// Rationale: NPIdentifiers are allocated on the browser side
|
|
// only. IDs are passed through to the viewer, and they have no
|
|
// meaning on that side as they are only used to get passed back to
|
|
// the browser side
|
|
static int do_send_NPIdentifier(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPIdentifier ident = *(NPIdentifier *)p_value;
|
|
int id = 0;
|
|
if (ident) {
|
|
#ifdef BUILD_WRAPPER
|
|
id = id_lookup_value(ident);
|
|
if (id < 0)
|
|
id = id_create(ident);
|
|
#endif
|
|
#ifdef BUILD_VIEWER
|
|
id = (uintptr_t)ident;
|
|
#endif
|
|
assert(id != 0);
|
|
}
|
|
return rpc_message_send_uint32(message, id);
|
|
}
|
|
|
|
static int do_recv_NPIdentifier(rpc_message_t *message, void *p_value)
|
|
{
|
|
int error;
|
|
uint32_t id;
|
|
|
|
if ((error = rpc_message_recv_uint32(message, &id)) < 0)
|
|
return error;
|
|
|
|
NPIdentifier ident = NULL;
|
|
if (id) {
|
|
#ifdef BUILD_WRAPPER
|
|
ident = id_lookup(id);
|
|
#endif
|
|
#ifdef BUILD_VIEWER
|
|
ident = (void *)(uintptr_t)id;
|
|
#endif
|
|
assert(ident != NULL);
|
|
}
|
|
*((NPIdentifier *)p_value) = ident;
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPUTF8 strings
|
|
*/
|
|
|
|
static int do_send_NPUTF8(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPUTF8 *string = (NPUTF8 *)p_value;
|
|
if (string == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
|
|
int len = strlen(string) + 1;
|
|
int error = rpc_message_send_uint32(message, len);
|
|
if (error < 0)
|
|
return error;
|
|
if (len > 0)
|
|
return rpc_message_send_bytes(message, (unsigned char *)string, len);
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPUTF8(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPUTF8 **string_p = (NPUTF8 **)p_value;
|
|
NPUTF8 *string = NULL;
|
|
|
|
uint32_t len;
|
|
int error = rpc_message_recv_uint32(message, &len);
|
|
if (error < 0)
|
|
return error;
|
|
if ((string = NPN_MemAlloc(len)) == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
if (len > 0) {
|
|
if ((error = rpc_message_recv_bytes(message, (unsigned char *)string, len)) < 0)
|
|
return error;
|
|
}
|
|
|
|
if (string_p)
|
|
*string_p = string;
|
|
else if (string)
|
|
NPN_MemFree(string);
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPString objects
|
|
*/
|
|
|
|
static int do_send_NPString(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPString *string = (NPString *)p_value;
|
|
if (string == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
|
|
int error = rpc_message_send_uint32(message, string->UTF8Length);
|
|
if (error < 0)
|
|
return error;
|
|
if (string->UTF8Length && string->UTF8Characters)
|
|
return rpc_message_send_bytes(message, (unsigned char *)string->UTF8Characters, string->UTF8Length);
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPString(rpc_message_t *message, void *p_value)
|
|
{
|
|
NPString *string = (NPString *)p_value;
|
|
if (string == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
string->UTF8Length = 0;
|
|
string->UTF8Characters = NULL;
|
|
|
|
int error = rpc_message_recv_uint32(message, &string->UTF8Length);
|
|
if (error < 0)
|
|
return error;
|
|
|
|
if ((string->UTF8Characters = NPN_MemAlloc(string->UTF8Length + 1)) == NULL)
|
|
return RPC_ERROR_NO_MEMORY;
|
|
if (string->UTF8Length > 0) {
|
|
if ((error = rpc_message_recv_bytes(message, (unsigned char *)string->UTF8Characters, string->UTF8Length)) < 0)
|
|
return error;
|
|
}
|
|
((char *)string->UTF8Characters)[string->UTF8Length] = '\0';
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* Process NPVariant objects
|
|
*/
|
|
|
|
static int do_send_NPVariant_helper(rpc_message_t *message, void *p_value,
|
|
bool pass_ref)
|
|
{
|
|
NPVariant *variant = (NPVariant *)p_value;
|
|
if (variant == NULL)
|
|
return RPC_ERROR_MESSAGE_ARGUMENT_INVALID;
|
|
|
|
int error = rpc_message_send_uint32(message, variant->type);
|
|
if (error < 0)
|
|
return error;
|
|
|
|
switch (variant->type) {
|
|
case NPVariantType_Void:
|
|
case NPVariantType_Null:
|
|
// nothing to do (initialized in receiver)
|
|
break;
|
|
case NPVariantType_Bool:
|
|
if ((error = rpc_message_send_uint32(message, variant->value.boolValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_Int32:
|
|
if ((error = rpc_message_send_int32(message, variant->value.intValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_Double:
|
|
if ((error = rpc_message_send_double(message, variant->value.doubleValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_String:
|
|
if ((error = do_send_NPString(message, &variant->value.stringValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_Object:
|
|
if ((error = do_send_NPObject_helper(message, variant->value.objectValue,
|
|
pass_ref)) < 0)
|
|
return error;
|
|
break;
|
|
}
|
|
|
|
// Clean up local data. If we had an NPObject,
|
|
// do_send_NPObject_pass_ref took care of it.
|
|
if (pass_ref && variant->type != NPVariantType_Object) {
|
|
NPN_ReleaseVariantValue(variant);
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_recv_NPVariant_helper(rpc_message_t *message, void *p_value,
|
|
bool pass_ref)
|
|
{
|
|
NPVariant *variant = (NPVariant *)p_value;
|
|
if (variant)
|
|
VOID_TO_NPVARIANT(*variant);
|
|
|
|
uint32_t type;
|
|
int error = rpc_message_recv_uint32(message, &type);
|
|
if (error < 0)
|
|
return error;
|
|
|
|
NPVariant result;
|
|
VOID_TO_NPVARIANT(result);
|
|
switch (type) {
|
|
case NPVariantType_Void:
|
|
VOID_TO_NPVARIANT(result);
|
|
break;
|
|
case NPVariantType_Null:
|
|
NULL_TO_NPVARIANT(result);
|
|
break;
|
|
case NPVariantType_Bool: {
|
|
uint32_t value;
|
|
if ((error = rpc_message_recv_uint32(message, &value)) < 0)
|
|
return error;
|
|
result.value.boolValue = value;
|
|
break;
|
|
}
|
|
case NPVariantType_Int32:
|
|
if ((error = rpc_message_recv_int32(message, &result.value.intValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_Double:
|
|
if ((error = rpc_message_recv_double(message, &result.value.doubleValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_String:
|
|
if ((error = do_recv_NPString(message, &result.value.stringValue)) < 0)
|
|
return error;
|
|
break;
|
|
case NPVariantType_Object:
|
|
if ((error = do_recv_NPObject_helper(message, &result.value.objectValue,
|
|
pass_ref)) < 0)
|
|
return error;
|
|
// NPVariant owns reference from do_recv_NPObject_helper.
|
|
break;
|
|
}
|
|
|
|
if (variant) {
|
|
*variant = result;
|
|
variant->type = type;
|
|
}
|
|
|
|
return RPC_ERROR_NO_ERROR;
|
|
}
|
|
|
|
static int do_send_NPVariant(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_send_NPVariant_helper(message, p_value, false);
|
|
}
|
|
|
|
static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_recv_NPVariant_helper(message, p_value, false);
|
|
}
|
|
|
|
static int do_send_NPVariant_pass_ref(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_send_NPVariant_helper(message, p_value, true);
|
|
}
|
|
|
|
static int do_recv_NPVariant_pass_ref(rpc_message_t *message, void *p_value)
|
|
{
|
|
return do_recv_NPVariant_helper(message, p_value, true);
|
|
}
|
|
|
|
/*
|
|
* Initialize marshalers for NPAPI types
|
|
*/
|
|
|
|
static const rpc_message_descriptor_t message_descs[] = {
|
|
{
|
|
RPC_TYPE_NPP,
|
|
sizeof(NPP),
|
|
do_send_NPP,
|
|
do_recv_NPP
|
|
},
|
|
{
|
|
RPC_TYPE_NPW_PLUGIN_INSTANCE,
|
|
sizeof(NPW_PluginInstance *),
|
|
do_send_NPW_PluginInstance,
|
|
do_recv_NPW_PluginInstance
|
|
},
|
|
{
|
|
RPC_TYPE_NP_STREAM,
|
|
sizeof(NPStream *),
|
|
do_send_NPStream,
|
|
do_recv_NPStream
|
|
},
|
|
{
|
|
RPC_TYPE_NP_BYTE_RANGE,
|
|
sizeof(NPByteRange *),
|
|
do_send_NPByteRange,
|
|
do_recv_NPByteRange
|
|
},
|
|
{
|
|
RPC_TYPE_NP_SAVED_DATA,
|
|
sizeof(NPSavedData *),
|
|
do_send_NPSavedData,
|
|
do_recv_NPSavedData
|
|
},
|
|
{
|
|
RPC_TYPE_NP_NOTIFY_DATA,
|
|
sizeof(void *),
|
|
do_send_NotifyData,
|
|
do_recv_NotifyData
|
|
},
|
|
{
|
|
RPC_TYPE_NP_RECT,
|
|
sizeof(NPRect),
|
|
do_send_NPRect,
|
|
do_recv_NPRect
|
|
},
|
|
{
|
|
RPC_TYPE_NP_WINDOW,
|
|
sizeof(NPWindow *),
|
|
do_send_NPWindow,
|
|
do_recv_NPWindow
|
|
},
|
|
{
|
|
RPC_TYPE_NP_EVENT,
|
|
sizeof(NPEvent),
|
|
do_send_NPEvent,
|
|
do_recv_NPEvent
|
|
},
|
|
{
|
|
RPC_TYPE_NP_PRINT,
|
|
sizeof(NPPrint),
|
|
do_send_NPPrint,
|
|
do_recv_NPPrint
|
|
},
|
|
{
|
|
RPC_TYPE_NP_FULL_PRINT,
|
|
sizeof(NPFullPrint),
|
|
do_send_NPFullPrint,
|
|
do_recv_NPFullPrint
|
|
},
|
|
{
|
|
RPC_TYPE_NP_EMBED_PRINT,
|
|
sizeof(NPEmbedPrint),
|
|
do_send_NPEmbedPrint,
|
|
do_recv_NPEmbedPrint
|
|
},
|
|
{
|
|
RPC_TYPE_NP_PRINT_DATA,
|
|
sizeof(NPPrintData),
|
|
do_send_NPPrintData,
|
|
do_recv_NPPrintData
|
|
},
|
|
{
|
|
RPC_TYPE_NP_OBJECT,
|
|
sizeof(NPObject *),
|
|
do_send_NPObject,
|
|
do_recv_NPObject
|
|
},
|
|
{
|
|
RPC_TYPE_NP_OBJECT_PASS_REF,
|
|
sizeof(NPObject *),
|
|
do_send_NPObject_pass_ref,
|
|
do_recv_NPObject_pass_ref
|
|
},
|
|
{
|
|
RPC_TYPE_NP_IDENTIFIER,
|
|
sizeof(NPIdentifier),
|
|
do_send_NPIdentifier,
|
|
do_recv_NPIdentifier
|
|
},
|
|
{
|
|
RPC_TYPE_NP_UTF8,
|
|
sizeof(NPUTF8 *),
|
|
do_send_NPUTF8,
|
|
do_recv_NPUTF8
|
|
},
|
|
{
|
|
RPC_TYPE_NP_STRING,
|
|
sizeof(NPString),
|
|
do_send_NPString,
|
|
do_recv_NPString
|
|
},
|
|
{
|
|
RPC_TYPE_NP_VARIANT,
|
|
sizeof(NPVariant),
|
|
do_send_NPVariant,
|
|
do_recv_NPVariant
|
|
},
|
|
{
|
|
RPC_TYPE_NP_VARIANT_PASS_REF,
|
|
sizeof(NPVariant),
|
|
do_send_NPVariant_pass_ref,
|
|
do_recv_NPVariant_pass_ref
|
|
}
|
|
};
|
|
|
|
int rpc_add_np_marshalers(rpc_connection_t *connection)
|
|
{
|
|
return rpc_connection_add_message_descriptors(connection, message_descs, sizeof(message_descs) / sizeof(message_descs[0]));
|
|
}
|