update copyright date
[gnash.git] / libcore / asobj / Global_as.cpp
blob356ff482a2c962d6e767c9e77f498e0919c0451f
1 // Global.cpp: Global ActionScript class setup, for Gnash.
2 //
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
4 // 2011 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.
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 #ifdef HAVE_CONFIG_H
22 #include "gnashconfig.h"
23 #endif
25 #include "Global_as.h"
27 #include <map>
28 #include <limits>
29 #include <sstream>
30 #include <boost/lexical_cast.hpp>
31 #include <boost/assign/list_of.hpp>
33 #include "as_object.h"
34 #include "builtin_function.h"
35 #include "movie_root.h"
36 #include "PropFlags.h"
37 #include "as_value.h"
38 #include "as_function.h"
39 #include "NativeFunction.h"
40 #include "AsBroadcaster.h"
41 #include "Boolean_as.h"
42 #include "Color_as.h"
43 #include "Date_as.h"
44 #include "Array_as.h"
45 #include "Error_as.h"
46 #include "String_as.h"
47 #include "Selection_as.h"
48 #include "Number_as.h"
49 #include "Math_as.h"
50 #include "Accessibility_as.h"
51 #include "ContextMenu_as.h"
52 #include "ContextMenuItem_as.h"
53 #include "Key_as.h"
54 #include "Mouse_as.h"
55 #include "Microphone_as.h"
56 #include "Sound_as.h"
57 #include "Camera_as.h"
58 #include "Stage_as.h"
59 #include "MovieClip_as.h"
60 #include "Function_as.h"
61 #include "flash/display/BitmapData_as.h"
62 #include "flash/filters/BitmapFilter_as.h"
63 #include "flash/geom/ColorTransform_as.h"
64 #include "LocalConnection_as.h"
65 #include "XMLSocket_as.h"
66 #include "SharedObject_as.h"
67 #include "NetConnection_as.h"
68 #include "NetStream_as.h"
69 #include "System_as.h"
70 #include "TextSnapshot_as.h"
71 #include "TextField_as.h"
72 #include "TextFormat_as.h"
73 #include "flash/text/TextRenderer_as.h"
74 #include "XML_as.h"
75 #include "XMLNode_as.h"
76 #include "flash/external/ExternalInterface_as.h"
77 #include "MovieClipLoader.h"
78 #include "movie_definition.h"
79 #include "Video.h"
80 #include "extension.h"
81 #include "VM.h"
82 #include "Timers.h"
83 #include "URL.h"
84 #include "rc.h"
85 #include "ClassHierarchy.h"
86 #include "namedStrings.h"
87 #include "GnashNumeric.h" // for isfinite replacement
88 #include "flash_pkg.h"
89 #include "fn_call.h"
90 #include "Button.h"
91 #include "LoadVars_as.h"
92 #include "Object.h"
93 #include "LoadableObject.h"
95 // Common code to warn and return if a required single arg is not present
96 // and to warn if there are extra args.
97 #define ASSERT_FN_ARGS_IS_1 \
98 if (fn.nargs < 1) { \
99 IF_VERBOSE_ASCODING_ERRORS( \
100 log_aserror(_("%s needs one argument"), __FUNCTION__); \
102 return as_value(); \
104 IF_VERBOSE_ASCODING_ERRORS( \
105 if (fn.nargs > 1) \
106 log_aserror(_("%s has more than one argument"), __FUNCTION__); \
109 namespace gnash {
111 namespace {
113 const ClassHierarchy::NativeClasses& avm1Classes();
115 as_value global_trace(const fn_call& fn);
116 as_value global_isNaN(const fn_call& fn);
117 as_value global_isfinite(const fn_call& fn);
118 as_value global_unescape(const fn_call& fn);
119 as_value global_escape(const fn_call& fn);
120 as_value global_parsefloat(const fn_call& fn);
121 as_value global_parseint(const fn_call& fn);
122 as_value global_assetpropflags(const fn_call& fn);
123 as_value global_assetuperror(const fn_call& fn);
124 as_value global_asnative(const fn_call& fn);
125 as_value global_asnew(const fn_call& fn);
126 as_value global_assetnative(const fn_call& fn);
127 as_value global_assetnativeaccessor(const fn_call& fn);
128 as_value global_asconstructor(const fn_call& fn);
129 as_value global_updateAfterEvent(const fn_call& fn);
130 as_value global_setTimeout(const fn_call& fn);
131 as_value global_clearInterval(const fn_call& fn);
132 as_value global_setInterval(const fn_call& fn);
134 // These are present in the standalone, not sure about the plugin.
135 as_value global_enableDebugConsole(const fn_call& fn);
136 as_value global_showRedrawRegions(const fn_call& fn);
138 // This is a help function for the silly AsSetupError function.
139 as_value local_errorConstructor(const fn_call& fn);
141 void registerNatives(as_object& global);
144 Global_as::Global_as(VM& vm)
146 as_object(vm),
147 _et(new Extension()),
148 _classes(this, _et.get()),
149 _objectProto(new as_object(*this))
153 Global_as::~Global_as()
157 as_function*
158 Global_as::createFunction(Global_as::ASFunction function)
160 as_object* proto = createObject(*this);
161 builtin_function* f = new builtin_function(*this, function);
163 proto->init_member(NSV::PROP_CONSTRUCTOR, f);
165 f->init_member(NSV::PROP_PROTOTYPE, proto);
167 as_function* fun =
168 gnash::getOwnProperty(*this, NSV::CLASS_FUNCTION).to_function();
169 if (fun) {
170 const int flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
171 f->init_member(NSV::PROP_uuPROTOuu, getMember(*fun,
172 NSV::PROP_PROTOTYPE), flags);
173 f->init_member(NSV::PROP_CONSTRUCTOR, fun);
175 return f;
178 as_object*
179 Global_as::createClass(Global_as::ASFunction ctor, as_object* prototype)
181 as_object* cl = new builtin_function(*this, ctor);
183 if (prototype) {
184 prototype->init_member(NSV::PROP_CONSTRUCTOR, cl);
185 cl->init_member(NSV::PROP_PROTOTYPE, prototype);
187 as_function* fun =
188 gnash::getOwnProperty(*this, NSV::CLASS_FUNCTION).to_function();
190 if (fun) {
191 const int flags = as_object::DefaultFlags | PropFlags::onlySWF6Up;
192 cl->init_member(NSV::PROP_uuPROTOuu, getMember(*fun,
193 NSV::PROP_PROTOTYPE), flags);
194 cl->init_member(NSV::PROP_CONSTRUCTOR, fun);
196 return cl;
200 /// Construct an Array.
202 /// This uses the _global Array class to initialize the "constructor" and
203 /// "__proto__" properties. If Array.prototype is undefined, those properties
204 /// are not added.
205 as_object*
206 Global_as::createArray()
208 as_object* array = new as_object(*this);
210 as_value ctor = getMember(*this, NSV::CLASS_ARRAY);
211 as_object* obj = toObject(ctor, gnash::getVM(*this));
212 if (obj) {
213 as_value proto;
214 if (obj->get_member(NSV::PROP_PROTOTYPE, &proto)) {
215 array->init_member(NSV::PROP_CONSTRUCTOR, ctor);
216 array->set_prototype(getMember(*obj, NSV::PROP_PROTOTYPE));
220 array->init_member(NSV::PROP_LENGTH, 0.0);
221 array->setArray();
222 return array;
225 void
226 Global_as::markReachableResources() const
228 _classes.markReachableResources();
229 _objectProto->setReachable();
230 as_object::markReachableResources();
233 void
234 Global_as::registerClasses()
236 registerNatives(*this);
238 function_class_init(*this, NSV::CLASS_FUNCTION);
239 initObjectClass(_objectProto, *this, NSV::CLASS_OBJECT);
241 string_class_init(*this, NSV::CLASS_STRING);
242 array_class_init(*this, NSV::CLASS_ARRAY);
244 // No idea why, but it seems there's a NULL _global.o
245 // defined at player startup...
246 // Probably due to the AS-based initialization
247 // Not enumerable but overridable and deletable.
249 as_value nullVal; nullVal.set_null();
250 init_member("o", nullVal, PropFlags::dontEnum);
253 VM& vm = getVM();
255 // _global functions.
256 // These functions are only available in SWF6+, but this is just
257 // because SWF5 or lower did not have a "_global"
258 // reference at all.
259 init_member("ASnative", createFunction(global_asnative));
260 init_member("ASconstructor", createFunction(global_asconstructor));
261 init_member("ASSetPropFlags", vm.getNative(1, 0));
262 init_member("ASSetNative", vm.getNative(4, 0));
263 init_member("ASSetNativeAccessor", vm.getNative(4, 1));
264 init_member("AsSetupError", createFunction(global_assetuperror));
265 init_member("updateAfterEvent", vm.getNative(9, 0));
266 init_member("trace", vm.getNative(100, 4));
268 init_member("setInterval", vm.getNative(250, 0));
269 init_member("clearInterval", vm.getNative(250, 1));
270 init_member("setTimeout", vm.getNative(250, 2));
272 // This is an odd function with no properties. There ought to be
273 // a better way of implementing this. See also TextFormat.getTextExtent.
274 as_function* edc = createFunction(global_enableDebugConsole);
275 edc->clearProperties();
276 init_member("enableDebugConsole", edc);
277 init_member("showRedrawRegions", vm.getNative(1021, 1));
279 init_member("clearTimeout", getMember(*this, getURI(vm, "clearInterval")));
281 _classes.declareAll(avm1Classes());
283 // SWF8 visibility:
284 const ObjectURI& flash = getURI(vm, "flash");
285 flash_package_init(*this, flash);
287 const int version = vm.getSWFVersion();
289 if (version > 4) {
290 // This is surely not correct, but they are not available
291 // in SWF4
292 init_member("escape", vm.getNative(100, 0));
293 init_member("unescape", vm.getNative(100, 1));
294 init_member("parseInt", vm.getNative(100, 2));
295 init_member("parseFloat", vm.getNative(100, 3));
296 init_member("isNaN", vm.getNative(200, 18));
297 init_member("isFinite", vm.getNative(200, 19));
299 init_member("NaN", as_value(NaN));
300 init_member("Infinity", as_value(
301 std::numeric_limits<double>::infinity()));
304 loadExtensions();
307 as_object*
308 createObject(const Global_as& gl)
310 as_object* obj = new as_object(gl);
311 gl.makeObject(*obj);
312 return obj;
315 //-----------------------
316 // Extensions
317 //-----------------------
318 // Scan the plugin directories for all plugins, and load them now.
319 // FIXME: this should actually be done dynamically, and only
320 // if a plugin defines a class that a movie actually wants to
321 // use.
322 void
323 Global_as::loadExtensions()
325 if (RcInitFile::getDefaultInstance().enableExtensions()) {
326 log_security(_("Extensions enabled, scanning plugin dir for load"));
327 _et->scanAndLoad(*this);
329 else {
330 log_security(_("Extensions disabled"));
334 void
335 Global_as::makeObject(as_object& o) const
337 o.set_prototype(_objectProto);
340 namespace {
342 const ClassHierarchy::NativeClasses&
343 avm1Classes()
345 typedef ClassHierarchy::NativeClass N;
347 // Since we maintain separate lists for AVM1 and AVM2, these are all
348 // considered to be in the 'Global' namespace (AVM1 has no namespaces)
349 // An ObjectURI constructed without a namespace is in the global namespace.
350 static const ClassHierarchy::NativeClasses s = boost::assign::list_of
352 (N(system_class_init, NSV::CLASS_SYSTEM, 1))
353 (N(stage_class_init, NSV::CLASS_STAGE, 1))
354 (N(movieclip_class_init, NSV::CLASS_MOVIE_CLIP, 3))
355 (N(textfield_class_init, NSV::CLASS_TEXT_FIELD, 3))
356 (N(math_class_init, NSV::CLASS_MATH, 4))
357 (N(boolean_class_init, NSV::CLASS_BOOLEAN, 5))
358 (N(button_class_init, NSV::CLASS_BUTTON, 5))
359 (N(color_class_init, NSV::CLASS_COLOR, 5))
360 (N(selection_class_init, NSV::CLASS_SELECTION, 5))
361 (N(sound_class_init, NSV::CLASS_SOUND, 5))
362 (N(xmlsocket_class_init, NSV::CLASS_XMLSOCKET, 5))
363 (N(date_class_init, NSV::CLASS_DATE, 5))
364 (N(xmlnode_class_init, NSV::CLASS_XMLNODE, 5))
365 (N(xml_class_init, NSV::CLASS_XML, 5))
366 (N(mouse_class_init, NSV::CLASS_MOUSE, 5))
367 (N(number_class_init, NSV::CLASS_NUMBER, 5))
368 (N(textformat_class_init, NSV::CLASS_TEXT_FORMAT, 5))
369 (N(key_class_init, NSV::CLASS_KEY, 5))
370 (N(AsBroadcaster::init, NSV::CLASS_AS_BROADCASTER, 5))
371 (N(textsnapshot_class_init, NSV::CLASS_TEXT_SNAPSHOT, 5))
372 (N(video_class_init, NSV::CLASS_VIDEO, 6))
373 (N(camera_class_init, NSV::CLASS_CAMERA, 5))
374 (N(microphone_class_init, NSV::CLASS_MICROPHONE, 5))
375 (N(sharedobject_class_init, NSV::CLASS_SHARED_OBJECT, 5))
376 (N(loadvars_class_init, NSV::CLASS_LOAD_VARS, 5))
377 (N(localconnection_class_init, NSV::CLASS_LOCALCONNECTION, 6))
378 (N(netconnection_class_init, NSV::CLASS_NET_CONNECTION, 6))
379 (N(netstream_class_init, NSV::CLASS_NET_STREAM, 6))
380 (N(contextmenu_class_init, NSV::CLASS_CONTEXTMENU, 5))
381 (N(contextmenuitem_class_init, NSV::CLASS_CONTEXTMENUITEM, 5))
382 (N(moviecliploader_class_init, NSV::CLASS_MOVIE_CLIP_LOADER, 5))
383 (N(Error_class_init, NSV::CLASS_ERROR, 5))
384 (N(accessibility_class_init, NSV::CLASS_ACCESSIBILITY, 5));
386 return s;
389 as_value
390 global_trace(const fn_call& fn)
392 ASSERT_FN_ARGS_IS_1
394 // Log our argument.
396 // @@ what if we get extra args?
398 // @@ Nothing needs special treatment,
399 // as_value::to_string() will take care of everything
400 log_trace("%s", fn.arg(0).to_string());
402 return as_value();
406 as_value
407 global_isNaN(const fn_call& fn)
409 ASSERT_FN_ARGS_IS_1
411 return as_value(static_cast<bool>(isNaN(
412 toNumber(fn.arg(0), getVM(fn)))));
416 as_value
417 global_isfinite(const fn_call& fn)
419 ASSERT_FN_ARGS_IS_1
421 return as_value(static_cast<bool>(isFinite(
422 toNumber(fn.arg(0), getVM(fn)))));
425 /// \brief Encode a string to URL-encoded format
426 /// converting all dodgy DisplayObjects to %AB hex sequences
428 /// Characters that need escaping are:
429 /// - ASCII control DisplayObjects: 0-31 and 127
430 /// - Non-ASCII chars: 128-255
431 /// - URL syntax DisplayObjects: $ & + , / : ; = ? @
432 /// - Unsafe DisplayObjects: SPACE " < > # % { } | \ ^ ~ [ ] `
433 /// Encoding is a % followed by two hexadecimal DisplayObjects, case insensitive.
434 /// See RFC1738 http://www.rfc-editor.org/rfc/rfc1738.txt,
435 /// Section 2.2 "URL Character Encoding Issues"
436 as_value
437 global_escape(const fn_call& fn)
439 ASSERT_FN_ARGS_IS_1
441 std::string input = fn.arg(0).to_string();
442 URL::encode(input);
443 return as_value(input);
446 /// \brief Decode a string from URL-encoded format
447 /// converting all hexadecimal sequences to ASCII DisplayObjects.
449 /// A sequence to convert is % followed by two case-independent hexadecimal
450 /// digits, which is replaced by the equivalent ASCII DisplayObject.
451 /// See RFC1738 http://www.rfc-editor.org/rfc/rfc1738.txt,
452 /// Section 2.2 "URL Character Encoding Issues"
453 as_value
454 global_unescape(const fn_call& fn)
456 ASSERT_FN_ARGS_IS_1
458 std::string input = fn.arg(0).to_string();
459 URL::decode(input);
460 return as_value(input);
463 // parseFloat (string)
464 as_value
465 global_parsefloat(const fn_call& fn)
467 ASSERT_FN_ARGS_IS_1
469 std::istringstream s(fn.arg(0).to_string());
470 double result;
472 if (!(s >> result)) {
473 return as_value(NaN);
476 return as_value(result);
479 // parseInt(string[, base])
480 // The second argument, if supplied, is the base.
481 // If none is supplied, we have to work out the
482 // base from the string. Decimal, octal and hexadecimal are
483 // possible, according to the following rules:
484 // 1. If the string starts with 0x or 0X, the number is hex.
485 // 2. The 0x or 0X may be *followed* by '-' or '+' to indicate sign. A number
486 // with no sign is positive.
487 // 3. If the string starts with 0, -0 or +0 and contains only the DisplayObjects
488 // 0-7.
489 // 4. If the string starts with *any* other sequence of DisplayObjects, including
490 // whitespace, it is decimal.
491 as_value
492 global_parseint(const fn_call& fn)
494 if (!fn.nargs) {
495 IF_VERBOSE_ASCODING_ERRORS(
496 log_aserror(_("%s needs at least one argument"), __FUNCTION__);
498 return as_value();
501 IF_VERBOSE_ASCODING_ERRORS(
502 if (fn.nargs > 2) {
503 log_aserror(_("%s has more than two arguments"), __FUNCTION__);
507 const std::string& expr = fn.arg(0).to_string();
509 // A second argument specifies the base.
510 // Parsing still starts after any positive/negative
511 // sign or hex identifier (parseInt("0x123", 8) gives
512 // 83, not 0; parseInt(" 0x123", 8) is 0), which is
513 // why we do this here.
514 size_t base;
515 if (fn.nargs > 1) {
516 base = toInt(fn.arg(1), getVM(fn));
518 // Bases from 2 to 36 are valid, otherwise return NaN
519 if (base < 2 || base > 36) return as_value(NaN);
521 else {
522 /// No radix specified, so try parsing as octal or hexadecimal
523 try {
524 double d;
525 if (parseNonDecimalInt(expr, d, false)) return d;
527 catch (const boost::bad_lexical_cast&) {
528 return as_value(NaN);
531 /// The number is not hex or octal, so we'll assume it's base-10.
532 base = 10;
536 std::string::const_iterator it = expr.begin();
538 // Check for expectional case "-0x" or "+0x", which
539 // return NaN
540 if ((expr.length() > 2) && (*it == '-' || *it == '+') &&
541 *(it + 1) == '0' && std::toupper(*(it + 2)) == 'X') {
542 return as_value(NaN);
545 // Try hexadecimal first
546 if (expr.substr(0, 2) == "0x" || expr.substr(0, 2) == "0X") it += 2;
547 else {
548 // Skip leading whitespace
549 while(*it == ' ' || *it == '\n' || *it == '\t' || *it == '\r') {
550 ++it;
552 if (it == expr.end()) return as_value(NaN);
555 bool negative = false;
556 if (*it == '-' || *it == '+') {
557 if (*it == '-') negative = true;
559 it++;
560 if (it == expr.end()) return as_value(NaN);
563 // Now we have the base, parse the digits. The iterator should
564 // be pointing at the first digit.
566 const std::string digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
568 // Check to see if the first digit is valid, otherwise
569 // return NaN.
570 std::string::size_type digit = digits.find(toupper(*it));
572 if (digit >= base || digit == std::string::npos) return as_value(NaN);
574 // The first digit was valid, so continue from the present position
575 // until we reach the end of the string or an invalid DisplayObject,
576 // adding valid DisplayObjects to our result.
577 // Which DisplayObjects are invalid depends on the base.
578 double result = digit;
579 ++it;
581 while (it != expr.end() && (digit = digits.find(toupper(*it))) < base
582 && digit != std::string::npos) {
583 result = result * base + digit;
584 ++it;
587 // Now return the parsed string as an integer.
588 return negative ? as_value(-result) : as_value(result);
591 // ASSetPropFlags function
592 as_value
593 global_assetpropflags(const fn_call& fn)
595 if (fn.nargs < 3) {
596 IF_VERBOSE_ASCODING_ERRORS(
597 log_aserror(_("%s needs at least three arguments"), __FUNCTION__);
599 return as_value();
602 IF_VERBOSE_ASCODING_ERRORS(
603 if (fn.nargs > 4) {
604 log_aserror(_("%s has more than four arguments"), "AsSetPropFlags");
608 // object
609 as_object* obj = toObject(fn.arg(0), getVM(fn));
610 if (!obj) {
611 IF_VERBOSE_ASCODING_ERRORS(
612 log_aserror(_("Invalid call to ASSetPropFlags: "
613 "first argument is not an object: %s"),
614 fn.arg(0));
616 return as_value();
619 // list of child names
621 const as_value& props = fn.arg(1);
623 const int flagsMask = PropFlags::dontEnum |
624 PropFlags::dontDelete |
625 PropFlags::readOnly |
626 PropFlags::onlySWF6Up |
627 PropFlags::ignoreSWF6 |
628 PropFlags::onlySWF7Up |
629 PropFlags::onlySWF8Up |
630 PropFlags::onlySWF9Up;
632 // a number which represents three bitwise flags which
633 // are used to determine whether the list of child names should be hidden,
634 // un-hidden, protected from over-write, un-protected from over-write,
635 // protected from deletion and un-protected from deletion
636 const int setTrue = int(toNumber(fn.arg(2), getVM(fn))) & flagsMask;
638 // Is another integer bitmask that works like set_true,
639 // except it sets the attributes to false. The
640 // set_false bitmask is applied before set_true is applied
642 // ASSetPropFlags was exposed in Flash 5, however the fourth argument
643 // 'set_false' was not required as it always defaulted to the value '~0'.
644 const int setFalse = (fn.nargs < 4 ? 0 : toInt(fn.arg(3), getVM(fn))) &
645 flagsMask;
647 obj->setPropFlags(props, setFalse, setTrue);
649 return as_value();
652 // ASconstructor function
653 // See: http://osflash.org/flashcoders/undocumented/asnative?s=asnative
654 as_value
655 global_asconstructor(const fn_call& fn)
657 if (fn.nargs < 2) {
658 IF_VERBOSE_ASCODING_ERRORS(
659 std::ostringstream ss; fn.dump_args(ss);
660 log_aserror(_("ASNative(%s): needs at least two arguments"),
661 ss.str());
663 return as_value();
666 const int sx = toInt(fn.arg(0), getVM(fn));
667 const int sy = toInt(fn.arg(1), getVM(fn));
669 if (sx < 0 || sy < 0) {
670 IF_VERBOSE_ASCODING_ERRORS(
671 std::ostringstream ss; fn.dump_args(ss);
672 log_aserror(_("ASconstructor(%s): args must be 0 or above"),
673 ss.str());
675 return as_value();
678 const unsigned int x = static_cast<unsigned int>(sx);
679 const unsigned int y = static_cast<unsigned int>(sy);
681 VM& vm = getVM(fn);
682 as_function* fun = vm.getNative(x, y);
683 if (!fun) {
684 log_debug(_("No ASnative(%d, %d) registered with the VM"), x, y);
685 return as_value();
688 Global_as& gl = getGlobal(fn);
689 fun->init_member(NSV::PROP_PROTOTYPE, createObject(gl));
691 return as_value(fun);
695 // ASNative function
696 // See: http://osflash.org/flashcoders/undocumented/asnative?s=asnative
697 as_value
698 global_asnative(const fn_call& fn)
700 if (fn.nargs < 2) {
701 IF_VERBOSE_ASCODING_ERRORS(
702 std::ostringstream ss; fn.dump_args(ss);
703 log_aserror(_("ASNative(%s): needs at least two arguments"),
704 ss.str());
706 return as_value();
709 const int sx = toInt(fn.arg(0), getVM(fn));
710 const int sy = toInt(fn.arg(1), getVM(fn));
712 if (sx < 0 || sy < 0) {
713 IF_VERBOSE_ASCODING_ERRORS(
714 std::ostringstream ss; fn.dump_args(ss);
715 log_aserror(_("ASnative(%s): args must be 0 or above"),
716 ss.str());
718 return as_value();
721 const unsigned int x = static_cast<unsigned int>(sx);
722 const unsigned int y = static_cast<unsigned int>(sy);
724 VM& vm = getVM(fn);
725 as_function* fun = vm.getNative(x, y);
726 if (!fun) {
727 log_debug(_("No ASnative(%d, %d) registered with the VM"), x, y);
728 return as_value();
730 return as_value(fun);
733 // Obsolete ASnew function (exists only as ASnative(2, 0))
734 as_value
735 global_asnew(const fn_call& /*fn*/)
737 LOG_ONCE(log_unimpl("ASNative (2, 0) - old ASnew"));
738 return as_value();
741 /// ASSetNative(targetObject, major, properties, minor)
743 /// Sets a series of properties on targetObject using the native table.
744 /// The third argument is generally documented to be an array, but in fact
745 /// it is always converted to a string and parsed.
746 as_value
747 global_assetnative(const fn_call& fn)
749 if (fn.nargs < 3) {
750 return as_value();
753 as_object* targetObject = toObject(fn.arg(0), getVM(fn));
754 if (!targetObject) {
755 return as_value();
758 const int major = toInt(fn.arg(1), getVM(fn));
759 if (major < 0) return as_value();
761 const std::string& props = fn.arg(2).to_string();
762 const int minor =
763 fn.nargs > 3 ? std::max<boost::int32_t>(toInt(fn.arg(3), getVM(fn)), 0) : 0;
765 std::string::const_iterator pos = props.begin();
767 VM& vm = getVM(fn);
769 size_t i = 0;
771 // pos is always the position after the last located property.
772 while (pos != props.end()) {
774 // If there are no further commas, find the end of the string.
775 std::string::const_iterator comma = std::find(pos, props.end(), ',');
777 const char num = *pos;
779 int flag;
781 switch (num) {
782 case '6':
783 flag = PropFlags::onlySWF6Up;
784 ++pos;
785 break;
786 case '7':
787 flag = PropFlags::onlySWF7Up;
788 ++pos;
789 break;
790 case '8':
791 flag = PropFlags::onlySWF8Up;
792 ++pos;
793 break;
794 case '9':
795 flag = PropFlags::onlySWF9Up;
796 ++pos;
797 break;
798 default:
799 flag = 0;
802 const std::string& property = std::string(pos, comma);
803 if (!property.empty()) {
804 targetObject->init_member(property,
805 vm.getNative(major, minor + i), flag);
807 if (comma == props.end()) break;
808 pos = comma + 1;
809 ++i;
811 return as_value();
814 // This is like ASSetNative, but attaches getter/setters.
815 as_value
816 global_assetnativeaccessor(const fn_call& fn)
818 if (fn.nargs < 3) {
819 return as_value();
822 as_object* targetObject = toObject(fn.arg(0), getVM(fn));
823 if (!targetObject) {
824 return as_value();
827 const int major = toInt(fn.arg(1), getVM(fn));
828 if (major < 0) return as_value();
830 const std::string& props = fn.arg(2).to_string();
831 const int minor =
832 fn.nargs > 3 ? std::max<boost::int32_t>(toInt(fn.arg(3), getVM(fn)), 0) : 0;
834 std::string::const_iterator pos = props.begin();
836 VM& vm = getVM(fn);
838 size_t i = 0;
840 // pos is always the position after the last located property.
841 while (pos != props.end()) {
843 // If there are no further commas, find the end of the string.
844 std::string::const_iterator comma = std::find(pos, props.end(), ',');
846 const char num = *pos;
848 int flag;
850 switch (num) {
851 case '6':
852 flag = PropFlags::onlySWF6Up;
853 ++pos;
854 break;
855 case '7':
856 flag = PropFlags::onlySWF7Up;
857 ++pos;
858 break;
859 case '8':
860 flag = PropFlags::onlySWF8Up;
861 ++pos;
862 break;
863 case '9':
864 flag = PropFlags::onlySWF9Up;
865 ++pos;
866 break;
867 default:
868 flag = 0;
871 const std::string& property = std::string(pos, comma);
872 if (!property.empty()) {
873 NativeFunction* getset = vm.getNative(major, minor + i);
874 targetObject->init_property(property, *getset, *getset, flag);
876 if (comma == props.end()) break;
877 pos = comma + 1;
878 ++i;
880 return as_value();
883 // updateAfterEvent function
884 as_value
885 global_updateAfterEvent(const fn_call& /*fn*/)
887 LOG_ONCE(log_unimpl("updateAfterEvent()"));
888 return as_value();
891 as_value
892 local_errorConstructor(const fn_call& fn)
894 as_object* obj = ensure<ValidThis>(fn);
895 const as_value& arg = fn.nargs ? fn.arg(0) : as_value();
896 VM& vm = getVM(fn);
897 obj->set_member(getURI(vm, "message"), arg);
898 return as_value();
902 /// Sets a range of Error subclasses.
903 as_value
904 global_assetuperror(const fn_call& fn)
906 if (!fn.nargs) return as_value();
908 // This should actually call String.split, but since our Array is
909 // wrong we may as well do it like this for now.
910 const std::string& errors = fn.arg(0).to_string();
912 std::string::const_iterator pos = errors.begin();
914 Global_as& gl = getGlobal(fn);
916 // pos is always the position after the last located error.
917 for (;;) {
919 // If there are no further commas, find the end of the string.
920 std::string::const_iterator comma = std::find(pos, errors.end(), ',');
922 const std::string& err = std::string(pos, comma);
924 VM& vm = getVM(fn);
926 as_function* ctor = getMember(gl, NSV::CLASS_ERROR).to_function();
927 if (ctor) {
928 fn_call::Args args;
929 as_object* proto = constructInstance(*ctor, fn.env(), args);
931 // Not really sure what the point of this is.
932 gl.createClass(local_errorConstructor, proto);
933 proto->set_member(getURI(vm, "name"), err);
934 proto->set_member(getURI(vm, "message"), err);
937 if (comma == errors.end()) break;
938 pos = comma + 1;
940 return as_value();
943 as_value
944 global_setInterval(const fn_call& fn)
946 if (fn.nargs < 2) {
947 IF_VERBOSE_ASCODING_ERRORS(
948 std::stringstream ss; fn.dump_args(ss);
949 log_aserror("Invalid call to setInterval(%s) "
950 "- need at least 2 arguments",
951 ss.str());
953 return as_value();
956 unsigned timer_arg = 1;
958 as_object* obj = toObject(fn.arg(0), getVM(fn));
959 if (!obj) {
961 IF_VERBOSE_ASCODING_ERRORS(
962 std::stringstream ss; fn.dump_args(ss);
963 log_aserror("Invalid call to setInterval(%s) "
964 "- first argument is not an object or function",
965 ss.str());
967 return as_value();
970 ObjectURI methodName;
972 // Get interval function
973 as_function* as_func = obj->to_function();
974 if (!as_func) {
975 methodName = getURI(getVM(fn), fn.arg(1).to_string());
976 timer_arg = 2;
980 if (fn.nargs < timer_arg + 1) {
981 IF_VERBOSE_ASCODING_ERRORS(
982 std::stringstream ss; fn.dump_args(ss);
983 log_aserror("Invalid call to setInterval(%s) "
984 "- missing timeout argument",
985 ss.str());
987 return as_value();
990 // Get interval time
991 unsigned long ms =
992 static_cast<unsigned long>(toNumber(fn.arg(timer_arg), getVM(fn)));
993 // TODO: check validity of interval time number ?
995 // Parse arguments
996 fn_call::Args args;
997 for (unsigned i = timer_arg + 1; i < fn.nargs; ++i) {
998 args += fn.arg(i);
1001 std::auto_ptr<Timer> timer;
1002 if (as_func) {
1003 timer.reset(new Timer(*as_func, ms, fn.this_ptr, args));
1005 else {
1006 timer.reset(new Timer(obj, methodName, ms, args));
1009 movie_root& root = getRoot(fn);
1011 // TODO: check what should happen to overflows.
1012 const int id = root.addIntervalTimer(timer);
1013 return as_value(id);
1016 as_value
1017 global_setTimeout(const fn_call& fn)
1019 if (fn.nargs < 2) {
1020 IF_VERBOSE_ASCODING_ERRORS(
1021 std::stringstream ss; fn.dump_args(ss);
1022 log_aserror("Invalid call to setTimeout(%s) "
1023 "- need at least 2 arguments",
1024 ss.str());
1026 return as_value();
1029 unsigned timer_arg = 1;
1031 as_object* obj = toObject(fn.arg(0), getVM(fn));
1032 if (!obj) {
1033 IF_VERBOSE_ASCODING_ERRORS(
1034 std::stringstream ss; fn.dump_args(ss);
1035 log_aserror("Invalid call to setInterval(%s) "
1036 "- first argument is not an object or function",
1037 ss.str());
1039 return as_value();
1042 ObjectURI methodName;
1044 // Get interval function
1045 as_function* as_func = obj->to_function();
1046 if (!as_func) {
1047 methodName = getURI(getVM(fn), fn.arg(1).to_string());
1048 timer_arg = 2;
1052 if (fn.nargs < timer_arg + 1) {
1053 IF_VERBOSE_ASCODING_ERRORS(
1054 std::stringstream ss; fn.dump_args(ss);
1055 log_aserror("Invalid call to setTimeout(%s): missing "
1056 "timeout argument", ss.str());
1058 return as_value();
1061 // Get interval time
1062 unsigned long ms =
1063 static_cast<unsigned long>(toNumber(fn.arg(timer_arg), getVM(fn)));
1065 // Parse arguments
1066 fn_call::Args args;
1067 for (unsigned i = timer_arg + 1; i < fn.nargs; ++i) {
1068 args += fn.arg(i);
1071 std::auto_ptr<Timer> timer;
1072 if (as_func) {
1073 timer.reset(new Timer(*as_func, ms, fn.this_ptr, args, true));
1075 else {
1076 timer.reset(new Timer(obj, methodName, ms, args, true));
1079 movie_root& root = getRoot(fn);
1081 // TODO: check what should happen to overflows.
1082 const int id = root.addIntervalTimer(timer);
1083 return as_value(id);
1086 as_value
1087 global_clearInterval(const fn_call& fn)
1089 if (!fn.nargs) {
1090 IF_VERBOSE_ASCODING_ERRORS(
1091 log_aserror("clearInterval requires one argument, got none");
1093 return as_value();
1096 const boost::uint32_t id = toInt(fn.arg(0), getVM(fn));
1098 movie_root& root = getRoot(fn);
1099 return as_value(root.clearIntervalTimer(id));
1102 as_value
1103 global_showRedrawRegions(const fn_call& /*fn*/)
1105 LOG_ONCE(log_unimpl("_global.showRedrawRegions"));
1106 return as_value();
1109 as_value
1110 global_enableDebugConsole(const fn_call& /*fn*/)
1112 LOG_ONCE(log_unimpl("_global.enableDebugConsole"));
1113 return as_value();
1116 void
1117 registerNatives(as_object& global)
1119 VM& vm = getVM(global);
1121 // ASNew was dropped as an API function but exists
1122 // as ASnative.
1123 vm.registerNative(global_assetpropflags, 1, 0);
1124 vm.registerNative(global_asnew, 2, 0);
1125 vm.registerNative(global_assetnative, 4, 0);
1126 vm.registerNative(global_assetnativeaccessor, 4, 1);
1127 vm.registerNative(global_updateAfterEvent, 9, 0);
1128 vm.registerNative(global_escape, 100, 0);
1129 vm.registerNative(global_unescape, 100, 1);
1130 vm.registerNative(global_parseint, 100, 2);
1131 vm.registerNative(global_parsefloat, 100, 3);
1132 vm.registerNative(global_trace, 100, 4);
1133 vm.registerNative(global_isNaN, 200, 18);
1134 vm.registerNative(global_isfinite, 200, 19);
1135 vm.registerNative(global_setInterval, 250, 0);
1136 vm.registerNative(global_clearInterval, 250, 1);
1137 vm.registerNative(global_setTimeout, 250, 2);
1139 vm.registerNative(global_showRedrawRegions, 1021, 1);
1141 registerObjectNative(global);
1142 registerFunctionNative(global);
1143 registerStringNative(global);
1144 registerArrayNative(global);
1145 registerNumberNative(global);
1146 registerBooleanNative(global);
1147 registerMovieClipNative(global);
1148 registerSelectionNative(global);
1149 registerColorNative(global);
1150 registerMathNative(global);
1151 registerSystemNative(global);
1152 registerAccessibilityNative(global);
1153 registerStageNative(global);
1154 registerTextFieldNative(global);
1155 registerButtonNative(global);
1156 registerVideoNative(global);
1157 registerMovieClipLoaderNative(global);
1158 registerXMLSocketNative(global);
1159 registerSharedObjectNative(global);
1160 registerKeyNative(global);
1161 registerNetStreamNative(global);
1162 registerCameraNative(global);
1163 registerMicrophoneNative(global);
1164 registerTextSnapshotNative(global);
1165 registerSoundNative(global);
1166 registerLocalConnectionNative(global);
1167 registerBitmapFilterNative(global);
1168 registerColorTransformNative(global);
1169 registerExternalInterfaceNative(global);
1170 registerBitmapDataNative(global);
1172 AsBroadcaster::registerNative(global);
1173 registerTextFormatNative(global);
1174 registerDateNative(global);
1175 Mouse_as::registerNative(global);
1177 // LoadableObject has natives shared between LoadVars and XML, so
1178 // should be registered first.
1179 registerLoadableNative(global);
1180 registerXMLNative(global);
1181 registerXMLNodeNative(global);
1184 } // anonymous namespace
1185 } // namespace gnash