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
21
#include "smart_ptr.h" // GNASH_USE_GC
22
#include "dsodefs.h" // DSOEXPORT
23
#include "as_value.h" // for composition (vector + frame_slot)
24
#include "StringPredicates.h" // for Variables
25
#include "as_object.h"
26
#include "SafeStack.h"
27
#include "CallStack.h" // for composition
29
#include <map> // for composition (Variables)
30
#include <string> // for frame_slot name
32
#include <iostream> // for dump_stack inline
36
// Forward declarations
40
/// ActionScript execution environment.
46
/// A stack of objects used for variables/members lookup
47
//typedef std::vector<with_stack_entry> ScopeStack;
48
typedef std::vector< boost::intrusive_ptr<as_object> > ScopeStack;
50
/// The variables container (case-insensitive)
51
typedef std::map<std::string, as_value, StringNoCaseLessThen> Variables;
53
typedef std::vector<as_value> Registers;
55
as_environment(VM& vm);
57
VM& getVM() { return _vm; }
59
character* get_target() { return m_target; }
61
/// Set default target for timeline opcodes
64
/// A character to apply timeline opcodes on.
65
/// Zero is a valid target, disabling timeline
66
/// opcodes (would get ignored).
68
void set_target(character* target);
70
void set_original_target(character* target) { _original_target = target; }
72
character* get_original_target() { return _original_target; }
74
// Reset target to its original value
75
void reset_target() { m_target = _original_target; }
77
/// @{ Stack access/manipulation
79
/// Push a value on the stack
80
void push(const as_value& val)
86
/// Pops an as_value off the stack top and return it.
91
} catch (StackException&) {
94
//assert( ! _stack.empty() );
95
//as_value result = m_stack.back();
100
/// Get stack value at the given distance from top.
102
/// top(0) is actual stack top
104
/// Throw StackException if index is out of range
106
as_value& top(size_t dist)
109
return _stack.top(dist);
110
} catch (StackException&) {
113
//size_t ssize = m_stack.size();
114
//assert ( ssize > dist );
115
//return m_stack[ssize - 1 - dist];
118
/// Get stack value at the given distance from bottom.
120
/// bottom(stack_size()-1) is actual stack top
122
/// Throw StackException if index is out of range
124
as_value& bottom(size_t index)
127
return _stack.value(index);
128
} catch (StackException&) {
131
//assert ( m_stack.size() > index );
132
//return m_stack[index];
135
/// Drop 'count' values off the top of the stack.
137
/// Throw StackException if there's not enough to drop
139
void drop(size_t count)
141
// in case count > stack size, just drop all, forget about
143
_stack.drop(std::min(count, _stack.size()));
144
//size_t ssize = m_stack.size();
145
//assert ( ssize >= count );
146
//m_stack.resize(ssize - count);
149
/// Insert 'count' undefined values before 'offset'.
151
/// An offset of 0 will prepend the values,
152
/// An offset of size() [too far] will append the values.
154
void padStack(size_t offset, size_t count);
156
size_t stack_size() const { return _stack.size(); }
158
/// @} stack access/manipulation
162
/// Return the (possibly UNDEFINED) value of the named variable
165
/// Variable name. Can contain path elements.
166
/// TODO: should be case-insensitive up to SWF6.
167
/// NOTE: no case conversion is performed currently,
168
/// so make sure you do it yourself. Note that
169
/// ActionExec performs the conversion
170
/// before calling this method.
172
as_value get_variable(const std::string& varname) const;
175
/// Delete a variable, w/out support for the path, using
179
/// Variable name. Can not contain path elements.
180
/// TODO: should be case-insensitive up to SWF6.
181
/// NOTE: no case conversion is performed currently,
182
/// so make sure you do it yourself. Note that
183
/// ActionExec performs the conversion
184
/// before calling this method.
186
/// @param scopeStack
187
/// The Scope stack to use for lookups.
189
bool del_variable_raw(const std::string& varname,
190
const ScopeStack& scopeStack);
192
/// Return the (possibly UNDEFINED) value of the named var.
195
/// Variable name. Can contain path elements.
196
/// TODO: should be case-insensitive up to SWF6.
197
/// NOTE: no case conversion is performed currently,
198
/// so make sure you do it yourself. Note that
199
/// ActionExec performs the conversion
200
/// before calling this method.
202
/// @param scopeStack
203
/// The Scope stack to use for lookups.
206
/// If not NULL, the pointer will be set to the actual object containing the
207
/// found variable (if found).
209
as_value get_variable(const std::string& varname,
210
const ScopeStack& scopeStack, as_object** retTarget=NULL) const;
213
/// Given a path to variable, set its value.
214
/// Variable name can contain path elements.
218
/// TODO: should be case-insensitive up to SWF6.
219
/// NOTE: no case conversion is performed currently,
220
/// so make sure you do it yourself. Note that
221
/// ActionExec performs the conversion
222
/// before calling this method.
225
/// The value to assign to the variable, if found.
227
/// TODO: make this function return some info about the
228
/// variable being found and set ?
230
void set_variable(const std::string& path, const as_value& val);
232
/// Given a variable name, set its value (no support for path)
234
/// If no variable with that name is found, a new one
235
/// will be created as a member of current target.
238
/// Variable name. Can not contain path elements.
239
/// TODO: should be case-insensitive up to SWF6.
242
/// The value to assign to the variable, if found.
244
void set_variable_raw(const std::string& var, const as_value& val);
247
/// Given a path to variable, set its value.
249
/// If no variable with that name is found, a new one is created.
251
/// For path-less variables, this would act as a proxy for
252
/// set_variable_raw.
256
/// TODO: should be case-insensitive up to SWF6.
259
/// The value to assign to the variable.
261
/// @param scopeStack
262
/// The Scope stack to use for lookups.
264
void set_variable(const std::string& path, const as_value& val,
265
const ScopeStack& scopeStack);
267
/// Set/initialize the value of the local variable.
269
/// If no *local* variable with that name is found, a new one
273
/// Variable name. Can not contain path elements.
274
/// TODO: should be case-insensitive up to SWF6.
277
/// The value to assign to the variable.
279
void set_local(const std::string& varname, const as_value& val);
282
/// Add a local var with the given name and value to our
283
/// current local frame.
285
/// Use this when you know the var
286
/// doesn't exist yet, since it's faster than set_local();
287
/// e.g. when setting up args for a function.
289
void add_local(const std::string& varname, const as_value& val);
291
/// Create the specified local var if it doesn't exist already.
292
void declare_local(const std::string& varname);
294
/// Add 'count' local registers (add space to end)
296
/// Local registers are only meaningful within a function2 context.
298
void add_local_registers(unsigned int register_count)
300
assert(!_localFrames.empty());
301
return _localFrames.back().registers.resize(register_count);
304
/// Set value of a register (local or global).
306
/// When not in a function context the register will be
307
/// global or none (if regnum is not in the valid range
308
/// of global registers).
310
/// When in a function context defining NO registers,
311
/// we'll behave the same as for a non-function context.
313
/// When in a function context defining non-zero number
314
/// of local registers, the register set will be local
315
/// or none (if regnum is not in the valid range of local
322
/// Value to assign to the register
324
/// @return 0 if register num is invalid
325
/// 1 if a global register was set
326
/// 2 if a local register was set
328
unsigned int setRegister(unsigned int regnum, const as_value& v);
330
/// Get value of a register (local or global).
332
/// When not in a function context the register will be
333
/// global or none (if regnum is not in the valid range
334
/// of global registers).
336
/// When in a function context defining NO registers,
337
/// we'll behave the same as for a non-function context.
339
/// When in a function context defining non-zero number
340
/// of local registers, the register set will be local
341
/// or none (if regnum is not in the valid range of local
348
/// Output parameter, will be set to register
349
/// value or untouched if 0 is returned.
351
/// @return 0 if register num is invalid (v unmodified in this case)
352
/// 1 if a global register was set
353
/// 2 if a local register was set
355
unsigned int getRegister(unsigned int regnum, as_value& v);
357
/// Return a reference to the Nth local register.
359
/// Local registers are only meaningful within a function2 context.
361
as_value& local_register(boost::uint8_t n)
363
assert(!_localFrames.empty());
364
return _localFrames.back().registers[n];
367
/// Set the Nth local register to something
368
void set_local_register(boost::uint8_t n, as_value &val)
370
if ( ! _localFrames.empty() )
372
Registers& registers = _localFrames.back().registers;
373
if ( n < registers.size() )
380
/// Return a reference to the Nth global register.
381
as_value& global_register(unsigned int n)
384
return m_global_register[n];
387
/// Set the Nth local register to something
388
void set_global_register(boost::uint8_t n, as_value &val) {
390
m_global_register[n] = val;
395
/// Mark all reachable resources.
397
/// Reachable resources from an as_environment
398
/// would be global registers, stack (expected to be empty
399
/// actually), stack frames and targets (original and current).
401
void markReachableResources() const;
404
/// Find the sprite/movie referenced by the given path.
406
/// Supports both /slash/syntax and dot.syntax
407
/// Case insensitive for SWF up to 6, sensitive from 7 up
409
character* find_target(const std::string& path) const;
411
/// Find the object referenced by the given path.
413
/// Supports both /slash/syntax and dot.syntax
414
/// Case insensitive for SWF up to 6, sensitive from 7 up
416
as_object* find_object(const std::string& path, const ScopeStack* scopeStack=NULL) const;
418
/// Dump content of the stack to a std::ostream
421
/// The output stream, standard error if omitted.
424
/// If > 0, limit number of printed item by the given amount (from the top).
425
/// Unlimited by default;
427
void dump_stack(std::ostream& out=std::cerr, unsigned int limit=0) const;
429
/// Dump the local registers to a std::ostream
431
/// NOTE that nothing will be written to the stream if NO local registers
434
void dump_local_registers(std::ostream& out=std::cerr) const;
436
/// Dump the global registers to a std::ostream
437
void dump_global_registers(std::ostream& out=std::cerr) const;
439
/// Dump the local variables to a std::ostream
440
void dump_local_variables(std::ostream& out=std::cerr) const;
442
/// Return the SWF version we're running for.
444
/// NOTE: this is the version encoded in the first loaded
445
/// movie, and cannot be changed during play even if
446
/// replacing the root movie with an externally loaded one.
448
int get_version() const;
450
/// See if the given variable name is actually a sprite path
451
/// followed by a variable name. These come in the format:
453
/// /path/to/some/sprite/:varname
455
/// (or same thing, without the last '/')
460
/// If that's the format, puts the path part (no colon or
461
/// trailing slash) in *path, and the varname part (no colon, no dot)
462
/// in *var and returns true.
464
/// If no colon or dot, returns false and leaves *path & *var alone.
466
/// TODO: return an integer: 0 not a path, 1 a slash-based path, 2 a dot-based path
468
static bool parse_path(const std::string& var_path, std::string& path,
472
/// Try to parse a string as a variable path
474
/// Variable paths come in the form:
476
/// /path/to/some/sprite/:varname
480
/// /path/to/some/sprite
485
/// If there's no dot nor colon, or if the 'path' part
486
/// does not resolve to an object, this function returns false.
487
/// Otherwise, true is returned and 'target' and 'val'
488
/// parameters are appropriaterly set.
490
/// Note that if the parser variable name doesn't exist in the found
491
/// target, the 'val' will be undefined, but no other way to tell whether
492
/// the variable existed or not from the caller...
494
bool parse_path(const std::string& var_path, as_object** target, as_value& val);
496
/// A class to wrap frame access. Stack allocating a frame guard
497
/// will ensure that all CallFrame pushes have a corresponding
498
/// CallFrame pop, even in the presence of extraordinary returns.
501
as_environment& _env;
503
FrameGuard(as_environment& env, as_function* func)
507
_env.pushCallFrame(func);
516
/// Get top element of the call stack
518
CallFrame& topCallFrame()
520
assert(!_localFrames.empty());
521
return _localFrames.back();
524
/// Return the depth of call stack
525
size_t callStackDepth()
527
return _localFrames.size();
534
/// Stack of as_values in this environment
535
//std::vector<as_value> m_stack;
536
SafeStack<as_value>& _stack;
538
static const short unsigned int numGlobalRegisters = 4;
540
CallStack& _localFrames;
542
as_value m_global_register[numGlobalRegisters];
548
character* _original_target;
550
/// Push a frame on the calls stack.
552
/// This should happen right before calling an ActionScript
553
/// function. Function local registers and variables
554
/// must be set *after* pushCallFrame has been invoked
556
/// Call popCallFrame() at ActionScript function return.
559
/// The function being called
561
DSOEXPORT void pushCallFrame(as_function* func);
563
/// Remove current call frame from the stack
565
/// This should happen when an ActionScript function returns.
567
DSOEXPORT void popCallFrame();
569
/// Return the (possibly UNDEFINED) value of the named variable.
572
/// Variable name. Can not contain path elements.
573
/// NOTE: no case conversion is performed currently,
574
/// so make sure you do it yourself.
576
as_value get_variable_raw(const std::string& varname) const;
578
/// Given a variable name, set its value (no support for path)
579
void set_variable_raw(const std::string& path, const as_value& val,
580
const ScopeStack& scopeStack);
582
/// Same of the above, but no support for path.
585
/// If not NULL, the pointer will be set to the actual object containing the
586
/// found variable (if found).
588
as_value get_variable_raw(const std::string& varname,
589
const ScopeStack& scopeStack, as_object** retTarget=NULL) const;
593
/// Get a local variable given its name,
596
/// Name of the local variable
599
/// If a variable is found it's assigned to this parameter.
600
/// Untouched if the variable is not found.
603
/// If not NULL, the pointer will be set to the actual object containing the
604
/// found variable (if found).
606
/// @return true if the variable was found, false otherwise
608
bool findLocal(const std::string& varname, as_value& ret, as_object** retTarget=NULL);
610
bool findLocal(const std::string& varname, as_value& ret, as_object** retTarget=NULL) const
612
return const_cast<as_environment*>(this)->findLocal(varname, ret, retTarget);
615
/// Find a variable in the given as_object
618
/// Name of the local variable
621
/// If a variable is found it's assigned to this parameter.
622
/// Untouched if the variable is not found.
624
/// @return true if the variable was found, false otherwise
626
bool findLocal(as_object* locals, const std::string& name, as_value& ret);
628
/// Delete a local variable
631
/// Name of the local variable
633
/// @return true if the variable was found and deleted, false otherwise
635
bool delLocal(const std::string& varname);
637
/// Delete a variable from the given as_object
640
/// Name of the local variable
642
/// @return true if the variable was found, false otherwise
644
bool delLocal(as_object* locals, const std::string& varname);
646
/// Set a local variable, if it exists.
649
/// Name of the local variable
652
/// Value to assign to the variable
654
/// @return true if the variable was found, false otherwise
656
bool setLocal(const std::string& varname, const as_value& val);
658
/// Set a variable of the given object, if it exists.
661
/// Name of the local variable
664
/// Value to assign to the variable
666
/// @return true if the variable was found, false otherwise
668
bool setLocal(as_object* locals, const std::string& varname, const as_value& val);
670
static as_value undefVal;
675
} // end namespace gnash
678
#endif // GNASH_AS_ENVIRONMENT_H
683
// indent-tabs-mode: t