1 // ExternalInterface_as.cpp:  ActionScript "ExternalInterface" class, for Gnash.
2 //
3 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014,
4 //   2015, 2016 Free Software 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.
10 //
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.
15 //
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
19 //
20 
21 #include "ExternalInterface_as.h"
22 
23 #include <map>
24 #include <vector>
25 #include <sstream>
26 #include <boost/algorithm/string/erase.hpp>
27 #include <algorithm>
28 #include "GnashSystemNetHeaders.h"
29 
30 #include "ExternalInterface.h"
31 #include "NativeFunction.h"
32 #include "StringPredicates.h"
33 #include "as_object.h" // for inheritance
34 #include "fn_call.h"
35 #include "Global_as.h"
36 #include "GnashException.h" // for ActionException
37 #include "VM.h"
38 #include "rc.h"
39 #include "as_value.h"
40 #include "as_object.h"
41 #include "XML_as.h"
42 #include "Array_as.h"
43 #include "namedStrings.h"
44 #include "Global_as.h"
45 #include "PropertyList.h"
46 #include "movie_root.h"
47 #include "log.h"
48 #include "RunResources.h"
49 #include "StreamProvider.h"
50 #include "ObjectURI.h"
51 
52 #define MAXHOSTNAMELEN 256 // max hostname size. However this is defined in netdb.h
53 
54 namespace gnash {
55 
56 namespace {
57     as_value externalInterfaceConstructor(const fn_call& fn);
58     as_value externalinterface_addCallback(const fn_call& fn);
59     as_value externalinterface_call(const fn_call& fn);
60     as_value externalinterface_available(const fn_call& fn);
61     as_value externalinterface_objectID(const fn_call& fn);
62     as_value externalinterface_uArgumentsToXML(const fn_call& fn);
63     as_value externalinterface_uArgumentsToAS(const fn_call& fn);
64     as_value externalinterface_uAddCallback(const fn_call& fn);
65     as_value externalinterface_uArrayToAS(const fn_call& fn);
66     as_value externalinterface_uArrayToJS(const fn_call& fn);
67     as_value externalinterface_uArrayToXML(const fn_call& fn);
68     as_value externalinterface_uCallIn(const fn_call& fn);
69     as_value externalinterface_uCallOut(const fn_call& fn);
70     as_value externalinterface_uEscapeXML(const fn_call& fn);
71     as_value externalinterface_uEvalJS(const fn_call& fn);
72     as_value externalinterface_uInitJS(const fn_call& fn);
73     as_value externalinterface_uJsQuoteString(const fn_call& fn);
74     as_value externalinterface_uObjectID(const fn_call& fn);
75     as_value externalinterface_uObjectToAS(const fn_call& fn);
76     as_value externalinterface_uObjectToJS(const fn_call& fn);
77     as_value externalinterface_uObjectToXML(const fn_call& fn);
78     as_value externalinterface_uToAS(const fn_call& fn);
79     as_value externalinterface_uToJS(const fn_call& fn);
80     as_value externalinterface_uToXML(const fn_call& fn);
81     as_value externalinterface_uUnescapeXML(const fn_call& fn);
82 }
83 
84 namespace {
85 
86 class Enumerator : public KeyVisitor
87 {
88 public:
Enumerator(std::vector<ObjectURI> & uris)89     Enumerator(std::vector<ObjectURI>& uris) : _uris(uris) {}
operator ()(const ObjectURI & u)90     void operator()(const ObjectURI& u) {
91         _uris.push_back(u);
92     }
93 private:
94     std::vector<ObjectURI>& _uris;
95 };
96 
97 class ArrayToXML
98 {
99 public:
ArrayToXML(as_value & ret,const fn_call & fn)100     ArrayToXML(as_value& ret, const fn_call& fn)
101         :
102         _ret(ret),
103         _fn(fn),
104         _count(0)
105     {}
106 
operator ()(const as_value & val)107     void operator()(const as_value& val) {
108         VM& vm = getVM(_fn);
109 
110         newAdd(_ret, "<property id=\"", vm);
111         newAdd(_ret, static_cast<double>(_count), vm);
112         newAdd(_ret, "\">", vm);
113         as_object* ei =
114             findObject(_fn.env(), "flash.external.ExternalInterface");
115         const as_value& x = callMethod(ei, getURI(vm, "_toXML"), val);
116         newAdd(_ret, x, vm);
117         newAdd(_ret, "</property>", vm);
118         ++_count;
119     }
120 private:
121     as_value& _ret;
122     const fn_call& _fn;
123     size_t _count;
124 };
125 
126 class ArgsToXML
127 {
128 public:
ArgsToXML(as_value & ret,const fn_call & fn)129     ArgsToXML(as_value& ret, const fn_call& fn)
130         :
131         _ret(ret),
132         _fn(fn)
133     {}
134 
operator ()(const as_value & val)135     void operator()(const as_value& val) {
136         VM& vm = getVM(_fn);
137         as_object* ei =
138             findObject(_fn.env(), "flash.external.ExternalInterface");
139         const as_value& x = callMethod(ei, getURI(vm, "_toXML"), val);
140         newAdd(_ret, x, vm);
141     }
142 private:
143     as_value& _ret;
144     const fn_call& _fn;
145 };
146 
147 }
148 
149 void
registerExternalInterfaceNative(as_object & global)150 registerExternalInterfaceNative(as_object& global)
151 {
152     VM& vm = getVM(global);
153     vm.registerNative(externalinterface_uInitJS, 14, 0);
154     vm.registerNative(externalinterface_uObjectID, 14, 1);
155     vm.registerNative(externalinterface_uAddCallback, 14, 2);
156     vm.registerNative(externalinterface_uEvalJS, 14, 3);
157     vm.registerNative(externalinterface_uCallOut, 14, 4);
158     vm.registerNative(externalinterface_uEscapeXML, 14, 5);
159     vm.registerNative(externalinterface_uUnescapeXML, 14, 6);
160     vm.registerNative(externalinterface_uJsQuoteString, 14, 7);
161 
162     vm.registerNative(externalinterface_available, 14, 100);
163 
164 }
165 
166 void
externalinterface_class_init(as_object & where,const ObjectURI & uri)167 externalinterface_class_init(as_object& where, const ObjectURI& uri)
168 {
169     where.init_destructive_property(uri, externalInterfaceConstructor, 0);
170 }
171 
172 namespace {
173 
174 void
attachExternalInterfaceStaticInterface(as_object & o)175 attachExternalInterfaceStaticInterface(as_object& o)
176 {
177 
178     const int swf8Flags = PropFlags::onlySWF8Up;
179 
180     VM& vm = getVM(o);
181 
182     // Native functions
183     o.init_member("_initJS", vm.getNative(14, 0), swf8Flags);
184     o.init_member("_objectID", vm.getNative(14, 1), swf8Flags);
185     o.init_member("_addCallback", vm.getNative(14, 2), swf8Flags);
186     o.init_member("_evalJS", vm.getNative(14, 3), swf8Flags);
187     o.init_member("_callOut", vm.getNative(14, 4), swf8Flags);
188     o.init_member("_escapeXML", vm.getNative(14, 5), swf8Flags);
189     o.init_member("_unescapeXML", vm.getNative(14, 6), swf8Flags);
190     o.init_member("_jsQuoteString", vm.getNative(14, 7), swf8Flags);
191 
192     // Native properties
193     NativeFunction* n = vm.getNative(14, 100);
194     o.init_property("available", *n, *n, swf8Flags);
195 
196     Global_as& gl = getGlobal(o);
197 
198     // ActionScript functions
199     o.init_member("addCallback",
200                   gl.createFunction(externalinterface_addCallback));
201 
202     o.init_member("call", gl.createFunction(externalinterface_call));
203 
204     // Undocumented ActionScript functions.
205     o.init_member("_argumentsToXML",
206               gl.createFunction(externalinterface_uArgumentsToXML));
207     o.init_member("_argumentsToAS",
208               gl.createFunction(externalinterface_uArgumentsToAS));
209     o.init_member("_arrayToAS",
210                   gl.createFunction(externalinterface_uArrayToAS));
211     o.init_member("_arrayToJS",
212                   gl.createFunction(externalinterface_uArrayToJS));
213     o.init_member("_arrayToXML",
214                   gl.createFunction(externalinterface_uArrayToXML));
215     o.init_member("_callIn",
216                   gl.createFunction(externalinterface_uCallIn));
217     o.init_member("_objectToAS",
218                   gl.createFunction(externalinterface_uObjectToAS));
219     o.init_member("_objectToJS",
220                   gl.createFunction(externalinterface_uObjectToJS));
221     o.init_member("_objectToXML",
222                   gl.createFunction(externalinterface_uObjectToXML));
223     o.init_member("_toAS",
224                   gl.createFunction(externalinterface_uToAS));
225     o.init_member("_toJS",
226                   gl.createFunction(externalinterface_uToJS));
227     o.init_member("_toXML",
228                   gl.createFunction(externalinterface_uToXML));
229 
230     // Apparently the pp calls:
231     //
232     // AsSetPropFlags(flash.external.ExternalInterface, null, 4103)
233     //
234     // here, but it seems that the properties actually are visible in SWF6
235     // and SWF7, at least for the flashplayer 9. So we just make sure they
236     // are read-only.
237     as_object* null = nullptr;
238     callMethod(&gl, NSV::PROP_AS_SET_PROP_FLAGS, &o, null, 7);
239 }
240 
241 /// This adds a function that can be called from javascript.
242 as_value
externalinterface_addCallback(const fn_call & fn)243 externalinterface_addCallback(const fn_call& fn)
244 {
245     movie_root& mr = getRoot(fn);
246 
247     if (mr.getControlFD() <= 0) {
248         log_debug("ExternalInterface not accessible when running standalone.");
249         return as_value(false);
250     }
251 
252     if (fn.nargs >= 3) {
253         const as_value& name_as = fn.arg(0);
254         const as_value& instance_as = fn.arg(1);
255         const as_value& method_as = fn.arg(2);
256         std::string name = name_as.to_string();
257 
258         if (method_as.is_undefined() || method_as.is_null()) {
259             // Adding callback without function specified is not allowed
260             return as_value(false);
261         }
262 
263         log_debug("adding callback %s", name);
264         as_object* asInstance = toObject(instance_as, getVM(fn));
265         as_object* asCallback = toObject(method_as, getVM(fn));
266         mr.addExternalCallback(name, asCallback, asInstance);
267     } else {
268         // Invalid addCallback call
269         return as_value(false);
270     }
271 
272     // Returns true unless unavailable or invalid (which we checked above)
273     return as_value(true);
274 }
275 
276 // This calls a Javascript function in the browser.
277 as_value
externalinterface_call(const fn_call & fn)278 externalinterface_call(const fn_call& fn)
279 {
280     movie_root& mr = getRoot(fn);
281     as_value val;
282 
283     if (mr.getControlFD() <= 0) {
284         log_debug("ExternalInterface not accessible on call.");
285         val.set_null();
286         return val;
287     }
288 
289     if (fn.nargs >= 1) {
290         const as_value& methodName_as = fn.arg(0);
291         const std::string methodName = methodName_as.to_string();
292         const std::vector<as_value>& args = fn.getArgs();
293         log_debug("Calling External method \"%s\"", methodName);
294         std::string result = mr.callExternalJavascript(methodName, args);
295         if (!result.empty()) {
296             val = ExternalInterface::parseXML(result);
297         }
298     }
299 
300     return val;
301 }
302 
303 as_value
externalinterface_available(const fn_call & fn)304 externalinterface_available(const fn_call& fn)
305 {
306 
307     movie_root& m = getRoot(fn);
308     bool mode = false;
309 
310     // If we're not running under a browser as a plugin, then just
311     // return, as ExternalInterface is only available as a plugin.
312     if (m.getHostFD() < 0) {
313         return false;
314     }
315 
316     switch (m.getAllowScriptAccess()) {
317       case movie_root::SCRIPT_ACCESS_NEVER:
318           mode = false;
319           break;
320 
321       case movie_root::SCRIPT_ACCESS_SAME_DOMAIN:
322       {
323           const RunResources& r = m.runResources();
324           const std::string& baseurl = r.streamProvider().baseURL().str();
325           char hostname[MAXHOSTNAMELEN] = {};
326 
327           if (::gethostname(hostname, MAXHOSTNAMELEN) != 0) {
328               mode = false;
329           }
330 
331           // The hostname is empty if running the standalone Gnash from
332           // a terminal, so we can assume the default of sameDomain applies.
333           URL localPath(hostname, baseurl);
334           // If the URL has a file protocol, then
335           if (r.streamProvider().allow(localPath)) {
336               return as_value(true);
337           }
338           if (localPath.hostname().empty()) {
339               mode = false;
340           } else {
341               StringNoCaseEqual noCaseCompare;
342 
343               if (!noCaseCompare(localPath.hostname(), hostname)) {
344                   log_security(_("ExternalInterface path %s is outside "
345                                  "the SWF domain %s. Cannot access this "
346                                  "object."), localPath, hostname);
347                   mode = false;
348               }
349           }
350           break;
351       }
352 
353       case movie_root::SCRIPT_ACCESS_ALWAYS:
354           mode = true;
355           break;
356     }
357 
358     return as_value(mode);
359 }
360 
361 as_value
externalinterface_objectID(const fn_call & fn)362 externalinterface_objectID(const fn_call& fn)
363 {
364 
365     movie_root& mr = getRoot(fn);
366     MovieClip *mc = mr.getLevel(0);
367     VM& vm = getVM(fn);
368 
369     as_value id;
370     getObject(mc)->get_member(getURI(vm, "id"), &id);
371 
372     as_value name;
373     getObject(mc)->get_member(getURI(vm, "name"), &name);
374 
375     if (id.is_undefined() && !name.is_undefined()) {
376         return name;
377     } else if (!id.is_undefined() && name.is_undefined()) {
378         return id;
379     } else if (id.is_undefined() && name.is_undefined()) {
380         return as_value();
381     }
382 
383     return as_value();
384 }
385 
386 as_value
externalInterfaceConstructor(const fn_call & fn)387 externalInterfaceConstructor(const fn_call& fn)
388 {
389     log_debug("Loading flash.external.ExternalInterface class");
390     Global_as& gl = getGlobal(fn);
391     as_object* proto = createObject(gl);
392     as_object* cl = gl.createClass(emptyFunction, proto);
393 
394     attachExternalInterfaceStaticInterface(*cl);
395     return cl;
396 }
397 
398 as_value
externalinterface_uArgumentsToXML(const fn_call & fn)399 externalinterface_uArgumentsToXML(const fn_call& fn)
400 {
401     as_value ret("<arguments>");
402 
403     if (fn.nargs) {
404         VM& vm = getVM(fn);
405         as_object *obj = toObject(fn.arg(0), vm);
406         if (obj) {
407             ArgsToXML tx(ret, fn);
408             size_t size = arrayLength(*obj);
409             if (size) {
410                 for (size_t i = 1; i < size; ++i) {
411                     tx(getOwnProperty(*obj, arrayKey(vm, i)));
412                 }
413             }
414         }
415     }
416 
417     newAdd(ret, "</arguments>", getVM(fn));
418     return ret;
419 }
420 
421 as_value
externalinterface_uArgumentsToAS(const fn_call &)422 externalinterface_uArgumentsToAS(const fn_call& /*fn*/)
423 {
424     LOG_ONCE(log_unimpl(__FUNCTION__) );
425     return as_value();
426 }
427 
428 as_value
externalinterface_uAddCallback(const fn_call &)429 externalinterface_uAddCallback(const fn_call& /*fn*/)
430 {
431     LOG_ONCE(log_unimpl(__FUNCTION__) );
432     return as_value();
433 }
434 
435 as_value
externalinterface_uArrayToAS(const fn_call &)436 externalinterface_uArrayToAS(const fn_call& /*fn*/)
437 {
438     LOG_ONCE(log_unimpl(__FUNCTION__) );
439     return as_value();
440 }
441 
442 as_value
externalinterface_uArrayToJS(const fn_call &)443 externalinterface_uArrayToJS(const fn_call& /*fn*/)
444 {
445     LOG_ONCE(log_unimpl(__FUNCTION__) );
446     return as_value();
447 }
448 
449 as_value
externalinterface_uArrayToXML(const fn_call & fn)450 externalinterface_uArrayToXML(const fn_call& fn)
451 {
452     as_value ret("<array>");
453 
454     if (fn.nargs) {
455         as_object *obj = toObject(fn.arg(0), getVM(fn));
456         if (obj) {
457             ArrayToXML tx(ret, fn);
458             foreachArray(*obj, tx);
459         }
460     }
461 
462     newAdd(ret, "</array>", getVM(fn));
463     return ret;
464 }
465 
466 as_value
externalinterface_uCallIn(const fn_call &)467 externalinterface_uCallIn(const fn_call& /*fn*/)
468 {
469     LOG_ONCE(log_unimpl(__FUNCTION__) );
470     return as_value();
471 }
472 
473 as_value
externalinterface_uCallOut(const fn_call &)474 externalinterface_uCallOut(const fn_call& /*fn*/)
475 {
476     LOG_ONCE(log_unimpl(__FUNCTION__) );
477     return as_value();
478 }
479 
480 as_value
externalinterface_uEvalJS(const fn_call &)481 externalinterface_uEvalJS(const fn_call& /*fn*/)
482 {
483     LOG_ONCE(log_unimpl(__FUNCTION__) );
484     return as_value();
485 }
486 
487 as_value
externalinterface_uInitJS(const fn_call &)488 externalinterface_uInitJS(const fn_call& /*fn*/)
489 {
490     LOG_ONCE(log_unimpl(__FUNCTION__) );
491     return as_value();
492 }
493 
494 as_value
externalinterface_uJsQuoteString(const fn_call &)495 externalinterface_uJsQuoteString(const fn_call& /*fn*/)
496 {
497     LOG_ONCE(log_unimpl(__FUNCTION__) );
498     return as_value();
499 }
500 
501 as_value
externalinterface_uObjectID(const fn_call &)502 externalinterface_uObjectID(const fn_call& /*fn*/)
503 {
504     LOG_ONCE(log_unimpl(__FUNCTION__) );
505     return as_value();
506 }
507 
508 as_value
externalinterface_uObjectToAS(const fn_call &)509 externalinterface_uObjectToAS(const fn_call& /*fn*/)
510 {
511     LOG_ONCE(log_unimpl(__FUNCTION__) );
512     return as_value();
513 }
514 
515 as_value
externalinterface_uObjectToJS(const fn_call &)516 externalinterface_uObjectToJS(const fn_call& /*fn*/)
517 {
518 	LOG_ONCE(log_unimpl(__FUNCTION__) );
519 	return as_value();
520 }
521 
522 as_value
externalinterface_uObjectToXML(const fn_call & fn)523 externalinterface_uObjectToXML(const fn_call& fn)
524 {
525     VM& vm = getVM(fn);
526 
527     as_value ret("<object>");
528 
529     if (fn.nargs) {
530         as_object* obj = toObject(fn.arg(0), getVM(fn));
531 
532         if (obj) {
533 
534             string_table& st = getStringTable(fn);
535 
536             typedef std::vector<ObjectURI> URIs;
537             URIs uris;
538 
539             // Fake AS enumeration.
540             Enumerator en(uris);
541             obj->visitKeys(en);
542 
543             for (URIs::const_reverse_iterator i = uris.rbegin(), e = uris.rend();
544                     i != e; ++i) {
545                 const std::string& id = i->toString(st);
546 
547                 newAdd(ret, "<property id=\"", vm);
548                 newAdd(ret, id, vm);
549                 newAdd(ret, "\">", vm);
550 
551                 as_object* ei =
552                     findObject(fn.env(), "flash.external.ExternalInterface");
553                 const as_value& val = getMember(*obj, *i);
554                 newAdd(ret, callMethod(ei, getURI(vm, "_toXML"), val), vm);
555                 newAdd(ret, "</property>", vm);
556             }
557         }
558     }
559 
560     newAdd(ret, "</object>", vm);
561     return ret;
562 
563 }
564 
565 as_value
externalinterface_uToJS(const fn_call &)566 externalinterface_uToJS(const fn_call& /*fn*/)
567 {
568     LOG_ONCE(log_unimpl(__FUNCTION__) );
569     return as_value();
570 }
571 
572 as_value
externalinterface_uToXML(const fn_call & fn)573 externalinterface_uToXML(const fn_call& fn)
574 {
575 
576     // Probably implemented with switch(typeof value)
577     if (fn.nargs) {
578 
579         as_object* ei =
580             findObject(fn.env(), "flash.external.ExternalInterface");
581         VM& vm = getVM(fn);
582 
583         const as_value& val = fn.arg(0);
584         if (val.is_string()) {
585             as_value ret = "<string>";
586             newAdd(ret, callMethod(ei, getURI(vm, "_escapeXML"), val), vm);
587             newAdd(ret, "</string>", vm);
588             return ret;
589         }
590         if (val.is_undefined()) {
591             return as_value("<undefined/>");
592         }
593         if (val.is_number()) {
594             as_value ret = "<number>";
595             newAdd(ret, val, vm);
596             newAdd(ret, "</number>", vm);
597             return ret;
598         }
599         if (val.is_null()) {
600             return as_value("<null/>");
601         }
602         if (val.is_bool()) {
603             return toBool(val, vm) ? as_value("<true/>") : as_value("<false/>");
604         }
605         if (val.is_object()) {
606             as_object* obj = toObject(val, vm);
607             assert(obj);
608             if (hasOwnProperty(*obj, NSV::PROP_LENGTH)) {
609                 return callMethod(ei, getURI(vm, "_arrayToXML"), val);
610             }
611             return callMethod(ei, getURI(vm, "_objectToXML"), val);
612         }
613     }
614     return as_value("<null/>");
615 }
616 
617 as_value
externalinterface_uToAS(const fn_call & fn)618 externalinterface_uToAS(const fn_call& fn)
619 {
620     if (!fn.nargs) return as_value();
621 
622     as_value arg = fn.arg(0);
623     as_object* o = toObject(arg, getVM(fn));
624 
625     if (!o) {
626         return as_value();
627     }
628 
629     VM& vm = getVM(fn);
630     // TODO: use NSV ?
631     const ObjectURI& nodeName = getURI(vm, "nodeName");
632     const ObjectURI& firstChild = getURI(vm, "firstChild");
633 
634     const as_value& nn = getMember(*o, nodeName);
635 
636     if (equals(nn, as_value("number"), vm)) {
637         as_object* fc = toObject(getMember(*o, firstChild), vm);
638         const as_value v = callMethod(fc, NSV::PROP_TO_STRING);
639         // This should call Number(obj.firstChild.toString()), i.e. use
640         // the non-constructing number conversion function, but the extra
641         // code needed to implement that isn't worth it.
642         return as_value(toNumber(v, vm));
643     }
644     if (equals(nn, as_value("string"), getVM(fn))) {
645         as_object* ei =
646             findObject(fn.env(), "flash.external.ExternalInterface");
647         as_value fc = getMember(*o, firstChild);
648         return callMethod(ei, getURI(vm, "_unescapeXML"),
649                 fc.to_string(getSWFVersion(fn)));
650     }
651     if (equals(nn, as_value("false"), getVM(fn))) {
652         return as_value(false);
653     }
654     if (equals(nn, as_value("true"), getVM(fn))) {
655         return as_value(true);
656     }
657     if (equals(nn, as_value("null"), getVM(fn))) {
658         as_value null;
659         null.set_null();
660         return null;
661     }
662     if (equals(nn, as_value("undefined"), getVM(fn))) {
663         return as_value();
664     }
665     if (equals(nn, as_value("object"), getVM(fn))) {
666         as_object* ei =
667             findObject(fn.env(), "flash.external.ExternalInterface");
668         return callMethod(ei, getURI(vm, "_objectToXML"), o);
669     }
670     if (equals(nn, as_value("array"), getVM(fn))) {
671         as_object* ei =
672             findObject(fn.env(), "flash.external.ExternalInterface");
673         return callMethod(ei, getURI(vm, "_arrayToXML"), o);
674     }
675     if (equals(nn, as_value("class"), getVM(fn))) {
676         as_value fc = getMember(*o, firstChild);
677         return findObject(fn.env(), fc.to_string(getSWFVersion(fn)));
678     }
679     return as_value();
680 }
681 
682 as_value
externalinterface_uEscapeXML(const fn_call & fn)683 externalinterface_uEscapeXML(const fn_call& fn)
684 {
685     if (fn.nargs == 1) {
686         std::string str(fn.arg(0).to_string());
687         escapeXML(str);
688         return as_value(str);
689     }
690 
691     return as_value();
692 }
693 
694 as_value
externalinterface_uUnescapeXML(const fn_call & fn)695 externalinterface_uUnescapeXML(const fn_call& fn)
696 {
697     if (fn.nargs == 1) {
698         std::string str = fn.arg(0).to_string();
699         gnash::unescapeXML(str);
700         return as_value(str);
701     }
702 
703     return as_value();
704 }
705 
706 } // end of anonymous namespace used for callbacks
707 
708 } // end of gnash namespace
709 
710 // local Variables:
711 // mode: C++
712 // indent-tabs-mode: nil
713 // End:
714