make SwfdecAsValue pointer-sized
[swfdec.git] / swfdec / swfdec_resource.c
blob3670a5bf15d1b4f952f771afc39f642f846af496
1 /* Swfdec
2 * Copyright (C) 2006-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 <errno.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "swfdec_resource.h"
28 #include "swfdec_access.h"
29 #include "swfdec_as_object.h"
30 #include "swfdec_as_internal.h"
31 #include "swfdec_as_interpret.h"
32 #include "swfdec_as_strings.h"
33 #include "swfdec_character.h"
34 #include "swfdec_debug.h"
35 #include "swfdec_decoder.h"
36 #include "swfdec_image_decoder.h"
37 #include "swfdec_loader_internal.h"
38 #include "swfdec_movie_clip_loader.h"
39 #include "swfdec_player_internal.h"
40 #include "swfdec_sandbox.h"
41 #include "swfdec_script.h"
42 #include "swfdec_sprite.h"
43 #include "swfdec_stream_target.h"
44 #include "swfdec_swf_decoder.h"
45 #include "swfdec_utils.h"
48 static void swfdec_resource_stream_target_init (SwfdecStreamTargetInterface *iface);
49 G_DEFINE_TYPE_WITH_CODE (SwfdecResource, swfdec_resource, SWFDEC_TYPE_GC_OBJECT,
50 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_STREAM_TARGET, swfdec_resource_stream_target_init))
52 /*** SWFDEC_STREAM_TARGET interface ***/
54 static gboolean
55 swfdec_resource_is_root (SwfdecResource *resource)
57 g_return_val_if_fail (SWFDEC_IS_RESOURCE (resource), FALSE);
59 return
60 resource == SWFDEC_MOVIE (SWFDEC_PLAYER (swfdec_gc_object_get_context (resource))->priv->roots->data)->resource;
63 static SwfdecPlayer *
64 swfdec_resource_stream_target_get_player (SwfdecStreamTarget *target)
66 return SWFDEC_PLAYER (swfdec_gc_object_get_context (target));
69 static void
70 swfdec_resource_stream_target_image (SwfdecResource *instance)
72 SwfdecPlayer *player = SWFDEC_PLAYER (swfdec_gc_object_get_context (instance));
73 SwfdecSpriteMovie *movie = (SwfdecSpriteMovie *) SWFDEC_AS_VALUE_GET_MOVIE (&instance->movie);
75 if (!SWFDEC_IS_SPRITE_MOVIE (movie) || movie->sprite != NULL)
76 return;
78 if (SWFDEC_IS_SWF_DECODER (instance->decoder)) {
79 SwfdecSwfDecoder *dec = SWFDEC_SWF_DECODER (instance->decoder);
80 SwfdecSandbox *old_sandbox;
82 old_sandbox = instance->sandbox;
83 instance->sandbox = swfdec_sandbox_get_for_url (player,
84 swfdec_loader_get_url (instance->loader), instance->version,
85 SWFDEC_SWF_DECODER (instance->decoder)->use_network);
86 if (instance->sandbox) {
87 movie->sprite = dec->main_sprite;
88 g_assert (movie->sprite->parse_frame > 0);
89 movie->n_frames = movie->sprite->n_frames;
90 swfdec_movie_invalidate_last (SWFDEC_MOVIE (movie));
91 swfdec_sandbox_use (instance->sandbox);
92 swfdec_as_object_set_constructor_by_name (swfdec_as_relay_get_as_object (
93 SWFDEC_AS_RELAY (movie)), SWFDEC_AS_STR_MovieClip, NULL);
94 swfdec_sandbox_unuse (instance->sandbox);
95 if (swfdec_resource_is_root (instance)) {
96 swfdec_player_start_ticking (player);
97 swfdec_movie_initialize (SWFDEC_MOVIE (movie));
98 swfdec_player_perform_actions (player);
100 } else {
101 SWFDEC_FIXME ("cannot continue loading %s, invalid rights",
102 swfdec_url_get_url (swfdec_loader_get_url (instance->loader)));
103 swfdec_stream_set_target (SWFDEC_STREAM (instance->loader), NULL);
104 instance->sandbox = old_sandbox;
105 /* FIXME: anyting else on the movie we need to clear? */
107 } else {
108 g_assert_not_reached ();
112 /* NB: name must be GC'ed */
113 static void
114 swfdec_resource_emit_signal (SwfdecResource *resource, const char *name, gboolean progress,
115 SwfdecAsValue *args, guint n_args)
117 SwfdecAsContext *cx;
118 SwfdecMovie *movie;
119 guint skip = progress ? 4 : 2;
120 SwfdecAsValue vals[n_args + skip];
122 if (resource->clip_loader == NULL)
123 return;
124 cx = swfdec_gc_object_get_context (resource->clip_loader);
126 SWFDEC_AS_VALUE_SET_STRING (&vals[0], name);
127 if (SWFDEC_AS_VALUE_IS_MOVIE (&resource->movie)) {
128 movie = SWFDEC_AS_VALUE_GET_MOVIE (&resource->movie);
129 if (movie == NULL) {
130 SWFDEC_DEBUG ("no movie, not emitting signal");
131 return;
133 if (name == SWFDEC_AS_STR_onLoadInit &&
134 movie->as_value != SWFDEC_AS_VALUE_GET_VALUE (&resource->movie)) {
135 SWFDEC_INFO ("not emitting onLoadInit - the movie is different");
136 return;
138 SWFDEC_AS_VALUE_SET_MOVIE (&vals[1], movie);
139 } else {
140 SWFDEC_AS_VALUE_SET_UNDEFINED (&vals[1]);
141 movie = NULL;
143 if (progress) {
144 SwfdecResource *res;
146 if (SWFDEC_IS_MOVIE (movie))
147 res = swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie));
148 else
149 res = NULL;
150 if (res && res->decoder) {
151 SwfdecDecoder *dec = res->decoder;
152 swfdec_as_value_set_integer (cx, &vals[2], dec->bytes_loaded);
153 swfdec_as_value_set_integer (cx, &vals[3], dec->bytes_total);
154 } else {
155 swfdec_as_value_set_integer (cx, &vals[2], 0);
156 swfdec_as_value_set_integer (cx, &vals[3], 0);
159 if (n_args)
160 memcpy (&vals[skip], args, sizeof (SwfdecAsValue) * n_args);
161 /* FIXME: what's the correct sandbox here? */
162 swfdec_sandbox_use (resource->clip_loader_sandbox);
163 swfdec_as_relay_call (SWFDEC_AS_RELAY (resource->clip_loader), SWFDEC_AS_STR_broadcastMessage,
164 n_args + skip, vals, NULL);
165 swfdec_sandbox_unuse (resource->clip_loader_sandbox);
168 static void
169 swfdec_resource_emit_error (SwfdecResource *resource, const char *message)
171 SwfdecAsValue vals[2];
173 SWFDEC_AS_VALUE_SET_STRING (&vals[0], message);
174 swfdec_as_value_set_integer (swfdec_gc_object_get_context (resource), &vals[1], 0);
176 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadError, FALSE, vals, 2);
179 static SwfdecSpriteMovie *
180 swfdec_resource_replace_movie (SwfdecSpriteMovie *movie, SwfdecResource *resource)
182 /* can't use swfdec_movie_duplicate() here, we copy to same depth */
183 SwfdecMovie *mov = SWFDEC_MOVIE (movie);
184 SwfdecMovie *copy;
186 copy = swfdec_movie_new (SWFDEC_PLAYER (swfdec_gc_object_get_context (movie)),
187 mov->depth, mov->parent, resource, NULL, mov->name);
188 if (copy == NULL)
189 return FALSE;
190 swfdec_movie_begin_update_matrix (copy);
191 copy->matrix = mov->matrix;
192 copy->modified = mov->modified;
193 copy->xscale = mov->xscale;
194 copy->yscale = mov->yscale;
195 copy->rotation = mov->rotation;
196 copy->lockroot = mov->lockroot;
197 swfdec_movie_end_update_matrix (copy);
198 /* FIXME: are events copied? If so, wouldn't that be a security issue? */
199 swfdec_movie_set_static_properties (copy, &mov->original_transform,
200 &mov->color_transform, mov->original_ratio, mov->clip_depth,
201 mov->blend_mode, NULL);
202 swfdec_movie_remove (mov);
203 return SWFDEC_SPRITE_MOVIE (copy);
206 static void
207 swfdec_resource_stream_target_open (SwfdecStreamTarget *target, SwfdecStream *stream)
209 SwfdecLoader *loader = SWFDEC_LOADER (stream);
210 SwfdecResource *instance = SWFDEC_RESOURCE (target);
211 SwfdecAsObject *object;
212 SwfdecMovie *movie;
213 const char *query;
215 g_assert (SWFDEC_AS_VALUE_IS_MOVIE (&instance->movie));
216 movie = SWFDEC_AS_VALUE_GET_MOVIE (&instance->movie);
217 g_assert (movie);
218 object = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (movie));
219 query = swfdec_url_get_query (swfdec_loader_get_url (loader));
220 if (query) {
221 SWFDEC_INFO ("set url query movie variables: %s", query);
222 swfdec_as_object_decode (object, query);
224 if (instance->variables) {
225 SWFDEC_INFO ("set manual movie variables: %s", instance->variables);
226 swfdec_as_object_decode (object, instance->variables);
228 swfdec_resource_emit_signal (instance, SWFDEC_AS_STR_onLoadStart, FALSE, NULL, 0);
229 instance->state = SWFDEC_RESOURCE_OPENED;
232 static gboolean
233 swfdec_resource_stream_target_parse (SwfdecStreamTarget *target, SwfdecStream *stream)
235 SwfdecLoader *loader = SWFDEC_LOADER (stream);
236 SwfdecResource *resource = SWFDEC_RESOURCE (target);
237 SwfdecBufferQueue *queue;
238 SwfdecBuffer *buffer;
239 SwfdecDecoder *dec = resource->decoder;
240 SwfdecStatus status;
241 guint parsed;
243 queue = swfdec_stream_get_queue (stream);
244 if (dec == NULL && swfdec_buffer_queue_get_offset (queue) == 0) {
245 if (swfdec_buffer_queue_get_depth (queue) < SWFDEC_DECODER_DETECT_LENGTH)
246 return FALSE;
247 buffer = swfdec_buffer_queue_peek (queue, 4);
248 dec = swfdec_decoder_new (buffer);
249 swfdec_buffer_unref (buffer);
250 if (dec == NULL) {
251 SWFDEC_ERROR ("no decoder found for format");
252 } else {
253 glong total;
254 resource->decoder = dec;
255 g_signal_connect_swapped (dec, "missing-plugin",
256 G_CALLBACK (swfdec_player_add_missing_plugin), swfdec_gc_object_get_context (resource));
257 total = swfdec_loader_get_size (loader);
258 if (total >= 0)
259 dec->bytes_total = total;
262 while (swfdec_buffer_queue_get_depth (queue)) {
263 parsed = 0;
264 status = 0;
265 do {
266 buffer = swfdec_buffer_queue_peek_buffer (queue);
267 if (buffer == NULL)
268 break;
269 if (parsed + buffer->length <= 65536) {
270 swfdec_buffer_unref (buffer);
271 buffer = swfdec_buffer_queue_pull_buffer (queue);
272 } else {
273 swfdec_buffer_unref (buffer);
274 buffer = swfdec_buffer_queue_pull (queue, 65536 - parsed);
276 parsed += buffer->length;
277 if (dec) {
278 status |= swfdec_decoder_parse (dec, buffer);
279 } else {
280 swfdec_buffer_unref (buffer);
282 } while (parsed < 65536 && (status & (SWFDEC_STATUS_ERROR | SWFDEC_STATUS_EOF)) == 0);
283 if (status & SWFDEC_STATUS_ERROR) {
284 SWFDEC_ERROR ("parsing error");
285 swfdec_stream_set_target (SWFDEC_STREAM (loader), NULL);
286 return FALSE;
288 if ((status & SWFDEC_STATUS_INIT)) {
289 if (SWFDEC_IS_SWF_DECODER (dec))
290 resource->version = SWFDEC_SWF_DECODER (dec)->version;
291 if (swfdec_resource_is_root (resource)) {
292 swfdec_player_initialize (SWFDEC_PLAYER (swfdec_gc_object_get_context (resource)),
293 dec->rate, dec->width, dec->height);
296 if (status & SWFDEC_STATUS_IMAGE)
297 swfdec_resource_stream_target_image (resource);
298 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadProgress, TRUE, NULL, 0);
299 if (status & SWFDEC_STATUS_EOF)
300 return FALSE;
302 return FALSE;
305 static gboolean
306 swfdec_resource_abort_if_not_initialized (SwfdecResource *resource)
308 if (resource->sandbox)
309 return FALSE;
311 swfdec_as_context_abort (swfdec_gc_object_get_context (resource),
312 "This is not a Flash file");
313 return TRUE;
316 static void
317 swfdec_resource_stream_target_close (SwfdecStreamTarget *target, SwfdecStream *stream)
319 SwfdecResource *resource = SWFDEC_RESOURCE (target);
320 SwfdecAsValue val;
322 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadProgress, TRUE, NULL, 0);
323 if (resource->decoder) {
324 SwfdecDecoder *dec = resource->decoder;
325 swfdec_decoder_eof (dec);
326 if (dec->data_type != SWFDEC_LOADER_DATA_UNKNOWN)
327 swfdec_loader_set_data_type (SWFDEC_LOADER (stream), dec->data_type);
330 swfdec_as_value_set_integer (swfdec_gc_object_get_context (resource), &val, 0); /* FIXME */
331 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadComplete, FALSE, &val, 1);
332 resource->state = SWFDEC_RESOURCE_COMPLETE;
333 if (swfdec_resource_abort_if_not_initialized (resource))
334 return;
336 if (SWFDEC_AS_VALUE_IS_MOVIE (&resource->movie)) {
337 SwfdecMovie *movie = SWFDEC_AS_VALUE_GET_MOVIE (&resource->movie);
338 if (movie)
339 swfdec_actor_queue_script (SWFDEC_ACTOR (movie), SWFDEC_EVENT_LOAD);
343 static void
344 swfdec_resource_stream_target_error (SwfdecStreamTarget *target, SwfdecStream *stream)
346 SwfdecResource *resource = SWFDEC_RESOURCE (target);
347 const char *message;
349 switch (resource->state) {
350 case SWFDEC_RESOURCE_REQUESTED:
351 message = SWFDEC_AS_STR_URLNotFound;
352 break;
353 case SWFDEC_RESOURCE_OPENED:
354 message = SWFDEC_AS_STR_LoadNeverCompleted;
355 break;
356 case SWFDEC_RESOURCE_NEW:
357 case SWFDEC_RESOURCE_COMPLETE:
358 case SWFDEC_RESOURCE_DONE:
359 default:
360 g_assert_not_reached ();
361 message = SWFDEC_AS_STR_EMPTY;
362 break;
364 swfdec_resource_emit_error (resource, message);
365 swfdec_resource_abort_if_not_initialized (resource);
368 static void
369 swfdec_resource_stream_target_init (SwfdecStreamTargetInterface *iface)
371 iface->get_player = swfdec_resource_stream_target_get_player;
372 iface->open = swfdec_resource_stream_target_open;
373 iface->parse = swfdec_resource_stream_target_parse;
374 iface->error = swfdec_resource_stream_target_error;
375 iface->close = swfdec_resource_stream_target_close;
378 static void
379 swfdec_resource_mark (SwfdecGcObject *object)
381 SwfdecResource *resource = SWFDEC_RESOURCE (object);
383 if (resource->clip_loader) {
384 swfdec_gc_object_mark (resource->clip_loader);
385 swfdec_gc_object_mark (resource->clip_loader_sandbox);
387 if (resource->sandbox)
388 swfdec_gc_object_mark (resource->sandbox);
389 if (resource->target)
390 swfdec_gc_object_mark (resource->target);
391 swfdec_as_value_mark (&resource->movie);
393 SWFDEC_GC_OBJECT_CLASS (swfdec_resource_parent_class)->mark (object);
396 static void
397 swfdec_resource_dispose (GObject *object)
399 SwfdecResource *resource = SWFDEC_RESOURCE (object);
401 if (resource->loader) {
402 swfdec_stream_set_target (SWFDEC_STREAM (resource->loader), NULL);
403 g_object_unref (resource->loader);
404 resource->loader = NULL;
406 if (resource->decoder) {
407 g_signal_handlers_disconnect_by_func (resource->decoder,
408 swfdec_player_add_missing_plugin, swfdec_gc_object_get_context (resource));
409 g_object_unref (resource->decoder);
410 resource->decoder = NULL;
412 g_free (resource->variables);
413 g_hash_table_destroy (resource->exports);
414 g_hash_table_destroy (resource->export_names);
416 G_OBJECT_CLASS (swfdec_resource_parent_class)->dispose (object);
419 static void
420 swfdec_resource_class_init (SwfdecResourceClass *klass)
422 GObjectClass *object_class = G_OBJECT_CLASS (klass);
423 SwfdecGcObjectClass *gc_class = SWFDEC_GC_OBJECT_CLASS (klass);
425 object_class->dispose = swfdec_resource_dispose;
427 gc_class->mark = swfdec_resource_mark;
430 static void
431 swfdec_resource_init (SwfdecResource *instance)
433 instance->exports = g_hash_table_new_full (swfdec_str_case_hash,
434 swfdec_str_case_equal, g_free, g_object_unref);
435 instance->export_names = g_hash_table_new_full (g_direct_hash, g_direct_equal,
436 g_object_unref, g_free);
439 static void
440 swfdec_resource_set_loader (SwfdecResource *resource, SwfdecLoader *loader)
442 g_return_if_fail (SWFDEC_IS_RESOURCE (resource));
443 g_return_if_fail (SWFDEC_IS_LOADER (loader));
444 g_return_if_fail (resource->loader == NULL);
446 resource->loader = g_object_ref (loader);
447 swfdec_stream_set_target (SWFDEC_STREAM (resource->loader), SWFDEC_STREAM_TARGET (resource));
448 resource->state = SWFDEC_RESOURCE_REQUESTED;
451 SwfdecResource *
452 swfdec_resource_new (SwfdecPlayer *player, SwfdecLoader *loader, const char *variables)
454 SwfdecResource *resource;
456 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
457 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), NULL);
459 resource = g_object_new (SWFDEC_TYPE_RESOURCE, "context", player, NULL);
460 resource->version = 8;
461 resource->variables = g_strdup (variables);
462 swfdec_resource_set_loader (resource, loader);
464 return resource;
467 gpointer
468 swfdec_resource_get_export (SwfdecResource *instance, const char *name)
470 g_return_val_if_fail (SWFDEC_IS_RESOURCE (instance), NULL);
471 g_return_val_if_fail (name != NULL, NULL);
473 return g_hash_table_lookup (instance->exports, name);
476 const char *
477 swfdec_resource_get_export_name (SwfdecResource *instance, SwfdecCharacter *character)
479 g_return_val_if_fail (SWFDEC_IS_RESOURCE (instance), NULL);
480 g_return_val_if_fail (SWFDEC_IS_CHARACTER (character), NULL);
482 return g_hash_table_lookup (instance->export_names, character);
485 void
486 swfdec_resource_add_export (SwfdecResource *instance, SwfdecCharacter *character, const char *name)
488 g_return_if_fail (SWFDEC_IS_RESOURCE (instance));
489 g_return_if_fail (SWFDEC_IS_CHARACTER (character));
490 g_return_if_fail (name != NULL);
492 g_hash_table_insert (instance->exports, g_strdup (name), g_object_ref (character));
493 g_hash_table_insert (instance->export_names, g_object_ref (character), g_strdup (name));
496 /*** RESOURC LOAD ***/
498 typedef struct _SwfdecResourceLoad SwfdecResourceLoad;
499 struct _SwfdecResourceLoad {
500 SwfdecSandbox * sandbox;
501 SwfdecAsValue target;
502 char * url;
503 SwfdecBuffer * buffer;
504 SwfdecMovieClipLoader * loader;
507 static void
508 swfdec_resource_load_free (gpointer loadp)
510 SwfdecResourceLoad *load = loadp;
512 g_free (load->url);
513 if (load->buffer)
514 swfdec_buffer_unref (load->buffer);
515 g_slice_free (SwfdecResourceLoad, load);
518 static void
519 swfdec_resource_load_mark (gpointer loadp, gpointer playerp)
521 SwfdecResourceLoad *load = loadp;
523 swfdec_gc_object_mark (load->sandbox);
524 if (load->loader)
525 swfdec_gc_object_mark (load->loader);
526 swfdec_as_value_mark (&load->target);
529 static gboolean
530 swfdec_resource_create_movie (SwfdecResource *resource, SwfdecResourceLoad *load)
532 SwfdecPlayer *player;
533 SwfdecSpriteMovie *movie;
535 if (SWFDEC_AS_VALUE_IS_MOVIE (&resource->movie))
536 return TRUE;
537 player = SWFDEC_PLAYER (swfdec_gc_object_get_context (resource));
538 if (SWFDEC_AS_VALUE_IS_MOVIE (&load->target)) {
539 movie = (SwfdecSpriteMovie *) SWFDEC_AS_VALUE_GET_MOVIE (&load->target);
540 if (SWFDEC_IS_SPRITE_MOVIE (movie))
541 movie = swfdec_resource_replace_movie (movie, resource);
542 else
543 movie = NULL;
544 } else if (SWFDEC_AS_VALUE_IS_STRING (&load->target)) {
545 int level = swfdec_player_get_level (player, SWFDEC_AS_VALUE_GET_STRING (&load->target), 7);
546 if (level >= 0) {
547 movie = swfdec_player_get_movie_at_level (player, level);
548 if (movie)
549 swfdec_movie_remove (SWFDEC_MOVIE (movie));
550 movie = swfdec_player_create_movie_at_level (player, resource, level);
551 } else {
552 movie = NULL;
554 } else {
555 /* we only set target to string or movie values */
556 g_assert_not_reached ();
558 if (movie == NULL) {
559 SWFDEC_WARNING ("target does not reference a movie, not loading %s", load->url);
560 return FALSE;
562 /* FIXME: does this belong here? */
563 SWFDEC_ACTOR (movie)->focusrect = SWFDEC_FLASH_YES;
564 return TRUE;
567 static void
568 swfdec_resource_do_load (SwfdecPlayer *player, gboolean allowed, gpointer loadp)
570 SwfdecResourceLoad *load = loadp;
571 SwfdecResource *resource;
572 SwfdecLoader *loader;
574 resource = g_object_new (SWFDEC_TYPE_RESOURCE, "context", player, NULL);
575 resource->version = 8;
576 if (load->loader) {
577 resource->clip_loader = load->loader;
578 resource->clip_loader_sandbox = load->sandbox;
580 resource->sandbox = load->sandbox;
581 if (!allowed) {
582 SWFDEC_WARNING ("SECURITY: no access to %s from %s",
583 load->url, swfdec_url_get_url (load->sandbox->url));
584 /* FIXME: is replacing correct? */
585 if (SWFDEC_AS_VALUE_IS_MOVIE (&load->target)) {
586 if (SWFDEC_AS_VALUE_IS_MOVIE (&load->target) &&
587 SWFDEC_IS_SPRITE_MOVIE (SWFDEC_AS_VALUE_GET_MOVIE (&load->target)))
588 resource->movie = load->target;
589 swfdec_resource_emit_error (resource, SWFDEC_AS_STR_IllegalRequest);
591 swfdec_player_unroot (player, load);
592 return;
595 /* FIXME: load nonetheless, even if there's no movie? */
596 if (swfdec_resource_create_movie (resource, load)) {
597 loader = swfdec_player_load (player, load->url, load->buffer);
598 swfdec_resource_set_loader (resource, loader);
599 g_object_unref (loader);
601 swfdec_player_unroot (player, load);
604 static const SwfdecAccessMatrix swfdec_resource_matrix = {
605 { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
606 { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES },
607 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
608 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES },
609 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES }
612 static void
613 swfdec_resource_load_request (gpointer loadp, gpointer playerp)
615 SwfdecResourceLoad *load = loadp;
616 SwfdecPlayer *player = playerp;
618 /* empty URL means unload (yay!) */
619 if (load->url[0] == '\0') {
620 SwfdecSpriteMovie *movie;
622 if (SWFDEC_AS_VALUE_IS_MOVIE (&load->target)) {
623 movie = (SwfdecSpriteMovie *) SWFDEC_AS_VALUE_GET_MOVIE (&load->target);
624 } else {
625 movie = NULL;
627 if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
628 swfdec_resource_replace_movie (movie, SWFDEC_MOVIE (movie)->resource);
629 } else {
630 SWFDEC_DEBUG ("no movie, not unloading");
632 swfdec_player_unroot (player, load);
633 return;
636 /* fscommand? */
637 if (g_ascii_strncasecmp (load->url, "FSCommand:", 10) == 0) {
638 char *command = load->url + 10;
639 const char *target = swfdec_as_value_to_string (SWFDEC_AS_CONTEXT (player), &load->target);
640 if (SWFDEC_AS_VALUE_IS_MOVIE (&load->target)) {
641 SWFDEC_FIXME ("Adobe 9.0.124.0 and later don't emit fscommands here. "
642 "We just do for compatibility reasons with the testsuite.");
644 g_signal_emit_by_name (player, "fscommand", command, target);
645 swfdec_player_unroot (player, load);
646 return;
649 /* LAUNCH command (aka getURL) */
650 if (SWFDEC_AS_VALUE_IS_STRING (&load->target) && swfdec_player_get_level (player,
651 SWFDEC_AS_VALUE_GET_STRING (&load->target), 7) < 0) {
652 swfdec_player_launch (player, load->url, SWFDEC_AS_VALUE_GET_STRING (&load->target), load->buffer);
653 swfdec_player_unroot (player, load);
654 return;
657 swfdec_player_allow_by_matrix (player, load->sandbox, load->url,
658 swfdec_resource_matrix, swfdec_resource_do_load, load);
661 /* NB: must be called from a script */
662 /* FIXME: 5 arguments?! */
663 static void
664 swfdec_resource_load_internal (SwfdecPlayer *player, const SwfdecAsValue *val,
665 const char *url, SwfdecBuffer *buffer, SwfdecMovieClipLoader *loader)
667 SwfdecResourceLoad *load;
669 g_assert (SWFDEC_AS_CONTEXT (player)->frame != NULL);
670 load = g_slice_new (SwfdecResourceLoad);
672 load->sandbox = swfdec_sandbox_get (player);
673 load->url = g_strdup (url);
674 load->target = *val;
675 load->buffer = buffer;
676 load->loader = loader;
678 swfdec_player_root_full (player, load, swfdec_resource_load_mark, swfdec_resource_load_free);
679 swfdec_player_request_resource (player, swfdec_resource_load_request, load, NULL);
682 gboolean
683 swfdec_resource_load_movie (SwfdecPlayer *player, const SwfdecAsValue *target,
684 const char *url, SwfdecBuffer *buffer, SwfdecMovieClipLoader *loader)
686 SwfdecMovie *movie;
687 SwfdecAsValue val;
688 const char *s;
690 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), FALSE);
691 g_return_val_if_fail (target != NULL, FALSE);
692 g_return_val_if_fail (url != NULL, FALSE);
693 g_return_val_if_fail (loader == NULL || SWFDEC_IS_MOVIE_CLIP_LOADER (loader), FALSE);
695 if (SWFDEC_AS_VALUE_IS_MOVIE (target)) {
696 movie = SWFDEC_AS_VALUE_GET_MOVIE (target);
697 if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
698 swfdec_resource_load_internal (player, target, url, buffer, loader);
699 return TRUE;
703 if (loader) {
704 if (SWFDEC_AS_VALUE_IS_NUMBER (target)) {
705 int i = swfdec_as_double_to_integer (SWFDEC_AS_VALUE_GET_NUMBER (target));
706 if (i < 0)
707 return FALSE;
708 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (
709 SWFDEC_AS_CONTEXT (player), g_strdup_printf ("_level%d", i)));
710 swfdec_resource_load_internal (player, &val, url, buffer, loader);
711 return TRUE;
712 } else if (SWFDEC_AS_VALUE_IS_STRING (target) || SWFDEC_AS_VALUE_IS_MOVIE(target)) {
713 s = swfdec_as_value_to_string (SWFDEC_AS_CONTEXT (player), target);
714 } else {
715 SWFDEC_WARNING ("target does not reference a movie, not loading %s", url);
716 return FALSE;
718 } else {
719 s = swfdec_as_value_to_string (SWFDEC_AS_CONTEXT (player), target);
721 if (swfdec_player_get_level (player, s, SWFDEC_AS_CONTEXT (player)->version) >= 0) {
722 /* lowercase the string, so we can do case insensitive level lookups later on */
723 char *tmp = g_ascii_strdown (s, -1);
724 SWFDEC_AS_VALUE_SET_STRING (&val, swfdec_as_context_give_string (
725 SWFDEC_AS_CONTEXT (player), tmp));
726 swfdec_resource_load_internal (player, &val, url, buffer, NULL);
727 return TRUE;
729 movie = swfdec_player_get_movie_from_string (player, s);
730 if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
731 SWFDEC_AS_VALUE_SET_MOVIE (&val, movie);
732 swfdec_resource_load_internal (player, &val, url, buffer, loader);
733 return TRUE;
735 SWFDEC_WARNING ("%s does not reference a movie, not loading %s", s, url);
736 return FALSE;
739 void
740 swfdec_resource_load (SwfdecPlayer *player, const char *target,
741 const char *url, SwfdecBuffer *buffer)
743 SwfdecAsValue val;
745 g_return_if_fail (SWFDEC_IS_PLAYER (player));
746 g_return_if_fail (target != NULL);
747 g_return_if_fail (url != NULL);
749 SWFDEC_AS_VALUE_SET_STRING (&val, target);
750 swfdec_resource_load_internal (player, &val, url, buffer, NULL);
753 gboolean
754 swfdec_resource_emit_on_load_init (SwfdecResource *resource)
756 g_return_val_if_fail (SWFDEC_IS_RESOURCE (resource), FALSE);
758 if (resource->state != SWFDEC_RESOURCE_COMPLETE)
759 return FALSE;
761 if (SWFDEC_AS_VALUE_IS_MOVIE (&resource->movie) && SWFDEC_IS_IMAGE_DECODER (resource->decoder)) {
762 SwfdecImage *image = SWFDEC_IMAGE_DECODER (resource->decoder)->image;
763 SwfdecMovie *movie = SWFDEC_AS_VALUE_GET_MOVIE (&resource->movie);
764 if (image && movie) {
765 swfdec_movie_invalidate_next (movie);
766 swfdec_movie_queue_update (movie, SWFDEC_MOVIE_INVALID_EXTENTS);
767 movie->image = g_object_ref (image);
770 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadInit, FALSE, NULL, 0);
771 resource->state = SWFDEC_RESOURCE_DONE;
772 /* free now unneeded resources */
773 resource->clip_loader = NULL;
774 resource->clip_loader_sandbox = NULL;
775 return TRUE;