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