2
// Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
#ifndef GNASH_AS_ENVIRONMENT_H
19
#define GNASH_AS_ENVIRONMENT_H
22
#include "gnashconfig.h"
25
#include "as_value.h" // for composition (vector + frame_slot)
26
#include "StringPredicates.h" // for Variables
27
#include "as_object.h"
29
#include <map> // for composition (Variables)
30
#include <string> // for frame_slot name
32
#include <iostream> // for dump_stack inline
36
// Forward declarations
38
//class with_stack_entry;
40
/// ActionScript execution environment.
45
/// A stack of objects used for variables/members lookup
46
//typedef std::vector<with_stack_entry> ScopeStack;
47
typedef std::vector< boost::intrusive_ptr<as_object> > ScopeStack;
49
/// Stack of as_values in this environment
50
std::vector<as_value> m_stack;
60
character* get_target() { return m_target; }
61
void set_target(character* target);
63
character* get_original_target() { return _original_target; }
65
// Reset target to its original value
66
void reset_target() { m_target = _original_target; }
68
/// @{ Stack access/manipulation
70
/// Push a value on the stack
71
void push(const as_value& val)
73
m_stack.push_back(val);
77
/// Pops an as_value off the stack top and return it.
80
assert( ! m_stack.empty() );
81
as_value result = m_stack.back();
86
/// Get stack value at the given distance from top.
88
/// top(0) is actual stack top
90
as_value& top(size_t dist)
92
size_t ssize = m_stack.size();
93
assert ( ssize > dist );
94
return m_stack[ssize - 1 - dist];
97
/// Get stack value at the given distance from bottom.
99
/// bottom(stack_size()-1) is actual stack top
101
as_value& bottom(size_t index)
103
assert ( m_stack.size() > index );
104
return m_stack[index];
107
/// Drop 'count' values off the top of the stack.
108
void drop(size_t count)
110
size_t ssize = m_stack.size();
111
assert ( ssize >= count );
112
m_stack.resize(ssize - count);
115
/// Insert 'count' undefined values before 'offset'.
117
/// An offset of 0 will prepend the values,
118
/// An offset of size() [too far] will append the values.
120
void padStack(size_t offset, size_t count);
122
/// Returns index of top stack element
123
// FIXME: what if stack is empty ??
124
// I'd obsolete this and convert calling code to use
125
// stack_size() instead.
126
int get_top_index() const { return m_stack.size() - 1; }
128
size_t stack_size() const { return m_stack.size(); }
130
/// @} stack access/manipulation
134
/// Return the (possibly UNDEFINED) value of the named variable
137
/// Variable name. Can contain path elements.
138
/// TODO: should be case-insensitive up to SWF6.
139
/// NOTE: no case conversion is performed currently,
140
/// so make sure you do it yourself. Note that
141
/// ActionExec performs the conversion
142
/// before calling this method.
144
as_value get_variable(const std::string& varname) const;
147
/// Delete a variable, w/out support for the path, using
151
/// Variable name. Can not contain path elements.
152
/// TODO: should be case-insensitive up to SWF6.
153
/// NOTE: no case conversion is performed currently,
154
/// so make sure you do it yourself. Note that
155
/// ActionExec performs the conversion
156
/// before calling this method.
158
/// @param scopeStack
159
/// The Scope stack to use for lookups.
161
bool del_variable_raw(const std::string& varname,
162
const ScopeStack& scopeStack);
164
/// Return the (possibly UNDEFINED) value of the named var.
167
/// Variable name. Can contain path elements.
168
/// TODO: should be case-insensitive up to SWF6.
169
/// NOTE: no case conversion is performed currently,
170
/// so make sure you do it yourself. Note that
171
/// ActionExec performs the conversion
172
/// before calling this method.
174
/// @param scopeStack
175
/// The Scope stack to use for lookups.
178
/// If not NULL, the pointer will be set to the actual object containing the
179
/// found variable (if found).
181
as_value get_variable(const std::string& varname,
182
const ScopeStack& scopeStack, as_object** retTarget=NULL) const;
185
/// Given a path to variable, set its value.
186
/// Variable name can contain path elements.
190
/// TODO: should be case-insensitive up to SWF6.
191
/// NOTE: no case conversion is performed currently,
192
/// so make sure you do it yourself. Note that
193
/// ActionExec performs the conversion
194
/// before calling this method.
197
/// The value to assign to the variable, if found.
199
/// TODO: make this function return some info about the
200
/// variable being found and set ?
202
void set_variable(const std::string& path, const as_value& val);
204
/// Given a variable name, set its value (no support for path)
206
/// If no variable with that name is found, a new one
207
/// will be created as a member of current target.
210
/// Variable name. Can not contain path elements.
211
/// TODO: should be case-insensitive up to SWF6.
214
/// The value to assign to the variable, if found.
216
void set_variable_raw(const std::string& var, const as_value& val);
219
/// Given a path to variable, set its value.
221
/// If no variable with that name is found, a new one is created.
223
/// For path-less variables, this would act as a proxy for
224
/// set_variable_raw.
228
/// TODO: should be case-insensitive up to SWF6.
231
/// The value to assign to the variable.
233
/// @param scopeStack
234
/// The Scope stack to use for lookups.
236
void set_variable(const std::string& path, const as_value& val,
237
const ScopeStack& scopeStack);
239
/// Set/initialize the value of the local variable.
241
/// If no *local* variable with that name is found, a new one
245
/// Variable name. Can not contain path elements.
246
/// TODO: should be case-insensitive up to SWF6.
249
/// The value to assign to the variable.
251
void set_local(const std::string& varname, const as_value& val);
254
/// Add a local var with the given name and value to our
255
/// current local frame.
257
/// Use this when you know the var
258
/// doesn't exist yet, since it's faster than set_local();
259
/// e.g. when setting up args for a function.
261
void add_local(const std::string& varname, const as_value& val);
263
/// Create the specified local var if it doesn't exist already.
264
void declare_local(const std::string& varname);
266
/// Add 'count' local registers (add space to end)
268
/// Local registers are only meaningful within a function2 context.
270
void add_local_registers(unsigned int register_count)
272
assert(!_localFrames.empty());
273
return _localFrames.back().registers.resize(register_count);
276
/// Return the number of local registers currently available
278
/// Local registers are only meaningful within a function2 context.
280
size_t num_local_registers() const
282
assert(!_localFrames.empty());
283
return _localFrames.back().registers.size();
286
/// Return a reference to the Nth local register.
288
/// Local registers are only meaningful within a function2 context.
290
as_value& local_register(boost::uint8_t n)
292
assert(!_localFrames.empty());
293
return _localFrames.back().registers[n];
296
/// Set the Nth local register to something
297
void set_local_register(boost::uint8_t n, as_value &val)
299
if ( ! _localFrames.empty() )
301
Registers& registers = _localFrames.back().registers;
302
if ( n < registers.size() )
309
/// Return a reference to the Nth global register.
310
as_value& global_register(unsigned int n)
313
return m_global_register[n];
316
/// Set the Nth local register to something
317
void set_global_register(boost::uint8_t n, as_value &val) {
319
m_global_register[n] = val;
324
/// Mark all reachable resources.
326
/// Reachable resources from an as_environment
327
/// would be global registers, stack (expected to be empty
328
/// actually), stack frames and targets (original and current).
330
void markReachableResources() const;
333
/// Find the sprite/movie referenced by the given path.
335
/// Supports both /slash/syntax and dot.syntax
336
/// Case insensitive for SWF up to 6, sensitive from 7 up
338
character* find_target(const std::string& path) const;
340
/// Find the object referenced by the given path.
342
/// Supports both /slash/syntax and dot.syntax
343
/// Case insensitive for SWF up to 6, sensitive from 7 up
345
as_object* find_object(const std::string& path, const ScopeStack* scopeStack=NULL) const;
347
/// Dump content of the stack to a std::ostream
348
void dump_stack(std::ostream& out=std::cerr)
351
for (unsigned int i=0, n=m_stack.size(); i<n; i++)
354
out << '"' << m_stack[i] << '"';
359
/// Dump the local registers to a std::ostream
361
/// NOTE that nothing will be written to the stream if NO local registers
364
void dump_local_registers(std::ostream& out=std::cerr) const;
366
/// Dump the global registers to a std::ostream
367
void dump_global_registers(std::ostream& out=std::cerr) const;
369
/// Dump the local variables to a std::ostream
370
void dump_local_variables(std::ostream& out=std::cerr) const;
372
/// Return the SWF version we're running for.
374
/// NOTE: this is the version encoded in the first loaded
375
/// movie, and cannot be changed during play even if
376
/// replacing the root movie with an externally loaded one.
378
int get_version() const;
380
/// See if the given variable name is actually a sprite path
381
/// followed by a variable name. These come in the format:
383
/// /path/to/some/sprite/:varname
385
/// (or same thing, without the last '/')
390
/// If that's the format, puts the path part (no colon or
391
/// trailing slash) in *path, and the varname part (no colon, no dot)
392
/// in *var and returns true.
394
/// If no colon or dot, returns false and leaves *path & *var alone.
396
/// TODO: return an integer: 0 not a path, 1 a slash-based path, 2 a dot-based path
398
static bool parse_path(const std::string& var_path, std::string& path,
402
/// Try to parse a string as a variable path
404
/// Variable paths come in the form:
406
/// /path/to/some/sprite/:varname
410
/// /path/to/some/sprite
415
/// If there's no dot nor colon, or if the 'path' part
416
/// does not resolve to an object, this function returns false.
417
/// Otherwise, true is returned and 'target' and 'val'
418
/// parameters are appropriaterly set.
420
/// Note that if the parser variable name doesn't exist in the found
421
/// target, the 'val' will be undefined, but no other way to tell whether
422
/// the variable existed or not from the caller...
424
bool parse_path(const std::string& var_path, as_object** target, as_value& val);
426
/// The variables container (case-insensitive)
427
typedef std::map<std::string, as_value, StringNoCaseLessThen> Variables;
429
/// The locals container
430
//typedef std::vector<frame_slot> LocalVars;
431
typedef boost::intrusive_ptr<as_object> LocalVars;
433
typedef std::vector<as_value> Registers;
437
CallFrame(as_function* funcPtr);
439
CallFrame(const CallFrame& other) : locals(other.locals),
440
registers(other.registers), func(other.func)
443
/// function use this
446
/// function2 also use this
452
/// Mark all reachable resources
454
/// Reachable resources would be registers and
455
/// locals (expected to be empty?) and function.
456
void markReachableResources() const;
457
#endif // GNASH_USE_GC
460
/// A class to wrap frame access. Stack allocating a frame guard
461
/// will ensure that all CallFrame pushes have a corresponding
462
/// CallFrame pop, even in the presence of extraordinary returns.
466
FrameGuard(as_function* func)
467
{ as_environment::pushCallFrame(func); }
468
~FrameGuard() { as_environment::popCallFrame(); }
471
/// Get top element of the call stack
473
CallFrame& topCallFrame()
475
assert(!_localFrames.empty());
476
return _localFrames.back();
479
/// Return the depth of call stack
480
size_t callStackDepth()
482
return _localFrames.size();
487
static const short unsigned int numGlobalRegisters = 4;
489
typedef std::vector<CallFrame> CallStack;
491
static CallStack _localFrames;
493
as_value m_global_register[numGlobalRegisters];
499
character* _original_target;
501
/// Push a frame on the calls stack.
503
/// This should happen right before calling an ActionScript
504
/// function. Function local registers and variables
505
/// must be set *after* pushCallFrame has been invoked
507
/// Call popCallFrame() at ActionScript function return.
510
/// The function being called
512
static void pushCallFrame(as_function* func);
514
/// Remove current call frame from the stack
516
/// This should happen when an ActionScript function returns.
518
static void popCallFrame();
520
/// Return the (possibly UNDEFINED) value of the named variable.
523
/// Variable name. Can not contain path elements.
524
/// NOTE: no case conversion is performed currently,
525
/// so make sure you do it yourself.
527
as_value get_variable_raw(const std::string& varname) const;
529
/// Given a variable name, set its value (no support for path)
530
void set_variable_raw(const std::string& path, const as_value& val,
531
const ScopeStack& scopeStack);
533
/// Same of the above, but no support for path.
536
/// If not NULL, the pointer will be set to the actual object containing the
537
/// found variable (if found).
539
as_value get_variable_raw(const std::string& varname,
540
const ScopeStack& scopeStack, as_object** retTarget=NULL) const;
544
/// Get a local variable given its name,
547
/// Name of the local variable
550
/// If a variable is found it's assigned to this parameter.
551
/// Untouched if the variable is not found.
554
/// If not NULL, the pointer will be set to the actual object containing the
555
/// found variable (if found).
557
/// @return true if the variable was found, false otherwise
559
bool findLocal(const std::string& varname, as_value& ret, as_object** retTarget=NULL);
561
bool findLocal(const std::string& varname, as_value& ret, as_object** retTarget=NULL) const
563
return const_cast<as_environment*>(this)->findLocal(varname, ret, retTarget);
566
/// Find a variable in the given LocalVars
569
/// Name of the local variable
572
/// If a variable is found it's assigned to this parameter.
573
/// Untouched if the variable is not found.
575
/// @return true if the variable was found, false otherwise
577
static bool findLocal(LocalVars& locals, const std::string& name, as_value& ret);
579
/// Delete a local variable
582
/// Name of the local variable
584
/// @return true if the variable was found and deleted, false otherwise
586
bool delLocal(const std::string& varname);
588
/// Delete a variable from the given LocalVars
591
/// Name of the local variable
593
/// @return true if the variable was found, false otherwise
595
static bool delLocal(LocalVars& locals, const std::string& varname);
597
/// Set a local variable, if it exists.
600
/// Name of the local variable
603
/// Value to assign to the variable
605
/// @return true if the variable was found, false otherwise
607
bool setLocal(const std::string& varname, const as_value& val);
609
/// Set a variable from the given LocalVars, if it exists.
612
/// Name of the local variable
615
/// Value to assign to the variable
617
/// @return true if the variable was found, false otherwise
619
static bool setLocal(LocalVars& locals, const std::string& varname, const as_value& val);
624
} // end namespace gnash
627
#endif // GNASH_AS_ENVIRONMENT_H
632
// indent-tabs-mode: t