1
// Object.cpp: Implementation of ActionScript Object class, for Gnash.
3
// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5
// This program is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 3 of the License, or
8
// (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
// GNU General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
/* $Id: Object.cpp,v 1.41 2008/02/19 19:20:55 bwy Exp $ */
22
#include "tu_config.h"
24
#include "smart_ptr.h"
26
#include "as_object.h" // for inheritance
27
#include "builtin_function.h" // need builtin_function
28
#include "movie_definition.h" // for Object.registerClass (get_exported_resource)
29
//#include "character.h" // for Object.registerClass (get_root_movie)
30
#include "sprite_instance.h" // for Object.registerClass (get_movie_definition)
31
#include "sprite_definition.h" // for Object.registerClass (get_movie_definition)
32
#include "VM.h" // for SWF version (attachObjectInterface)
41
// Forward declarations
42
static as_value object_addproperty(const fn_call&);
43
static as_value object_registerClass(const fn_call& fn);
44
static as_value object_hasOwnProperty(const fn_call&);
45
static as_value object_isPropertyEnumerable(const fn_call&);
46
static as_value object_isPrototypeOf(const fn_call&);
47
static as_value object_watch(const fn_call&);
48
static as_value object_unwatch(const fn_call&);
52
attachObjectInterface(as_object& o)
55
int target_version = vm.getSWFVersion();
58
vm.registerNative(as_object::valueof_method, 101, 3);
59
o.init_member("valueOf", vm.getNative(101, 3));
62
vm.registerNative(as_object::tostring_method, 101, 4);
63
o.init_member("toString", vm.getNative(101, 4));
65
if ( target_version < 6 ) return;
67
// Object.addProperty()
68
vm.registerNative(object_addproperty, 101, 2);
69
o.init_member("addProperty", vm.getNative(101, 2));
71
// Object.hasOwnProperty()
72
vm.registerNative(object_hasOwnProperty, 101, 5);
73
o.init_member("hasOwnProperty", vm.getNative(101, 5));
75
// Object.isPropertyEnumerable()
76
vm.registerNative(object_isPropertyEnumerable, 101, 7);
77
o.init_member("isPropertyEnumerable", vm.getNative(101, 7));
79
// Object.isPrototypeOf()
80
vm.registerNative(object_isPrototypeOf, 101, 6);
81
o.init_member("isPrototypeOf", vm.getNative(101, 6));
84
vm.registerNative(object_watch, 101, 0);
85
o.init_member("watch", vm.getNative(101, 0));
88
vm.registerNative(object_unwatch, 101, 1);
89
o.init_member("unwatch", vm.getNative(101, 1));
95
static boost::intrusive_ptr<as_object> o;
98
o = new as_object(); // end of the inheritance chain
99
attachObjectInterface(*o);
100
//o->set_prototype(o.get()); // proto is self ?
105
// FIXME: add some useful methods :)
106
class object_as_object : public as_object
113
as_object(getObjectInterface())
120
object_ctor(const fn_call& fn)
121
// Constructor for ActionScript class Object.
123
if ( fn.nargs == 1 ) // copy constructor
125
// just copy the reference
127
// WARNING: it is likely that fn.result and fn.arg(0)
128
// are the same location... so we might skip
129
// the set_as_object() call as a whole.
130
return as_value(fn.arg(0).to_object());
133
boost::intrusive_ptr<as_object> new_obj;
136
new_obj = new object_as_object();
140
IF_VERBOSE_ASCODING_ERRORS (
141
log_aserror(_("Too many args to Object constructor"));
143
new_obj = new object_as_object();
146
return as_value(new_obj.get()); // will keep alive
149
std::auto_ptr<as_object>
150
init_object_instance()
152
return std::auto_ptr<as_object>(new object_as_object);
156
// extern (used by Global.cpp)
157
void object_class_init(as_object& global)
159
// This is going to be the global Object "class"/"function"
160
static boost::intrusive_ptr<builtin_function> cl=NULL;
166
cl=new builtin_function(&object_ctor, getObjectInterface());
168
// TODO: is this needed ?
169
//cl->init_member("prototype", as_value(getObjectInterface()));
171
// Object.registerClass() -- TODO: should this only be in SWF6 or higher ?
172
vm.registerNative(object_registerClass, 101, 8);
173
cl->init_member("registerClass", vm.getNative(101, 8));
178
// Register _global.Object
179
global.init_member("Object", cl.get());
184
object_addproperty(const fn_call& fn)
187
boost::intrusive_ptr<as_object> obj = fn.this_ptr;
191
IF_VERBOSE_ASCODING_ERRORS(
192
std::stringstream ss;
194
log_aserror(_("Invalid call to Object.addProperty(%s) - "
195
"expected 3 arguments (<name>, <getter>, <setter>)"),
199
// if we've been given more args then needed there's
200
// no need to abort here
203
return as_value(false);
207
const std::string& propname = fn.arg(0).to_string();
208
if ( propname.empty() )
210
IF_VERBOSE_ASCODING_ERRORS(
211
log_aserror(_("Invalid call to Object.addProperty() - "
212
"empty property name"));
214
return as_value(false);
217
as_function* getter = fn.arg(1).to_as_function();
220
IF_VERBOSE_ASCODING_ERRORS(
221
log_aserror(_("Invalid call to Object.addProperty() - "
222
"getter is not an AS function"));
224
return as_value(false);
227
as_function* setter = fn.arg(2).to_as_function();
230
IF_VERBOSE_ASCODING_ERRORS(
231
log_aserror(_("Invalid call to Object.addProperty() - "
232
"setter is not an AS function"));
234
return as_value(false);
238
// Now that we checked everything, let's call the as_object
239
// interface for getter/setter properties :)
241
bool result = obj->add_property(propname, *getter, *setter);
243
//log_debug("Object.addProperty(): testing");
244
return as_value(result);
248
object_registerClass(const fn_call& fn)
251
//as_object* obj = fn.this_ptr;
255
IF_VERBOSE_ASCODING_ERRORS(
256
std::stringstream ss;
258
log_aserror(_("Invalid call to Object.registerClass(%s) - "
259
"expected 2 arguments (<symbol>, <constructor>)"),
263
// if we've been given more args then needed there's
264
// no need to abort here
267
return as_value(false);
271
const std::string& symbolid = fn.arg(0).to_string();
272
if ( symbolid.empty() )
274
IF_VERBOSE_ASCODING_ERRORS(
275
std::stringstream ss;
277
log_aserror(_("Invalid call to Object.registerClass(%s) - "
278
"first argument (symbol id) evaluates to empty string"), ss.str().c_str());
280
return as_value(false);
283
as_function* theclass = fn.arg(1).to_as_function();
286
IF_VERBOSE_ASCODING_ERRORS(
287
std::stringstream ss;
289
log_aserror(_("Invalid call to Object.registerClass(%s) - "
290
"second argument (class) is not a function)"), ss.str().c_str());
292
return as_value(false);
295
// Find the exported resource
297
// TODO: check to *which* definition should we ask the export
298
// this code uses the *relative* root of current environment's target
299
movie_definition* def = VM::get().getRoot().get_movie_definition();
300
boost::intrusive_ptr<resource> exp_res = def->get_exported_resource(symbolid.c_str());
303
IF_VERBOSE_ASCODING_ERRORS(
304
log_aserror(_("Object.registerClass(%s, %s): "
305
"can't find exported symbol"),
307
typeid(theclass).name());
309
return as_value(false);
312
// Check that the exported resource is a sprite_definition
313
// (we're looking for a MovieClip symbol)
315
boost::intrusive_ptr<sprite_definition> exp_clipdef =
316
boost::intrusive_ptr<sprite_definition>(dynamic_cast<sprite_definition*>(exp_res.get()));
321
IF_VERBOSE_ASCODING_ERRORS(
322
log_aserror(_("Object.registerClass(%s, %s): "
323
"exported symbol is not a MovieClip symbol "
324
"(sprite_definition), but a %s"),
326
typeid(theclass).name(),
327
typeid(*exp_res).name());
329
return as_value(false);
332
exp_clipdef->registerClass(theclass);
333
return as_value(true);
337
object_hasOwnProperty(const fn_call& fn)
339
//assert(fn.result->is_undefined());
342
IF_VERBOSE_ASCODING_ERRORS(
343
log_aserror(_("Object.hasOwnProperty() requires one arg"));
345
return as_value(false);
347
as_value& arg = fn.arg(0);
348
const std::string& propname = arg.to_string();
349
if ( arg.is_undefined() || propname.empty() )
351
IF_VERBOSE_ASCODING_ERRORS(
352
log_aserror(_("Invalid call to Object.hasOwnProperty('%s')"), arg.to_debug_string().c_str());
354
return as_value(false);
356
return as_value(fn.this_ptr->getOwnProperty(VM::get().getStringTable().find(propname)) != NULL);
360
object_isPropertyEnumerable(const fn_call& fn)
362
//assert(fn.result->is_undefined());
365
IF_VERBOSE_ASCODING_ERRORS(
366
log_aserror(_("Object.isPropertyEnumerable() requires one arg"));
370
as_value& arg = fn.arg(0);
371
const std::string& propname = arg.to_string();
372
if ( arg.is_undefined() || propname.empty() )
374
IF_VERBOSE_ASCODING_ERRORS(
375
log_aserror(_("Invalid call to Object.isPropertyEnumerable('%s')"), arg.to_debug_string().c_str());
380
Property* prop = fn.this_ptr->getOwnProperty(VM::get().getStringTable().find(propname));
383
return as_value(false);
386
return as_value( ! prop->getFlags().get_dont_enum() );
390
object_isPrototypeOf(const fn_call& fn)
392
//assert(fn.result->is_undefined());
395
IF_VERBOSE_ASCODING_ERRORS(
396
log_aserror(_("Object.isPrototypeOf() requires one arg"));
398
return as_value(false);
401
boost::intrusive_ptr<as_object> obj = fn.arg(0).to_object();
404
IF_VERBOSE_ASCODING_ERRORS(
405
log_aserror(_("First arg to Object.isPrototypeOf(%s) is not an object"), fn.arg(0).to_debug_string().c_str());
407
return as_value(false);
410
return as_value(fn.this_ptr->prototypeOf(*obj));
415
object_watch(const fn_call&)
417
static bool warned = false;
419
log_unimpl (__FUNCTION__);
426
object_unwatch(const fn_call&)
428
static bool warned = false;
430
log_unimpl (__FUNCTION__);