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(std::string(buffer
.get(), ret
));
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 boost::shared_ptr
<ExternalInterface::invoke_t
> invoke
;
185 invoke
.reset(new ExternalInterface::invoke_t
);
186 std::string::size_type start
= 0;
187 std::string::size_type end
;
190 // Look for the ending > in the first part of the data for the tag
192 if (end
!= std::string::npos
) {
193 end
++; // go past the > character
194 tag
= xml
.substr(start
, end
);
195 // Look for the easy ones first
196 if (tag
.substr(0, 7) == "<invoke") {
197 // extract the name of the method to invoke
198 start
= tag
.find("name=") + 5;
199 end
= tag
.find(" ", start
);
200 invoke
->name
= tag
.substr(start
, end
-start
);
201 // Ignore any quote characters around the string
202 boost::erase_first(invoke
->name
, "\"");
203 boost::erase_last(invoke
->name
, "\"");
205 // extract the return type of the method
206 start
= tag
.find("returntype=") + 11;
207 end
= tag
.find(">", start
);
208 invoke
->type
= tag
.substr(start
, end
-start
);
209 // Ignore any quote characters around the string
210 boost::erase_first(invoke
->type
, "\"");
211 boost::erase_last(invoke
->type
, "\"");
213 // extract the arguments to the method
214 start
= xml
.find("<arguments>");
215 end
= xml
.find("</invoke");
216 tag
= xml
.substr(start
, end
-start
);
217 invoke
->args
= ExternalInterface::parseArguments(tag
);
225 ExternalInterface::parseXML(const std::string
&xml
)
231 std::string::size_type start
= 0;
232 std::string::size_type end
;
236 // Look for the ending > in the first part of the data for the tag
238 if (end
!= std::string::npos
) {
239 end
++; // go past the > character
240 tag
= xml
.substr(start
, end
);
241 // Look for the easy ones first
242 if (tag
== "<null/>") {
244 } else if (tag
== "<void/>") {
245 value
.set_undefined();
246 } else if (tag
== "<true/>") {
247 value
.set_bool(true);
248 } else if (tag
== "<false/>") {
249 value
.set_bool(false);
250 } else if (tag
== "<number>") {
252 end
= xml
.find("</number>");
253 std::string str
= xml
.substr(start
, end
-start
);
254 double num
= strtod(str
.c_str(), NULL
);
255 value
.set_double(num
);
256 } else if (tag
== "<string>") {
258 end
= xml
.find("</string>");
259 std::string str
= xml
.substr(start
, end
-start
);
260 value
.set_string(str
);
264 // log_debug("Argument is: %s", value.to_string());
268 std::vector
<as_value
>
269 ExternalInterface::parseArguments(const std::string
&xml
)
271 // GNASH_REPORT_FUNCTION;
273 std::vector
<as_value
> args
;
274 std::string::size_type start
= 0;
275 std::string::size_type end
;
278 std::string data
= xml
;
279 std::string tag
= "<arguments>";
280 start
= data
.find(tag
);
281 if (start
!= std::string::npos
) {
282 data
.erase(0, tag
.size());
284 while (!data
.empty()) {
286 start
= data
.find("<", 1); // start past the opening <
287 end
= data
.find(">", start
) + 1;
288 std::string sub
= data
.substr(0, end
);
289 if (data
== "</arguments>") {
292 args
.push_back(parseXML(sub
));
299 // Create an Invoke message for the standalone Gnash
301 ExternalInterface::makeInvoke (const std::string
&method
,
302 const std::vector
<as_value
> &args
)
304 std::stringstream ss
;
305 std::vector
<as_value
>::const_iterator it
;
307 ss
<< "<invoke name=\"" << method
<< "\" returntype=\"xml\">";
309 for (it
=args
.begin(); it
!= args
.end(); ++it
) {
310 // Should we avoid re-serializing the same object ?
314 ss
<< "</arguments>";
317 // Add a CR on the end so the output is more readable on the other
318 // end. XL should be ignoring the CR anyway.
325 ExternalInterface::writeBrowser(int fd
, const std::string
&data
)
328 return ::write(fd
, data
.c_str(), data
.size());
335 ExternalInterface::readBrowser(int fd
)
338 // Wait for some data from the player
341 ioctlSocket(fd
, FIONREAD
, &bytes
);
348 log_debug("There are %d bytes in the network buffer", bytes
);
350 std::string
buf(bytes
, '\0');
352 const int ret
= ::read(fd
, &buf
[0], bytes
);
361 std::cout
<< buf
<< std::endl
;
366 } // end of gnash namespace
370 // indent-tabs-mode: nil