1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 //   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 #ifndef GNASH_ACTIONEXEC_H
20 #define GNASH_ACTIONEXEC_H
21 
22 #include <string>
23 #include <stack>
24 #include <vector>
25 #include <boost/noncopyable.hpp>
26 
27 #include "as_environment.h"
28 #include "SWF.h"
29 #include "action_buffer.h"
30 
31 // Forward declarations
32 namespace gnash {
33 	class as_value;
34 	class Function;
35 	class ActionExec;
36 }
37 
38 namespace gnash {
39 
40 class TryBlock
41 {
42 public:
43 	friend class ActionExec;
44 
45 	enum tryState
46 	{
47 		TRY_TRY, // In a try block.
48 		TRY_CATCH, // In a catch block.
49 		TRY_FINALLY, // In a finally block.
50 		TRY_END // Finished with finally
51 	};
52 
TryBlock(size_t cur_off,size_t try_size,size_t catch_size,size_t finally_size,std::string catchName)53     TryBlock(size_t cur_off, size_t try_size, size_t catch_size,
54 		size_t finally_size, std::string catchName)
55 		:
56 		_catchOffset(cur_off + try_size),
57 		_finallyOffset(cur_off + try_size + catch_size),
58 		_afterTriedOffset(cur_off + try_size + catch_size + finally_size),
59 		_savedEndOffset(0),
60 		_hasName(true),
61 		_name(std::move(catchName)),
62 		_registerIndex(0),
63 		_tryState(TryBlock::TRY_TRY),
64 		_lastThrow()
65 	{}
66 
TryBlock(size_t cur_off,size_t try_size,size_t catch_size,size_t finally_size,std::uint8_t register_index)67 	TryBlock(size_t cur_off, size_t try_size, size_t catch_size,
68 		size_t finally_size, std::uint8_t register_index)
69 		:
70 		_catchOffset(cur_off + try_size),
71 		_finallyOffset(cur_off + try_size + catch_size),
72 		_afterTriedOffset(cur_off + try_size + catch_size + finally_size),
73 		_savedEndOffset(0),
74 		_hasName(false),
75 		_name(),
76 		_registerIndex(register_index),
77 		_tryState(TryBlock::TRY_TRY),
78 		_lastThrow()
79 	{}
80 
81 private:
82 	size_t _catchOffset;
83 	size_t _finallyOffset;
84 	size_t _afterTriedOffset;
85 	size_t _savedEndOffset;
86 	bool _hasName;
87 	std::string _name;
88 	unsigned int _registerIndex;
89 	tryState _tryState;
90 	as_value _lastThrow;
91 };
92 
93 class With
94 {
95 public:
96 
With(as_object * obj,size_t end)97 	With(as_object* obj, size_t end)
98 		:
99 		_object(obj),
100 		_block_end_pc(end)
101 	{
102 	}
103 
end_pc()104 	size_t end_pc() const {
105 		return _block_end_pc;
106 	}
107 
object()108 	as_object* object() const {
109 		return _object;
110 	}
111 
112 private:
113 	as_object* _object;
114 	size_t _block_end_pc;
115 };
116 
117 /// Executor of an action_buffer
118 class ActionExec : boost::noncopyable
119 {
120 
121     typedef as_environment::ScopeStack ScopeStack;
122 
123 public:
124 
125 	/// Create an execution thread
126 	//
127 	/// @param abuf	            the action code
128 	/// @param newEnv 	        the timeline context.
129 	/// @param abortOnUnloaded  If true (default) execution aborts as soon
130     ///                         as the target sprite is unloaded.
131 	///	NOTE: original target is fetched from the environment.
132 	ActionExec(const action_buffer& abuf, as_environment& newEnv,
133             bool abortOnUnloaded = true);
134 
135 	/// Create an execution thread for a function call.
136 	//
137 	/// @param func     The function
138 	/// @param newEnv   The execution environment (variables scope, stack etc.)
139 	/// @param nRetval  Where to return a value. If NULL any return will
140     ///                 be discarded.
141 	ActionExec(const Function& func, as_environment& newEnv,
142             as_value* nRetVal, as_object* this_ptr);
143 
144 	/// Use this to push a try block. It will be copied
145 	void pushTryBlock(TryBlock t);
146 
147 	/// Set the return value.
148 	void pushReturn(const as_value& t);
149 
150 	/// The actual action buffer
151 	//
152 	/// TODO: provide a getter and make private
153 	const action_buffer& code;
154 
155 	/// TODO: provide a getter and make private ?
156 	as_environment& env;
157 
158 	/// TODO: provide a setter and make private ?
159 	as_value* retval;
160 
161 	/// Is this execution thread a function call ?
isFunction()162 	bool isFunction() const { return _func != nullptr; }
163 
164 	/// Get the current 'this' pointer, for use in function calls
165 	as_object* getThisPointer();
166 
167 	/// Returns the scope stack associated with this execution thread
getScopeStack()168 	const ScopeStack& getScopeStack() const {
169 		return _scopeStack;
170 	}
171 
172 	/// Push an entry to the with stack
173 	//
174 	/// @return     true if the entry was pushed, false otherwise. This
175     ///             depends on the with stack limit.
176 	bool pushWith(const With& entry);
177 
178 	/// Skip the specified number of action tags
179 	//
180 	/// The offset is relative to next_pc
181 	void skip_actions(size_t offset);
182 
183 	/// Delete named variable, seeking for it in the with stack if any
184 	//
185 	/// @param name     Name of the variable. Supports slash and dot syntax.
186 	bool delVariable(const std::string& name);
187 
188 	/// Set a named variable, seeking for it in the with stack if any.
189 	//
190 	/// @param name     Name of the variable. Supports slash and dot syntax.
191 	void setVariable(const std::string& name, const as_value& val);
192 
193 	/// Set a function-local variable
194     //
195     /// If we're not in a function, set a normal variable.
196 	//
197 	/// @param name Name of the variable. Supports slash and dot syntax.
198     /// @param val  The value to set the variable to.
199 	void setLocalVariable(const std::string& name, const as_value& val);
200 
201 	/// Get a named variable, seeking for it in the with stack if any.
202 	//
203 	/// @param name     Name of the variable. Supports slash and dot syntax.
204 	/// @param target   An output parameter, will be set to point to the object
205 	///	                containing any found variable. If you aren't interested,
206     ///                 pass null (default). If the variable does not belong
207     ///                 to an object, target will be set to null.
208 	as_value getVariable(const std::string& name, as_object** target = nullptr);
209 
210 	/// Get current target.
211 	//
212 	/// This function returns top 'with' stack entry, if any.
213 	/// Main use for this function is for calling methods and
214 	/// properly setting the "this" pointer.
215 	///
216 	/// TODO:
217 	/// A better, cleaner and less error-prone approach
218 	/// would be providing a callFunction() method in
219 	/// ActionExec. This will likely help debugger too
220 	as_object* getTarget();
221 
222 	/// Execute.
223 	void operator()();
224 
225     // TODO: cut down these accessors.
atActionTag(SWF::ActionType t)226     bool atActionTag(SWF::ActionType t) { return code[pc] == t; }
227 
getCurrentPC()228 	size_t getCurrentPC() const { return pc; }
229 
skipRemainingBuffer()230 	void skipRemainingBuffer() { next_pc = stop_pc; }
231 
232 	void adjustNextPC(int offset);
233 
getNextPC()234 	size_t getNextPC() const { return next_pc; }
235 
setNextPC(size_t pc)236 	void setNextPC(size_t pc) { next_pc = pc; }
237 
getStopPC()238 	size_t getStopPC() const { return stop_pc; }
239 
240 private:
241 
242 	/// \brief
243 	/// Debugging function:
244 	/// print opcodes from start (included) to end (not-included) PCs.
245 	//
246 	/// @param start
247 	///	First opcode to dump
248 	///
249 	/// @param end
250 	///	One-past last opcode to dump
251 	///
252 	/// @param os
253 	///	Output stream to dump to
254 	///
255 	void dumpActions(size_t start, size_t end, std::ostream& os);
256 
257     /// Processes the current try - catch - finally block
258     //
259     /// This function is called after each stage of a
260     /// try/catch/finally block. It ensures it is called
261     /// after each stage by setting stop_pc to the appropriate
262     /// number. If an exception is on the stack at any stage,
263     /// it takes the appropriate action (catch, set register
264     /// values, return, or leave it on the stack). Return
265     /// false means that the action processing loop should be
266     /// interrupted.
267     //
268     /// @return whether to continue executing the buffer
269     /// @param t the try block to process.
270     bool processExceptions(TryBlock& t);
271 
272 	/// Run after a complete run, or after an run interrupted by
273 	/// a bail-out exception (ActionLimitException, for example)
274 	//
275 	/// The method restores original target of the as_environment,
276 	/// checks for stack smashing (stack contains less entries
277 	/// then it had at time of execution start) or leftovers
278 	/// (stack contains more entries then it had at time of execution
279 	/// start) and finally gives movie_root a chance to execute
280 	/// actions queued in higher priority action queues.
281 	///
282 	/// The higher priority action queue flush is needed to allow
283 	/// initialize/construct/initactions queued by effect of gotoFrame
284 	/// calls in DOACTION block before frame actions queued by the same
285 	/// cause (the latter would be pushed in the same level gotoFrame is
286 	/// found)
287 	void cleanupAfterRun();
288 
289 	/// the 'with' stack associated with this execution thread
290 	std::vector<With> _withStack;
291 
292 	/// the scope stack associated with this execution thread
293 	ScopeStack _scopeStack;
294 
295 	/// A pointer to the function being executed, or NULL
296 	/// for non-function execution
297 	///
298 	/// TODO:
299 	/// This should likely be put in a larger
300 	/// structure including return address
301 	/// and maintained in a stack (the call stack)
302 	///
303 	const Function* _func;
304 
305 	/// The 'this' pointer, if this is a function call
306 	as_object* _this_ptr;
307 
308 	/// Stack size at start of execution
309 	size_t _initialStackSize;
310 
311 	DisplayObject* _originalTarget;
312 
313 	int _origExecSWFVersion;
314 
315 	std::stack<TryBlock> _tryList;
316 
317 	bool _returning;
318 
319 	bool _abortOnUnload;
320 
321     /// Program counter (offset of current action tag)
322 	size_t pc;
323 
324 	/// Offset to next action tag
325 	size_t next_pc;
326 
327 	/// End of current function execution
328 	/// Used for try/throw/catch blocks.
329 	size_t stop_pc;
330 
331 };
332 
333 } // namespace gnash
334 
335 #endif // GNASH_ACTIONEXEC_H
336 
337 // Local Variables:
338 // mode: C++
339 // indent-tabs-mode: t
340 // End:
341