Update with current status
[gnash.git] / plugin / npapi / pluginScriptObject.cpp
blob59e8a060a11adbbd5966de78e952134792b839d9
1 //
2 // Copyright (C) 2010, 2011, 2012, 2014, 2016 Free Software Foundation, Inc
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
23 #include <map>
24 #include <string>
25 #if defined(HAVE_WINSOCK_H) && !defined(__OS2__)
26 # include <winsock2.h>
27 # include <windows.h>
28 # include <sys/stat.h>
29 # include <io.h>
30 # include <ws2tcpip.h>
31 #else
32 # include <sys/ioctl.h>
33 # include <unistd.h>
34 # include <poll.h>
35 #endif
36 #include "npapi.h"
37 #include "npruntime.h"
38 #include "plugin.h"
39 #include "callbacks.h"
40 #include "external.h"
41 #include "pluginScriptObject.h"
43 extern NPNetscapeFuncs NPNFuncs;
45 namespace gnash {
47 // NPClass of GnashPluginScriptObject
48 static NPClass GnashPluginScriptObjectClass = {
49 NP_CLASS_STRUCT_VERSION,
50 GnashPluginScriptObject::marshalAllocate,
51 GnashPluginScriptObject::marshalDeallocate,
52 GnashPluginScriptObject::marshalInvalidate,
53 GnashPluginScriptObject::marshalHasMethod,
54 GnashPluginScriptObject::marshalInvoke,
55 GnashPluginScriptObject::marshalInvokeDefault,
56 GnashPluginScriptObject::marshalHasProperty,
57 GnashPluginScriptObject::marshalGetProperty,
58 GnashPluginScriptObject::marshalSetProperty,
59 GnashPluginScriptObject::marshalRemoveProperty,
60 GnashPluginScriptObject::marshalEnumerate,
61 GnashPluginScriptObject::marshalConstruct
64 void
65 printNPVariant(const NPVariant *value)
67 if (NPVARIANT_IS_DOUBLE(*value)) {
68 double num = NPVARIANT_TO_DOUBLE(*value);
69 log_debug("is double, value %g", num);
70 } else if (NPVARIANT_IS_STRING(*value)) {
71 std::string str = NPStringToString(NPVARIANT_TO_STRING(*value));
72 log_debug("is string, value %s", str);
73 } else if (NPVARIANT_IS_BOOLEAN(*value)) {
74 bool flag = NPVARIANT_TO_BOOLEAN(*value);
75 log_debug("is boolean, value %d", flag);
76 } else if (NPVARIANT_IS_INT32(*value)) {
77 int num = NPVARIANT_TO_INT32(*value);
78 log_debug("is int, value %d", num);
79 } else if (NPVARIANT_IS_NULL(*value)) {
80 log_debug("value is null");
81 } else if (NPVARIANT_IS_VOID(*value)) {
82 log_debug("value is void");
83 } else if (NPVARIANT_IS_OBJECT(*value)) {
84 log_debug("value is object");
89 // The methods for GnashPluginScriptObject start here.
92 void
93 GnashPluginScriptObject::AddProperty(const std::string &name,
94 const std::string &val)
96 NPIdentifier id = NPN_GetStringIdentifier(name.c_str());
98 NPVariant strvar;
99 STRINGN_TO_NPVARIANT(val.c_str(), static_cast<int>(val.size()), strvar);
100 SetProperty(id, strvar);
103 void
104 GnashPluginScriptObject::AddProperty(const std::string &name, double num)
106 NPIdentifier id = NPN_GetStringIdentifier(name.c_str());
107 NPVariant value;
108 DOUBLE_TO_NPVARIANT(num, value);
109 SetProperty(id, value);
112 void
113 GnashPluginScriptObject::AddProperty(const std::string &name, int num)
115 NPIdentifier id = NPN_GetStringIdentifier(name.c_str());
116 NPVariant value;
117 INT32_TO_NPVARIANT(num, value);
118 SetProperty(id, value);
121 // Sets up the property and method identifier arrays used by the browser
122 // via the hasProperty and hasMethod fuction pointers
123 void
124 GnashPluginScriptObject::initializeIdentifiers()
126 // log_debug("initializeIdentifiers");
128 // NPN_Status(nppinstance, __FUNCTION__);
130 // http://www.adobe.com/support/flash/publishexport/scriptingwithflash/scriptingwithflash_04.html
132 // We maintain an internal property for our version number, rather
133 // than asking the player.
134 AddProperty("$version", "10,1,r999");
135 // id and name appear to be the same tag, but differeing browsers access
136 // one or the other, or both.
137 // name=send_this_page_swf
138 AddProperty("name", "Hello World");
139 // id=send_this_page_swf
140 AddProperty("id", "Hello World");
142 // http://s.ytimg.com/yt/swf/watch-vfl161193.swf
143 AddProperty("src", "example");
144 AddProperty("align", "middle");
145 AddProperty("quality", "high");
146 AddProperty("bgcolor", "#FFFFFF");
147 AddProperty("allowScriptAccess", "sameDomain");
148 AddProperty("type", "application/x-shockwave-flash");
149 AddProperty("codebase", "http://www.getgnash.org");
150 AddProperty("pluginspage", "http://www.getgnash.org");
152 AddProperty("classid", "2b70f2b1-fc72-4734-bb81-4eb2a7713e49");
153 AddProperty("movie", "unknown");
154 AddProperty("width", 0);
155 AddProperty("height", 0);
156 AddProperty("vspace", 0);
157 AddProperty("hspace", 0);
158 AddProperty("class", "class unknown");
159 AddProperty("title", "title unknown");
160 AddProperty("accesskey", 0);
161 AddProperty("name", "name unknown");
162 AddProperty("tabindex", 8);
163 AddProperty("FlashVars", "flashVars unknown");
165 // Javascript and flash events
166 AddProperty("onafterupdate", "unknown");
167 AddProperty("onbeforeupdate", "unknown");
168 AddProperty("onblur", "unknown");
169 AddProperty("oncellchange", "unknown");
170 AddProperty("onclick", "unknown");
171 AddProperty("ondblClick", "unknown");
172 AddProperty("ondrag", "unknown");
173 AddProperty("ondragend", "unknown");
174 AddProperty("ondragenter", "unknown");
175 AddProperty("ondragleave", "unknown");
176 AddProperty("ondragover", "unknown");
177 AddProperty("ondrop", "unknown");
178 AddProperty("onfinish", "unknown");
179 AddProperty("onfocus", "unknown");
180 AddProperty("onhelp", "unknown");
181 AddProperty("onmousedown", "unknown");
182 AddProperty("onmouseup", "unknown");
183 AddProperty("onmouseover", "unknown");
184 AddProperty("onmousemove", "unknown");
185 AddProperty("onmouseout", "unknown");
186 AddProperty("onkeypress", "unknown");
187 AddProperty("onkeydown", "unknown");
188 AddProperty("onkeyup", "unknown");
189 AddProperty("onload", "unknown");
190 AddProperty("onlosecapture", "unknown");
191 AddProperty("onpropertychange", "unknown");
192 AddProperty("onreadystatechange", "unknown");
193 AddProperty("onrowsdelete", "unknown");
194 AddProperty("onrowenter", "unknown");
195 AddProperty("onrowexit", "unknown");
196 AddProperty("onrowsinserted", "unknown");
197 AddProperty("onstart", "");
198 AddProperty("onscroll", "unknown");
199 AddProperty("onbeforeeditfocus", "unknown");
200 AddProperty("onactivate", "unknown");
201 AddProperty("onbeforedeactivate", "unknown");
202 AddProperty("ondeactivate", "unknown");
204 // Add the default methods
205 NPIdentifier id = NPN_GetStringIdentifier("SetVariable");
206 AddMethod(id, SetVariableCallback);
208 id = NPN_GetStringIdentifier("GetVariable");
209 AddMethod(id, GetVariableCallback);
211 id = NPN_GetStringIdentifier("GotoFrame");
212 AddMethod(id, GotoFrame);
214 id = NPN_GetStringIdentifier("IsPlaying");
215 AddMethod(id, IsPlaying);
217 id = NPN_GetStringIdentifier("LoadMovie");
218 AddMethod(id, LoadMovie);
220 id = NPN_GetStringIdentifier("Pan");
221 AddMethod(id, Pan);
223 id = NPN_GetStringIdentifier("PercentLoaded");
224 AddMethod(id, PercentLoaded);
226 id = NPN_GetStringIdentifier("Play");
227 AddMethod(id, Play);
229 id = NPN_GetStringIdentifier("Rewind");
230 AddMethod(id, Rewind);
232 id = NPN_GetStringIdentifier("SetZoomRect");
233 AddMethod(id, SetZoomRect);
235 id = NPN_GetStringIdentifier("StopPlay");
236 AddMethod(id, StopPlay);
238 id = NPN_GetStringIdentifier("Zoom");
239 AddMethod(id, Zoom);
241 id = NPN_GetStringIdentifier("TotalFrames");
242 AddMethod(id, TotalFrames);
244 // id = NPN_GetStringIdentifier("TestASMethod");
245 // AddMethod(id, remoteCallback);
248 // Constructor
249 GnashPluginScriptObject::GnashPluginScriptObject()
250 : nppinstance (nullptr),
251 _controlfd(-1),
252 _hostfd(-1)
254 // log_debug(__PRETTY_FUNCTION__);
256 initializeIdentifiers();
260 // Constructor
261 GnashPluginScriptObject::GnashPluginScriptObject(NPP npp)
262 : nppinstance (npp),
263 _controlfd(-1),
264 _hostfd(-1)
266 // log_debug(__PRETTY_FUNCTION__);
268 initializeIdentifiers();
272 // Destructor
273 GnashPluginScriptObject::~GnashPluginScriptObject()
275 // log_debug(__PRETTY_FUNCTION__);
278 // Marshal Functions
279 NPClass *
280 GnashPluginScriptObject::marshalGetNPClass()
282 // log_debug(__PRETTY_FUNCTION__);
283 return &GnashPluginScriptObjectClass;
286 NPObject *
287 GnashPluginScriptObject::marshalAllocate (NPP npp, NPClass */* aClass */)
289 // log_debug(__PRETTY_FUNCTION__);
290 return new GnashPluginScriptObject(npp);
294 void
295 GnashPluginScriptObject::marshalDeallocate (NPObject *npobj)
297 // log_debug(__PRETTY_FUNCTION__);
298 delete (GnashPluginScriptObject *)npobj;
301 void
302 GnashPluginScriptObject::marshalInvalidate (NPObject */* npobj */)
304 // log_debug(__PRETTY_FUNCTION__);
308 bool
309 GnashPluginScriptObject::marshalHasMethod (NPObject *npobj, NPIdentifier name)
311 // log_debug(__PRETTY_FUNCTION__);
313 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
315 #if 0
316 log_debug("Checking for Method: ");
317 if (NPN_IdentifierIsString(name)) {
318 log_debug("%s", NPN_UTF8FromIdentifier(name));
319 } else {
320 log_debug("%d", NPN_IntFromIdentifier(name));
322 #endif
324 return gpso->HasMethod(name);
327 bool
328 GnashPluginScriptObject::marshalInvoke (NPObject *npobj, NPIdentifier name,
329 const NPVariant *args, uint32_t argCount,
330 NPVariant *result)
332 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
334 return gpso->Invoke(npobj, name, args, argCount, result);
337 bool
338 GnashPluginScriptObject::marshalInvokeDefault (NPObject *npobj,
339 const NPVariant *args,
340 uint32_t argCount,
341 NPVariant *result)
343 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
345 return gpso->InvokeDefault(args, argCount, result);
348 bool
349 GnashPluginScriptObject::marshalHasProperty (NPObject *npobj, NPIdentifier name)
351 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
353 return gpso->HasProperty(name);
356 bool
357 GnashPluginScriptObject::marshalGetProperty (NPObject *npobj, NPIdentifier name,
358 NPVariant *result)
360 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
362 return gpso->GetProperty(name, result);
365 bool
366 GnashPluginScriptObject::marshalSetProperty (NPObject *npobj, NPIdentifier name,
367 const NPVariant *value)
369 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
370 return gpso->SetProperty(name, *value);
373 bool
374 GnashPluginScriptObject::marshalRemoveProperty (NPObject *npobj, NPIdentifier name)
376 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
377 return gpso->RemoveProperty(name);
380 bool
381 GnashPluginScriptObject::marshalEnumerate (NPObject *npobj, void***identifier,
382 uint32_t *count)
384 log_debug(__PRETTY_FUNCTION__);
386 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
387 return gpso->Enumerate(identifier, count);
389 return false;
392 bool
393 GnashPluginScriptObject::marshalConstruct (NPObject *npobj, const NPVariant *data,
394 uint32_t count, NPVariant *result)
396 log_debug(__PRETTY_FUNCTION__);
398 GnashPluginScriptObject *gpso = (GnashPluginScriptObject *)npobj;
399 return gpso->Construct(data, count, result);
401 return false;
404 bool
405 GnashPluginScriptObject::HasProperty(NPIdentifier name)
407 #if 0
408 log_debug("Checking for Property \"");
409 if (NPN_IdentifierIsString(name)) {
410 log_debug("%s\"...", NPN_UTF8FromIdentifier(name));
411 } else {
412 log_debug("%d\"...", NPN_IntFromIdentifier(name));
414 #endif
416 return _properties.find(name) != _properties.end();
419 bool
420 GnashPluginScriptObject::GetProperty(NPIdentifier name, NPVariant *result)
422 if (NPN_IdentifierIsString(name)) {
423 log_debug("Getting Property \"%s\"...", NPN_UTF8FromIdentifier(name));
424 } else {
425 log_debug("Getting Property \"%d\"...", NPN_IntFromIdentifier(name));
428 std::map<NPIdentifier, GnashNPVariant>::const_iterator it;
429 it = _properties.find(name);
430 if (it == _properties.end()) {
431 return false;
434 const GnashNPVariant& val = it->second;
435 val.copy(*result);
437 return true;
440 bool
441 GnashPluginScriptObject::SetProperty(NPIdentifier name, const NPVariant& value)
443 _properties[name] = value;
445 return false;
448 bool
449 GnashPluginScriptObject::RemoveProperty(NPIdentifier name)
451 std::map<NPIdentifier, GnashNPVariant>::iterator it;
452 it = _properties.find(name);
453 if (it != _properties.end()) {
454 _properties.erase(it);
455 return true;
458 return false;
461 bool
462 GnashPluginScriptObject::Enumerate(NPIdentifier **/*identifier */, uint32_t */* count */)
464 log_debug(__PRETTY_FUNCTION__);
466 return false;
469 bool
470 GnashPluginScriptObject::Construct(const NPVariant */* args */, uint32_t /* argCount */,
471 NPVariant */* result */)
473 log_debug(__PRETTY_FUNCTION__);
475 return false;
478 bool
479 GnashPluginScriptObject::HasMethod(NPIdentifier name)
481 #if 0
482 log_debug("Checking for Method \"");
483 if (NPN_IdentifierIsString(name)) {
484 log_debug("%s\"...", NPN_UTF8FromIdentifier(name));
485 } else {
486 log_debug("%d\"...", NPN_IntFromIdentifier(name));
488 #endif
490 return _methods.find(name) != _methods.end();
493 bool
494 GnashPluginScriptObject::Invoke(NPObject */* npobj */, NPIdentifier name,
495 const NPVariant *args, uint32_t argCount,
496 NPVariant *result)
498 // log_debug(__PRETTY_FUNCTION__);
500 #if 1
501 if (NPN_IdentifierIsString(name)) {
502 log_debug("Invoking Method \"%s\"...", NPN_UTF8FromIdentifier(name));
503 } else {
504 log_debug("Invoking Method: \"%d\"...", NPN_IntFromIdentifier(name));
506 // log_debug("SCRIPT OBJECT invoke %s: %x", NPN_UTF8FromIdentifier(name),
507 // (void *)npobj);
508 #endif
510 std::map<NPIdentifier, NPInvokeFunctionPtr>::iterator it;
511 it = _methods.find(name);
512 if (it != _methods.end()) {
513 // log_debug("FOUND Method \"%s\"!", NPN_UTF8FromIdentifier(name));
514 NPInvokeFunctionPtr func = it->second;
515 return func(this, name, args, argCount, result);
516 } else {
517 log_error("Couldn't find Method \"%s\"", NPN_UTF8FromIdentifier(name));
520 return false;
522 // return NPN_Invoke(nppinstance, this, name, args, argCount, result);
525 bool
526 GnashPluginScriptObject::InvokeDefault(const NPVariant */* args */,
527 uint32_t /* argCount */, NPVariant */* result */)
529 log_debug(__PRETTY_FUNCTION__);
530 #if 0
531 log_debug("Invoking Default Method \"");
532 if (NPN_IdentifierIsString(name)) {
533 log_debug("%s\"...", NPN_UTF8FromIdentifier(name));
534 } else {
535 log_debug("%d\"...", NPN_IntFromIdentifier(name));
537 #endif
539 return false;
542 bool
543 GnashPluginScriptObject::AddMethod(NPIdentifier name, NPInvokeFunctionPtr func)
545 // log_debug(__PRETTY_FUNCTION__);
547 #if 0
548 if (NPN_IdentifierIsString(name)) {
549 log_debug("Adding Method \"%s\"...", NPN_UTF8FromIdentifier(name));
550 } else {
551 log_debug("Adding Method \"%d\"...", NPN_IntFromIdentifier(name));
553 #endif
555 _methods[name] = func;
557 return true;
560 // SetVariable sends a message to the player that looks like this:
561 // "Command Name Type value\n", ie... "SetVariable var1 string value1\n"
562 bool
563 GnashPluginScriptObject::SetVariable(const std::string &name,
564 const NPVariant& value)
566 std::vector<std::string> iargs;
567 std::string str = plugin::ExternalInterface::makeString(name);
568 iargs.push_back(str);
569 str = plugin::ExternalInterface::convertNPVariant(&value);
570 iargs.push_back(str);
571 str = plugin::ExternalInterface::makeInvoke("SetVariable", iargs);
573 log_debug("Trying to set a value for %s.", name);
575 // Write the message to the Control FD.
576 size_t ret = writePlayer(str);
577 // Unless we wrote the same amount of data as the message contained,
578 // something went wrong.
579 if (ret != str.size()) {
580 log_error("Couldn't set the variable, network problems.");
581 return false;
584 return true;
587 // GetVariable sends a message to the player that looks like this:
588 // "Command Name\n", ie... "GetVariable var1\n". Then it waits
589 // for the response with the type and value.
590 GnashNPVariant
591 GnashPluginScriptObject::GetVariable(const std::string &name)
593 std::vector<std::string> iargs;
594 std::string str = plugin::ExternalInterface::makeString(name);
595 iargs.push_back(str);
596 str = plugin::ExternalInterface::makeInvoke("GetVariable", iargs);
598 log_debug("Trying to get a value for %s.", name);
600 size_t ret = writePlayer(str);
601 if (ret != str.size()) {
602 // If all the browser wants is the version, we don't need to
603 // ask the standalone player for this value. YouTube at
604 // least depends on this for some pages which want this to
605 // be greater than 8.0.0. This appears to potentially be
606 // Google's way of trying to revent downloaders, as this requires
607 // plugin support.
608 NPVariant value;
609 if (name == "$version") {
610 STRINGN_TO_NPVARIANT("LNX 10,0,r999", 13, value);
611 } else {
612 log_error("Couldn't send GetVariable request, network problems.");
613 NULL_TO_NPVARIANT(value);
615 return value;
618 // Have the read function allocate the memory
619 std::string data = readPlayer();
620 if (data.empty()) {
621 return GnashNPVariant();
624 GnashNPVariant parsed = plugin::ExternalInterface::parseXML(this, data);
626 printNPVariant(&parsed.get());
628 return parsed;
631 void
632 GnashPluginScriptObject::setControlFD(int x)
634 // log_debug("%s: %d", __FUNCTION__, x);
635 _controlfd = x; // FIXME: this should go away
639 GnashPluginScriptObject::getControlFD()
641 // log_debug("getControlFD: %d", controlfd);
643 return _controlfd;
646 void
647 GnashPluginScriptObject::setHostFD(int x)
649 // log_debug("%s: %d", __FUNCTION__, x);
650 _hostfd = x; // FIXME: this should go away
654 GnashPluginScriptObject::getHostFD()
656 // log_debug("getControlFD: %d", controlfd);
658 return _hostfd;
662 // Write to the standalone player over the control socket
664 GnashPluginScriptObject::writePlayer(const std::string &data)
666 return writePlayer(_controlfd, data);
670 GnashPluginScriptObject::writePlayer(int fd, const std::string &data)
672 // log_debug(__PRETTY_FUNCTION__);
674 // log_debug("Writing data to fd #%d:\n %s", fd, data);
676 if (fd > 2) {
677 return ::write(fd, data.c_str(), data.size());
680 return 0;
683 std::string
684 GnashPluginScriptObject::readPlayer()
686 return readPlayer(_hostfd);
689 std::string
690 GnashPluginScriptObject::readPlayer(int fd)
692 std::string empty;
694 if (fd <= 0) {
695 log_error("Invalid fd passed");
696 return empty;
699 // Wait for some data from the player
700 int bytes = 0;
702 pollfd pfds[1] = { pollfd() };
703 pfds[0].fd = fd;
704 pfds[0].events = POLLIN;
706 int rv = poll(pfds, 1 /* arraySize */, 2000 /* ms */);
708 // No data yet
709 if (rv <= 0) {
710 return empty;
713 #ifndef _WIN32
714 rv = ioctl(fd, FIONREAD, &bytes);
715 #else
716 rv = ioctlSocket(fd, FIONREAD, &bytes);
717 #endif
718 if (rv < 0) {
719 log_error("FIONREAD ioctl failed, unable to get network buffer length");
720 return empty;
722 log_debug("There are %d bytes in the network buffer", bytes);
724 if (bytes <= 0) {
725 return empty;
728 char buf[bytes];
730 int ret = ::read(fd, buf, bytes);
731 if (ret <= 0 || ret > bytes) {
732 return empty;
735 return std::string(buf, ret);
741 } // end of gnash namespace
743 // local Variables:
744 // mode: C++
745 // indent-tabs-mode: nil
746 // End: