1 // ExternalInterface.cpp: ActionScript "ExternalInterface" support
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014,
4 // 2015, 2016 Free Software Foundation, Inc
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "ExternalInterface.h"
26 #include <boost/algorithm/string/erase.hpp>
30 # include <sys/filio.h> // for FIONREAD
33 #include "GnashSystemNetHeaders.h"
34 #include "GnashSystemFDHeaders.h"
36 #include "StringPredicates.h"
38 #include "Global_as.h"
42 #include "as_object.h"
45 #include "namedStrings.h"
46 #include "Global_as.h"
47 #include "PropertyList.h"
48 #include "movie_root.h"
55 class Enumerator
: public KeyVisitor
58 Enumerator(std::vector
<ObjectURI
>& uris
) : _uris(uris
) {}
59 void operator()(const ObjectURI
& u
) {
63 std::vector
<ObjectURI
>& _uris
;
68 /// Convert an AS object to an XML string.
70 ExternalInterface::_objectToXML(as_object
*obj
)
72 // GNASH_REPORT_FUNCTION;
74 if ( ! _visited
.insert(obj
).second
) {
83 // Get all the properties
85 string_table
& st
= vm
.getStringTable();
86 typedef std::vector
<ObjectURI
> URIs
;
90 for (URIs::const_reverse_iterator i
= uris
.rbegin(), e
= uris
.rend();
92 as_value val
= getMember(*obj
, *i
);
93 const std::string
& id
= i
->toString(st
);
94 ss
<< "<property id=\"" << id
<< "\">";
105 /// Convert an AS object to an XML string.
107 ExternalInterface::_toXML(const as_value
&val
)
109 // GNASH_REPORT_FUNCTION;
111 std::stringstream ss
;
113 if (val
.is_string()) {
114 ss
<< "<string>" << val
.to_string() << "</string>";
115 } else if (val
.is_number()) {
116 ss
<< "<number>" << val
.to_string() << "</number>";
117 } else if (val
.is_undefined()) {
119 } else if (val
.is_null()) {
121 // Exception isn't listed in any docs, but we'll use it for
122 // marshallExceptions.
123 } else if (val
.is_exception()) {
124 ss
<< "<exception>" << val
.to_string()<< "</exception>";
125 } else if (val
.is_bool()) {
126 ss
<< (val
.to_bool(8) ? "<true/>" : "<false/>");
127 // Function also isn't listed, but it's the only other type
128 // supported by as_value, so leaving it out doesn't seem right.
129 } else if (val
.is_function()) {
130 ss
<< "<function>" << val
.to_string() << "</function>";
131 } else if (val
.is_object()) {
132 as_object
*obj
= val
.get_object();
133 ss
<< _objectToXML(obj
);
135 log_error(_("Can't convert unknown type %d"), val
.to_string());
141 std::unique_ptr
<ExternalInterface::invoke_t
>
142 ExternalInterface::ExternalEventCheck(int fd
)
144 // GNASH_REPORT_FUNCTION;
146 std::unique_ptr
<ExternalInterface::invoke_t
> error
;
150 ioctlSocket(fd
, FIONREAD
, &bytes
);
154 log_debug("There are %d bytes in the network buffer", bytes
);
155 std::unique_ptr
<char[]> buffer(new char[bytes
+ 1]);
156 // Since we know how bytes are in the network buffer, allocate
157 // some memory to read the data.
158 // terminate incase we want to treat the data like a string.
160 const int ret
= ::read(fd
, buffer
.get(), bytes
);
162 return parseInvoke(std::string(buffer
.get(), ret
));
169 // Parse the XML Invoke message, which looks like this:
171 // <invoke name="LoadMovie" returntype="xml">
173 // <number>2</number>
174 // <string>bogus</string>
178 std::unique_ptr
<ExternalInterface::invoke_t
>
179 ExternalInterface::parseInvoke(const std::string
&xml
)
181 std::unique_ptr
<ExternalInterface::invoke_t
> invoke
;
186 invoke
.reset(new ExternalInterface::invoke_t
);
187 std::string::size_type start
= 0;
188 std::string::size_type end
;
191 // Look for the ending > in the first part of the data for the tag
193 if (end
!= std::string::npos
) {
194 end
++; // go past the > character
195 tag
= xml
.substr(start
, end
);
196 // Look for the easy ones first
197 if (tag
.substr(0, 7) == "<invoke") {
198 // extract the name of the method to invoke
199 start
= tag
.find("name=") + 5;
200 end
= tag
.find(" ", start
);
201 invoke
->name
= tag
.substr(start
, end
-start
);
202 // Ignore any quote characters around the string
203 boost::erase_first(invoke
->name
, "\"");
204 boost::erase_last(invoke
->name
, "\"");
206 // extract the return type of the method
207 start
= tag
.find("returntype=") + 11;
208 end
= tag
.find(">", start
);
209 invoke
->type
= tag
.substr(start
, end
-start
);
210 // Ignore any quote characters around the string
211 boost::erase_first(invoke
->type
, "\"");
212 boost::erase_last(invoke
->type
, "\"");
214 // extract the arguments to the method
215 start
= xml
.find("<arguments>");
216 end
= xml
.find("</invoke");
217 tag
= xml
.substr(start
, end
-start
);
218 invoke
->args
= ExternalInterface::parseArguments(tag
);
226 ExternalInterface::parseXML(const std::string
&xml
)
232 std::string::size_type start
= 0;
233 std::string::size_type end
;
237 // Look for the ending > in the first part of the data for the tag
239 if (end
!= std::string::npos
) {
240 end
++; // go past the > character
241 tag
= xml
.substr(start
, end
);
242 // Look for the easy ones first
243 if (tag
== "<null/>") {
245 } else if (tag
== "<void/>") {
246 value
.set_undefined();
247 } else if (tag
== "<true/>") {
248 value
.set_bool(true);
249 } else if (tag
== "<false/>") {
250 value
.set_bool(false);
251 } else if (tag
== "<number>") {
253 end
= xml
.find("</number>");
254 std::string str
= xml
.substr(start
, end
-start
);
255 double num
= strtod(str
.c_str(), nullptr);
256 value
.set_double(num
);
257 } else if (tag
== "<string>") {
259 end
= xml
.find("</string>");
260 std::string str
= xml
.substr(start
, end
-start
);
261 value
.set_string(str
);
265 // log_debug("Argument is: %s", value.to_string());
269 std::vector
<as_value
>
270 ExternalInterface::parseArguments(const std::string
&xml
)
272 // GNASH_REPORT_FUNCTION;
274 std::vector
<as_value
> args
;
275 std::string::size_type start
= 0;
276 std::string::size_type end
;
279 std::string data
= xml
;
280 std::string tag
= "<arguments>";
281 start
= data
.find(tag
);
282 if (start
!= std::string::npos
) {
283 data
.erase(0, tag
.size());
285 while (!data
.empty()) {
287 start
= data
.find("<", 1); // start past the opening <
288 end
= data
.find(">", start
) + 1;
289 std::string sub
= data
.substr(0, end
);
290 if (data
== "</arguments>") {
293 args
.push_back(parseXML(sub
));
300 // Create an Invoke message for the standalone Gnash
302 ExternalInterface::makeInvoke (const std::string
&method
,
303 const std::vector
<as_value
> &args
)
305 std::stringstream ss
;
306 std::vector
<as_value
>::const_iterator it
;
308 ss
<< "<invoke name=\"" << method
<< "\" returntype=\"xml\">";
310 for (it
=args
.begin(); it
!= args
.end(); ++it
) {
311 // Should we avoid re-serializing the same object ?
315 ss
<< "</arguments>";
318 // Add a CR on the end so the output is more readable on the other
319 // end. XL should be ignoring the CR anyway.
326 ExternalInterface::writeBrowser(int fd
, const std::string
&data
)
329 return ::write(fd
, data
.c_str(), data
.size());
336 ExternalInterface::readBrowser(int fd
)
340 struct timeval timeout
;
344 // Wait for some data from the player
349 fdstatus
= select(fd
+ 1, &fdset
, nullptr, nullptr, &timeout
);
351 // Timed out, return no data
352 log_error("Host container communication timed out\n");
354 } else if(fdstatus
< 0) {
355 // select() failed, return no data
356 log_error("select failed on host container communication: %s",
357 std::strerror(errno
));
361 // Check for the size of available data
362 ioctlSocket(fd
, FIONREAD
, &bytes
);
364 // No more data to read (end of stream, or stream error)
368 log_debug("There are %d bytes in the network buffer", bytes
);
370 std::string
buf(bytes
, '\0');
372 const int ret
= ::read(fd
, &buf
[0], bytes
);
384 } // end of gnash namespace
388 // indent-tabs-mode: nil