nspluginwrapper/src/npw-rpc.c

920 lines
21 KiB
C

/*
* npw-rpc.c - Remote Procedure Calls (NPAPI specialisation)
*
* nspluginwrapper (C) 2005-2006 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sysdeps.h"
#include <assert.h>
#include "rpc.h"
#include "npw-rpc.h"
#include "utils.h"
#define XP_UNIX 1
#define MOZ_X11 1
#include <npapi.h>
#include <npruntime.h>
#include "npruntime-impl.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:
type = RPC_TYPE_BOOLEAN;
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:
type = RPC_TYPE_STRING;
break;
case NPPVpluginWindowBool:
case NPPVpluginTransparentBool:
case NPPVpluginWindowSize:
case NPPVpluginTimerInterval:
type = RPC_TYPE_INT32;
break;
case NPPVpluginNeedsXEmbed:
type = RPC_TYPE_BOOLEAN;
break;
case NPPVpluginScriptableNPObject:
type = RPC_TYPE_NP_OBJECT;
break;
default:
type = RPC_ERROR_GENERIC;
break;
}
return type;
}
/*
* Process NPP objects
*/
typedef struct {
NPP instance;
uint32_t instance_id;
} PluginInstance;
#ifdef BUILD_WRAPPER
#define PLUGIN_INSTANCE(instance) ((instance)->pdata)
#endif
#ifdef BUILD_VIEWER
#define PLUGIN_INSTANCE(instance) ((instance)->ndata)
#endif
static int do_send_NPP(rpc_message_t *message, void *p_value)
{
uint32_t instance_id = 0;
NPP instance = (NPP)p_value;
if (instance) {
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
if (plugin)
instance_id = plugin->instance_id;
}
return rpc_message_send_uint32(message, instance_id);
}
static int do_recv_NPP(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;
PluginInstance *plugin = id_lookup(instance_id);
if (instance_id && plugin == NULL)
npw_printf("ERROR: passing an unknown instance\n");
if (plugin && plugin->instance == NULL)
npw_printf("ERROR: passing a NULL instance through plugin instance id\n");
*((NPP *)p_value) = plugin ? plugin->instance : NULL;
return RPC_ERROR_NO_ERROR;
}
/*
* Process NPStream objects
*/
typedef struct {
NPStream *stream;
uint32_t stream_id;
} StreamInstance;
#ifdef BUILD_WRAPPER
#define STREAM_INSTANCE(instance) ((instance)->pdata)
#endif
#ifdef BUILD_VIEWER
#define STREAM_INSTANCE(instance) ((instance)->ndata)
#endif
static int do_send_NPStream(rpc_message_t *message, void *p_value)
{
uint32_t stream_id = 0;
NPStream *stream = (NPStream *)p_value;
if (stream) {
StreamInstance *sip = 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;
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 = malloc(sizeof(*save_area))) == NULL)
return RPC_ERROR_NO_MEMORY;
if ((buf = malloc(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) {
free(save_area->buf);
free(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_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, (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;
}
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_id;
int32_t window_type;
int error;
if ((error = rpc_message_recv_uint32(message, &window_id)) < 0)
return error;
*window_p = NULL;
if (window_id) {
if ((window = *window_p = malloc(sizeof(NPWindow))) == NULL)
return RPC_ERROR_NO_MEMORY;
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;
window->type = window_type;
window->ws_info = NULL; // to be filled in by the plugin
window->window = (void *)(Window)window_id;
}
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_NPWindow(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_NPWindow(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
*/
// XXX propagate reference counters?
static int do_send_NPObject(rpc_message_t *message, void *p_value)
{
uint32_t npobj_id = 0;
NPObject *npobj = (NPObject *)p_value;
if (npobj) {
NPObjectInfo *npobj_info = npobject_info_lookup(npobj);
if (npobj_info)
npobj_id = npobj_info->npobj_id;
#ifdef BUILD_WRAPPER
else {
// create a new mapping (browser-side)
if ((npobj_info = npobject_info_new(npobj)) == NULL)
return RPC_ERROR_NO_MEMORY;
npobj_id = npobj_info->npobj_id;
npobject_associate(npobj, npobj_info);
}
#endif
assert(npobj_id != 0);
}
return rpc_message_send_uint32(message, npobj_id);
}
static int do_recv_NPObject(rpc_message_t *message, void *p_value)
{
int error;
uint32_t npobj_id;
if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0)
return error;
NPObject *npobj = NULL;
if (npobj_id) {
npobj = npobject_lookup(npobj_id);
#ifdef BUILD_VIEWER
// create a new mapping (plugin-side)
if (npobj == NULL) {
if ((npobj = npobject_new(npobj_id, NULL, NULL)) == NULL)
return RPC_ERROR_NO_MEMORY;
}
#endif
assert(npobj != NULL);
}
*((NPObject **)p_value) = npobj;
return RPC_ERROR_NO_ERROR;
}
/*
* 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 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->utf8length > 0) {
// calloc() will make the string nul-terminated, even if utf8characters is a const NPUTF8 *
if ((string->utf8characters = calloc(1, string->utf8length + 1)) == NULL)
return RPC_ERROR_NO_MEMORY;
if ((error = rpc_message_recv_bytes(message, (unsigned char *)string->utf8characters, string->utf8length)) < 0)
return error;
}
return RPC_ERROR_NO_ERROR;
}
/*
* Process NPVariant objects
*/
static int do_send_NPVariant(rpc_message_t *message, void *p_value)
{
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_uint32(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(message, variant->value.objectValue)) < 0)
return error;
break;
}
return RPC_ERROR_NO_ERROR;
}
static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
{
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_uint32(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(message, &result.value.objectValue)) < 0)
return error;
break;
}
if (variant) {
*variant = result;
variant->type = type;
}
return RPC_ERROR_NO_ERROR;
}
/*
* 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_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_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_IDENTIFIER,
sizeof(NPIdentifier),
do_send_NPIdentifier,
do_recv_NPIdentifier
},
{
RPC_TYPE_NP_STRING,
sizeof(NPString),
do_send_NPString,
do_recv_NPString
},
{
RPC_TYPE_NP_VARIANT,
sizeof(NPVariant),
do_send_NPVariant,
do_recv_NPVariant
}
};
int rpc_add_np_marshalers(void)
{
return rpc_message_add_callbacks(message_descs, sizeof(message_descs) / sizeof(message_descs[0]));
}