use the VERSION instead of master in the revno.h generated from a src tarball
[gnash.git] / libcore / ExternalInterface.cpp
blobb25e2cf80619e403c02191b2af92480291293618
1 // ExternalInterface.cpp: ActionScript "ExternalInterface" support
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
4 // Foundation, Inc
5 //
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"
23 #include <map>
24 #include <vector>
25 #include <sstream>
26 #include <boost/algorithm/string/erase.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <boost/scoped_array.hpp>
29 #include <algorithm>
31 #include "GnashSystemNetHeaders.h"
32 #include "GnashSystemFDHeaders.h"
34 #include "StringPredicates.h"
35 #include "fn_call.h"
36 #include "Global_as.h"
37 #include "smart_ptr.h" // for boost intrusive_ptr
38 #include "VM.h"
39 #include "rc.h"
40 #include "as_value.h"
41 #include "as_object.h"
42 #include "XML_as.h"
43 #include "Array_as.h"
44 #include "namedStrings.h"
45 #include "Global_as.h"
46 #include "PropertyList.h"
47 #include "movie_root.h"
48 #include "log.h"
50 namespace gnash {
52 namespace {
54 class Enumerator : public KeyVisitor
56 public:
57 Enumerator(std::vector<ObjectURI>& uris) : _uris(uris) {}
58 void operator()(const ObjectURI& u) {
59 _uris.push_back(u);
61 private:
62 std::vector<ObjectURI>& _uris;
67 /// Convert an AS object to an XML string.
68 std::string
69 ExternalInterface::_objectToXML(as_object *obj)
71 // GNASH_REPORT_FUNCTION;
73 if ( ! _visited.insert(obj).second ) {
74 return "<circular/>";
77 std::stringstream ss;
79 ss << "<object>";
81 if (obj) {
82 // Get all the properties
83 VM& vm = getVM(*obj);
84 string_table& st = vm.getStringTable();
85 typedef std::vector<ObjectURI> URIs;
86 URIs uris;
87 Enumerator en(uris);
88 obj->visitKeys(en);
89 for (URIs::const_reverse_iterator i = uris.rbegin(), e = uris.rend();
90 i != e; ++i) {
91 as_value val = getMember(*obj, *i);
92 const std::string& id = i->toString(st);
93 ss << "<property id=\"" << id << "\">";
94 ss << _toXML(val);
95 ss << "</property>";
99 ss << "</object>";
101 return ss.str();
104 /// Convert an AS object to an XML string.
105 std::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()) {
119 ss << "<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);
133 } else {
134 log_error("Can't convert unknown type %d", val.to_string());
137 return ss.str();
140 boost::shared_ptr<ExternalInterface::invoke_t>
141 ExternalInterface::ExternalEventCheck(int fd)
143 // GNASH_REPORT_FUNCTION;
145 boost::shared_ptr<ExternalInterface::invoke_t> error;
147 if (fd > 0) {
148 int bytes = 0;
149 ioctlSocket(fd, FIONREAD, &bytes);
150 if (bytes == 0) {
151 return error;
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.
158 buffer[bytes+1] = 0;
159 const int ret = ::read(fd, buffer.get(), bytes);
160 if (ret) {
161 return parseInvoke(buffer.get());
165 return error;
168 // Parse the XML Invoke message, which looks like this:
170 // <invoke name="LoadMovie" returntype="xml">
171 // <arguments>
172 // <number>2</number>
173 // <string>bogus</string>
174 // </arguments>
175 // </invoke>
177 boost::shared_ptr<ExternalInterface::invoke_t>
178 ExternalInterface::parseInvoke(const std::string &xml)
180 boost::shared_ptr<ExternalInterface::invoke_t> invoke;
181 if (xml.empty()) {
182 return invoke;
185 invoke.reset(new ExternalInterface::invoke_t);
186 std::string::size_type start = 0;
187 std::string::size_type end;
188 std::string tag;
190 // Look for the ending > in the first part of the data for the tag
191 end = xml.find(">");
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);
221 return invoke;
224 as_value
225 ExternalInterface::parseXML(const std::string &xml)
227 if (xml.empty()) {
228 return as_value();
231 std::string::size_type start = 0;
232 std::string::size_type end;
233 std::string tag;
234 as_value value;
236 // Look for the ending > in the first part of the data for the tag
237 end = xml.find(">");
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/>") {
243 value.set_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>") {
251 start = end;
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>") {
257 start = end;
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());
265 return value;
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;
277 std::string name;
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()) {
285 // Extract the data
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>") {
290 break;
292 args.push_back(parseXML(sub));
293 data.erase(0, end);
296 return args;
299 // Create an Invoke message for the standalone Gnash
300 std::string
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\">";
308 ss << "<arguments>";
309 for (it=args.begin(); it != args.end(); ++it) {
310 // Should we avoid re-serializing the same object ?
311 ss << toXML(*it);
314 ss << "</arguments>";
315 ss << "</invoke>";
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.
319 ss << std::endl;
321 return ss.str();
324 size_t
325 ExternalInterface::writeBrowser(int fd, const std::string &data)
327 if (fd > 0) {
328 return ::write(fd, data.c_str(), data.size());
331 return -1;
334 std::string
335 ExternalInterface::readBrowser(int fd)
337 std::string empty;
338 // Wait for some data from the player
339 int bytes = 0;
341 ioctlSocket(fd, FIONREAD, &bytes);
343 // No data yet
344 if (bytes == 0) {
345 return empty;
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);
353 if (ret <= 0) {
354 return empty;
357 if (ret < bytes) {
358 buf.resize(ret);
361 std::cout << buf << std::endl;
363 return buf;
366 } // end of gnash namespace
368 // local Variables:
369 // mode: C++
370 // indent-tabs-mode: nil
371 // End: