~ubuntu-branches/ubuntu/saucy/gnash/saucy-proposed

« back to all changes in this revision

Viewing changes to libcore/as_environment.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_environment.cpp:  Variable, Sprite, and Movie locators, 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
 
 
20
#include "smart_ptr.h" // GNASH_USE_GC
 
21
#include "as_environment.h"
 
22
#include "sprite_instance.h"
 
23
#include "shape_character_def.h"
 
24
#include "as_value.h"
 
25
#include "with_stack_entry.h"
 
26
#include "VM.h"
 
27
#include "log.h"
 
28
#include "Property.h"
 
29
#include "as_object.h"
 
30
#include "namedStrings.h"
 
31
#include "as_function.h" 
 
32
#include "CallStack.h"
 
33
 
 
34
#include <cstring> // std::strpbrk
 
35
#include <string>
 
36
#include <utility> // for std::pair
 
37
#include <boost/algorithm/string/case_conv.hpp>
 
38
#include <boost/format.hpp>
 
39
 
 
40
// Define this to have find_target() calls trigger debugging output
 
41
//#define DEBUG_TARGET_FINDING 1
 
42
 
 
43
// Define this to have get_variable() calls trigger debugging output
 
44
//#define GNASH_DEBUG_GET_VARIABLE 1
 
