oops, I shifted the wrong value.
[swfdec.git] / swfdec / swfdec_as_types.c
blobd609d62ed1c4b8c2d2f210fbaaa32542ef05c4ac
1 /* Swfdec
2 * Copyright (C) 2007-2008 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <math.h>
25 #include <string.h>
27 #include "swfdec_as_types.h"
28 #include "swfdec_as_object.h"
29 #include "swfdec_as_context.h"
30 #include "swfdec_as_function.h"
31 #include "swfdec_as_number.h"
32 #include "swfdec_as_stack.h"
33 #include "swfdec_as_string.h"
34 #include "swfdec_as_strings.h"
35 #include "swfdec_as_super.h"
36 #include "swfdec_debug.h"
37 #include "swfdec_internal.h"
38 #include "swfdec_movie.h"
40 /*** GTK-DOC ***/
42 /**
43 * SECTION:SwfdecAsValue
44 * @title: SwfdecAsValue
45 * @short_description: exchanging values with the Actionscript engine
47 * This section describes how values are handled inside the Actionscript
48 * engine. Since Actionscript is a dynamically typed language, the variable type
49 * has to be carried with every value. #SwfdecAsValue accomplishes that. Swfdec
50 * allows two possible ways of accessing these values: The common method is to
51 * use the provided functions to explicitly convert the values to a given type
52 * with a function such as swfdec_as_value_to_string (). This is convenient,
53 * but can be very slow as it can call back into the Actionscript engine when
54 * converting various objects. So it can be unsuitable in some cases.
55 * A different possibiltiy is accessing the values directly using the accessor
56 * macros. You must check the type before doing so though. For setting values,
57 * there only exist macros, since type conversion is not necessary.
60 /**
61 * SwfdecAsValueType:
62 * @SWFDEC_AS_TYPE_UNDEFINED: the special undefined value
63 * @SWFDEC_AS_TYPE_BOOLEAN: a boolean value - true or false
64 * @SWFDEC_AS_TYPE_INT: reserved value for integers. Should the need arise for
65 * performance enhancements - especially on embedded
66 * devices - it might be useful to implement this type.
67 * For now, this type will never appear in Swfdec. Using
68 * it will cause Swfdec to crash.
69 * @SWFDEC_AS_TYPE_NUMBER: a double value - also used for integer numbers
70 * @SWFDEC_AS_TYPE_STRING: a string. Strings are garbage-collected and unique.
71 * @SWFDEC_AS_TYPE_NULL: the spaecial null value
72 * @SWFDEC_AS_TYPE_OBJECT: an object - must be of type #SwfdecAsObject
74 * These are the possible values the Swfdec Actionscript engine knows about.
77 /**
78 * SwfdecAsValue:
79 * @type: the type of this value.
81 * This is the type used to present an opaque value in the Actionscript
82 * engine. See #SwfdecAsValueType for possible types. It's similar in
83 * spirit to #GValue. The value held is garbage-collected. Apart from the type
84 * member, use the provided macros to access this structure.
85 * <note>If you memset a SwfdecAsValue to 0, it is a valid undefined value.</note>
88 /**
89 * SWFDEC_AS_VALUE_SET_UNDEFINED:
90 * @val: value to set as undefined
92 * Sets @val to the special undefined value. If you create a temporary value,
93 * you can instead use code such as |[ SwfdecAsValue val = { 0, }; ]|
96 /**
97 * SWFDEC_AS_VALUE_GET_BOOLEAN:
98 * @val: value to get, the value must reference a boolean
100 * Gets the boolean associated with value. If you are not sure if the value is
101 * a boolean, use swfdec_as_value_to_boolean () instead.
103 * Returns: %TRUE or %FALSE
107 * SWFDEC_AS_VALUE_SET_BOOLEAN:
108 * @val: value to set
109 * @b: boolean value to set, must be either %TRUE or %FALSE
111 * Sets @val to the specified boolean value.
115 * SWFDEC_AS_VALUE_GET_NUMBER:
116 * @val: value to get, the value must reference a number
118 * Gets the number associated with @val. If you are not sure that the value is
119 * a valid number value, consider using swfdec_as_value_to_number() or
120 * swfdec_as_value_to_int() instead.
122 * Returns: a double. It can be NaN or +-Infinity, but not -0.0
126 * SWFDEC_AS_VALUE_SET_NUMBER:
127 * @val: value to set
128 * @d: double value to set
130 * Sets @val to the given value. If you are sure the value is a valid
131 * integer value, use SWFDEC_AS_VALUE_SET_INT() instead.
135 * SWFDEC_AS_VALUE_SET_INT:
136 * @val: value to set
137 * @d: integer value to set
139 * Sets @val to the given value. Currently this macro is equivalent to
140 * SWFDEC_AS_VALUE_SET_NUMBER(), but this may change in future versions of
141 * Swfdec.
145 * SWFDEC_AS_VALUE_GET_STRING:
146 * @val: value to get, the value must reference a string
148 * Gets the string associated with @val. If you are not sure that the value is
149 * a string value, consider using swfdec_as_value_to_string() instead.
151 * Returns: a garbage-collected string.
155 * SWFDEC_AS_VALUE_SET_STRING:
156 * @val: value to set
157 * @s: garbage-collected string to use
159 * Sets @val to the given string value.
163 * SWFDEC_AS_VALUE_SET_NULL:
164 * @val: value to set
166 * Sets @val to the special null value.
170 * SWFDEC_AS_VALUE_GET_OBJECT:
171 * @val: value to get, the value must reference an object
173 * Gets the object associated with @val. If you are not sure that the value is
174 * an object value, consider using swfdec_as_value_to_object() instead.
176 * Returns: a #SwfdecAsObject
180 * SWFDEC_AS_VALUE_SET_OBJECT:
181 * @val: value to set
182 * @o: garbage-collected #SwfdecAsObject to use
184 * Sets @val to the given object. The object must have been added to the
185 * garbage collector via swfdec_as_object_add() previously.
188 /*** actual code ***/
191 * swfdec_as_str_concat:
192 * @cx: a #SwfdecAsContext
193 * @s1: first string
194 * @s2: second string
196 * Convenience function to concatenate two garbage-collected strings. This
197 * function is equivalent to g_strconcat ().
199 * Returns: A new garbage-collected string
201 const char *
202 swfdec_as_str_concat (SwfdecAsContext *cx, const char * s1, const char *s2)
204 const char *ret;
205 char *s;
207 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx), SWFDEC_AS_STR_EMPTY);
208 g_return_val_if_fail (s1, SWFDEC_AS_STR_EMPTY);
209 g_return_val_if_fail (s2, SWFDEC_AS_STR_EMPTY);
211 s = g_strconcat (s1, s2, NULL);
212 ret = swfdec_as_context_get_string (cx, s);
213 g_free (s);
215 return ret;
219 * swfdec_as_integer_to_string:
220 * @context: a #SwfdecAsContext
221 * @i: an integer that fits into 32 bits
223 * Converts @d into a string using the same conversion algorithm as the
224 * official Flash player.
226 * Returns: a garbage-collected string
228 const char *
229 swfdec_as_integer_to_string (SwfdecAsContext *context, int i)
231 return swfdec_as_context_give_string (context, g_strdup_printf ("%d", i));
235 * swfdec_as_double_to_string:
236 * @context: a #SwfdecAsContext
237 * @d: a double
239 * Converts @d into a string using the same conversion algorithm as the
240 * official Flash player.
242 * Returns: a garbage-collected string
244 /* FIXME: this function is still buggy - and it's ugly as hell.
245 * Someone with the right expertise should rewrite it
246 * Some pointers:
247 * http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
248 * http://lxr.mozilla.org/mozilla/source/js/tamarin/core/MathUtils.cpp
250 const char *
251 swfdec_as_double_to_string (SwfdecAsContext *context, double d)
253 gboolean found = FALSE, gotdot = FALSE;
254 guint digits = 15;
255 char tmp[50], *end, *start, *s;
257 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), SWFDEC_AS_STR_EMPTY);
259 if (isnan (d))
260 return SWFDEC_AS_STR_NaN;
261 if (isinf (d))
262 return d < 0 ? SWFDEC_AS_STR__Infinity : SWFDEC_AS_STR_Infinity;
263 /* stupid -0.0 */
264 if (fabs (d) == 0.0)
265 return SWFDEC_AS_STR_0;
267 tmp[0] = ' ';
268 s = &tmp[1];
269 if (ABS (d) > 0.00001 && ABS (d) < 1e+15) {
270 g_ascii_formatd (s, 50, "%.22f", d);
271 } else {
272 g_ascii_formatd (s, 50, "%.25e", d);
274 start = s;
275 /* skip - sign */
276 if (*start == '-')
277 start++;
278 /* count digits (maximum allowed is 15) */
279 while (digits) {
280 if (*start == '.') {
281 start++;
282 gotdot = TRUE;
283 continue;
285 if (*start < '0' || *start > '9')
286 break;
287 if (found || *start != '0') {
288 digits--;
289 found = TRUE;
291 start++;
293 end = start;
294 /* go to end of string */
295 while (*end != 'e' && *end != 0)
296 end++;
297 /* round using the next digit */
298 if (*start >= '5' && *start <= '9') {
299 char *finish = NULL;
300 /* skip all 9s at the end */
301 while (start[-1] == '9')
302 start--;
303 /* if we're before the dot, replace 9s with 0s */
304 if (start[-1] == '.') {
305 finish = start;
306 start--;
308 while (start[-1] == '9') {
309 start[-1] = '0';
310 start--;
312 /* write out correct number */
313 if (start[-1] == '-') {
314 s--;
315 start[-2] = '-';
316 start[-1] = '1';
317 } else if (start[-1] == ' ') {
318 s--;
319 start[-1] = '1';
320 } else {
321 start[-1]++;
323 /* reposition cursor at end */
324 if (finish)
325 start = finish;
327 /* remove trailing zeros (note we skipped zero above, so there will be non-0 bytes left) */
328 if (gotdot) {
329 while (start[-1] == '0')
330 start--;
331 if (start[-1] == '.')
332 start--;
334 /* add exponent */
335 if (*end == 'e') {
336 /* 'e' */
337 *start++ = *end++;
338 /* + or - */
339 *start++ = *end++;
340 /* skip 0s */
341 while (*end == '0')
342 end++;
343 /* add rest */
344 while (*end != 0)
345 *start++ = *end++;
347 /* end string */
348 *start = 0;
349 return swfdec_as_context_get_string (context, s);
353 * swfdec_as_value_to_string:
354 * @context: a #SwfdecAsContext
355 * @value: value to be expressed as string
357 * Converts @value to a string according to the rules of Flash. This might
358 * cause calling back into the script engine if the @value is an object. In
359 * that case, the object's valueOf function is called.
360 * <warning>Never use this function for debugging purposes.</warning>
362 * Returns: a garbage-collected string representing @value. The value will
363 * never be %NULL.
365 const char *
366 swfdec_as_value_to_string (SwfdecAsContext *context, const SwfdecAsValue *value)
368 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), SWFDEC_AS_STR_EMPTY);
369 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), SWFDEC_AS_STR_EMPTY);
371 switch (value->type) {
372 case SWFDEC_AS_TYPE_STRING:
373 return SWFDEC_AS_VALUE_GET_STRING (value);
374 case SWFDEC_AS_TYPE_UNDEFINED:
375 if (context->version > 6)
376 return SWFDEC_AS_STR_undefined;
377 else
378 return SWFDEC_AS_STR_EMPTY;
379 case SWFDEC_AS_TYPE_BOOLEAN:
380 return SWFDEC_AS_VALUE_GET_BOOLEAN (value) ? SWFDEC_AS_STR_true : SWFDEC_AS_STR_false;
381 case SWFDEC_AS_TYPE_NULL:
382 return SWFDEC_AS_STR_null;
383 case SWFDEC_AS_TYPE_NUMBER:
384 return swfdec_as_double_to_string (context, SWFDEC_AS_VALUE_GET_NUMBER (value));
385 case SWFDEC_AS_TYPE_OBJECT:
387 SwfdecAsObject *object = SWFDEC_AS_VALUE_GET_OBJECT (value);
388 if (SWFDEC_IS_MOVIE (object)) {
389 SwfdecMovie *movie = swfdec_movie_resolve (SWFDEC_MOVIE (object));
390 if (movie == NULL) {
391 return SWFDEC_AS_STR_EMPTY;
392 } else {
393 char *str = swfdec_movie_get_path (SWFDEC_MOVIE (object), TRUE);
394 return swfdec_as_context_give_string (context, str);
396 } else if (SWFDEC_IS_AS_STRING (object)) {
397 return SWFDEC_AS_STRING (object)->string;
398 } else {
399 SwfdecAsValue ret;
400 swfdec_as_object_call (object, SWFDEC_AS_STR_toString, 0, NULL, &ret);
401 if (SWFDEC_AS_VALUE_IS_STRING (&ret))
402 return SWFDEC_AS_VALUE_GET_STRING (&ret);
403 else if (SWFDEC_IS_AS_SUPER (SWFDEC_AS_VALUE_GET_OBJECT (value)))
404 return SWFDEC_AS_STR__type_Object_;
405 else if (SWFDEC_IS_AS_FUNCTION (SWFDEC_AS_VALUE_GET_OBJECT (value)))
406 return SWFDEC_AS_STR__type_Function_;
407 else
408 return SWFDEC_AS_STR__type_Object_;
411 case SWFDEC_AS_TYPE_INT:
412 default:
413 g_assert_not_reached ();
414 return SWFDEC_AS_STR_EMPTY;
419 * swfdec_as_value_to_debug:
420 * @value: a #SwfdecAsValue
422 * Converts the given @value to a string in a safe way. It will not call into
423 * the scripting engine. Its intended use is for output in debuggers.
425 * Returns: a newly allocated string. Free with g_free().
427 char *
428 swfdec_as_value_to_debug (const SwfdecAsValue *value)
430 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), NULL);
432 switch (value->type) {
433 case SWFDEC_AS_TYPE_STRING:
434 return g_shell_quote (SWFDEC_AS_VALUE_GET_STRING (value));
435 case SWFDEC_AS_TYPE_UNDEFINED:
436 return g_strdup ("undefined");
437 case SWFDEC_AS_TYPE_BOOLEAN:
438 return g_strdup (SWFDEC_AS_VALUE_GET_BOOLEAN (value) ? "true" : "false");
439 case SWFDEC_AS_TYPE_NULL:
440 return g_strdup ("null");
441 case SWFDEC_AS_TYPE_NUMBER:
442 return g_strdup_printf ("%g", SWFDEC_AS_VALUE_GET_NUMBER (value));
443 case SWFDEC_AS_TYPE_OBJECT:
444 return swfdec_as_object_get_debug (SWFDEC_AS_VALUE_GET_OBJECT (value));
445 case SWFDEC_AS_TYPE_INT:
446 default:
447 g_assert_not_reached ();
448 return NULL;
453 * swfdec_as_value_to_number:
454 * @context: a #SwfdecAsContext
455 * @value: a #SwfdecAsValue used by context
457 * Converts the value to a number according to Flash's conversion routines and
458 * the current Flash version. This conversion routine is similar, but not equal
459 * to ECMAScript. For objects, it can call back into the script engine by
460 * calling the object's valueOf function.
462 * Returns: a double value. It can be NaN or +-Infinity. It will not be -0.0.
464 double
465 swfdec_as_value_to_number (SwfdecAsContext *context, const SwfdecAsValue *value)
467 SwfdecAsValue tmp;
469 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), 0.0);
470 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), 0.0);
472 tmp = *value;
473 swfdec_as_value_to_primitive (&tmp);
475 switch (tmp.type) {
476 case SWFDEC_AS_TYPE_UNDEFINED:
477 case SWFDEC_AS_TYPE_NULL:
478 return (context->version >= 7) ? NAN : 0.0;
479 case SWFDEC_AS_TYPE_BOOLEAN:
480 return SWFDEC_AS_VALUE_GET_BOOLEAN (&tmp) ? 1 : 0;
481 case SWFDEC_AS_TYPE_NUMBER:
482 return SWFDEC_AS_VALUE_GET_NUMBER (&tmp);
483 case SWFDEC_AS_TYPE_STRING:
485 const char *s;
486 char *end;
487 double d;
489 // FIXME: We should most likely copy Tamarin's code here (MathUtils.cpp)
490 s = SWFDEC_AS_VALUE_GET_STRING (&tmp);
491 if (s == SWFDEC_AS_STR_EMPTY)
492 return (context->version >= 5) ? NAN : 0.0;
493 if (context->version > 5 && s[0] == '0' &&
494 (s[1] == 'x' || s[1] == 'X')) {
495 d = g_ascii_strtoll (s + 2, &end, 16);
496 } else if (context->version > 5 &&
497 (s[0] == '0' || ((s[0] == '+' || s[0] == '-') && s[1] == '0')) &&
498 s[strspn (s+1, "01234567")+1] == '\0') {
499 d = g_ascii_strtoll (s, &end, 8);
500 } else {
501 if (strpbrk (s, "xXiI") != NULL)
502 return (context->version >= 5) ? NAN : 0.0;
503 d = g_ascii_strtod (s, &end);
505 if (*end == '\0' || context->version < 5)
506 return d == -0.0 ? 0.0 : d;
507 else
508 return NAN;
510 case SWFDEC_AS_TYPE_OBJECT:
511 return (context->version >= 5) ? NAN : 0.0;
512 case SWFDEC_AS_TYPE_INT:
513 default:
514 g_assert_not_reached ();
515 return NAN;
520 * swfdec_as_double_to_integer:
521 * @d: any double
523 * Converts the given double to an integer using the same rules as the Flash
524 * player.
526 * Returns: an integer
529 swfdec_as_double_to_integer (double d)
531 if (!isfinite (d))
532 return 0;
533 if (d < 0) {
534 d = fmod (-d, 4294967296.0);
535 return - (guint) d;
536 } else {
537 d = fmod (d, 4294967296.0);
538 return (guint) d;
543 * swfdec_as_value_to_integer:
544 * @context: a #SwfdecAsContext
545 * @value: value to convert
547 * Converts the given value to an integer. This is done similar to the
548 * conversion used by swfdec_as_value_to_number().
550 * Returns: An Integer that can be represented in 32 bits.
553 swfdec_as_value_to_integer (SwfdecAsContext *context, const SwfdecAsValue *value)
555 double d;
557 d = swfdec_as_value_to_number (context, value);
558 return swfdec_as_double_to_integer (d);
562 * swfdec_as_value_to_object:
563 * @context: a #SwfdecAsContext
564 * @value: value to convert
566 * Converts a given value to its representation as an object. The object
567 * representation for primitive types is a wrapper object of the corresponding
568 * class (Number for numbers, String for strings, Boolean for bools). If the
569 * value does not have an object representing it, such as undefined and null
570 * values, %NULL is returned.
572 * Returns: object representing @value or %NULL.
574 SwfdecAsObject *
575 swfdec_as_value_to_object (SwfdecAsContext *context, const SwfdecAsValue *value)
577 SwfdecAsFunction *fun;
578 SwfdecAsValue val;
579 const char *s;
581 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
582 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), NULL);
584 switch (value->type) {
585 case SWFDEC_AS_TYPE_UNDEFINED:
586 case SWFDEC_AS_TYPE_NULL:
587 return NULL;
588 case SWFDEC_AS_TYPE_NUMBER:
589 s = SWFDEC_AS_STR_Number;
590 break;
591 case SWFDEC_AS_TYPE_STRING:
592 s = SWFDEC_AS_STR_String;
593 break;
594 case SWFDEC_AS_TYPE_BOOLEAN:
595 s = SWFDEC_AS_STR_Boolean;
596 break;
597 case SWFDEC_AS_TYPE_OBJECT:
598 return SWFDEC_AS_VALUE_GET_OBJECT (value);
599 case SWFDEC_AS_TYPE_INT:
600 default:
601 g_assert_not_reached ();
602 return NULL;
605 swfdec_as_object_get_variable (context->global, s, &val);
606 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val) ||
607 !SWFDEC_IS_AS_FUNCTION (fun = (SwfdecAsFunction *) SWFDEC_AS_VALUE_GET_OBJECT (&val)))
608 return NULL;
609 swfdec_as_object_create (fun, 1, value, &val);
610 if (SWFDEC_AS_VALUE_IS_OBJECT (&val)) {
611 return SWFDEC_AS_VALUE_GET_OBJECT (&val);
612 } else {
613 SWFDEC_ERROR ("did not construct an object");
614 return NULL;
619 * swfdec_as_value_to_boolean:
620 * @context: a #SwfdecAsContext
621 * @value: value to convert
623 * Converts the given value to a boolean according to Flash's rules. Note that
624 * these rules changed significantly for strings between Flash 6 and 7.
626 * Returns: either %TRUE or %FALSE.
628 gboolean
629 swfdec_as_value_to_boolean (SwfdecAsContext *context, const SwfdecAsValue *value)
631 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), FALSE);
632 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), FALSE);
634 /* FIXME: what do we do when called in flash 4? */
635 switch (value->type) {
636 case SWFDEC_AS_TYPE_UNDEFINED:
637 case SWFDEC_AS_TYPE_NULL:
638 return FALSE;
639 case SWFDEC_AS_TYPE_BOOLEAN:
640 return SWFDEC_AS_VALUE_GET_BOOLEAN (value);
641 case SWFDEC_AS_TYPE_NUMBER:
643 double d = SWFDEC_AS_VALUE_GET_NUMBER (value);
644 return d != 0.0 && !isnan (d);
646 case SWFDEC_AS_TYPE_STRING:
647 if (context->version <= 6) {
648 double d = swfdec_as_value_to_number (context, value);
649 return d != 0.0 && !isnan (d);
650 } else {
651 return SWFDEC_AS_VALUE_GET_STRING (value) != SWFDEC_AS_STR_EMPTY;
653 case SWFDEC_AS_TYPE_OBJECT:
654 return TRUE;
655 case SWFDEC_AS_TYPE_INT:
656 default:
657 g_assert_not_reached ();
658 return FALSE;
663 * swfdec_as_value_to_primitive:
664 * @value: value to convert
666 * Tries to convert the given @value inline to its primitive value. Primitive
667 * values are values that are not objects. If the value is an object, the
668 * object's valueOf function is called. If the result of that function is still
669 * an object, it is returned nonetheless.
671 void
672 swfdec_as_value_to_primitive (SwfdecAsValue *value)
674 g_return_if_fail (SWFDEC_IS_AS_VALUE (value));
676 if (SWFDEC_AS_VALUE_IS_OBJECT (value) && !SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (value))) {
677 swfdec_as_object_call (SWFDEC_AS_VALUE_GET_OBJECT (value), SWFDEC_AS_STR_valueOf,
678 0, NULL, value);
682 /* from swfdec_internal.h */
683 gboolean
684 swfdec_as_value_to_twips (SwfdecAsContext *context, const SwfdecAsValue *val,
685 gboolean is_length, SwfdecTwips *result)
687 double d;
689 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), FALSE);
690 g_return_val_if_fail (val != NULL, FALSE);
691 g_return_val_if_fail (result != NULL, FALSE);
693 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val) || SWFDEC_AS_VALUE_IS_NULL (val))
694 return FALSE;
696 d = swfdec_as_value_to_number (context, val);
697 if (isnan (d))
698 return FALSE;
699 if (is_length && d < 0)
700 return FALSE;
702 d *= SWFDEC_TWIPS_SCALE_FACTOR;
703 *result = swfdec_as_double_to_integer (d);
704 if (is_length)
705 *result = ABS (*result);
706 return TRUE;