~ubuntu-branches/ubuntu/karmic/gnash/karmic

« back to all changes in this revision

Viewing changes to libcore/as_object.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// as_object.cpp:  ActionScript Object class and its properties, for Gnash.
 
2
// 
 
3
//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
4
// 
 
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.
 
9
// 
 
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.
 
14
// 
 
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
 
18
 
 
19
#ifdef HAVE_CONFIG_H
 
20
#include "gnashconfig.h"
 
21
#endif
 
22
 
 
23
#include "log.h"
 
24
 
 
25
#include "smart_ptr.h" // GNASH_USE_GC
 
26
#include "as_object.h"
 
27
#include "as_function.h"
 
28
#include "as_environment.h" // for enumerateProperties
 
29
#include "Property.h" // for findGetterSetter
 
30
#include "VM.h"
 
31
#include "GnashException.h"
 
32
#include "fn_call.h" // for generic methods
 
33
#include "Object.h" // for getObjectInterface
 
34
#include "action.h" // for call_method
 
35
#include "array.h" // for setPropFlags
 
36
#include "as_function.h" // for inheritance of as_super
 
37
 
 
38
#include <set>
 
39
#include <string>
 
40
#include <boost/algorithm/string/case_conv.hpp>
 
41
#include <utility> // for std::pair
 
42
#include "namedStrings.h"
 
43
#include "asName.h"
 
44
#include "asClass.h"
 
45
 
 
46
// Anonymous namespace used for module-static defs
 
47
namespace {
 
48
 
 
49
using namespace gnash;
 
50
 
 
51
/// 'super' is a special kind of object
 
52
//
 
53
/// See http://wiki.gnashdev.org/wiki/index.php/ActionScriptSuper
 
54
///
 
55
/// We make it derive from as_function instead of as_object
 
56
/// to avoid touching too many files (ie: an as_object is not considered
 
57
/// something that can be called by current Gnash code). We may want
 
58
/// to change this in the future to implement what ECMA-262 refers to
 
59
/// as the [[Call]] property of objects.
 
60
///
 
61
class as_super : public as_function
 
62
{
 
63
public:
 
64
 
 
65
        as_super(as_function* ctor, as_object* proto)
 
66
                :
 
67
                _ctor(ctor),
 
68
                _proto(proto)
 
69
        {
 
70
                set_prototype(proto);
 
71
                //log_debug("as_super %p constructed with ctor %p and proto %p", this, ctor, proto);
 
72
        }
 
73
 
 
74
        virtual bool isSuper() const { return true; }
 
75
 
 
76
        virtual as_object* get_super(const char* fname=0);
 
77
 
 
78
        std::string get_text_value() const
 
79
        {
 
80
                return "[object Object]";
 
81
        }
 
82
 
 
83
        // Fetching members from 'super' yelds a lookup on the associated prototype
 
84
        virtual bool get_member(string_table::key name, as_value* val,
 
85
                string_table::key nsname = 0)
 
86
        {
 
87
                //log_debug("as_super::get_member %s called - _proto is %p", getVM().getStringTable().value(name), _proto);
 
88
                if ( _proto ) return _proto->get_member(name, val, nsname);
 
89
                log_debug("Super has no associated prototype");
 
90
                return false;
 
91
        }
 
92
 
 
93
        // Setting members on 'super' is a no-op
 
94
        virtual void set_member(string_table::key /*key*/, const as_value& /*val*/,
 
95
                string_table::key /*nsname*/ = 0)
 
96
        {
 
97
                // can't assign to super
 
98
                IF_VERBOSE_ASCODING_ERRORS(
 
99
                log_aserror("Can't set members on the 'super' object");
 
100
                );
 
101
        }
 
102
 
 
103
        /// Dispatch.
 
104
        virtual as_value operator()(const fn_call& fn)
 
105
        {
 
106
                //log_debug("Super call operator. fn.this_ptr is %p", fn.this_ptr);
 
107
                if ( _ctor ) return _ctor->call(fn);
 
108
                log_debug("Super has no associated constructor");
 
109
                return as_value();
 
110
        }
 
111
 
 
112
protected:
 
113
 
 
114
        virtual void markReachableResources() const
 
115
        {
 
116
                if ( _ctor ) _ctor->setReachable();
 
117
                if ( _proto ) _proto->setReachable();
 
118
                markAsFunctionReachable();
 
119
        }
 
120
 
 
121
private:
 
122
 
 
123
        as_function* _ctor;
 
124
        as_object* _proto;
 
125
};
 
126
 
 
127
as_object*
 
128
as_super::get_super(const char* fname)
 
129
{
 
130
        // Super references the super class of our class prototype.
 
131
        // Our class prototype is __proto__.
 
132
        // Our class superclass prototype is __proto__.__proto__
 
133
 
 
134
        // Our class prototype is __proto__.
 
135
        as_object* proto = get_prototype().get(); 
 
136
        if ( ! proto )
 
137
        {
 
138
                //log_debug("We (a super) have no associated prototype, returning a null-referencing as_super from get_super()");
 
139
                return new as_super(0, 0);
 
140
        }
 
141
 
 
142
        // proto's __proto__ is superProto 
 
143
        as_object* superProto = proto->get_prototype().get();
 
144
 
 
145
        // proto's __constructor__ is superCtor
 
146
        as_function* superCtor = proto->get_constructor();
 
147
        assert(superCtor == get_constructor());
 
148
 
 
149
        //log_debug("super %p proto is %p, its prototype %p", this, proto, proto->get_prototype());
 
150
 
 
151
        VM& vm = getVM();
 
152
        if ( fname && vm.getSWFVersion() > 6)
 
153
        {
 
154
                as_object* owner = 0;
 
155
                string_table& st = vm.getStringTable();
 
156
                string_table::key k = st.find(fname);
 
157
 
 
158
                proto->findProperty(k, 0, &owner);
 
159
                if ( ! owner )
 
160
                {
 
161
                        //log_debug("get_super: can't find property %s", fname);
 
162
                        return 0;
 
163
                }
 
164
 
 
165
                //log_debug("object containing method %s is %p, its __proto__ is %p", fname, owner, owner->get_prototype());
 
166
 
 
167
                assert(owner);
 
168
 
 
169
                if ( owner != proto )
 
170
                {
 
171
                        as_object* tmp = proto;
 
172
                        while (tmp && tmp->get_prototype() != owner) tmp = tmp->get_prototype().get();
 
173
                        // ok, now 'tmp' should be the object whose __proto__ member contains
 
174
                        // the actual named method.
 
175
                        //
 
176
                        // in the C:B:A:F case this would be B when calling super.myName() from
 
177
                        // C.prototype.myName()
 
178
                        //
 
179
 
 
180
                        assert(tmp); // well, since we found the property, it must be somewhere!
 
181
 
 
182
                        //log_debug("tmp is %p", tmp);
 
183
 
 
184
                        if ( tmp != proto )
 
185
                        {
 
186
                                //assert(superProto == tmp->get_prototype().get());
 
187
 
 
188
                                //superCtor = superProto->get_constructor();
 
189
                                superCtor = tmp->get_constructor();
 
190
                                //if ( ! superCtor ) log_debug("superProto (owner) has no __constructor__");
 
191
                        }
 
192
                        else
 
193
                        {
 
194
                                //log_debug("tmp == proto");
 
195
                                superCtor = owner->get_constructor(); // most likely..
 
196
                                if ( superProto ) superProto = superProto->get_prototype().get();
 
197
                        }
 
198
                }
 
199
                else
 
200
                {
 
201
                        // TODO: check if we've anything to do here...
 
202
                        //log_debug("owner == proto == %p", owner);
 
203
                        //if ( superProto ) superProto = superProto->get_prototype().get();
 
204
                        //superCtor = superProto->get_constructor();
 
205
                        //if ( superProto )
 
206
                        //{
 
207
                        //      superCtor = superProto->get_constructor();
 
208
                        //} // else superCtor = NULL ?
 
209
                }
 
210
        }
 
211
 
 
212
        as_object* super = new as_super(superCtor, superProto);
 
213
 
 
214
        return super;
 
215
}
 
216
 
 
217
 
 
218
/// A PropertyList visitor copying properties to an object
 
219
class PropsCopier : public AbstractPropertyVisitor {
 
220
 
 
221
        as_object& _tgt;
 
222
 
 
223
public:
 
224
 
 
225
        /// \brief
 
226
        /// Initialize a PropsCopier instance associating it
 
227
        /// with a target object (an object whose members has to be set)
 
228
        ///
 
229
        PropsCopier(as_object& tgt)
 
230
                :
 
231
                _tgt(tgt)
 
232
        {}
 
233
 
 
234
        /// \brief
 
235
        /// Use the set_member function to properly set *inherited* properties
 
236
        /// of the given target object
 
237
        ///
 
238
        void accept(string_table::key name, const as_value& val)
 
239
        {
 
240
                if (name == NSV::PROP_uuPROTOuu) return;
 
241
                //log_debug(_("Setting member '%s' to value '%s'"), name, val);
 
242
                _tgt.set_member(name, val);
 
243
        }
 
244
};
 
245
 
 
246
} // end of anonymous namespace
 