45
 
 
46
namespace gnash {
 
47
 
 
48
as_value as_environment::undefVal;
 
49
 
 
50
as_environment::as_environment(VM& vm)
 
51
        :
 
52
        _vm(vm),
 
53
        _stack(_vm.getStack()),
 
54
        _localFrames(_vm.getCallStack()),
 
55
        m_target(0),
 
56
        _original_target(0)
 
57
{
 
58
}
 
59
 
 
60
// Return the value of the given var, if it's defined.
 
61
as_value
 
62
as_environment::get_variable(const std::string& varname,
 
63
                const ScopeStack& scopeStack, as_object** retTarget) const
 
64
{
 
65
    // Path lookup rigamarole.
 
66
    std::string path;
 
67
    std::string var;
 
68
 
 
69
#ifdef GNASH_DEBUG_GET_VARIABLE
 
70
    log_debug(_("get_variable(%s)"), varname);
 
71
#endif
 
72
 
 
73
    if ( parse_path(varname, path, var) )
 
74
    {
 
75
        // TODO: let find_target return generic as_objects, or use 'with' stack,
 
76
        //       see player2.swf or bug #18758 (strip.swf)
 
77
        // @@ TODO: should we use scopeStack here too ?
 
78
        as_object* target = find_object(path, &scopeStack); 
 
79
 
 
80
        if (target)
 
81
        {
 
82
            as_value    val;
 
83
            target->get_member(_vm.getStringTable().find(var), &val);
 
84
            if ( retTarget ) *retTarget = target;
 
85
            return val;
 
86
        }
 
87
        else
 
88
        {
 
89
 
 
90
            IF_VERBOSE_ASCODING_ERRORS(
 
91
            log_aserror(_("find_object(\"%s\") [ varname = '%s' - "
 
92
                        "current target = '%s' ] failed"),
 
93
                        path, varname, m_target ? m_target->get_text_value() : "<null>");
 
94
            as_value tmp = get_variable_raw(path, scopeStack, retTarget);
 
95
            if ( ! tmp.is_undefined() )
 
96
            {
 
97
                log_aserror(_("...but get_variable_raw(%s, <scopeStack>) "
 
98
                            "succeeded (%s)!"), path, tmp);
 
99
            }
 
100
            );
 
101
            return as_value(); // TODO: should we check get_variable_raw ?
 
102
        }
 
103
    }
 
104
    else
 
105
    {
 
106
        // TODO: have this checked by parse_path as an optimization 
 
107
        if ( varname.find_first_of('/') != std::string::npos && varname.find_first_of(':') == std::string::npos )
 
108
        {
 
109
                // Consider it all a path ...
 
110
                as_object* target = find_object(varname, &scopeStack); 
 
111
                if ( target ) 
 
112
                {
 
113
                        // ... but only if it resolves to a sprite
 
114
                        sprite_instance* m = target->to_movie();
 
115
                        if ( m ) return as_value(m);
 
116
                }
 
117
        }
 
118
        return get_variable_raw(varname, scopeStack, retTarget);
 
119
    }
 
120
}
 
121
 
 
122
as_value
 
123
as_environment::get_variable(const std::string& varname) const
 
124
{
 
125
        static ScopeStack empty_scopeStack;
 
126
        return get_variable(varname, empty_scopeStack);
 
127
}
 
128
 
 
129
static bool validRawVariableName(const std::string& varname)
 
130
{
 
131
    return (varname.find(":::") == std::string::npos);
 
132
}
 
133
 
 
134
as_value
 
135
as_environment::get_variable_raw(
 
136
    const std::string& varname,
 
137
    const ScopeStack& scopeStack, as_object** retTarget) const
 
138
    // varname must be a plain variable name; no path parsing.
 
139
{
 
140
    //assert(strchr(varname.c_str(), ':') == NULL);
 
141
 
 
142
        if ( ! validRawVariableName(varname) )
 
143
        {
 
144
                IF_VERBOSE_ASCODING_ERRORS(
 
145
                log_aserror(_("Won't get invalid raw variable name: %s"), varname);
 
146
                );
 
147
                return as_value();
 
148
        }
 
149
 
 
150
    as_value    val;
 
151
 
 
152
    VM& vm = _vm;
 
153
    int swfVersion = vm.getSWFVersion();
 
154
    string_table& st = vm.getStringTable();
 
155
    string_table::key key = st.find(varname);
 
156
 
 
157
    // Check the scope stack.
 
158
    for (size_t i = scopeStack.size(); i > 0; --i)
 
159
    {
 
160
        // const_cast needed due to non-const as_object::get_member 
 
161
        as_object* obj = const_cast<as_object*>(scopeStack[i-1].get());
 
162
        if (obj && obj->get_member(key, &val))
 
163
        {
 
164
            // Found the var in with context.
 
165
            //log_debug("Found %s in object %d/%d of scope stack (%p)", varname, i, scopeStack.size(), obj);
 
166
            if ( retTarget ) *retTarget = obj;
 
167
            return val;
 
168
        }
 
169
    }
 
170
 
 
171
    // Check locals for getting them
 
172
    if ( swfVersion < 6 ) // for SWF6 and up locals should be in the scope stack
 
173
    {
 
174
        if ( findLocal(varname, val, retTarget) ) 
 
175
        {
 
176
            return val;
 
177
        }
 
178
    }
 
179
 
 
180
 
 
181
    // Check current target members. TODO: shouldn't target be in scope stack ?
 
182
    if (m_target)
 
183
    {
 
184
        if (m_target->get_member(key, &val)) {
 
185
            if ( retTarget ) *retTarget = m_target;
 
186
            return val;
 
187
        }
 
188
    }
 
189
    else if ( _original_target ) // this only for swf5+ ?
 
190
    {
 
191
        if (_original_target->get_member(key, &val)) {
 
192
            if ( retTarget ) *retTarget = _original_target;
 
193
            return val;
 
194
        }
 
195
    }
 
196
 
 
197
    // Looking for "this" 
 
198
    if (varname == "this") {
 
199
        val.set_as_object(_original_target);
 
200
        if ( retTarget ) *retTarget = NULL; // correct ??
 
201
        return val;
 
202
    }
 
203
 
 
204
    as_object* global = vm.getGlobal();
 
205
 
 
206
    if ( swfVersion > 5 && key == NSV::PROP_uGLOBAL )
 
207
    {
 
208
        // The "_global" ref was added in SWF6
 
209
        if ( retTarget ) *retTarget = NULL; // correct ??
 
210
        return as_value(global);
 
211
    }
 
212
 
 
213
    if (global->get_member(key, &val))
 
214
    {
 
215
        if ( retTarget ) *retTarget = global;
 
216
        return val;
 
217
    }
 
218
    
 
219
    // Fallback.
 
220
    // FIXME, should this be log_error?  or log_swferror?
 
221
    IF_VERBOSE_ASCODING_ERRORS (
 
222
    log_aserror(_("reference to non-existent variable '%s'"),
 
223
           varname);
 
224
    );
 
225
 
 
226
    return as_value();
 
227
}
 
228
 
 
229
bool
 
230
as_environment::del_variable_raw(
 
231
    const std::string& varname,
 
232
    const ScopeStack& scopeStack) 
 
233
    // varname must be a plain variable name; no path parsing.
 
234
{
 
235
        assert( ! std::strpbrk(varname.c_str(), ":/.") );
 
236
 
 
237
        string_table::key varkey = _vm.getStringTable().find(varname);
 
238
        as_value        val;
 
239
 
 
240
        // Check the with-stack.
 
241
        for (size_t i = scopeStack.size(); i > 0; --i)
 
242
        {
 
243
                // const_cast needed due to non-const as_object::get_member 
 
244
                as_object* obj = const_cast<as_object*>(scopeStack[i-1].get());
 
245
                if (obj)
 
246
                {
 
247
                        std::pair<bool,bool> ret = obj->delProperty(varkey);
 
248
                        if (ret.first)
 
249
                        {
 
250
                            return ret.second;
 
251
                        }
 
252
                }
 
253
        }
 
254
 
 
255
        // Check locals for deletion.
 
256
        if ( delLocal(varname) )
 
257
        {
 
258
                return true;
 
259
        }
 
260
 
 
261
 
 
262
        // Try target
 
263
        std::pair<bool,bool> ret = m_target->delProperty(varkey);
 
264
        if ( ret.first )
 
265
        {
 
266
                return ret.second;
 
267
        }
 
268
 
 
269
        // TODO: try 'this' ? Add a testcase for it !
 
270
 
 
271
        // Try _global 
 
272
        return _vm.getGlobal()->delProperty(varkey).second;
 
273
}
 
274
 
 
275
// varname must be a plain variable name; no path parsing.
 
276
as_value
 
277
as_environment::get_variable_raw(const std::string& varname) const
 
278
{
 
279
        static ScopeStack empty_scopeStack;
 
280
        return get_variable_raw(varname, empty_scopeStack);
 
281
}
 
282
 
 
283
// Given a path to variable, set its value.
 
284
void
 
285
as_environment::set_variable(
 
286
    const std::string& varname,
 
287
    const as_value& val,
 
288
    const ScopeStack& scopeStack)
 
289
{
 
290
        IF_VERBOSE_ACTION (
 
291
    log_action("-------------- %s = %s",
 
292
               varname, val);
 
293
        );
 
294
 
 
295
    // Path lookup rigamarole.
 
296
    as_object* target = m_target;
 
297
    std::string path;
 
298
    std::string var;
 
299
    //log_debug(_("set_variable(%s, %s)"), varname, val);
 
300
    if ( parse_path(varname, path, var) )
 
301
    {
 
302
        //log_debug(_("Variable '%s' parsed into path='%s', var='%s'"), varname, path, var);
 
303
        //target = find_target(path);
 
304
        target = find_object(path, &scopeStack); 
 
305
        if (target)
 
306
        {
 
307
            target->set_member(_vm.getStringTable().find(var), val);
 
308
        }
 
309
        else
 
310
        {
 
311
                IF_VERBOSE_ASCODING_ERRORS(
 
312
                log_aserror(_("Path target '%s' not found while setting %s=%s"),
 
313
                        path, varname, val);
 
314
                );
 
315
        }
 
316
    } else {
 
317
        set_variable_raw(varname, val, scopeStack);
 
318
    }
 
319
}
 
320
 
 
321
void
 
322
as_environment::set_variable(
 
323
                const std::string& varname,
 
324
                const as_value& val)
 
325
{
 
326
        static ScopeStack empty_scopeStack;
 
327
        set_variable(varname, val, empty_scopeStack);
 
328
}
 
329
 
 
330
// No path rigamarole.
 
331
void
 
332
as_environment::set_variable_raw(
 
333
    const std::string& varname,
 
334
    const as_value& val,
 
335
    const ScopeStack& scopeStack)
 
336
{
 
337
 
 
338
        if ( ! validRawVariableName(varname) )
 
339
        {
 
340
                IF_VERBOSE_ASCODING_ERRORS(
 
341
                log_aserror(_("Won't set invalid raw variable name: %s"), varname);
 
342
                );
 
343
                return;
 
344
        }
 
345
 
 
346
    VM& vm = _vm;
 
347
    int swfVersion = vm.getSWFVersion();
 
348
    string_table& st = vm.getStringTable();
 
349
    string_table::key varkey = st.find(varname);
 
350
 
 
351
    if ( swfVersion < 6 ) 
 
352
    {
 
353
        // in SWF5 and lower, scope stack should just contain 'with' elements 
 
354
 
 
355
        // Check the with-stack.
 
356
        for (size_t i = scopeStack.size(); i > 0; --i)
 
357
        {
 
358
            // const_cast needed due to non-const as_object::get_member 
 
359
            as_object* obj = const_cast<as_object*>(scopeStack[i-1].get());
 
360
            if (obj && obj->set_member(varkey, val, 0, true) )
 
361
            {
 
362
                return;
 
363
            }
 
364
        }
 
365
 
 
366
        // Check locals for setting them
 
367
        if ( setLocal(varname, val) ) return;
 
368
 
 
369
    }
 
370
    else // SWF >= 6
 
371
    {
 
372
 
 
373
        // Check the scope-stack (would include locals)
 
374
        //
 
375
        for (size_t i = scopeStack.size(); i > 0; --i)
 
376
        {
 
377
            // const_cast needed due to non-const as_object::get_member 
 
378
            as_object* obj = const_cast<as_object*>(scopeStack[i-1].get());
 
379
            if (obj && obj->set_member(varkey, val, 0, true))
 
380
            {
 
381
                return;
 
382
            }
 
383
        }
 
384
 
 
385
    }
 
386
    
 
387
    // TODO: shouldn't m_target be in the scope chain ?
 
388
    //assert(m_target);
 
389
    if ( m_target ) m_target->set_member(varkey, val);
 
390
    else if ( _original_target ) _original_target->set_member(varkey, val);
 
391
    else
 
392
    {
 
393
        log_error("as_environment(%p)::set_variable_raw(%s, %s): "
 
394
           "neither current target nor original target are defined, "
 
395
           "can't set the variable",
 
396
           this, varname, val);
 
397
    }
 
398
}
 
399
 
 
400
void
 
401
as_environment::set_variable_raw(
 
402
                const std::string& varname,
 
403
                const as_value& val)
 
404
{
 
405
        static ScopeStack empty_scopeStack;
 
406
        set_variable_raw(varname, val, empty_scopeStack);
 
407
}
 
408
 
 
409
// Set/initialize the value of the local variable.
 
410
void
 
411
as_environment::set_local(const std::string& varname, const as_value& val)
 
412
{
 
413
        // why would you want to set a local if there's no call frame on the
 
414
        // stack ?
 
415
        assert( ! _localFrames.empty() );
 
416
 
 
417
        string_table::key varkey = _vm.getStringTable().find(varname);
 
418
        // Is it in the current frame already?
 
419
        if ( setLocal(varname, val) )
 
420
        {
 
421
                return;
 
422
        }
 
423
        else
 
424
        {
 
425
                // Not in frame; create a new local var.
 
426
                assert( ! varname.empty() ); // null varnames are invalid!
 
427
                as_object* locals = _localFrames.back().locals;
 
428
                //locals.push_back(as_environment::frame_slot(varname, val));
 
429
                locals->set_member(varkey, val);
 
430
        }
 
431
}
 
432
        
 
433
// Create the specified local var if it doesn't exist already.
 
434
void
 
435
as_environment::declare_local(const std::string& varname)
 
436
{
 
437
        as_value tmp;
 
438
        if ( ! findLocal(varname, tmp) )
 
439
        {
 
440
                // Not in frame; create a new local var.
 
441
                assert( ! _localFrames.empty() );
 
442
                assert( ! varname.empty() );    // null varnames are invalid!
 
443
                as_object* locals = _localFrames.back().locals;
 
444
                //locals.push_back(as_environment::frame_slot(varname, as_value()));
 
445
                locals->set_member(_vm.getStringTable().find(varname), as_value());
 
446
        }
 
447
}
 
448
 
 
449
/* public static */
 
450
bool
 
451
as_environment::parse_path(const std::string& var_path_in,
 
452
                std::string& path, std::string& var)
 
453
{
 
454
#ifdef DEBUG_TARGET_FINDING 
 
455
        log_debug("parse_path(%s)", var_path_in);
 
456
#endif
 
457
 
 
458
        size_t lastDotOrColon = var_path_in.find_last_of(":.");
 
459
        if ( lastDotOrColon == std::string::npos ) return false;
 
460
 
 
461
        std::string thePath, theVar;
 
462
 
 
463
        thePath.assign(var_path_in, 0, lastDotOrColon);
 
464
        theVar.assign(var_path_in, lastDotOrColon+1, var_path_in.length());
 
465
 
 
466
#ifdef DEBUG_TARGET_FINDING 
 
467
        log_debug("path: %s, var: %s", thePath, theVar);
 
468
#endif
 
469
 
 
470
        if ( thePath.empty() ) return false;
 
471
 
 
472
        // this check should be performed by callers (getvariable/setvariable in particular)
 
473
        size_t pathlen = thePath.length();
 
474
        size_t i = pathlen-1;
 
475
        size_t contiguoscommas = 0;
 
476
        while ( i && thePath[i--] == ':' )
 
477
        {
 
478
                if ( ++contiguoscommas > 1 )
 
479
                {
 
480
#ifdef DEBUG_TARGET_FINDING 
 
481
                        log_debug("path '%s' ends with too many colon chars, not considering a path", thePath);
 
482
#endif
 
483
                        return false;
 
484
                }
 
485
        }
 
486
 
 
487
#ifdef DEBUG_TARGET_FINDING 
 
488
        log_debug("contiguoscommas: %d", contiguoscommas);
 
489
#endif
 
490
 
 
491
        //if ( var.empty() ) return false;
 
492
 
 
493
        path = thePath;
 
494
        var = theVar;
 
495
 
 
496
        return true;
 
497
}
 
498
 
 
499
bool
 
500
as_environment::parse_path(const std::string& var_path,
 
501
                as_object** target, as_value& val)
 
502
{
 
503
        std::string path;
 
504
        std::string var;
 
505
        if ( ! parse_path(var_path, path, var) ) return false;
 
506
        as_object* target_ptr = find_object(path); 
 
507
        if ( ! target_ptr ) return false;
 
508
 
 
509
        target_ptr->get_member(_vm.getStringTable().find(var), &val);
 
510
        *target = target_ptr;
 
511
        return true;
 
512
}
 
513
 
 
514
// Search for next '.' or '/' character in this word.  Return
 
515
// a pointer to it, or to NULL if it wasn't found.
 
516
static const char*
 
517
next_slash_or_dot(const char* word)
 
518
{
 
519
    for (const char* p = word; *p; p++) {
 
520
        if (*p == '.' && p[1] == '.') {
 
521
            p++;
 
522
        } else if (*p == '.' || *p == '/' || *p == ':') {
 
523
            return p;
 
524
        }
 
525
    }
 
526
    
 
527
    return NULL;
 
528
}
 
529
 
 
530
// Find the sprite/movie referenced by the given path.
 
531
//
 
532
// Supports both /slash/syntax and dot.syntax
 
533
//
 
534
character*
 
535
as_environment::find_target(const std::string& path_in) const
 
536
{
 
537
        as_object* o = find_object(path_in);
 
538
        if ( o ) return o->to_character(); // can be NULL (not a character)...
 
539
        else return NULL;
 
540
}
 
541
 
 
542
as_object*
 
543
as_environment::find_object(const std::string& path_in, const ScopeStack* scopeStack) const
 
544
{
 
545
#ifdef DEBUG_TARGET_FINDING 
 
546
        log_debug(_("find_object(%s) called"), path_in);
 
547
#endif
 
548
 
 
549
    if (path_in.empty())
 
550
    {
 
551
#ifdef DEBUG_TARGET_FINDING 
 
552
        log_debug(_("Returning m_target (empty path)"));
 
553
#endif
 
554
        return m_target; // or should we return the *original* path ?
 
555
    }
 
556
    
 
557
    std::string path = PROPNAME(path_in);
 
558
    VM& vm = _vm;
 
559
    string_table& st = vm.getStringTable();
 
560
    int swfVersion = vm.getSWFVersion(); 
 
561
 
 
562
    as_object* env = 0;
 
563
    env = m_target; 
 
564
 
 
565
    bool firstElementParsed = false;
 
566
    bool dot_allowed=true;
 
567
 
 
568
    const char* p = path.c_str();
 
569
    if (*p == '/')
 
570
    {
 
571
        // Absolute path.  Start at the (AS) root (handle _lockroot)
 
572
        sprite_instance* root = 0;
 
573
        if ( m_target ) root = const_cast<sprite_instance*>(m_target->getAsRoot());
 
574
        else {
 
575
            if ( _original_target )
 
576
            {
 
577
                log_debug("current target is undefined on as_environment::find_object, we'll use original");
 
578
                root = const_cast<sprite_instance*>(_original_target->getAsRoot());
 
579
            }
 
580
            else
 
581
            {
 
582
                log_debug("both current and original target are undefined on as_environment::find_object, we'll return 0");
 
583
                return 0;
 
584
            }
 
585
        }
 
586
 
 
587
        if ( ! *(++p) )
 
588
        {
 
589
#ifdef DEBUG_TARGET_FINDING 
 
590
                log_debug(_("Path is '/', return the root (%p)"), (void*)root);
 
591
#endif
 
592
                return root; // that's all folks.. 
 
593
        }
 
594
 
 
595
        env = root;
 
596
        firstElementParsed = true;
 
597
        dot_allowed = false;
 
598
 
 
599
#ifdef DEBUG_TARGET_FINDING 
 
600
        log_debug(_("Absolute path, start at the root (%p)"), (void*)env);
 
601
#endif
 
602
 
 
603
    }
 
604
#ifdef DEBUG_TARGET_FINDING 
 
605
    else
 
606
    {
 
607
        log_debug(_("Relative path, start at (%s)"), m_target->getTarget());
 
608
    }
 
609
#endif
 
610
    
 
611
    assert (*p);
 
612
 
 
613
    std::string subpart;
 
614
    while (1)
 
615
    {
 
616
        while ( *p == ':' ) ++p;
 
617
 
 
618
        // No more components to scan
 
619
        if ( ! *p )
 
620
        {
 
621
#ifdef DEBUG_TARGET_FINDING 
 
622
                log_debug(_("Path is %s, returning whatever we were up to"), path);
 
623
#endif
 
624
                return env;
 
625
        }
 
626
 
 
627
 
 
628
        const char*     next_slash = next_slash_or_dot(p);
 
629
        subpart = p;
 
630
        if (next_slash == p)
 
631
        {
 
632
            IF_VERBOSE_ASCODING_ERRORS(
 
633
            log_aserror(_("invalid path '%s' (p=next_slash=%s)"), path, next_slash);
 
634
            );
 
635
            return NULL;
 
636
        }
 
637
        else if (next_slash)
 
638
        {
 
639
                if ( *next_slash == '.' )
 
640
                {
 
641
                        if ( ! dot_allowed )
 
642
                        {
 
643
                                IF_VERBOSE_ASCODING_ERRORS(
 
644
                                log_aserror(_("invalid path '%s' (dot not allowed after having seen a slash)"), path);
 
645
                                );
 
646
                                return NULL;
 
647
                        }
 
648
                }
 
649
                else if ( *next_slash == '/' )
 
650
                {
 
651
                        dot_allowed = false;
 
652
                }
 
653
 
 
654
                // Cut off the slash and everything after it.
 
655
                subpart.resize(next_slash - p);
 
656
        }
 
657
        
 
658
        assert(subpart[0] != ':');
 
659
 
 
660
        // No more components to scan
 
661
        if ( subpart.empty() )
 
662
        {
 
663
#ifdef DEBUG_TARGET_FINDING 
 
664
                log_debug(_("No more subparts, env is %p"), (void*)env);
 
665
#endif
 
666
                break;
 
667
        }
 
668
 
 
669
        string_table::key subpartKey = st.find(subpart);
 
670
 
 
671
        if ( ! firstElementParsed )
 
672
        {
 
673
                as_object* element = NULL;
 
674
 
 
675
                do {
 
676
 
 
677
                        // Try scope stack
 
678
                        if ( scopeStack )
 
679
                        {
 
680
                                for (size_t i = scopeStack->size(); i > 0; --i)
 
681
                                {
 
682
                                        // const_cast needed due to non-const as_object::get_member 
 
683
                                        as_object* obj = const_cast<as_object*>((*scopeStack)[i-1].get());
 
684
                                        element = obj->get_path_element(subpartKey);
 
685
                                        if ( element ) break;
 
686
                                }
 
687
                                if ( element ) break;
 
688
                        }
 
689
 
 
690
                        // Try current target  (if any)
 
691
                        assert(env == m_target);
 
692
                        if ( env )
 
693
                        {
 
694
                                element = env->get_path_element(subpartKey);
 
695
                                if ( element ) break;
 
696
                        }
 
697
                        // else if ( _original_target) // TODO: try orig target too ?
 
698
 
 
699
                        // Looking for _global ?
 
700
                        as_object* global = _vm.getGlobal();
 
701
                        if ( swfVersion > 5 && subpartKey == NSV::PROP_uGLOBAL )
 
702
                        {
 
703
                                element = global;
 
704
                                break;
 
705
                        }
 
706
 
 
707
                        // Try globals
 
708
                        element = global->get_path_element(subpartKey);
 
709
                        //if ( element ) break;
 
710
 
 
711
                } while (0);
 
712
 
 
713
                if ( ! element ) 
 
714
                {
 
715
#ifdef DEBUG_TARGET_FINDING 
 
716
                        log_debug("subpart %s of path %s not found in any "
 
717
                        "scope stack element", subpart, path);
 
718
#endif
 
719
                        return NULL;
 
720
                }
 
721
 
 
722
                env = element;
 
723
                firstElementParsed = true;
 
724
        }
 
725
        else
 
726
        {
 
727
 
 
728
                assert(env);
 
729
 
 
730
#ifdef DEBUG_TARGET_FINDING 
 
731
                log_debug(_("Invoking get_path_element(%s) on object "
 
732
                                "%p (%s)"), subpart, (void *)env, env->get_text_value());
 
733
#endif
 
734
 
 
735
                as_object* element = env->get_path_element(subpartKey);
 
736
                if ( ! element )
 
737
                {
 
738
#ifdef DEBUG_TARGET_FINDING 
 
739
                        log_debug(_("Path element %s not found in "
 
740
                                                "object %p"), subpart, (void *)env);
 
741
#endif
 
742
                        return NULL;
 
743
                }
 
744
                env = element;
 
745
        }
 
746
 
 
747
        if (next_slash == NULL)
 
748
        {
 
749
            break;
 
750
        }
 
751
        
 
752
        p = next_slash + 1;
 
753
    }
 
754
    return env;
 
755
}
 
756
 
 
757
int
 
758
as_environment::get_version() const
 
759
{
 
760
        return _vm.getSWFVersion();
 
761
}
 
762
 
 
763
static void
 
764
dump(const as_environment::Registers& r, std::ostream& out) 
 
765
{
 
766
        for (size_t i=0; i<r.size(); ++i)
 
767
        {
 
768
                if (i) out << ", ";
 
769
                out << i << ':' << '"' << r[i] << '"';
 
770
        }
 
771
}
 
772
 
 
773
void
 
774
as_environment::dump_local_registers(std::ostream& out) const
 
775
{
 
776
        if ( _localFrames.empty() ) return;
 
777
        out << "Local registers: ";
 
778
#ifndef DUMP_LOCAL_REGISTERS_IN_ALL_CALL_FRAMES
 
779
        dump(_localFrames.back().registers, out);
 
780
#else
 
781
        for (CallStack::const_iterator it=_localFrames.begin(),
 
782
                        itEnd=_localFrames.end();
 
783
                        it != itEnd; ++it)
 
784
        {
 
785
                if ( it != _localFrames.begin() ) out << " | ";
 
786
                dump(it->registers, out);
 
787
        }
 
788
#endif
 
789
        out << std::endl;
 
790
}
 
791
 
 
792
static void
 
793
dump(const as_object* locals, std::ostream& out)
 
794
{
 
795
        typedef std::map<std::string, as_value> PropMap;
 
796
        PropMap props;
 
797
        const_cast<as_object*>(locals)->dump_members(props);
 
798
        
 
799
        //log_debug("FIXME: implement dumper for local variables now that they are simple objects");
 
800
        int count = 0;
 
801
        for (PropMap::iterator i=props.begin(), e=props.end(); i!=e; ++i)
 
802
        {
 
803
                if (count++) out << ", ";
 
804
                // TODO: define output operator for as_value !
 
805
                out << i->first << "==" << i->second;
 
806
        }
 
807
        out << std::endl;
 
808
}
 
809
 
 
810
void
 
811
as_environment::dump_local_variables(std::ostream& out) const
 
812
{
 
813
        if ( _localFrames.empty() ) return;
 
814
        out << "Local variables: ";
 
815
#ifndef DUMP_LOCAL_VARIABLES_IN_ALL_CALL_FRAMES
 
816
        dump(_localFrames.back().locals, out);
 
817
#else
 
818
        for (CallStack::const_iterator it=_localFrames.begin(),
 
819
                        itEnd=_localFrames.end();
 
820
                        it != itEnd; ++it)
 
821
        {
 
822
                if ( it != _localFrames.begin() ) out << " | ";
 
823
                dump(it->locals, out);
 
824
        }
 
825
#endif
 
826
        out << std::endl;
 
827
}
 
828
 
 
829
void
 
830
as_environment::dump_global_registers(std::ostream& out) const
 
831
{
 
832
        std::string registers;
 
833
 
 
834
        std::stringstream ss;
 
835
 
 
836
        ss << "Global registers: ";
 
837
        int defined=0;
 
838
        for (unsigned int i=0; i<numGlobalRegisters; ++i)
 
839
        {
 
840
                if ( m_global_register[i].is_undefined() ) continue;
 
841
 
 
842
                if ( defined++ ) ss <<  ", ";
 
843
 
 
844
                ss << i << ":" << m_global_register[i];
 
845
 
 
846
        }
 
847
        if ( defined ) out << ss.str() << std::endl;
 
848
}
 
849
 
 
850
/*private*/
 
851
bool
 
852
as_environment::findLocal(const std::string& varname, as_value& ret, as_object** retTarget)
 
853
{
 
854
        if ( _localFrames.empty() ) return false;
 
855
        if ( findLocal(_localFrames.back().locals, varname, ret) )
 
856
        {
 
857
                if ( retTarget ) *retTarget = _localFrames.back().locals;
 
858
                return true;
 
859
        }
 
860
        return false;
 
861
}
 
862
 
 
863
/* private */
 
864
bool
 
865
as_environment::findLocal(as_object* locals, const std::string& name, as_value& ret)
 
866
{
 
867
        // TODO: get VM passed as arg
 
868
        return locals->get_member(_vm.getStringTable().find(name), &ret);
 
869
}
 
870
 
 
871
/* private */
 
872
bool
 
873
as_environment::delLocal(as_object* locals, const std::string& varname)
 
874
{
 
875
        // TODO: get VM passed as arg
 
876
        return locals->delProperty(_vm.getStringTable().find(varname)).second;
 
877
}
 
878
 
 
879
/* private */
 
880
bool
 
881
as_environment::delLocal(const std::string& varname)
 
882
{
 
883
        if ( _localFrames.empty() ) return false;
 
884
        return delLocal(_localFrames.back().locals, varname);
 
885
}
 
886
 
 
887
/* private */
 
888
bool
 
889
as_environment::setLocal(const std::string& varname, const as_value& val)
 
890
{
 
891
        if ( _localFrames.empty() ) return false;
 
892
        return setLocal(_localFrames.back().locals, varname, val);
 
893
}
 
894
 
 
895
/* private */
 
896
bool
 
897
as_environment::setLocal(as_object* locals,
 
898
                const std::string& varname, const as_value& val)
 
899
{
 
900
        Property* prop = locals->getOwnProperty(_vm.getStringTable().find(varname));
 
901
        if ( ! prop ) return false;
 
902
        prop->setValue(*locals, val);
 
903
        return true;
 
904
}
 
905
 
 
906
 
 
907
void
 
908
as_environment::padStack(size_t /*offset*/, size_t /*count*/)
 
909
{
 
910
        // do nothing here, instead return undefined from top() and pop()
 
911
        //assert( offset <= _stack.size() );
 
912
        //m_stack.insert(m_stack.begin()+offset, count, as_value());
 
913
}
 
914
 
 
915
void
 
916
as_environment::pushCallFrame(as_function* func)
 
917
{
 
918
 
 
919
    // The stack size can be changed by the ScriptLimits
 
920
    // tag. There is *no* difference between SWF versions.
 
921
    // TODO: override from gnashrc.
 
922
    
 
923
    // A stack size of 0 is apparently legitimate.
 
924
        const boost::uint16_t maxstacksize = func->getVM().getRoot().getRecursionLimit();
 
925
 
 
926
    // Doesn't proceed if the stack size would reach the limit; should
 
927
    // this check be done somewhere after adding to the stack? Would
 
928
    // it make any difference?
 
929
        if ( _localFrames.size() + 1 >= maxstacksize )
 
930
        {
 
931
                std::ostringstream ss;
 
932
                ss << boost::format(_("Max stack count reached (%u)")) % _localFrames.size();
 
933
 
 
934
                // throw something
 
935
                throw ActionLimitException(ss.str()); 
 
936
        }
 
937
 
 
938
        _localFrames.push_back(CallFrame(func));
 
939
 
 
940
}
 
941
 
 
942
void 
 
943
as_environment::popCallFrame()
 
944
{
 
945
        assert(!_localFrames.empty());
 
946
        _localFrames.pop_back();
 
947
}
 
948
        
 
949
void
 
950
as_environment::set_target(character* target)
 
951
{
 
952
        //assert(target);
 
953
        if ( ! _original_target )
 
954
        {
 
955
                //assert(target); // we assume any as_environment creator sets a target too I guess..
 
956
                // WRONG ASSUMPTION: ^^^^^^^^^ : as_value::to_primitive doesn't care about setting a target here
 
957
 
 
958
                //log_debug("as_environment(%p)::set_target(%p): setting original target to %s", this, target, target ? target->getTarget() : "<null>");
 
959
                _original_target = target;
 
960
        }
 
961
        m_target = target;
 
962
}
 
963
 
 
964
void
 
965
as_environment::add_local(const std::string& varname, const as_value& val)
 
966
{
 
967
        assert( ! varname.empty() );    // null varnames are invalid!
 
968
        assert( ! _localFrames.empty() );
 
969
        as_object* locals = _localFrames.back().locals;
 
970
        //locals.push_back(frame_slot(varname, val));
 
971
        locals->set_member(_vm.getStringTable().find(varname), val);
 
972
}
 
973
 
 
974
void
 
975
as_environment::dump_stack(std::ostream& out, unsigned int limit) const
 
976
{
 
977
        unsigned int si=0, n=_stack.size();
 
978
        if ( limit && n > limit )
 
979
        {
 
980
                si=n-limit;
 
981
                out << "Stack (last " << limit << " of " << n << " items): ";
 
982
        }
 
983
        else
 
984
        {
 
985
                out << "Stack: ";
 
986
        }
 
987
 
 
988
        for (unsigned int i=si; i<n; i++)
 
989
        {
 
990
                if (i!=si) out << " | ";
 
991
                out << '"' << _stack.value(i) << '"';
 
992
        }
 
993
        out << std::endl;
 
994
}
 
995
 
 
996
#ifdef GNASH_USE_GC
 
997
 
 
998
unsigned int
 
999
as_environment::setRegister(unsigned int regnum, const as_value& v)
 
1000
{
 
1001
        if ( _localFrames.empty() || _localFrames.back().registers.empty() )
 
1002
        {
 
1003
                if ( regnum >= numGlobalRegisters ) return 0;
 
1004
                m_global_register[regnum] = v;
 
1005
                return 1;
 
1006
        }
 
1007
 
 
1008
        Registers& registers = _localFrames.back().registers;
 
1009
        if ( regnum < registers.size() )
 
1010
        {
 
1011
                registers[regnum] = v;
 
1012
                return 2;
 
1013
        }
 
1014
 
 
1015
        return 0;
 
1016
}
 
1017
 
 
1018
unsigned int
 
1019
as_environment::getRegister(unsigned int regnum, as_value& v)
 
1020
{
 
1021
        if ( _localFrames.empty() || _localFrames.back().registers.empty() )
 
1022
        {
 
1023
                if ( regnum >= numGlobalRegisters ) return 0;
 
1024
                v = m_global_register[regnum];
 
1025
                return 1;
 
1026
        }
 
1027
 
 
1028
        Registers& registers = _localFrames.back().registers;
 
1029
        if ( regnum < registers.size() )
 
1030
        {
 
1031
                v = registers[regnum];
 
1032
                return 2;
 
1033
        }
 
1034
 
 
1035
        return 0;
 
1036
}
 
1037
 
 
1038
void
 
1039
as_environment::markReachableResources() const
 
1040
{
 
1041
        for (size_t i=0; i<4; ++i)
 
1042
        {
 
1043
                m_global_register[i].setReachable();
 
1044
        }
 
1045
 
 
1046
        if ( m_target ) m_target->setReachable();
 
1047
        if ( _original_target ) _original_target->setReachable();
 
1048
 
 
1049
        assert ( _localFrames.empty() );
 
1050
#if 1 // I think we expect the stack to be empty !
 
1051
        for (CallStack::const_iterator i=_localFrames.begin(), e=_localFrames.end(); i!=e; ++i)
 
1052
        {
 
1053
                i->markReachableResources();
 
1054
        }
 
1055
#endif
 
1056
 
 
1057
        assert ( _stack.empty() );
 
1058
}
 
1059
#endif // GNASH_USE_GC
 
1060
 
 
1061
} // end of gnash namespace
 
1062
 
 
1063
 
 
1064
 
 
1065
// Local Variables:
 
1066
// mode: C++
 
1067
// indent-tabs-mode: t
 
1068
// End: