1 // ExternalInterface.cpp: ActionScript "ExternalInterface" support
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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>
27 #include <boost/shared_ptr.hpp>
28 #include <boost/scoped_array.hpp>
31 #include "GnashSystemNetHeaders.h"
32 #include "GnashSystemFDHeaders.h"
34 #include "StringPredicates.h"
36 #include "Global_as.h"
37 #include "smart_ptr.h" // for boost intrusive_ptr
41 #include "as_object.h"
44 #include "namedStrings.h"
45 #include "Global_as.h"
46 #include "PropertyList.h"
47 #include "movie_root.h"
54 class Enumerator
: public KeyVisitor
57 Enumerator(std::vector
<ObjectURI
>& uris
) : _uris(uris
) {}
58 void operator()(const ObjectURI
& u
) {
62 std::vector
<ObjectURI
>& _uris
;
67 /// Convert an AS object to an XML string.
69 ExternalInterface::_objectToXML(as_object
*obj
)
71 // GNASH_REPORT_FUNCTION;
73 if ( ! _visited
.insert(obj
).second
) {
82 // Get all the properties
84 string_table
& st
= vm
.getStringTable();
85 typedef std::vector
<ObjectURI
> URIs
;
89 for (URIs::const_reverse_iterator i
= uris
.rbegin(), e
= uris
.rend();
91 as_value val
= getMember(*obj
, *i
);
92 const std::string
& id
= i
->toString(st
);
93 ss
<< "<property id=\"" << id
<< "\">";
104 /// Convert an AS object to an XML string.
106 ExternalInterface::_toXML(const as_value
&val
)
108 // GNASH_REPORT_FUNCTION;
110 std::stringstream ss
;
112 if (val
.is_string()) {
113 ss
<< "<string>" << val
.to_string() << "</string>";
114 } else if (val
.is_number()) {
115 ss
<< "<number>" << val
.to_string() << "</number>";
116 } else if (val
.is_undefined()) {
117 ss
<< "<undefined/>";
118 } else if (val
.is_null()) {
120 // Exception isn't listed in any docs, but we'll use it for
121 // marshallExceptions.
122 } else if (val
.is_exception()) {
123 ss
<< "<exception>" << val
.to_string()<< "</exception>";
124 } else if (val
.is_bool()) {
125 ss
<< (val
.to_bool(8) ? "<true/>" : "<false/>");
126 // Function also isn't listed, but it's the only other type
127 // supported by as_value, so leaving it out doesn't seem right.
128 } else if (val
.is_function()) {
129 ss
<< "<function>" << val
.to_string() << "</function>";
130 } else if (val
.is_object()) {
131 as_object
*obj
= val
.get_object();
132 ss
<< _objectToXML(obj
);
134 log_error("Can't convert unknown type %d", val
.to_string());
140 boost::shared_ptr
<ExternalInterface::invoke_t
>
141 ExternalInterface::ExternalEventCheck(int fd
)
143 // GNASH_REPORT_FUNCTION;
145 boost::shared_ptr
<ExternalInterface::invoke_t
> error
;
149 ioctlSocket(fd
, FIONREAD
, &bytes
);
153 log_debug("There are %d bytes in the network buffer", bytes
);
154 boost::scoped_array
<char> buffer(new char[bytes
+1]);
155 // Since we know how bytes are in the network buffer, allocate
156 // some memory to read the data.
157 // terminate incase we want to treat the data like a string.
159 const int ret
= ::read(fd
, buffer
.get(), bytes
);
161 return parseInvoke(buffer
.get());
168 // Parse the XML Invoke message, which looks like this:
170 // <invoke name="LoadMovie" returntype="xml">
172 // <number>2</number>
173 // <string>bogus</string>
177 boost::shared_ptr
<ExternalInterface::invoke_t
>
178 ExternalInterface::parseInvoke(const std::string
&xml
)
180 // GNASH_REPORT_FUNCTION;
182 boost::shared_ptr
<ExternalInterface::invoke_t
> invoke
;
187 invoke
.reset(new ExternalInterface::invoke_t
);
188 std::string::size_type start
= 0;
189 std::string::size_type end
;
192 // Look for the ending > in the first part of the data for the tag
194 if (end
!= std::string::npos
) {
195 end
++; // go past the > character
196 tag
= xml
.substr(start
, end
);
197 // Look for the easy ones first
198 if (tag
.substr(0, 7) == "<invoke") {
199 // extract the name of the method to invoke
200 start
= tag
.find("name=") + 5;
201 end
= tag
.find(" ", start
);
202 invoke
->name
= tag
.substr(start
, end
-start
);
203 // Ignore any quote characters around the string
204 boost::erase_first(invoke
->name
, "\"");
205 boost::erase_last(invoke
->name
, "\"");
207 // extract the return type of the method
208 start
= tag
.find("returntype=") + 11;
209 end
= tag
.find(">", start
);
210 invoke
->type
= tag
.substr(start
, end
-start
);
211 // Ignore any quote characters around the string
212 boost::erase_first(invoke
->type
, "\"");
213 boost::erase_last(invoke
->type
, "\"");
215 // extract the arguments to the method
216 start
= xml
.find("<arguments>");
217 end
= xml
.find("</invoke");
218 tag
= xml
.substr(start
, end
-start
);
219 invoke
->args
= ExternalInterface::parseArguments(tag
);
227 ExternalInterface::parseXML(const std::string
&xml
)
229 // GNASH_REPORT_FUNCTION;
235 std::string::size_type start
= 0;
236 std::string::size_type end
;
240 // Look for the ending > in the first part of the data for the tag
242 if (end
!= std::string::npos
) {
243 end
++; // go past the > character
244 tag
= xml
.substr(start
, end
);
245 // Look for the easy ones first
246 if (tag
== "<null/>") {
248 } else if (tag
== "<void/>") {
249 value
.set_undefined();
250 } else if (tag
== "<true/>") {
251 value
.set_bool(true);
252 } else if (tag
== "<false/>") {
253 value
.set_bool(false);
254 } else if (tag
== "<number>") {
256 end
= xml
.find("</number>");
257 std::string str
= xml
.substr(start
, end
-start
);
258 double num
= strtod(str
.c_str(), NULL
);
259 value
.set_double(num
);
260 } else if (tag
== "<string>") {
262 end
= xml
.find("</string>");
263 std::string str
= xml
.substr(start
, end
-start
);
264 value
.set_string(str
);
268 // log_debug("Argument is: %s", value.to_string());
272 std::vector
<as_value
>
273 ExternalInterface::parseArguments(const std::string
&xml
)
275 // GNASH_REPORT_FUNCTION;
277 std::vector
<as_value
> args
;
278 std::string::size_type start
= 0;
279 std::string::size_type end
;
282 std::string data
= xml
;
283 std::string tag
= "<arguments>";
284 start
= data
.find(tag
);
285 if (start
!= std::string::npos
) {
286 data
.erase(0, tag
.size());
288 while (!data
.empty()) {
290 start
= data
.find("<", 1); // start past the opening <
291 end
= data
.find(">", start
) + 1;
292 std::string sub
= data
.substr(0, end
);
293 if (data
== "</arguments>") {
296 args
.push_back(parseXML(sub
));
303 // Create an Invoke message for the standalone Gnash
305 ExternalInterface::makeInvoke (const std::string
&method
,
306 const std::vector
<as_value
> &args
)
308 std::stringstream ss
;
309 std::vector
<as_value
>::const_iterator it
;
311 ss
<< "<invoke name=\"" << method
<< "\" returntype=\"xml\">";
313 for (it
=args
.begin(); it
!= args
.end(); ++it
) {
314 // Should we avoid re-serializing the same object ?
318 ss
<< "</arguments>";
321 // Add a CR on the end so the output is more readable on the other
322 // end. XL should be ignoring the CR anyway.
329 ExternalInterface::makeNull ()
335 ExternalInterface::makeTrue ()
341 ExternalInterface::makeFalse ()
347 ExternalInterface::makeString (const std::string
&str
)
349 std::stringstream ss
;
351 ss
<< "<string>" << str
<< "</string>";
358 ExternalInterface::makeProperty (const std::string
&id
, double num
)
360 std::stringstream ss
;
362 return makeProperty(id
, ss
.str());
366 ExternalInterface::makeProperty (const std::string
&id
, int num
)
368 std::stringstream ss
;
370 return makeProperty(id
, ss
.str());
374 ExternalInterface::makeProperty (const std::string
&id
, const std::string
&data
)
376 std::stringstream ss
;
378 ss
<< "<property id=\"" << id
<< "\">" << data
<< "</property>";
384 ExternalInterface::makeNumber (double num
)
386 std::stringstream ss
;
388 ss
<< "<number>" << num
<< "</number>";
394 ExternalInterface::makeNumber (int num
)
396 std::stringstream ss
;
398 ss
<< "<number>" << num
<< "</number>";
404 ExternalInterface::makeNumber (unsigned int num
)
406 std::stringstream ss
;
408 ss
<< "<number>" << num
<< "</number>";
414 ExternalInterface::makeArray (std::vector
<std::string
> &args
)
416 std::stringstream ss
;
417 std::vector
<std::string
>::iterator it
;
421 for (it
=args
.begin(); it
!= args
.end(); ++it
) {
422 ss
<< "<property id=\"" << index
<< "\">" << *it
<< "</property>";
432 ExternalInterface::makeObject (std::map
<std::string
, std::string
> &args
)
434 std::stringstream ss
;
435 std::map
<std::string
, std::string
>::iterator it
;
438 for (it
= args
.begin(); it
!= args
.end(); ++it
) {
439 ss
<< "<property id=\"" << it
->first
<< "\">" << it
->second
<< "</property>";
447 ExternalInterface::writeBrowser(int fd
, const std::string
&data
)
450 return ::write(fd
, data
.c_str(), data
.size());
457 ExternalInterface::readBrowser(int fd
)
460 // Wait for some data from the player
463 ioctlSocket(fd
, FIONREAD
, &bytes
);
470 log_debug("There are %d bytes in the network buffer", bytes
);
472 std::string
buf(bytes
, '\0');
474 const int ret
= ::read(fd
, &buf
[0], bytes
);
483 std::cout
<< buf
<< std::endl
;
488 } // end of gnash namespace
492 // indent-tabs-mode: nil