247
 
 
248
 
 
249
namespace gnash {
 
250
 
 
251
bool
 
252
as_object::add_property(const std::string& name, as_function& getter,
 
253
                as_function* setter)
 
254
{
 
255
        string_table &st = _vm.getStringTable();
 
256
        string_table::key k = st.find(name);
 
257
 
 
258
        as_value cacheVal;
 
259
 
 
260
        Property* prop = _members.getProperty(k);
 
261
        if ( prop )
 
262
        {
 
263
                cacheVal = prop->getCache();
 
264
                return _members.addGetterSetter(k, getter, setter, cacheVal);
 
265
 
 
266
                // NOTE: watch triggers not called when adding a new getter-setter property
 
267
        }
 
268
        else
 
269
        {
 
270
 
 
271
                bool ret = _members.addGetterSetter(k, getter, setter, cacheVal);
 
272
                if (!ret) return false;
 
273
 
 
274
#if 1
 
275
                // check if we have a trigger, if so, invoke it
 
276
                // and set val to it's return
 
277
                TriggerContainer::iterator trigIter = _trigs.find(std::make_pair(k, 0));
 
278
                if ( trigIter != _trigs.end() )
 
279
                {
 
280
                        Trigger& trig = trigIter->second;
 
281
 
 
282
                        log_debug("add_property: property %s is being watched, current val: %s", name, cacheVal);
 
283
                        cacheVal = trig.call(cacheVal, as_value(), *this);
 
284
 
 
285
                        // The trigger call could have deleted the property,
 
286
                        // so we check for its existance again, and do NOT put
 
287
                        // it back in if it was deleted
 
288
                        prop = _members.getProperty(k);
 
289
                        if ( ! prop )
 
290
                        {
 
291
                                log_debug("Property %s deleted by trigger on create (getter-setter)", name);
 
292
                                return false; // or true ?
 
293
                        }
 
294
                        prop->setCache(cacheVal);
 
295
                        //prop->setValue(*this, cacheVal);
 
296
                }
 
297
#endif
 
298
 
 
299
                return ret;
 
300
        }
 
301
}
 
302
 
 
303
 
 
304
bool
 
305
as_object::get_member(string_table::key name, as_value* val,
 
306
        string_table::key nsname)
 
307
{
 
308
        assert(val);
 
309
 
 
310
        Property* prop = findProperty(name, nsname);
 
311
        if (!prop)
 
312
                return false;
 
313
 
 
314
        try 
 
315
        {
 
316
                *val = prop->getValue(*this);
 
317
                return true;
 
318
        }
 
319
        catch (ActionLimitException& exc)
 
320
        {
 
321
                // will be logged by outer catcher
 
322
                throw;
 
323
        }
 
324
        catch (ActionTypeError& exc)
 
325
        {
 
326
                // TODO: check if this should be an 'as' error.. (log_aserror)
 
327
                log_error(_("Caught exception: %s"), exc.what());
 
328
                return false;
 
329
        }
 
330
}
 
331
 
 
332
 
 
333
const Property*
 
334
as_object::getByIndex(int index)
 
335
{
 
336
        // The low byte is used to contain the depth of the property.
 
337
        unsigned char depth = index & 0xFF;
 
338
        index /= 256; // Signed
 
339
        as_object *obj = this;
 
340
        while (depth--)
 
341
        {
 
342
                obj = obj->get_prototype().get();
 
343
                if (!obj)
 
344
                        return NULL;
 
345
        }
 
346
 
 
347
        return obj->_members.getPropertyByOrder(index);
 
348
}
 
349
 
 
350
as_object*
 
351
as_object::get_super(const char* fname)
 
352
{
 
353
        // Super references the super class of our class prototype.
 
354
        // Our class prototype is __proto__.
 
355
        // Our class superclass prototype is __proto__.__proto__
 
356
 
 
357
        // Our class prototype is __proto__.
 
358
        as_object* proto = get_prototype().get();
 
359
 
 
360
        VM& vm = getVM();
 
361
        if ( fname && vm.getSWFVersion() > 6)
 
362
        {
 
363
                as_object* owner = 0;
 
364
                string_table& st = vm.getStringTable();
 
365
                string_table::key k = st.find(fname);
 
366
                /*Property* p =*/ findProperty(k, 0, &owner);
 
367
                if ( owner != this ) proto = owner; // should be 0 if findProperty returned 0
 
368
        }
 
369
 
 
370
        // proto's __proto__ is superProto 
 
371
        as_object* superProto = proto ? proto->get_prototype().get() : 0;
 
372
 
 
373
        // proto's __constructor__ is superCtor
 
374
        as_function* superCtor = proto ? proto->get_constructor() : 0;
 
375
 
 
376
        as_object* super = new as_super(superCtor, superProto);
 
377
 
 
378
        return super;
 
379
}
 
380
 
 
381
as_function*
 
382
as_object::get_constructor()
 
383
{
 
384
        as_value ctorVal;
 
385
        if ( ! get_member(NSV::PROP_uuCONSTRUCTORuu, &ctorVal) )
 
386
        {
 
387
                //log_debug("Object %p has no __constructor__ member");
 
388
                return NULL;
 
389
        }
 
390
        //log_debug("%p.__constructor__ is %s", ctorVal);
 
391
        return ctorVal.to_as_function();
 
392
}
 
393
 
 
394
int
 
395
as_object::nextIndex(int index, as_object **owner)
 
396
{
 
397
skip_duplicates:
 
398
        unsigned char depth = index & 0xFF;
 
399
        unsigned char i = depth;
 
400
        index /= 256; // Signed
 
401
        as_object *obj = this;
 
402
        while (i--)
 
403
        {
 
404
                obj = obj->get_prototype().get();
 
405
                if (!obj)
 
406
                        return 0;
 
407
        }
 
408
        
 
409
        const Property *p = obj->_members.getOrderAfter(index);
 
410
        if (!p)
 
411
        {
 
412
                obj = obj->get_prototype().get();
 
413
                if (!obj)
 
414
                        return 0;
 
415
                p = obj->_members.getOrderAfter(0);
 
416
                ++depth;
 
417
        }
 
418
        if (p)
 
419
        {
 
420
                if (findProperty(p->getName(), p->getNamespace()) != p)
 
421
                {
 
422
                        index = p->getOrder() * 256 | depth;
 
423
                        goto skip_duplicates; // Faster than recursion.
 
424
                }
 
425
                if (owner)
 
426
                        *owner = obj;
 
427
                return p->getOrder() * 256 | depth;
 
428
        }
 
429
        return 0;
 
430
}
 
431
 
 
432
/*private*/
 
433
Property*
 
434
as_object::findProperty(string_table::key key, string_table::key nsname, 
 
435
        as_object **owner)
 
436
{
 
437
        int swfVersion = _vm.getSWFVersion();
 
438
 
 
439
        // don't enter an infinite loop looking for __proto__ ...
 
440
        if (key == NSV::PROP_uuPROTOuu && !nsname)
 
441
        {
 
442
                Property* prop = _members.getProperty(key, nsname);
 
443
                // TODO: add ignoreVisibility parameter to allow using __proto__ even when not visible ?
 
444
                if (prop && prop->isVisible(swfVersion))
 
445
                {
 
446
                        if (owner != NULL)
 
447
                                *owner = this;
 
448
                        return prop;
 
449
                }
 
450
                return NULL;
 
451
        }
 
452
 
 
453
        // keep track of visited objects, avoid infinite loops.
 
454
        std::set<as_object*> visited;
 
455
 
 
456
        int i = 0;
 
457
 
 
458
        boost::intrusive_ptr<as_object> obj = this;
 
459
                
 
460
    // This recursion prevention seems not to exist in the PP.
 
461
    // Instead, it stops when its general timeout for the
 
462
    // execution of scripts is reached.
 
463
        while (obj && visited.insert(obj.get()).second)
 
464
        {
 
465
                ++i;
 
466
                if ((i > 255 && swfVersion == 5) || i > 257)
 
467
                        throw ActionLimitException("Lookup depth exceeded.");
 
468
 
 
469
                Property* prop = obj->_members.getProperty(key);
 
470
                if (prop && prop->isVisible(swfVersion) )
 
471
                {
 
472
                        if (owner != NULL)
 
473
                                *owner = obj.get();
 
474
                        return prop;
 
475
                }
 
476
                else
 
477
                        obj = obj->get_prototype();
 
478
        }
 
479
 
 
480
        // No Property found
 
481
        return NULL;
 
482
}
 
483
 
 
484
Property*
 
485
as_object::findUpdatableProperty(string_table::key key, string_table::key nsname)
 
486
{
 
487
        int swfVersion = _vm.getSWFVersion();
 
488
 
 
489
        Property* prop = _members.getProperty(key, nsname);
 
490
        // 
 
491
        // We won't scan the inheritance chain if we find a member,
 
492
        // even if invisible.
 
493
        // 
 
494
        if ( prop )     return prop;  // TODO: what about isVisible ?
 
495
 
 
496
        // don't enter an infinite loop looking for __proto__ ...
 
497
        if (key == NSV::PROP_uuPROTOuu) return NULL;
 
498
 
 
499
        std::set<as_object*> visited;
 
500
        visited.insert(this);
 
501
 
 
502
        int i = 0;
 
503
 
 
504
        boost::intrusive_ptr<as_object> obj = get_prototype();
 
505
 
 
506
    // TODO: does this recursion protection exist in the PP?
 
507
        while (obj && visited.insert(obj.get()).second)
 
508
        {
 
509
                ++i;
 
510
                if ((i > 255 && swfVersion == 5) || i > 257)
 
511
                        throw ActionLimitException("Property lookup depth exceeded.");
 
512
 
 
513
                Property* p = obj->_members.getProperty(key, nsname);
 
514
                if (p && (p->isGetterSetter() | p->isStatic()) && p->isVisible(swfVersion))
 
515
                {
 
516
                        return p; // What should we do if this is not a getter/setter ?
 
517
                }
 
518
                obj = obj->get_prototype();
 
519
        }
 
520
        return NULL;
 
521
}
 
522
 
 
523
/*protected*/
 
524
void
 
525
as_object::set_prototype(boost::intrusive_ptr<as_object> proto, int flags)
 
526
{
 
527
        static string_table::key key = NSV::PROP_uuPROTOuu;
 
528
 
 
529
        // TODO: check what happens if __proto__ is set as a user-defined getter/setter
 
530
        // TODO: check triggers !!
 
531
        _members.setValue(key, as_value(proto.get()), *this, 0, flags);
 
532
}
 
533
 
 
534
void
 
535
as_object::reserveSlot(string_table::key name, string_table::key nsId,
 
536
        unsigned short slotId)
 
537
{
 
538
        _members.reserveSlot(name, nsId, slotId);
 
539
}
 
540
 
 
541
// Handles read_only and static properties properly.
 
542
bool
 
543
as_object::set_member(string_table::key key, const as_value& val,
 
544
        string_table::key nsname, bool ifFound)
 
545
{
 
546
        //log_debug(_("set_member_default(%s)"), key);
 
547
        Property* prop = findUpdatableProperty(key, nsname);
 
548
        if (prop)
 
549
        {
 
550
                if (prop->isReadOnly())
 
551
                {
 
552
                        IF_VERBOSE_ASCODING_ERRORS(log_aserror(_(""
 
553
                                "Attempt to set read-only property '%s'"),
 
554
                                _vm.getStringTable().value(key)););
 
555
                        return true;
 
556
                }
 
557
 
 
558
                try
 
559
                {
 
560
                        // check if we have a trigger, if so, invoke it
 
561
                        // and set val to it's return
 
562
                        TriggerContainer::iterator trigIter = _trigs.find(std::make_pair(key, nsname));
 
563
                        if ( trigIter != _trigs.end() )
 
564
                        {
 
565
                                Trigger& trig = trigIter->second;
 
566
 
 
567
                                // WARNING: getValue might itself invoke a trigger
 
568
                                // (getter-setter)... ouch ?
 
569
                                // TODO: in this case, return the underlying value !
 
570
                                as_value curVal = prop->getCache(); // getValue(*this); 
 
571
 
 
572
                                log_debug("Existing property %s is being watched: firing trigger on update (current val:%s, new val:%s)",
 
573
                                        _vm.getStringTable().value(key), curVal, val);
 
574
                                as_value newVal = trig.call(curVal, val, *this);
 
575
                                // The trigger call could have deleted the property,
 
576
                                // so we check for its existance again, and do NOT put
 
577
                                // it back in if it was deleted
 
578
                                prop = findUpdatableProperty(key, nsname);
 
579
                                if ( ! prop )
 
580
                                {
 
581
                                        log_debug("Property %s deleted by trigger on update", _vm.getStringTable().value(key));
 
582
                                        return true;
 
583
                                }
 
584
 
 
585
                                //if ( prop->isGetterSetter() ) prop->setCache(newVal); 
 
586
                                prop->setValue(*this, newVal); 
 
587
                        }
 
588
                        else
 
589
                        {
 
590
                                // log_debug("No trigger for key %d ns %d", key, nsname);
 
591
                                prop->setValue(*this, val);
 
592
                        }
 
593
 
 
594
                        prop->clearVisible(_vm.getSWFVersion());
 
595
                }
 
596
                catch (ActionTypeError& exc)
 
597
                {
 
598
                        log_aserror(_("%s: Exception %s. Will create a new member"),
 
599
                                _vm.getStringTable().value(key), exc.what());
 
600
                }
 
601
 
 
602
                return true;
 
603
        }
 
604
 
 
605
        // Else, add new property...
 
606
        if ( ifFound ) return false;
 
607
 
 
608
        // Property does not exist, so it won't be read-only. Set it.
 
609
        if (!_members.setValue(key, val, *this, nsname))
 
610
        {
 
611
                IF_VERBOSE_ASCODING_ERRORS(
 
612
                        log_aserror(_("Unknown failure in setting property '%s' on "
 
613
                        "object '%p'"), _vm.getStringTable().value(key), (void*) this);
 
614
            );
 
615
                return false;
 
616
        }
 
617
 
 
618
        // Now check if we have a trigger, if so, invoke it
 
619
        // and reset val to it's return
 
620
        // NOTE that we do this *after* setting it in first place 
 
621
        // as the trigger seems allowed to delete the property again
 
622
        TriggerContainer::iterator trigIter = _trigs.find(std::make_pair(key, nsname));
 
623
        if ( trigIter != _trigs.end() )
 
624
        {
 
625
                Trigger& trig = trigIter->second;
 
626
 
 
627
                log_debug("Property %s is being watched, calling trigger on create", _vm.getStringTable().value(key));
 
628
 
 
629
                // NOTE: the trigger call might delete the propery being added
 
630
                //       so we first add the property, then call the trigger
 
631
                //       and finally check if the property still exists (ufff...)
 
632
                //
 
633
 
 
634
                as_value curVal; // undefined, didn't exist...
 
635
                as_value newVal = trig.call(curVal, val, *this);
 
636
                Property* prop = _members.getProperty(key);
 
637
                if ( ! prop )
 
638
                {
 
639
                        log_debug("Property %s deleted by trigger on create", _vm.getStringTable().value(key));
 
640
                }
 
641
                else
 
642
                {
 
643
                        prop->setValue(*this, newVal);
 
644
                }
 
645
        }
 
646
 
 
647
        return false;
 
648
}
 
649
 
 
650
#if 0
 
651
std::pair<bool,bool>
 
652
as_object::update_member(string_table::key key, const as_value& val,
 
653
        string_table::key nsname)
 
654
{
 
655
        std::pair<bool,bool> ret; // first is found, second is updated
 
656
 
 
657
        //log_debug(_("set_member_default(%s)"), key);
 
658
        Property* prop = findUpdatableProperty(key, nsname);
 
659
        if (prop)
 
660
        {
 
661
                if (prop->isReadOnly())
 
662
                {
 
663
                        IF_VERBOSE_ASCODING_ERRORS(log_aserror(_(""
 
664
                                "Attempt to set read-only property '%s'"),
 
665
                                _vm.getStringTable().value(key)););
 
666
                        return std::make_pair(true, false);
 
667
                }
 
668
 
 
669
                try
 
670
                {
 
671
                        as_value newVal = val;
 
672
 
 
673
                        // check if we have a trigger, if so, invoke it
 
674
                        // and set val to it's return
 
675
                        TriggerContainer::iterator trigIter = _trigs.find(std::make_pair(key, nsname));
 
676
                        if ( trigIter != _trigs.end() )
 
677
                        {
 
678
                                Trigger& trig = trigIter->second;
 
679
                                // WARNING: getValue might itself invoke a trigger (getter-setter)... ouch ?
 
680
                                as_value curVal = prop->getCache(); // Value(*this); 
 
681
                                log_debug("Property %s is being watched: firing trigger on update (current val:%s, new val:%s",
 
682
                                        _vm.getStringTable().value(key),
 
683
                                        curVal, val);
 
684
                                newVal = trig.call(curVal, val, *this);
 
685
                                // The trigger call could have deleted the property,
 
686
                                // so we check for its existance again, and do NOT put
 
687
                                // it back in if it was deleted
 
688
                                prop = findUpdatableProperty(key, nsname);
 
689
                                if ( ! prop )
 
690
                                {
 
691
                                        return std::make_pair(true, true);
 
692
                                }
 
693
                        }
 
694
 
 
695
                        prop->setValue(*this, newVal);
 
696
                        return std::make_pair(true, true);
 
697
                }
 
698
                catch (ActionTypeError& exc)
 
699
                {
 
700
                        log_debug(_("%s: Exception %s. Will create a new member"),
 
701
                                _vm.getStringTable().value(key), exc.what());
 
702
                }
 
703
 
 
704
                return std::make_pair(true, false);
 
705
        }
 
706
 
 
707
        return std::make_pair(false, false);
 
708
}
 
709
#endif
 
710
 
 
711
void
 
712
as_object::init_member(const std::string& key1, const as_value& val, int flags,
 
713
        string_table::key nsname)
 
714
{
 
715
        init_member(_vm.getStringTable().find(PROPNAME(key1)), val, flags, nsname);
 
716
}
 
717
 
 
718
void
 
719
as_object::init_member(string_table::key key, const as_value& val, int flags,
 
720
        string_table::key nsname, int order)
 
721
{
 
722
        //log_debug(_("Initializing member %s for object %p"), _vm.getStringTable().value(key), (void*) this);
 
723
 
 
724
        if (order >= 0 && !_members.
 
725
                reserveSlot(static_cast<unsigned short>(order), key, nsname))
 
726
        {
 
727
                log_error(_("Attempt to set a slot for either a slot or a property "
 
728
                        "which already exists."));
 
729
                return;
 
730
        }
 
731
                
 
732
        // Set (or create) a SimpleProperty 
 
733
        if (! _members.setValue(key, val, *this, nsname, flags) )
 
734
        {
 
735
                log_error(_("Attempt to initialize read-only property ``%s''"
 
736
                        " on object ``%p'' twice"),
 
737
                        _vm.getStringTable().value(key), (void*)this);
 
738
                // We shouldn't attempt to initialize a member twice, should we ?
 
739
                abort();
 
740
        }
 
741
}
 
742
 
 
743
void
 
744
as_object::init_property(const std::string& key, as_function& getter,
 
745
                as_function& setter, int flags, string_table::key nsname)
 
746
{
 
747
        string_table::key k = _vm.getStringTable().find(PROPNAME(key));
 
748
        init_property(k, getter, setter, flags, nsname);
 
749
}
 
750
 
 
751
void
 
752
as_object::init_property(string_table::key key, as_function& getter,
 
753
                as_function& setter, int flags, string_table::key nsname)
 
754
{
 
755
        as_value cacheValue;
 
756
 
 
757
        bool success;
 
758
        success = _members.addGetterSetter(key, getter, &setter, cacheValue, flags, nsname);
 
759
 
 
760
        // We shouldn't attempt to initialize a property twice, should we ?
 
761
        assert(success);
 
762
 
 
763
        //log_debug(_("Initialized property '%s'"), name);
 
764
 
 
765
        // TODO: optimize this, don't scan again !
 
766
        //_members.setFlags(key, flags, nsname);
 
767
 
 
768
}
 
769
 
 
770
void
 
771
as_object::init_property(const std::string& key, as_c_function_ptr getter,
 
772
                as_c_function_ptr setter, int flags, string_table::key nsname)
 
773
{
 
774
        string_table::key k = _vm.getStringTable().find(PROPNAME(key));
 
775
        init_property(k, getter, setter, flags, nsname);
 
776
}
 
777
 
 
778
void
 
779
as_object::init_property(string_table::key key, as_c_function_ptr getter,
 
780
                as_c_function_ptr setter, int flags, string_table::key nsname)
 
781
{
 
782
        bool success;
 
783
        success = _members.addGetterSetter(key, getter, setter, nsname);
 
784
 
 
785
        // We shouldn't attempt to initialize a property twice, should we ?
 
786
        assert(success);
 
787
 
 
788
        //log_debug(_("Initialized property '%s'"), name);
 
789
 
 
790
        // TODO: optimize this, don't scan again !
 
791
        _members.setFlags(key, flags, nsname);
 
792
 
 
793
}
 
794
 
 
795
bool
 
796
as_object::init_destructive_property(string_table::key key, as_function& getter,
 
797
        int flags, string_table::key nsname)
 
798
{
 
799
        bool success;
 
800
 
 
801
        // No case check, since we've already got the key.
 
802
        success = _members.addDestructiveGetter(key, getter, nsname, flags);
 
803
        return success;
 
804
}
 
805
 
 
806
bool
 
807
as_object::init_destructive_property(string_table::key key, as_c_function_ptr getter,
 
808
        int flags, string_table::key nsname)
 
809
{
 
810
        bool success;
 
811
 
 
812
        // No case check, since we've already got the key.
 
813
        success = _members.addDestructiveGetter(key, getter, nsname, flags);
 
814
        return success;
 
815
}
 
816
 
 
817
void
 
818
as_object::init_readonly_property(const std::string& key, as_function& getter,
 
819
        int initflags, string_table::key nsname)
 
820
{
 
821
        string_table::key k = _vm.getStringTable().find(PROPNAME(key));
 
822
 
 
823
        init_property(k, getter, getter, initflags | as_prop_flags::readOnly
 
824
                | as_prop_flags::isProtected, nsname);
 
825
        assert(_members.getProperty(k, nsname));
 
826
}
 
827
 
 
828
void
 
829
as_object::init_readonly_property(const string_table::key& k, as_function& getter,
 
830
        int initflags, string_table::key nsname)
 
831
{
 
832
        init_property(k, getter, getter, initflags | as_prop_flags::readOnly
 
833
                | as_prop_flags::isProtected, nsname);
 
834
        assert(_members.getProperty(k, nsname));
 
835
}
 
836
 
 
837
void
 
838
as_object::init_readonly_property(const std::string& key, as_c_function_ptr getter,
 
839
        int initflags, string_table::key nsname)
 
840
{
 
841
        string_table::key k = _vm.getStringTable().find(PROPNAME(key));
 
842
 
 
843
        init_property(k, getter, getter, initflags | as_prop_flags::readOnly
 
844
                | as_prop_flags::isProtected, nsname);
 
845
        assert(_members.getProperty(k, nsname));
 
846
}
 
847
 
 
848
void
 
849
as_object::init_readonly_property(const string_table::key& k, as_c_function_ptr getter,
 
850
        int initflags, string_table::key nsname)
 
851
{
 
852
        init_property(k, getter, getter, initflags | as_prop_flags::readOnly
 
853
                | as_prop_flags::isProtected, nsname);
 
854
        assert(_members.getProperty(k, nsname));
 
855
}
 
856
 
 
857
std::string
 
858
as_object::asPropName(string_table::key name)
 
859
{
 
860
        std::string orig = _vm.getStringTable().value(name);
 
861
 
 
862
        return PROPNAME(orig); // why is PROPNAME needed here ?
 
863
}
 
864
 
 
865
 
 
866
bool
 
867
as_object::set_member_flags(string_table::key name,
 
868
                int setTrue, int setFalse, string_table::key nsname)
 
869
{
 
870
        return _members.setFlags(name, setTrue, setFalse, nsname);
 
871
}
 
872
 
 
873
void
 
874
as_object::add_interface(as_object* obj)
 
875
{
 
876
        assert(obj);
 
877
 
 
878
        if (std::find(mInterfaces.begin(), mInterfaces.end(), obj) == mInterfaces.end())
 
879
                mInterfaces.push_back(obj);
 
880
}
 
881
 
 
882
bool
 
883
as_object::instanceOf(as_object* ctor)
 
884
{
 
885
//#define GNASH_DEBUG_INSTANCE_OF 1
 
886
 
 
887
        as_value protoVal;
 
888
        if ( ! ctor->get_member(NSV::PROP_PROTOTYPE, &protoVal) )
 
889
        {
 
890
#ifdef GNASH_DEBUG_INSTANCE_OF
 
891
                log_debug("Object %p can't be an instance of an object (%p) w/out 'prototype'",
 
892
                        (void*)this, (void*)ctor);
 
893
#endif
 
894
                return false;
 
895
        }
 
896
        as_object* ctorProto = protoVal.to_object().get();
 
897
        if ( ! ctorProto )
 
898
        {
 
899
#ifdef GNASH_DEBUG_INSTANCE_OF
 
900
                log_debug("Object %p can't be an instance of an object (%p) with non-object 'prototype' (%s)",
 
901
                        (void*)this, (void*)ctor, protoVal);
 
902
#endif
 
903
                return false;
 
904
        }
 
905
 
 
906
        // TODO: cleanup the iteration, make it more readable ...
 
907
 
 
908
        std::set< as_object* > visited;
 
909
 
 
910
        as_object* obj = this;
 
911
        while (obj && visited.insert(obj).second )
 
912
        {
 
913
                as_object* thisProto = obj->get_prototype().get();
 
914
                if ( ! thisProto )
 
915
                {
 
916
                        break;
 
917
                }
 
918
 
 
919
                // Check our proto
 
920
                if ( thisProto == ctorProto )
 
921
                {
 
922
#ifdef GNASH_DEBUG_INSTANCE_OF
 
923
                        log_debug("Object %p is an instance of constructor %p as the constructor exposes our __proto__ %p",
 
924
                                (void*)obj, (void*)ctor, (void*)thisProto);
 
925
#endif
 
926
                        return true;
 
927
                }
 
928
 
 
929
                // Check our proto interfaces
 
930
                if (std::find(thisProto->mInterfaces.begin(), thisProto->mInterfaces.end(), ctorProto) != thisProto->mInterfaces.end())
 
931
                {
 
932
#ifdef GNASH_DEBUG_INSTANCE_OF
 
933
                        log_debug("Object %p __proto__ %p had one interface matching with the constructor prototype %p",
 
934
                                (void*)obj, (void*)thisProto, (void*)ctorProto);
 
935
#endif
 
936
                        return true;
 
937
                }
 
938
 
 
939
                obj = thisProto;
 
940
        }
 
941
 
 
942
        return false;
 
943
}
 
944
 
 
945
bool
 
946
as_object::prototypeOf(as_object& instance)
 
947
{
 
948
        boost::intrusive_ptr<as_object> obj = &instance;
 
949
 
 
950
        std::set< as_object* > visited;
 
951
 
 
952
        while (obj && visited.insert(obj.get()).second )
 
953
        {
 
954
                if ( obj->get_prototype() == this ) return true;
 
955
                obj = obj->get_prototype(); 
 
956
        }
 
957
 
 
958
        // See actionscript.all/Inheritance.as for a way to trigger this
 
959
        IF_VERBOSE_ASCODING_ERRORS(
 
960
        if ( obj ) log_aserror(_("Circular inheritance chain detected during isPrototypeOf call"));
 
961
        );
 
962
 
 
963
        return false;
 
964
}
 
965
 
 
966
void
 
967
as_object::dump_members() 
 
968
{
 
969
        log_debug(_("%d members of object %p follow"),
 
970
                _members.size(), (const void*)this);
 
971
        _members.dump(*this);
 
972
}
 
973
 
 
974
void
 
975
as_object::dump_members(std::map<std::string, as_value>& to)
 
976
{
 
977
        _members.dump(*this, to);
 
978
}
 
979
 
 
980
class FlagsSetterVisitor {
 
981
        string_table& _st;
 
982
        PropertyList& _pl;
 
983
        int _setTrue;
 
984
        int _setFalse;
 
985
public:
 
986
        FlagsSetterVisitor(string_table& st, PropertyList& pl, int setTrue, int setFalse)
 
987
                :
 
988
                _st(st),
 
989
                _pl(pl),
 
990
                _setTrue(setTrue),
 
991
                _setFalse(setFalse)
 
992
        {}
 
993
 
 
994
        void visit(as_value& v)
 
995
        {
 
996
                string_table::key key = _st.find(v.to_string());
 
997
                _pl.setFlags(key, _setTrue, _setFalse);
 
998
        }
 
999
};
 
1000
 
 
1001
void
 
1002
as_object::setPropFlags(const as_value& props_val, int set_false, int set_true)
 
1003
{
 
1004
        if (props_val.is_string())
 
1005
        {
 
1006
                std::string propstr = PROPNAME(props_val.to_string()); 
 
1007
 
 
1008
                for(;;)
 
1009
                {
 
1010
                        std::string prop;
 
1011
                        size_t next_comma=propstr.find(",");
 
1012
                        if ( next_comma == std::string::npos )
 
1013
                        {
 
1014
                                prop=propstr;
 
1015
                        } 
 
1016
                        else
 
1017
                        {
 
1018
                                prop=propstr.substr(0,next_comma);
 
1019
                                propstr=propstr.substr(next_comma+1);
 
1020
                        }
 
1021
 
 
1022
                        // set_member_flags will take care of case conversion
 
1023
                        if (!set_member_flags(_vm.getStringTable().find(prop), set_true, set_false) )
 
1024
                        {
 
1025
                                IF_VERBOSE_ASCODING_ERRORS(
 
1026
                                log_aserror(_("Can't set propflags on object "
 
1027
                                        "property %s "
 
1028
                                        "(either not found or protected)"),     prop);
 
1029
                                );
 
1030
                        }
 
1031
 
 
1032
                        if ( next_comma == std::string::npos )
 
1033
                        {
 
1034
                                break;
 
1035
                        }
 
1036
                }
 
1037
                return;
 
1038
        }
 
1039
 
 
1040
        // Evan: it seems that if set_true == 0 and set_false == 0,
 
1041
        // this function acts as if the parameters were (object, null, 0x1, 0)
 
1042
#if 0 // bullshit, see actionscript.all/Global.as
 
1043
        if (set_false == 0 && set_true == 0)
 
1044
        {
 
1045
            props_val.set_null();
 
1046
            set_false = 0;
 
1047
            set_true = 0x1;
 
1048
        }
 
1049
#endif
 
1050
 
 
1051
        if (props_val.is_null())
 
1052
        {
 
1053
                // Take all the members of the object
 
1054
                //std::pair<size_t, size_t> result = 
 
1055
                _members.setFlagsAll(set_true, set_false);
 
1056
 
 
1057
                // Are we sure we need to descend to __proto__ ?
 
1058
                // should we recurse then ?
 
1059
#if 0
 
1060
                if (m_prototype)
 
1061
                {
 
1062
                        m_prototype->_members.setFlagsAll(set_true, set_false);
 
1063
                }
 
1064
#endif
 
1065
                return;
 
1066
        }
 
1067
 
 
1068
        boost::intrusive_ptr<as_object> props = props_val.to_object();
 
1069
        Array_as* ary = dynamic_cast<Array_as*>(props.get());
 
1070
        if ( ! ary )
 
1071
        {
 
1072
                IF_VERBOSE_ASCODING_ERRORS(
 
1073
                log_aserror(_("Invalid call to AsSetPropFlags: "
 
1074
                        "invalid second argument %s "
 
1075
                        "(expected string, null or an array)"),
 
1076
                        props_val);
 
1077
                );
 
1078
                return;
 
1079
        }
 
1080
 
 
1081
        // The passed argument has to be considered an array
 
1082
        //std::pair<size_t, size_t> result = 
 
1083
        FlagsSetterVisitor visitor(getVM().getStringTable(), _members, set_true, set_false);
 
1084
        ary->visitAll(visitor);
 
1085
        //_members.setFlagsAll(props->_members, set_true, set_false);
 
1086
}
 
1087
 
 
1088
 
 
1089
void
 
1090
as_object::copyProperties(const as_object& o)
 
1091
{
 
1092
        PropsCopier copier(*this);
 
1093
 
 
1094
        // TODO: check if non-visible properties should be also copied !
 
1095
        o.visitPropertyValues(copier);
 
1096
}
 
1097
 
 
1098
void
 
1099
as_object::enumerateProperties(as_environment& env) const
 
1100
{
 
1101
        assert( env.top(0).is_null() );
 
1102
 
 
1103
        enumerateNonProperties(env);
 
1104
 
 
1105
        // this set will keep track of visited objects,
 
1106
        // to avoid infinite loops
 
1107
        std::set< const as_object* > visited;
 
1108
        PropertyList::propNameSet named;
 
1109
 
 
1110
        boost::intrusive_ptr<const as_object> obj(this);
 
1111
        
 
1112
        while ( obj && visited.insert(obj.get()).second )
 
1113
        {
 
1114
                obj->_members.enumerateKeys(env, named);
 
1115
                obj = obj->get_prototype();
 
1116
        }
 
1117
 
 
1118
        // This happens always since top object in hierarchy
 
1119
        // is always Object, which in turn derives from itself
 
1120
        //if ( obj ) log_error(_("prototype loop during Enumeration"));
 
1121
}
 
1122
 
 
1123
void
 
1124
as_object::enumerateProperties(std::map<std::string, std::string>& to) const
 
1125
{
 
1126
 
 
1127
        // this set will keep track of visited objects,
 
1128
        // to avoid infinite loops
 
1129
        std::set< const as_object* > visited;
 
1130
 
 
1131
        boost::intrusive_ptr<const as_object> obj(this);
 
1132
        while ( obj && visited.insert(obj.get()).second )
 
1133
        {
 
1134
                obj->_members.enumerateKeyValue(*this, to);
 
1135
                obj = obj->get_prototype();
 
1136
        }
 
1137
 
 
1138
}
 
1139
 
 
1140
as_object::as_object()
 
1141
        :
 
1142
        _members(),
 
1143
        _vm(VM::get())
 
1144
        //, m_prototype(NULL)
 
1145
{
 
1146
}
 
1147
 
 
1148
as_object::as_object(as_object* proto)
 
1149
        :
 
1150
        _members(),
 
1151
        _vm(VM::get())
 
1152
        //, m_prototype(proto)
 
1153
{
 
1154
        init_member(NSV::PROP_uuPROTOuu, as_value(proto));
 
1155
}
 
1156
 
 
1157
as_object::as_object(boost::intrusive_ptr<as_object> proto)
 
1158
        :
 
1159
        _members(),
 
1160
        _vm(VM::get())
 
1161
        //, m_prototype(proto)
 
1162
{
 
1163
        //set_prototype(proto);
 
1164
        init_member(NSV::PROP_uuPROTOuu, as_value(proto));
 
1165
}
 
1166
 
 
1167
as_object::as_object(const as_object& other)
 
1168
        :
 
1169
#ifndef GNASH_USE_GC
 
1170
        ref_counted(),
 
1171
#else
 
1172
        GcResource(), 
 
1173
#endif
 
1174
        _members(other._members),
 
1175
        _vm(VM::get())
 
1176
        //, m_prototype(other.m_prototype) // done by _members copy
 
1177
{
 
1178
}
 
1179
 
 
1180
std::pair<bool,bool>
 
1181
as_object::delProperty(string_table::key name, string_table::key nsname)
 
1182
{
 
1183
        return _members.delProperty(name, nsname);
 
1184
}
 
1185
 
 
1186
Property*
 
1187
as_object::getOwnProperty(string_table::key key, string_table::key nsname)
 
1188
{
 
1189
        return _members.getProperty(key, nsname);
 
1190
}
 
1191
 
 
1192
bool
 
1193
as_object::hasOwnProperty(string_table::key key, string_table::key nsname)
 
1194
{
 
1195
        return getOwnProperty(key, nsname) != NULL;
 
1196
}
 
1197
 
 
1198
as_value
 
1199
as_object::tostring_method(const fn_call& fn)
 
1200
{
 
1201
        boost::intrusive_ptr<as_object> obj = fn.this_ptr;
 
1202
 
 
1203
        std::string text_val = obj->get_text_value();
 
1204
        return as_value(text_val);
 
1205
}
 
1206
 
 
1207
as_value
 
1208
as_object::valueof_method(const fn_call& fn)
 
1209
{
 
1210
        boost::intrusive_ptr<as_object> obj = fn.this_ptr;
 
1211
 
 
1212
        return obj->get_primitive_value();
 
1213
}
 
1214
 
 
1215
boost::intrusive_ptr<as_object>
 
1216
as_object::get_prototype()
 
1217
{
 
1218
#if 0
 
1219
        as_value val;
 
1220
        if ( ! get_member(NSV::PROP_uuPROTOuu, &val) )
 
1221
        {
 
1222
                //log_debug("Object %p has no __proto__ member");
 
1223
                return NULL;
 
1224
        }
 
1225
        //log_debug("%p.__proto__ is %s", val);
 
1226
        return val.to_object().get();
 
1227
#else
 
1228
        static string_table::key key = NSV::PROP_uuPROTOuu;
 
1229
 
 
1230
        int swfVersion = _vm.getSWFVersion();
 
1231
 
 
1232
        boost::intrusive_ptr<as_object> nullRet = NULL;
 
1233
 
 
1234
        Property* prop = _members.getProperty(key);
 
1235
        if ( ! prop ) return nullRet;
 
1236
        if ( ! prop->isVisible(swfVersion) ) return nullRet;
 
1237
 
 
1238
        as_value tmp = prop->getValue(*this);
 
1239
 
 
1240
        return tmp.to_object();
 
1241
#endif
 
1242
}
 
1243
 
 
1244
bool
 
1245
as_object::on_event(const event_id& id )
 
1246
{
 
1247
        as_value event_handler;
 
1248
 
 
1249
        if (get_member(id.get_function_key(), &event_handler) )
 
1250
        {
 
1251
                call_method0(event_handler, NULL, this);
 
1252
                return true;
 
1253
        }
 
1254
 
 
1255
        return false;
 
1256
}
 
1257
 
 
1258
as_value
 
1259
as_object::getMember(string_table::key name, string_table::key nsname)
 
1260
{
 
1261
        as_value ret;
 
1262
        get_member(name, &ret, nsname);
 
1263
        //get_member(PROPNAME(name), &ret);
 
1264
        return ret;
 
1265
}
 
1266
 
 
1267
as_value
 
1268
as_object::callMethod(string_table::key methodName)
 
1269
{
 
1270
        as_value ret;
 
1271
        as_value method;
 
1272
 
 
1273
        if (! get_member(methodName, &method))
 
1274
        {
 
1275
                return ret;
 
1276
        }
 
1277
 
 
1278
        as_environment env(_vm);
 
1279
 
 
1280
        return call_method0(method, &env, this);
 
1281
}
 
1282
 
 
1283
as_value
 
1284
as_object::callMethod(string_table::key methodName, const as_value& arg0)
 
1285
{
 
1286
        as_value ret;
 
1287
        as_value method;
 
1288
 
 
1289
        if (!get_member(methodName, &method))
 
1290
        {
 
1291
                return ret;
 
1292
        }
 
1293
 
 
1294
        as_environment env(_vm);
 
1295
 
 
1296
        std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
 
1297
        args->push_back(arg0);
 
1298
 
 
1299
        ret = call_method(method, &env, this, args);
 
1300
 
 
1301
        return ret;
 
1302
}
 
1303
 
 
1304
as_value
 
1305
as_object::callMethod(string_table::key methodName,
 
1306
        const as_value& arg0, const as_value& arg1)
 
1307
{
 
1308
        as_value ret;
 
1309
        as_value method;
 
1310
 
 
1311
        if (! get_member(methodName, &method))
 
1312
        {
 
1313
                return ret;
 
1314
        }
 
1315
 
 
1316
        as_environment env(_vm);
 
1317
 
 
1318
        std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
 
1319
        args->push_back(arg0);
 
1320
        args->push_back(arg1);
 
1321
 
 
1322
        ret = call_method(method, &env, this, args);
 
1323
 
 
1324
        return ret;
 
1325
}
 
1326
 
 
1327
as_value
 
1328
as_object::callMethod(string_table::key methodName,
 
1329
        const as_value& arg0, const as_value& arg1, const as_value& arg2)
 
1330
{
 
1331
        as_value ret;
 
1332
        as_value method;
 
1333
 
 
1334
        if (! get_member(methodName, &method))
 
1335
        {
 
1336
                return ret;
 
1337
        }
 
1338
 
 
1339
        as_environment env(_vm);
 
1340
 
 
1341
        std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
 
1342
        args->push_back(arg0);
 
1343
        args->push_back(arg1);
 
1344
        args->push_back(arg2);
 
1345
 
 
1346
        ret = call_method(method, &env, this, args);
 
1347
 
 
1348
        return ret;
 
1349
}
 
1350
 
 
1351
as_value
 
1352
as_object::callMethod(string_table::key methodName,
 
1353
        const as_value& arg0, const as_value& arg1,
 
1354
        const as_value& arg2, const as_value& arg3)
 
1355
{
 
1356
        as_value ret;
 
1357
        as_value method;
 
1358
 
 
1359
        if (! get_member(methodName, &method))
 
1360
        {
 
1361
                return ret;
 
1362
        }
 
1363
 
 
1364
        as_environment env(_vm);
 
1365
 
 
1366
        std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
 
1367
        args->push_back(arg0);
 
1368
        args->push_back(arg1);
 
1369
        args->push_back(arg2);
 
1370
        args->push_back(arg3);
 
1371
 
 
1372
        ret = call_method(method, &env, this, args);
 
1373
 
 
1374
        return ret;
 
1375
}
 
1376
 
 
1377
as_object*
 
1378
as_object::get_path_element(string_table::key key)
 
1379
{
 
1380
//#define DEBUG_TARGET_FINDING 1
 
1381
 
 
1382
        as_value tmp;
 
1383
        if ( ! get_member(key, &tmp ) )
 
1384
        {
 
1385
#ifdef DEBUG_TARGET_FINDING 
 
1386
                log_debug("Member %s not found in object %p",
 
1387
                        _vm.getStringTable().value(key), (void*)this);
 
1388
#endif
 
1389
                return NULL;
 
1390
        }
 
1391
        if ( ! tmp.is_object() )
 
1392
        {
 
1393
#ifdef DEBUG_TARGET_FINDING 
 
1394
                log_debug("Member %s of object %p is not an object (%s)",
 
1395
                        _vm.getStringTable().value(key), (void*)this, tmp);
 
1396
#endif
 
1397
                return NULL;
 
1398
        }
 
1399
 
 
1400
        return tmp.to_object().get();
 
1401
}
 
1402
 
 
1403
void
 
1404
as_object::getURLEncodedVars(std::string& data)
 
1405
{
 
1406
    typedef std::map<std::string, std::string> PropMap;
 
1407
    PropMap props;
 
1408
    enumerateProperties(props);
 
1409
 
 
1410
    std::string del;
 
1411
    data.clear();
 
1412
    
 
1413
    for (PropMap::const_iterator i=props.begin(), e=props.end(); i!=e; ++i)
 
1414
    {
 
1415
      std::string name = i->first;
 
1416
      std::string value = i->second;
 
1417
      if ( ! name.empty() && name[0] == '$' ) continue; // see bug #22006
 
1418
      URL::encode(value);
 
1419
      
 
1420
      data += del + name + "=" + value;
 
1421
      
 
1422
      del = "&";
 
1423
        
 
1424
    }
 
1425
    
 
1426
}
 
1427
 
 
1428
bool
 
1429
as_object::watch(string_table::key key, as_function& trig,
 
1430
                const as_value& cust, string_table::key ns)
 
1431
{
 
1432
        
 
1433
        FQkey k = std::make_pair(key, ns);
 
1434
        std::string propname = VM::get().getStringTable().value(key);
 
1435
 
 
1436
        TriggerContainer::iterator it = _trigs.find(k);
 
1437
        if ( it == _trigs.end() )
 
1438
        {
 
1439
                return _trigs.insert(std::make_pair(k, Trigger(propname, trig, cust))).second;
 
1440
        }
 
1441
        it->second = Trigger(propname, trig, cust);
 
1442
        return true;
 
1443
}
 
1444
 
 
1445
bool
 
1446
as_object::unwatch(string_table::key key, string_table::key ns)
 
1447
{
 
1448
        TriggerContainer::iterator trigIter = _trigs.find(std::make_pair(key, ns));
 
1449
        if ( trigIter == _trigs.end() )
 
1450
        {
 
1451
                log_debug("No watch for property %s", getVM().getStringTable().value(key));
 
1452
                return false;
 
1453
        }
 
1454
        Property* prop = _members.getProperty(key, ns);
 
1455
        if ( prop && prop->isGetterSetter() )
 
1456
        {
 
1457
                log_debug("Watch on %s not removed (is a getter-setter)", getVM().getStringTable().value(key));
 
1458
                return false;
 
1459
        }
 
1460
        _trigs.erase(trigIter);
 
1461
        return true;
 
1462
}
 
1463
 
 
1464
#ifdef GNASH_USE_GC
 
1465
void
 
1466
as_object::markAsObjectReachable() const
 
1467
{
 
1468
        _members.setReachable();
 
1469
 
 
1470
        for (TriggerContainer::const_iterator it = _trigs.begin();
 
1471
                        it != _trigs.end(); ++it)
 
1472
        {
 
1473
                it->second.setReachable();
 
1474
        }
 
1475
}
 
1476
#endif // GNASH_USE_GC
 
1477
 
 
1478
void
 
1479
Trigger::setReachable() const
 
1480
{
 
1481
        _func->setReachable();
 
1482
        _customArg.setReachable();
 
1483
}
 
1484
 
 
1485
as_value
 
1486
Trigger::call(const as_value& oldval, const as_value& newval, as_object& this_obj)
 
1487
{
 
1488
        if ( _executing ) return newval;
 
1489
 
 
1490
        _executing = true;
 
1491
 
 
1492
        try {
 
1493
                as_environment env(VM::get()); // TODO: get VM in some other way 
 
1494
 
 
1495
                std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
 
1496
                args->push_back(_propname);
 
1497
                args->push_back(oldval);
 
1498
                args->push_back(newval);
 
1499
                args->push_back(_customArg);
 
1500
 
 
1501
                fn_call fn(&this_obj, &env, args);
 
1502
 
 
1503
                as_value ret = _func->call(fn);
 
1504
 
 
1505
                _executing = false;
 
1506
 
 
1507
                return ret;
 
1508
 
 
1509
        }
 
1510
        catch (...)
 
1511
        {
 
1512
                _executing = false;
 
1513
                throw;
 
1514
        }
 
1515
}
 
1516
 
 
1517
void
 
1518
as_object::visitPropertyValues(AbstractPropertyVisitor& visitor) const
 
1519
{
 
1520
    _members.visitValues(visitor, *this);
 
1521
}
 
1522
 
 
1523
void
 
1524
as_object::visitNonHiddenPropertyValues(AbstractPropertyVisitor& visitor) const
 
1525
{
 
1526
    _members.visitNonHiddenValues(visitor, *this);
 
1527
}
 
1528
 
 
1529
 
 
1530
 
 
1531
} // end of gnash namespace