actually set the variable here
[swfdec.git] / swfdec / swfdec_as_types.c
bloba4c644e44f1d5ca00094d86bb7136e0ccfa3d6d9
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_context.h"
29 #include "swfdec_as_function.h"
30 #include "swfdec_as_gcable.h"
31 #include "swfdec_as_internal.h"
32 #include "swfdec_as_number.h"
33 #include "swfdec_as_object.h"
34 #include "swfdec_as_stack.h"
35 #include "swfdec_as_string.h"
36 #include "swfdec_as_strings.h"
37 #include "swfdec_as_super.h"
38 #include "swfdec_debug.h"
39 #include "swfdec_internal.h"
40 #include "swfdec_movie.h"
42 /*** GTK-DOC ***/
44 /**
45 * SECTION:SwfdecAsValue
46 * @title: SwfdecAsValue
47 * @short_description: exchanging values with the Actionscript engine
49 * This section describes how values are handled inside the Actionscript
50 * engine. Since Actionscript is a dynamically typed language, the variable type
51 * has to be carried with every value. #SwfdecAsValue accomplishes that. Swfdec
52 * allows two possible ways of accessing these values: The common method is to
53 * use the provided functions to explicitly convert the values to a given type
54 * with a function such as swfdec_as_value_to_string (). This is convenient,
55 * but can be very slow as it can call back into the Actionscript engine when
56 * converting various objects. So it can be unsuitable in some cases.
57 * A different possibiltiy is accessing the values directly using the accessor
58 * macros. You must check the type before doing so though. For setting values,
59 * there only exist macros, since type conversion is not necessary.
62 /**
63 * SwfdecAsValueType:
64 * @SWFDEC_AS_TYPE_UNDEFINED: the special undefined value
65 * @SWFDEC_AS_TYPE_BOOLEAN: a boolean value - true or false
66 * @SWFDEC_AS_TYPE_INT: reserved value for integers. Should the need arise for
67 * performance enhancements - especially on embedded
68 * devices - it might be useful to implement this type.
69 * For now, this type will never appear in Swfdec. Using
70 * it will cause Swfdec to crash.
71 * @SWFDEC_AS_TYPE_NUMBER: a double value - also used for integer numbers
72 * @SWFDEC_AS_TYPE_STRING: a string. Strings are garbage-collected and unique.
73 * @SWFDEC_AS_TYPE_NULL: the spaecial null value
74 * @SWFDEC_AS_TYPE_OBJECT: an object - must be of type #SwfdecAsObject
76 * These are the possible values the Swfdec Actionscript engine knows about.
79 /**
80 * SwfdecAsValue:
81 * @type: the type of this value.
83 * This is the type used to present an opaque value in the Actionscript
84 * engine. See #SwfdecAsValueType for possible types. It's similar in
85 * spirit to #GValue. The value held is garbage-collected. Apart from the type
86 * member, use the provided macros to access this structure.
87 * <note>If you memset a SwfdecAsValue to 0, it is a valid undefined value.</note>
90 /**
91 * SWFDEC_AS_VALUE_SET_UNDEFINED:
92 * @val: value to set as undefined
94 * Sets @val to the special undefined value. If you create a temporary value,
95 * you can instead use code such as |[ SwfdecAsValue val = { 0, }; ]|
98 /**
99 * SWFDEC_AS_VALUE_GET_BOOLEAN:
100 * @val: value to get, the value must reference a boolean
102 * Gets the boolean associated with value. If you are not sure if the value is
103 * a boolean, use swfdec_as_value_to_boolean () instead.
105 * Returns: %TRUE or %FALSE
109 * SWFDEC_AS_VALUE_SET_BOOLEAN:
110 * @val: value to set
111 * @b: boolean value to set, must be either %TRUE or %FALSE
113 * Sets @val to the specified boolean value.
117 * SWFDEC_AS_VALUE_GET_NUMBER:
118 * @val: value to get, the value must reference a number
120 * Gets the number associated with @val. If you are not sure that the value is
121 * a valid number value, consider using swfdec_as_value_to_number() or
122 * swfdec_as_value_to_int() instead.
124 * Returns: a double. It can be NaN or +-Infinity, but not -0.0
128 * SWFDEC_AS_VALUE_GET_STRING:
129 * @val: value to get, the value must reference a string
131 * Gets the string associated with @val. If you are not sure that the value is
132 * a string value, consider using swfdec_as_value_to_string() instead.
134 * Returns: a garbage-collected string.
138 * SWFDEC_AS_VALUE_SET_STRING:
139 * @val: value to set
140 * @s: garbage-collected string to use
142 * Sets @val to the given string value.
146 * SWFDEC_AS_VALUE_SET_NULL:
147 * @val: value to set
149 * Sets @val to the special null value.
153 * SWFDEC_AS_VALUE_GET_OBJECT:
154 * @val: value to get, the value must reference an object
156 * Gets the object associated with @val. If you are not sure that the value is
157 * an object value, consider using swfdec_as_value_to_object() instead.
159 * Returns: a #SwfdecAsObject
163 * SWFDEC_AS_VALUE_SET_OBJECT:
164 * @val: value to set
165 * @o: garbage-collected #SwfdecAsObject to use
167 * Sets @val to the given object. The object must have been added to the
168 * garbage collector via swfdec_as_object_add() previously.
171 /*** actual code ***/
174 * swfdec_as_value_set_int:
175 * @val: value to set
176 * @i: integer value to set
178 * Sets @val to the given value. Currently this function is a macro that calls
179 * swfdec_as_value_set_number(), but this may change in future versions of
180 * Swfdec.
184 * swfdec_as_value_set_number:
185 * @context: The context to use
186 * @val: value to set
187 * @number: double value to set
189 * Sets @val to the given value. If you are sure the value is a valid
190 * integer value, use wfdec_as_value_set_int() instead.
192 void
193 swfdec_as_value_set_number (SwfdecAsContext *context, SwfdecAsValue *val,
194 double d)
196 SwfdecAsDoubleValue *dval;
198 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
199 g_return_if_fail (val != NULL);
201 dval = swfdec_as_gcable_new (context, SwfdecAsDoubleValue);
202 dval->number = d;
203 SWFDEC_AS_GCABLE_SET_NEXT (dval, context->numbers);
204 context->numbers = dval;
206 val->type = SWFDEC_AS_TYPE_NUMBER;
207 val->value.gcable = (SwfdecAsGcable *) dval;
211 * swfdec_as_str_concat:
212 * @cx: a #SwfdecAsContext
213 * @s1: first string
214 * @s2: second string
216 * Convenience function to concatenate two garbage-collected strings. This
217 * function is equivalent to g_strconcat ().
219 * Returns: A new garbage-collected string
221 const char *
222 swfdec_as_str_concat (SwfdecAsContext *cx, const char * s1, const char *s2)
224 const char *ret;
225 char *s;
227 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx), SWFDEC_AS_STR_EMPTY);
228 g_return_val_if_fail (s1, SWFDEC_AS_STR_EMPTY);
229 g_return_val_if_fail (s2, SWFDEC_AS_STR_EMPTY);
231 s = g_strconcat (s1, s2, NULL);
232 ret = swfdec_as_context_get_string (cx, s);
233 g_free (s);
235 return ret;
239 * swfdec_as_integer_to_string:
240 * @context: a #SwfdecAsContext
241 * @i: an integer that fits into 32 bits
243 * Converts @d into a string using the same conversion algorithm as the
244 * official Flash player.
246 * Returns: a garbage-collected string
248 const char *
249 swfdec_as_integer_to_string (SwfdecAsContext *context, int i)
251 return swfdec_as_context_give_string (context, g_strdup_printf ("%d", i));
255 * swfdec_as_double_to_string:
256 * @context: a #SwfdecAsContext
257 * @d: a double
259 * Converts @d into a string using the same conversion algorithm as the
260 * official Flash player.
262 * Returns: a garbage-collected string
264 /* FIXME: this function is still buggy - and it's ugly as hell.
265 * Someone with the right expertise should rewrite it
266 * Some pointers:
267 * http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
268 * http://lxr.mozilla.org/mozilla/source/js/tamarin/core/MathUtils.cpp
270 const char *
271 swfdec_as_double_to_string (SwfdecAsContext *context, double d)
273 gboolean found = FALSE, gotdot = FALSE;
274 guint digits = 15;
275 char tmp[50], *end, *start, *s;
277 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), SWFDEC_AS_STR_EMPTY);
279 if (isnan (d))
280 return SWFDEC_AS_STR_NaN;
281 if (isinf (d))
282 return d < 0 ? SWFDEC_AS_STR__Infinity : SWFDEC_AS_STR_Infinity;
283 /* stupid -0.0 */
284 if (fabs (d) == 0.0)
285 return SWFDEC_AS_STR_0;
287 tmp[0] = ' ';
288 s = &tmp[1];
289 if (ABS (d) > 0.00001 && ABS (d) < 1e+15) {
290 g_ascii_formatd (s, 50, "%.22f", d);
291 } else {
292 g_ascii_formatd (s, 50, "%.25e", d);
294 start = s;
295 /* skip - sign */
296 if (*start == '-')
297 start++;
298 /* count digits (maximum allowed is 15) */
299 while (digits) {
300 if (*start == '.') {
301 start++;
302 gotdot = TRUE;
303 continue;
305 if (*start < '0' || *start > '9')
306 break;
307 if (found || *start != '0') {
308 digits--;
309 found = TRUE;
311 start++;
313 end = start;
314 /* go to end of string */
315 while (*end != 'e' && *end != 0)
316 end++;
317 /* round using the next digit */
318 if (*start >= '5' && *start <= '9') {
319 char *finish = NULL;
320 /* skip all 9s at the end */
321 while (start[-1] == '9')
322 start--;
323 /* if we're before the dot, replace 9s with 0s */
324 if (start[-1] == '.') {
325 finish = start;
326 start--;
328 while (start[-1] == '9') {
329 start[-1] = '0';
330 start--;
332 /* write out correct number */
333 if (start[-1] == '-') {
334 s--;
335 start[-2] = '-';
336 start[-1] = '1';
337 } else if (start[-1] == ' ') {
338 s--;
339 start[-1] = '1';
340 } else {
341 start[-1]++;
343 /* reposition cursor at end */
344 if (finish)
345 start = finish;
347 /* remove trailing zeros (note we skipped zero above, so there will be non-0 bytes left) */
348 if (gotdot) {
349 while (start[-1] == '0')
350 start--;
351 if (start[-1] == '.')
352 start--;
354 /* add exponent */
355 if (*end == 'e') {
356 /* 'e' */
357 *start++ = *end++;
358 /* + or - */
359 *start++ = *end++;
360 /* skip 0s */
361 while (*end == '0')
362 end++;
363 /* add rest */
364 while (*end != 0)
365 *start++ = *end++;
367 /* end string */
368 *start = 0;
369 return swfdec_as_context_get_string (context, s);
373 * swfdec_as_value_to_string:
374 * @context: a #SwfdecAsContext
375 * @value: value to be expressed as string
377 * Converts @value to a string according to the rules of Flash. This might
378 * cause calling back into the script engine if the @value is an object. In
379 * that case, the object's valueOf function is called.
380 * <warning>Never use this function for debugging purposes.</warning>
382 * Returns: a garbage-collected string representing @value. The value will
383 * never be %NULL.
385 const char *
386 swfdec_as_value_to_string (SwfdecAsContext *context, const SwfdecAsValue *value)
388 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), SWFDEC_AS_STR_EMPTY);
389 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), SWFDEC_AS_STR_EMPTY);
391 switch (SWFDEC_AS_VALUE_GET_TYPE (value)) {
392 case SWFDEC_AS_TYPE_STRING:
393 return SWFDEC_AS_VALUE_GET_STRING (value);
394 case SWFDEC_AS_TYPE_UNDEFINED:
395 if (context->version > 6)
396 return SWFDEC_AS_STR_undefined;
397 else
398 return SWFDEC_AS_STR_EMPTY;
399 case SWFDEC_AS_TYPE_BOOLEAN:
400 return SWFDEC_AS_VALUE_GET_BOOLEAN (value) ? SWFDEC_AS_STR_true : SWFDEC_AS_STR_false;
401 case SWFDEC_AS_TYPE_NULL:
402 return SWFDEC_AS_STR_null;
403 case SWFDEC_AS_TYPE_NUMBER:
404 return swfdec_as_double_to_string (context, SWFDEC_AS_VALUE_GET_NUMBER (value));
405 case SWFDEC_AS_TYPE_OBJECT:
407 SwfdecAsObject *object = SWFDEC_AS_VALUE_GET_OBJECT (value);
408 if (SWFDEC_IS_AS_STRING (object->relay)) {
409 return SWFDEC_AS_STRING (object->relay)->string;
410 } else {
411 SwfdecAsValue ret;
412 swfdec_as_object_call (object, SWFDEC_AS_STR_toString, 0, NULL, &ret);
413 if (SWFDEC_AS_VALUE_IS_STRING (&ret))
414 return SWFDEC_AS_VALUE_GET_STRING (&ret);
415 else if (SWFDEC_IS_AS_SUPER (object->relay))
416 return SWFDEC_AS_STR__type_Object_;
417 else if (SWFDEC_IS_AS_FUNCTION (object->relay))
418 return SWFDEC_AS_STR__type_Function_;
419 else
420 return SWFDEC_AS_STR__type_Object_;
423 case SWFDEC_AS_TYPE_MOVIE:
425 SwfdecMovie *movie = SWFDEC_AS_VALUE_GET_MOVIE (value);
426 char *str;
428 if (movie == NULL)
429 return SWFDEC_AS_STR_EMPTY;
430 str = swfdec_movie_get_path (movie, TRUE);
431 return swfdec_as_context_give_string (context, str);
433 case SWFDEC_AS_TYPE_INT:
434 default:
435 g_assert_not_reached ();
436 return SWFDEC_AS_STR_EMPTY;
441 * swfdec_as_value_to_number:
442 * @context: a #SwfdecAsContext
443 * @value: a #SwfdecAsValue used by context
445 * Converts the value to a number according to Flash's conversion routines and
446 * the current Flash version. This conversion routine is similar, but not equal
447 * to ECMAScript. For objects, it can call back into the script engine by
448 * calling the object's valueOf function.
450 * Returns: a double value. It can be NaN or +-Infinity. It will not be -0.0.
452 double
453 swfdec_as_value_to_number (SwfdecAsContext *context, const SwfdecAsValue *value)
455 SwfdecAsValue tmp;
457 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), 0.0);
458 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), 0.0);
460 tmp = *value;
461 swfdec_as_value_to_primitive (&tmp);
463 switch (SWFDEC_AS_VALUE_GET_TYPE (&tmp)) {
464 case SWFDEC_AS_TYPE_UNDEFINED:
465 case SWFDEC_AS_TYPE_NULL:
466 return (context->version >= 7) ? NAN : 0.0;
467 case SWFDEC_AS_TYPE_BOOLEAN:
468 return SWFDEC_AS_VALUE_GET_BOOLEAN (&tmp) ? 1 : 0;
469 case SWFDEC_AS_TYPE_NUMBER:
470 return SWFDEC_AS_VALUE_GET_NUMBER (&tmp);
471 case SWFDEC_AS_TYPE_STRING:
473 const char *s;
474 char *end;
475 double d;
477 // FIXME: We should most likely copy Tamarin's code here (MathUtils.cpp)
478 s = SWFDEC_AS_VALUE_GET_STRING (&tmp);
479 if (s == SWFDEC_AS_STR_EMPTY)
480 return (context->version >= 5) ? NAN : 0.0;
481 if (context->version > 5 && s[0] == '0' &&
482 (s[1] == 'x' || s[1] == 'X')) {
483 d = g_ascii_strtoll (s + 2, &end, 16);
484 } else if (context->version > 5 &&
485 (s[0] == '0' || ((s[0] == '+' || s[0] == '-') && s[1] == '0')) &&
486 s[strspn (s+1, "01234567")+1] == '\0') {
487 d = g_ascii_strtoll (s, &end, 8);
488 } else {
489 if (strpbrk (s, "xXiI") != NULL)
490 return (context->version >= 5) ? NAN : 0.0;
491 d = g_ascii_strtod (s, &end);
493 if (*end == '\0' || context->version < 5)
494 return d == -0.0 ? 0.0 : d;
495 else
496 return NAN;
498 case SWFDEC_AS_TYPE_OBJECT:
499 case SWFDEC_AS_TYPE_MOVIE:
500 return (context->version >= 5) ? NAN : 0.0;
501 case SWFDEC_AS_TYPE_INT:
502 default:
503 g_assert_not_reached ();
504 return NAN;
509 * swfdec_as_double_to_integer:
510 * @d: any double
512 * Converts the given double to an integer using the same rules as the Flash
513 * player.
515 * Returns: an integer
518 swfdec_as_double_to_integer (double d)
520 if (!isfinite (d))
521 return 0;
522 if (d < 0) {
523 d = fmod (-d, 4294967296.0);
524 return - (guint) d;
525 } else {
526 d = fmod (d, 4294967296.0);
527 return (guint) d;
532 * swfdec_as_value_to_integer:
533 * @context: a #SwfdecAsContext
534 * @value: value to convert
536 * Converts the given value to an integer. This is done similar to the
537 * conversion used by swfdec_as_value_to_number().
539 * Returns: An Integer that can be represented in 32 bits.
542 swfdec_as_value_to_integer (SwfdecAsContext *context, const SwfdecAsValue *value)
544 double d;
546 d = swfdec_as_value_to_number (context, value);
547 return swfdec_as_double_to_integer (d);
551 * swfdec_as_value_to_object:
552 * @context: a #SwfdecAsContext
553 * @value: value to convert
555 * Converts a given value to its representation as an object. The object
556 * representation for primitive types is a wrapper object of the corresponding
557 * class (Number for numbers, String for strings, Boolean for bools). If the
558 * value does not have an object representing it, such as undefined and null
559 * values, %NULL is returned.
561 * Returns: object representing @value or %NULL.
563 SwfdecAsObject *
564 swfdec_as_value_to_object (SwfdecAsContext *context, const SwfdecAsValue *value)
566 SwfdecAsFunction *fun;
567 SwfdecAsValue val;
568 const char *s;
570 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
571 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), NULL);
573 switch (SWFDEC_AS_VALUE_GET_TYPE (value)) {
574 case SWFDEC_AS_TYPE_UNDEFINED:
575 case SWFDEC_AS_TYPE_NULL:
576 return NULL;
577 case SWFDEC_AS_TYPE_NUMBER:
578 s = SWFDEC_AS_STR_Number;
579 break;
580 case SWFDEC_AS_TYPE_STRING:
581 s = SWFDEC_AS_STR_String;
582 break;
583 case SWFDEC_AS_TYPE_BOOLEAN:
584 s = SWFDEC_AS_STR_Boolean;
585 break;
586 case SWFDEC_AS_TYPE_OBJECT:
587 case SWFDEC_AS_TYPE_MOVIE:
588 return SWFDEC_AS_VALUE_GET_COMPOSITE (value);
589 case SWFDEC_AS_TYPE_INT:
590 default:
591 g_assert_not_reached ();
592 return NULL;
595 swfdec_as_object_get_variable (context->global, s, &val);
596 if (!SWFDEC_AS_VALUE_IS_OBJECT (&val) ||
597 !SWFDEC_IS_AS_FUNCTION (fun = (SwfdecAsFunction *) (SWFDEC_AS_VALUE_GET_OBJECT (&val)->relay)))
598 return NULL;
599 swfdec_as_object_create (fun, 1, value, &val);
600 if (SWFDEC_AS_VALUE_IS_OBJECT (&val)) {
601 return SWFDEC_AS_VALUE_GET_OBJECT (&val);
602 } else {
603 SWFDEC_ERROR ("did not construct an object");
604 return NULL;
609 * swfdec_as_value_to_boolean:
610 * @context: a #SwfdecAsContext
611 * @value: value to convert
613 * Converts the given value to a boolean according to Flash's rules. Note that
614 * these rules changed significantly for strings between Flash 6 and 7.
616 * Returns: either %TRUE or %FALSE.
618 gboolean
619 swfdec_as_value_to_boolean (SwfdecAsContext *context, const SwfdecAsValue *value)
621 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), FALSE);
622 g_return_val_if_fail (SWFDEC_IS_AS_VALUE (value), FALSE);
624 /* FIXME: what do we do when called in flash 4? */
625 switch (SWFDEC_AS_VALUE_GET_TYPE (value)) {
626 case SWFDEC_AS_TYPE_UNDEFINED:
627 case SWFDEC_AS_TYPE_NULL:
628 return FALSE;
629 case SWFDEC_AS_TYPE_BOOLEAN:
630 return SWFDEC_AS_VALUE_GET_BOOLEAN (value);
631 case SWFDEC_AS_TYPE_NUMBER:
633 double d = SWFDEC_AS_VALUE_GET_NUMBER (value);
634 return d != 0.0 && !isnan (d);
636 case SWFDEC_AS_TYPE_STRING:
637 if (context->version <= 6) {
638 double d = swfdec_as_value_to_number (context, value);
639 return d != 0.0 && !isnan (d);
640 } else {
641 return SWFDEC_AS_VALUE_GET_STRING (value) != SWFDEC_AS_STR_EMPTY;
643 case SWFDEC_AS_TYPE_OBJECT:
644 case SWFDEC_AS_TYPE_MOVIE:
645 return TRUE;
646 case SWFDEC_AS_TYPE_INT:
647 default:
648 g_assert_not_reached ();
649 return FALSE;
654 * swfdec_as_value_to_primitive:
655 * @value: value to convert
657 * Tries to convert the given @value inline to its primitive value. Primitive
658 * values are values that are not objects. If the value is an object, the
659 * object's valueOf function is called. If the result of that function is still
660 * an object, it is returned nonetheless.
662 void
663 swfdec_as_value_to_primitive (SwfdecAsValue *value)
665 g_return_if_fail (SWFDEC_IS_AS_VALUE (value));
667 if (SWFDEC_AS_VALUE_IS_OBJECT (value)) {
668 swfdec_as_object_call (SWFDEC_AS_VALUE_GET_OBJECT (value), SWFDEC_AS_STR_valueOf,
669 0, NULL, value);
674 * swfdec_as_value_get_variable:
675 * @cx: the context
676 * @value: the value to get the variable from
677 * @name: name of the variable to get
678 * @ret: The return value to set. May be identical to the passed in @value.
680 * Gets a variable from the given @value. This function is a shortcut for
681 * converting to a #SwfdecAsObject and then calling
682 * swfdec_As_object_get_variable(). When the @value cannot be converted to an
683 * object, @ret is set to undefined.
685 void
686 swfdec_as_value_get_variable (SwfdecAsContext *cx, const SwfdecAsValue *value,
687 const char *name, SwfdecAsValue *ret)
689 SwfdecAsObject *object;
691 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (cx));
692 g_return_if_fail (value != NULL);
693 g_return_if_fail (name != NULL);
694 g_return_if_fail (ret != NULL);
696 object = swfdec_as_value_to_object (cx, value);
697 if (object == NULL) {
698 SWFDEC_AS_VALUE_SET_UNDEFINED (ret);
699 return;
701 swfdec_as_object_get_variable (object, name, ret);
704 /* from swfdec_internal.h */
705 gboolean
706 swfdec_as_value_to_twips (SwfdecAsContext *context, const SwfdecAsValue *val,
707 gboolean is_length, SwfdecTwips *result)
709 double d;
711 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), FALSE);
712 g_return_val_if_fail (val != NULL, FALSE);
713 g_return_val_if_fail (result != NULL, FALSE);
715 if (SWFDEC_AS_VALUE_IS_UNDEFINED (val) || SWFDEC_AS_VALUE_IS_NULL (val))
716 return FALSE;
718 d = swfdec_as_value_to_number (context, val);
719 if (isnan (d))
720 return FALSE;
721 if (is_length && d < 0)
722 return FALSE;
724 d *= SWFDEC_TWIPS_SCALE_FACTOR;
725 *result = swfdec_as_double_to_integer (d);
726 if (is_length)
727 *result = ABS (*result);
728 return TRUE;