Update with current status
[gnash.git] / libcore / as_value.h
blob1bf3c0aae521b8df395ef0669f2330ec4b3406cd
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
19 #ifndef GNASH_AS_VALUE_H
20 #define GNASH_AS_VALUE_H
22 #include <limits>
23 #include <string>
24 #include <boost/variant.hpp>
25 #include <iosfwd> // for inlined output operator
26 #include <type_traits>
27 #include <cstdint>
29 #include "dsodefs.h" // for DSOTEXPORT
30 #include "CharacterProxy.h"
31 #include "GnashNumeric.h" // for isNaN
34 // Forward declarations
35 namespace gnash {
36 class VM;
37 class as_object;
38 class Global_as;
39 class fn_call;
40 class as_function;
41 class MovieClip;
42 class DisplayObject;
43 namespace amf {
44 class Writer;
48 namespace gnash {
51 // NaN constant for use in as_value implementation
52 static const double NaN = std::numeric_limits<double>::quiet_NaN();
54 template <typename T>
55 inline bool
56 isInf(const T& num)
58 return isNaN(num - num);
62 /// These are the primitive types, see the ECMAScript reference.
63 enum primitive_types
65 PTYPE_STRING,
66 PTYPE_NUMBER,
67 PTYPE_BOOLEAN
70 /// ActionScript value type.
72 /// The as_value class can store basic ActionScript types.
74 /// These are the primitive types (Number, Boolean, String, null, and
75 /// undefined), as well as complex types (Object and DisplayObject).
77 /// Most type handling is hidden within the class. There are two different
78 /// types of access to the as_value: converting and non-converting.
80 /// Non-converting access
81 /// Non-converting access is available for the complex types, for instance
82 /// to_function() and toMovieClip(). In these cases, an object pointer is
83 /// return only if the as_value is currently of the requested type. There
84 /// are no ActionScript side-effects in such cases.
86 /// Converting access
87 /// The primitive types and Objects have converting access. This means that
88 /// as_values of a different type are converted to the requested type. These
89 /// functions may have ActionScript side-effects, for instance the calling of
90 /// toString or valueOf, or construction of an object.
92 /// It is possible to check the current type of an as_value using is_string(),
93 /// is_number() etc. These functions have no ActionScript side effects.
94 class as_value
97 public:
99 // The exception type should always be one greater than the normal type.
100 enum AsType
102 UNDEFINED,
103 UNDEFINED_EXCEPT,
104 NULLTYPE,
105 NULLTYPE_EXCEPT,
106 BOOLEAN,
107 BOOLEAN_EXCEPT,
108 STRING,
109 STRING_EXCEPT,
110 NUMBER,
111 NUMBER_EXCEPT,
112 OBJECT,
113 OBJECT_EXCEPT,
114 DISPLAYOBJECT,
115 DISPLAYOBJECT_EXCEPT
118 /// Construct an undefined value
119 DSOEXPORT as_value()
121 _type(UNDEFINED),
122 _value(boost::blank())
126 /// Copy constructor.
127 DSOEXPORT as_value(const as_value& v)
129 _type(v._type),
130 _value(v._value)
134 /// Move constructor.
135 DSOEXPORT as_value(as_value&& other)
136 : _type(other._type),
137 _value(std::move(other._value))
139 other._type = UNDEFINED;
142 ~as_value() {}
144 /// Construct a primitive String value
145 DSOEXPORT as_value(const char* str)
147 _type(STRING),
148 _value(std::string(str))
151 /// Construct a primitive String value
152 DSOEXPORT as_value(std::string str)
154 _type(STRING),
155 _value(std::move(str))
158 /// Construct a primitive Boolean value
159 template <typename T, typename U =
160 typename std::enable_if<std::is_same<bool, T>::value>::type>
161 as_value(T val)
163 _type(BOOLEAN),
164 _value(val)
167 /// Construct a primitive Number value
168 as_value(double num)
170 _type(NUMBER),
171 _value(num)
174 /// Construct a null, Object, or DisplayObject value
175 as_value(as_object* obj)
177 _type(UNDEFINED)
179 set_as_object(obj);
182 /// Assign to an as_value.
183 DSOEXPORT as_value& operator=(const as_value& v)
185 _type = v._type;
186 _value = v._value;
187 return *this;
190 DSOEXPORT as_value& operator=(as_value&& other)
192 _type = other._type;
193 _value = std::move(other._value);
194 other._type = UNDEFINED;
195 return *this;
198 friend std::ostream& operator<<(std::ostream& o, const as_value&);
200 /// Return the primitive type of this value as a string.
201 const char* typeOf() const;
203 /// Return true if this value is a function
204 bool is_function() const;
206 /// Return true if this value is a string
207 bool is_string() const {
208 return _type == STRING;
211 /// Return true if this value is strictly a number
212 bool is_number() const {
213 return _type == NUMBER;
216 /// Return true if this value is an object
218 /// Both DisplayObjects and Objects count as Objects
219 bool is_object() const {
220 return _type == OBJECT || _type == DISPLAYOBJECT;
223 /// Return true if this value is a DISPLAYOBJECT
224 bool is_sprite() const {
225 return _type == DISPLAYOBJECT;
228 /// Get a std::string representation for this value.
230 /// @param version The SWF version to use to transform the string.
231 /// This only affects undefined values, which trace
232 /// "undefined" for version 7 and above, nothing
233 /// for lower versions.
235 /// TODO: drop the default argument.
236 DSOTEXPORT std::string to_string(int version = 7) const;
238 /// Get a number representation for this value
240 /// This function performs conversion if necessary.
241 double to_number(int version) const;
243 /// Conversion to boolean.
245 /// This function performs conversion if necessary.
246 DSOTEXPORT bool to_bool(int version) const;
248 /// Return value as an object, converting primitive values as needed.
250 /// This function performs conversion where necessary.
252 /// string values are converted to String objects
253 /// numeric values are converted to Number objects
254 /// boolean values are converted to Boolean objects
256 /// If you want to avoid the conversion, check with is_object() before
257 /// calling this function.
259 /// @param global The global object object for the conversion. This
260 /// contains the prototypes or constructors necessary for
261 /// conversion.
262 as_object* to_object(VM& vm) const;
264 /// Return the value as an as_object only if it is an as_object.
266 /// Note that this performs no conversion, so returns 0 if the as_value
267 /// is not an object.
268 as_object* get_object() const;
270 /// Returns value as a MovieClip if it is a MovieClip.
272 /// This function performs no conversion, so returns 0 if the as_value is
273 /// not a MovieClip.
275 /// This is just a wrapper around toDisplayObject() performing
276 /// an additional final cast.
277 MovieClip* toMovieClip(bool skipRebinding = false) const;
279 /// Return value as a DisplayObject or NULL if this is not possible.
281 /// Note that this function performs no conversion, so returns 0 if the
282 /// as_value is not a DisplayObject.
284 /// If the value is a DisplayObject value, the stored DisplayObject target
285 /// is evaluated using the root movie's environment.
286 /// If the target points to something that doesn't cast to a DisplayObject,
287 /// 0 is returned.
289 /// @param skipRebinding If true a reference to a destroyed
290 /// DisplayObject is still returned, rather than
291 /// attempting to resolve it as a soft-reference.
292 /// Main use for this is during paths resolution,
293 /// to avoid infinite loops. See bug #21647.
294 DisplayObject* toDisplayObject(bool skipRebinding = false) const;
296 /// Return the value as a function only if it is a function.
298 /// Note that this performs no conversion, so returns 0 if the as_value
299 /// is not a function.
300 as_function* to_function() const;
302 AsType defaultPrimitive(int version) const;
304 /// Return value as a primitive type, with a preference
306 /// This function performs no conversion.
308 /// Primitive types are: undefined, null, boolean, string, number.
309 /// See ECMA-2.6.2 (sections 4.3.2 and 8.6.2.6).
311 /// @param hint
312 /// NUMBER or STRING, the preferred representation we're asking for.
314 /// @throw ActionTypeError if an object can't be converted to a primitive
316 as_value to_primitive(AsType hint) const;
318 /// Set to a primitive string.
319 void set_string(const std::string& str);
321 /// Set to a primitive number.
322 void set_double(double val);
324 /// Set to a primitive boolean.
325 void set_bool(bool val);
327 /// Make this value a NULL, OBJECT, DISPLAYOBJECT value
328 void set_as_object(as_object* obj);
330 /// Set to undefined.
331 void set_undefined();
333 /// Set this value to the NULL value
334 void set_null();
336 bool is_undefined() const {
337 return (_type == UNDEFINED);
340 bool is_null() const {
341 return (_type == NULLTYPE);
344 bool is_bool() const {
345 return (_type == BOOLEAN);
348 bool is_exception() const {
349 return (_type == UNDEFINED_EXCEPT || _type == NULLTYPE_EXCEPT
350 || _type == BOOLEAN_EXCEPT || _type == NUMBER_EXCEPT
351 || _type == OBJECT_EXCEPT || _type == DISPLAYOBJECT_EXCEPT
352 || _type == STRING_EXCEPT);
355 // Flag or unflag an as_value as an exception -- this gets flagged
356 // when an as_value is 'thrown'.
357 void flag_exception() {
358 if (!is_exception()) {
359 _type = static_cast<AsType>(static_cast<int>(_type) + 1);
363 void unflag_exception() {
364 if (is_exception()) {
365 _type = static_cast<AsType>(static_cast<int>(_type) - 1);
369 /// Return true if this value is strictly equal to the given one
371 /// Strict equality is defined as the two values being of the
372 /// same type and the same value.
373 DSOTEXPORT bool strictly_equals(const as_value& v) const;
375 /// Return true if this value is abstractly equal to the given one
377 /// See ECMA-262 abstract equality comparison (sect 11.9.3)
379 /// NOTE: these invariants should hold
381 /// - A != B is equivalent to ! ( A == B )
382 /// - A == B is equivalent to B == A, except for order of
383 /// evaluation of A and B.
385 /// @param v The as_value to compare to
386 DSOEXPORT bool equals(const as_value& v, int version) const;
388 /// Set any object value as reachable (for the GC)
390 /// Object values are values stored by pointer (objects and functions)
391 void setReachable() const;
393 /// Serialize value in AMF0 format.
395 /// @param buf
396 /// The buffer to append serialized version of this value to.
398 /// @param offsetTable
399 /// A map of already-parsed objects, pass an empty map on first call as
400 /// it will be used internally.
402 /// @param vm
403 /// Virtual machine to use for serialization of property names
404 /// (string_table)
406 /// @param allowStrictArray
407 /// If true strict arrays will be encoded a STRICT_ARRAY types.
409 bool writeAMF0(amf::Writer& w) const;
411 private:
413 /// AsValueType handles the following AS types:
415 /// 1. undefined / null
416 /// 2. Number
417 /// 3. Boolean
418 /// 4. Object
419 /// 5. MovieClip
420 /// 6. String
421 typedef boost::variant<boost::blank,
422 double,
423 bool,
424 as_object*,
425 CharacterProxy,
426 std::string>
427 AsValueType;
429 /// Use the relevant equality function, not operator==
430 bool operator==(const as_value& v) const;
432 /// Use the relevant inequality function, not operator!=
433 bool operator!=(const as_value& v) const;
435 /// Compare values of the same type
437 /// NOTE: will abort if values are not of the same type!
439 bool equalsSameType(const as_value& v) const;
441 AsType _type;
443 AsValueType _value;
445 /// Get the object pointer variant member.
447 /// Callers must check that this is an Object (including DisplayObjects).
448 as_object* getObj() const;
450 /// Get the DisplayObject variant member.
452 /// The caller must check that this is a DisplayObject.
453 DisplayObject* getCharacter(bool skipRebinding = false) const;
455 /// Get the DisplayObject proxy variant member.
457 /// The caller must check that this value is a DisplayObject
458 CharacterProxy getCharacterProxy() const;
460 /// Get the number variant member.
462 /// The caller must check that this value is a Number.
463 double getNum() const {
464 assert(_type == NUMBER);
465 return boost::get<double>(_value);
468 /// Get the boolean variant member.
470 /// The caller must check that this value is a Boolean.
471 bool getBool() const {
472 assert(_type == BOOLEAN);
473 return boost::get<bool>(_value);
476 /// Get the boolean variant member.
478 /// The caller must check that this value is a String.
479 const std::string& getStr() const {
480 assert(_type == STRING);
481 return boost::get<std::string>(_value);
486 /// Stream operator.
487 DSOTEXPORT std::ostream& operator<<(std::ostream& os, const as_value& v);
489 /// Convert numeric value to string value, following ECMA-262 specification
491 // Printing formats:
493 // If _val > 1, Print up to 15 significant digits, then switch
494 // to scientific notation, rounding at the last place and
495 // omitting trailing zeroes.
496 // For values < 1, print up to 4 leading zeroes after the
497 // decimal point, then switch to scientific notation with up
498 // to 15 significant digits, rounding with no trailing zeroes
499 // If the value is negative, just add a '-' to the start; this
500 // does not affect the precision of the printed value.
502 // This almost corresponds to iomanip's std::setprecision(15)
503 // format, except that iomanip switches to scientific notation
504 // at e-05 not e-06, and always prints at least two digits for the exponent.
505 std::string doubleToString(double val, int radix = 10);
507 /// Try to parse a string into a 32-bit signed int using base 8 or 16. //
508 /// This function will throw a boost::bad_lexical_cast (or a derived
509 /// exception) if the passed string cannot be converted.
511 /// @param s The string to parse
512 /// @param d The 32-bit int represented as a double. This is only a
513 /// valid number if the return value is true.
514 /// @param whole If true, expect the whole string to be valid, i.e.
515 /// throw if there are any invalid DisplayObjects. If false,
516 /// returns any valid number up to the first invalid
517 /// DisplayObject.
518 /// @return True if the string was non-decimal and successfully
519 /// parsed.
520 bool parseNonDecimalInt(const std::string& s, double& d, bool whole = true);
522 /// Set a value to NaN
523 inline void
524 setNaN(as_value& v) {
525 v.set_double(NaN);
528 } // namespace gnash
530 #endif // GNASH_AS_VALUE_H
532 // Local Variables:
533 // mode: C++
534 // indent-tabs-mode: nil
535 // End: