rework code to allow passing numbers as levels in MovieClipLoader.loadClip()
[swfdec.git] / swfdec / swfdec_resource.c
blobcfbbbfdc795f8530b3ff941846b4db7cf843a699
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_AS_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->movie == SWFDEC_PLAYER (SWFDEC_AS_OBJECT (resource)->context)->priv->roots->data;
63 static SwfdecPlayer *
64 swfdec_resource_stream_target_get_player (SwfdecStreamTarget *target)
66 return SWFDEC_PLAYER (SWFDEC_AS_OBJECT (target)->context);
69 static void
70 swfdec_resource_stream_target_image (SwfdecResource *instance)
72 SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (instance)->context);
73 SwfdecSpriteMovie *movie = instance->movie;
75 if (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_as_object_set_constructor (SWFDEC_AS_OBJECT (movie), instance->sandbox->MovieClip);
92 if (swfdec_resource_is_root (instance)) {
93 swfdec_player_start_ticking (player);
94 swfdec_movie_initialize (SWFDEC_MOVIE (movie));
95 swfdec_player_perform_actions (player);
97 } else {
98 SWFDEC_FIXME ("cannot continue loading %s, invalid rights",
99 swfdec_url_get_url (swfdec_loader_get_url (instance->loader)));
100 swfdec_stream_set_target (SWFDEC_STREAM (instance->loader), NULL);
101 instance->sandbox = old_sandbox;
102 /* FIXME: anyting else on the movie we need to clear? */
104 } else {
105 g_assert_not_reached ();
109 /* NB: name must be GC'ed */
110 static void
111 swfdec_resource_emit_signal (SwfdecResource *resource, const char *name, gboolean progress,
112 SwfdecAsValue *args, guint n_args)
114 SwfdecAsContext *cx;
115 SwfdecMovie *movie;
116 guint skip = progress ? 4 : 2;
117 SwfdecAsValue vals[n_args + skip];
119 if (resource->clip_loader == NULL)
120 return;
121 cx = SWFDEC_AS_OBJECT (resource->clip_loader)->context;
123 SWFDEC_AS_VALUE_SET_STRING (&vals[0], name);
124 if (resource->movie) {
125 movie = swfdec_movie_resolve (SWFDEC_MOVIE (resource->movie));
126 if (movie == NULL) {
127 SWFDEC_DEBUG ("no movie, not emitting signal");
128 return;
130 if (name == SWFDEC_AS_STR_onLoadInit &&
131 movie != SWFDEC_MOVIE (resource->movie)) {
132 SWFDEC_INFO ("not emitting onLoadInit - the movie is different");
133 return;
135 SWFDEC_AS_VALUE_SET_OBJECT (&vals[1], SWFDEC_AS_OBJECT (movie));
136 } else {
137 SWFDEC_AS_VALUE_SET_UNDEFINED (&vals[1]);
139 if (progress) {
140 SwfdecResource *res;
142 if (SWFDEC_IS_MOVIE (movie))
143 res = swfdec_movie_get_own_resource (SWFDEC_MOVIE (movie));
144 else
145 res = NULL;
146 if (res && res->decoder) {
147 SwfdecDecoder *dec = res->decoder;
148 SWFDEC_AS_VALUE_SET_INT (&vals[2], dec->bytes_loaded);
149 SWFDEC_AS_VALUE_SET_INT (&vals[3], dec->bytes_total);
150 } else {
151 SWFDEC_AS_VALUE_SET_INT (&vals[2], 0);
152 SWFDEC_AS_VALUE_SET_INT (&vals[3], 0);
155 if (n_args)
156 memcpy (&vals[skip], args, sizeof (SwfdecAsValue) * n_args);
157 /* FIXME: what's the correct sandbox here? */
158 swfdec_sandbox_use (resource->clip_loader_sandbox);
159 swfdec_as_object_call (SWFDEC_AS_OBJECT (resource->clip_loader), SWFDEC_AS_STR_broadcastMessage,
160 n_args + skip, vals, NULL);
161 swfdec_sandbox_unuse (resource->clip_loader_sandbox);
164 static void
165 swfdec_resource_emit_error (SwfdecResource *resource, const char *message)
167 SwfdecAsValue vals[2];
169 SWFDEC_AS_VALUE_SET_STRING (&vals[0], message);
170 SWFDEC_AS_VALUE_SET_INT (&vals[1], 0);
172 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadError, FALSE, vals, 2);
175 static SwfdecSpriteMovie *
176 swfdec_resource_replace_movie (SwfdecSpriteMovie *movie, SwfdecResource *resource)
178 /* can't use swfdec_movie_duplicate() here, we copy to same depth */
179 SwfdecMovie *mov = SWFDEC_MOVIE (movie);
180 SwfdecMovie *copy;
182 copy = swfdec_movie_new (SWFDEC_PLAYER (SWFDEC_AS_OBJECT (movie)->context),
183 mov->depth, mov->parent, resource, NULL, mov->name);
184 if (copy == NULL)
185 return FALSE;
186 swfdec_movie_begin_update_matrix (copy);
187 copy->matrix = mov->matrix;
188 copy->original_name = mov->original_name;
189 copy->modified = mov->modified;
190 copy->xscale = mov->xscale;
191 copy->yscale = mov->yscale;
192 copy->rotation = mov->rotation;
193 copy->lockroot = mov->lockroot;
194 swfdec_movie_end_update_matrix (copy);
195 /* FIXME: are events copied? If so, wouldn't that be a security issue? */
196 swfdec_movie_set_static_properties (copy, &mov->original_transform,
197 &mov->color_transform, mov->original_ratio, mov->clip_depth,
198 mov->blend_mode, NULL);
199 swfdec_movie_remove (mov);
200 return SWFDEC_SPRITE_MOVIE (copy);
203 static void
204 swfdec_resource_stream_target_open (SwfdecStreamTarget *target, SwfdecStream *stream)
206 SwfdecLoader *loader = SWFDEC_LOADER (stream);
207 SwfdecResource *instance = SWFDEC_RESOURCE (target);
208 const char *query;
210 g_assert (instance->movie);
211 query = swfdec_url_get_query (swfdec_loader_get_url (loader));
212 if (query) {
213 SWFDEC_INFO ("set url query movie variables: %s", query);
214 swfdec_as_object_decode (SWFDEC_AS_OBJECT (instance->movie), query);
216 if (instance->variables) {
217 SWFDEC_INFO ("set manual movie variables: %s", instance->variables);
218 swfdec_as_object_decode (SWFDEC_AS_OBJECT (instance->movie), instance->variables);
220 swfdec_resource_emit_signal (instance, SWFDEC_AS_STR_onLoadStart, FALSE, NULL, 0);
221 instance->state = SWFDEC_RESOURCE_OPENED;
224 static gboolean
225 swfdec_resource_stream_target_parse (SwfdecStreamTarget *target, SwfdecStream *stream)
227 SwfdecLoader *loader = SWFDEC_LOADER (stream);
228 SwfdecResource *resource = SWFDEC_RESOURCE (target);
229 SwfdecBufferQueue *queue;
230 SwfdecBuffer *buffer;
231 SwfdecDecoder *dec = resource->decoder;
232 SwfdecStatus status;
233 guint parsed;
235 queue = swfdec_stream_get_queue (stream);
236 if (dec == NULL && swfdec_buffer_queue_get_offset (queue) == 0) {
237 if (swfdec_buffer_queue_get_depth (queue) < SWFDEC_DECODER_DETECT_LENGTH)
238 return FALSE;
239 buffer = swfdec_buffer_queue_peek (queue, 4);
240 dec = swfdec_decoder_new (buffer);
241 swfdec_buffer_unref (buffer);
242 if (dec == NULL) {
243 SWFDEC_ERROR ("no decoder found for format");
244 } else {
245 glong total;
246 resource->decoder = dec;
247 g_signal_connect_swapped (dec, "missing-plugin",
248 G_CALLBACK (swfdec_player_add_missing_plugin), SWFDEC_AS_OBJECT (resource)->context);
249 total = swfdec_loader_get_size (loader);
250 if (total >= 0)
251 dec->bytes_total = total;
254 while (swfdec_buffer_queue_get_depth (queue)) {
255 parsed = 0;
256 status = 0;
257 do {
258 buffer = swfdec_buffer_queue_peek_buffer (queue);
259 if (buffer == NULL)
260 break;
261 if (parsed + buffer->length <= 65536) {
262 swfdec_buffer_unref (buffer);
263 buffer = swfdec_buffer_queue_pull_buffer (queue);
264 } else {
265 swfdec_buffer_unref (buffer);
266 buffer = swfdec_buffer_queue_pull (queue, 65536 - parsed);
268 parsed += buffer->length;
269 if (dec) {
270 status |= swfdec_decoder_parse (dec, buffer);
271 } else {
272 swfdec_buffer_unref (buffer);
274 } while (parsed < 65536 && (status & (SWFDEC_STATUS_ERROR | SWFDEC_STATUS_EOF)) == 0);
275 if (status & SWFDEC_STATUS_ERROR) {
276 SWFDEC_ERROR ("parsing error");
277 swfdec_stream_set_target (SWFDEC_STREAM (loader), NULL);
278 return FALSE;
280 if ((status & SWFDEC_STATUS_INIT)) {
281 if (SWFDEC_IS_SWF_DECODER (dec))
282 resource->version = SWFDEC_SWF_DECODER (dec)->version;
283 if (swfdec_resource_is_root (resource)) {
284 swfdec_player_initialize (SWFDEC_PLAYER (SWFDEC_AS_OBJECT (resource)->context),
285 dec->rate, dec->width, dec->height);
288 if (status & SWFDEC_STATUS_IMAGE)
289 swfdec_resource_stream_target_image (resource);
290 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadProgress, TRUE, NULL, 0);
291 if (status & SWFDEC_STATUS_EOF)
292 return FALSE;
294 return FALSE;
297 static gboolean
298 swfdec_resource_abort_if_not_initialized (SwfdecResource *resource)
300 if (resource->sandbox)
301 return FALSE;
303 swfdec_as_context_abort (SWFDEC_AS_OBJECT (resource)->context,
304 "This is not a Flash file");
305 return TRUE;
308 static void
309 swfdec_resource_stream_target_close (SwfdecStreamTarget *target, SwfdecStream *stream)
311 SwfdecResource *resource = SWFDEC_RESOURCE (target);
312 SwfdecAsValue val;
314 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadProgress, TRUE, NULL, 0);
315 if (resource->decoder) {
316 SwfdecDecoder *dec = resource->decoder;
317 swfdec_decoder_eof (dec);
318 if (dec->data_type != SWFDEC_LOADER_DATA_UNKNOWN)
319 swfdec_loader_set_data_type (SWFDEC_LOADER (stream), dec->data_type);
322 SWFDEC_AS_VALUE_SET_INT (&val, 0); /* FIXME */
323 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadComplete, FALSE, &val, 1);
324 resource->state = SWFDEC_RESOURCE_COMPLETE;
325 if (swfdec_resource_abort_if_not_initialized (resource))
326 return;
328 if (resource->movie != NULL)
329 swfdec_actor_queue_script (SWFDEC_ACTOR (resource->movie), SWFDEC_EVENT_LOAD);
332 static void
333 swfdec_resource_stream_target_error (SwfdecStreamTarget *target, SwfdecStream *stream)
335 SwfdecResource *resource = SWFDEC_RESOURCE (target);
336 const char *message;
338 switch (resource->state) {
339 case SWFDEC_RESOURCE_REQUESTED:
340 message = SWFDEC_AS_STR_URLNotFound;
341 break;
342 case SWFDEC_RESOURCE_OPENED:
343 message = SWFDEC_AS_STR_LoadNeverCompleted;
344 break;
345 case SWFDEC_RESOURCE_NEW:
346 case SWFDEC_RESOURCE_COMPLETE:
347 case SWFDEC_RESOURCE_DONE:
348 default:
349 g_assert_not_reached ();
350 message = SWFDEC_AS_STR_EMPTY;
351 break;
353 swfdec_resource_emit_error (resource, message);
354 swfdec_resource_abort_if_not_initialized (resource);
357 static void
358 swfdec_resource_stream_target_init (SwfdecStreamTargetInterface *iface)
360 iface->get_player = swfdec_resource_stream_target_get_player;
361 iface->open = swfdec_resource_stream_target_open;
362 iface->parse = swfdec_resource_stream_target_parse;
363 iface->error = swfdec_resource_stream_target_error;
364 iface->close = swfdec_resource_stream_target_close;
367 static void
368 swfdec_resource_mark (SwfdecAsObject *object)
370 SwfdecResource *resource = SWFDEC_RESOURCE (object);
372 if (resource->clip_loader) {
373 swfdec_as_object_mark (SWFDEC_AS_OBJECT (resource->clip_loader));
374 swfdec_as_object_mark (SWFDEC_AS_OBJECT (resource->clip_loader_sandbox));
376 if (resource->sandbox)
377 swfdec_as_object_mark (SWFDEC_AS_OBJECT (resource->sandbox));
378 if (resource->target)
379 swfdec_as_object_mark (SWFDEC_AS_OBJECT (resource->target));
381 SWFDEC_AS_OBJECT_CLASS (swfdec_resource_parent_class)->mark (object);
384 static void
385 swfdec_resource_dispose (GObject *object)
387 SwfdecResource *resource = SWFDEC_RESOURCE (object);
389 if (resource->loader) {
390 swfdec_stream_set_target (SWFDEC_STREAM (resource->loader), NULL);
391 g_object_unref (resource->loader);
392 resource->loader = NULL;
394 if (resource->decoder) {
395 g_signal_handlers_disconnect_by_func (resource->decoder,
396 swfdec_player_add_missing_plugin, SWFDEC_AS_OBJECT (resource)->context);
397 g_object_unref (resource->decoder);
398 resource->decoder = NULL;
400 g_free (resource->variables);
401 g_hash_table_destroy (resource->exports);
402 g_hash_table_destroy (resource->export_names);
404 G_OBJECT_CLASS (swfdec_resource_parent_class)->dispose (object);
407 static void
408 swfdec_resource_class_init (SwfdecResourceClass *klass)
410 GObjectClass *object_class = G_OBJECT_CLASS (klass);
411 SwfdecAsObjectClass *asobject_class = SWFDEC_AS_OBJECT_CLASS (klass);
413 object_class->dispose = swfdec_resource_dispose;
415 asobject_class->mark = swfdec_resource_mark;
418 static void
419 swfdec_resource_init (SwfdecResource *instance)
421 instance->exports = g_hash_table_new_full (swfdec_str_case_hash,
422 swfdec_str_case_equal, g_free, g_object_unref);
423 instance->export_names = g_hash_table_new_full (g_direct_hash, g_direct_equal,
424 g_object_unref, g_free);
427 static void
428 swfdec_resource_set_loader (SwfdecResource *resource, SwfdecLoader *loader)
430 g_return_if_fail (SWFDEC_IS_RESOURCE (resource));
431 g_return_if_fail (SWFDEC_IS_LOADER (loader));
432 g_return_if_fail (resource->loader == NULL);
434 resource->loader = g_object_ref (loader);
435 swfdec_stream_set_target (SWFDEC_STREAM (resource->loader), SWFDEC_STREAM_TARGET (resource));
436 resource->state = SWFDEC_RESOURCE_REQUESTED;
439 SwfdecResource *
440 swfdec_resource_new (SwfdecPlayer *player, SwfdecLoader *loader, const char *variables)
442 SwfdecResource *resource;
443 guint size;
445 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);
446 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), NULL);
448 size = sizeof (SwfdecResource);
449 if (!swfdec_as_context_use_mem (SWFDEC_AS_CONTEXT (player), size))
450 size = 0;
451 resource = g_object_new (SWFDEC_TYPE_RESOURCE, NULL);
452 swfdec_as_object_add (SWFDEC_AS_OBJECT (resource), SWFDEC_AS_CONTEXT (player), size);
453 resource->version = 8;
454 resource->variables = g_strdup (variables);
455 swfdec_resource_set_loader (resource, loader);
457 return resource;
460 gpointer
461 swfdec_resource_get_export (SwfdecResource *instance, const char *name)
463 g_return_val_if_fail (SWFDEC_IS_RESOURCE (instance), NULL);
464 g_return_val_if_fail (name != NULL, NULL);
466 return g_hash_table_lookup (instance->exports, name);
469 const char *
470 swfdec_resource_get_export_name (SwfdecResource *instance, SwfdecCharacter *character)
472 g_return_val_if_fail (SWFDEC_IS_RESOURCE (instance), NULL);
473 g_return_val_if_fail (SWFDEC_IS_CHARACTER (character), NULL);
475 return g_hash_table_lookup (instance->export_names, character);
478 void
479 swfdec_resource_add_export (SwfdecResource *instance, SwfdecCharacter *character, const char *name)
481 g_return_if_fail (SWFDEC_IS_RESOURCE (instance));
482 g_return_if_fail (SWFDEC_IS_CHARACTER (character));
483 g_return_if_fail (name != NULL);
485 g_hash_table_insert (instance->exports, g_strdup (name), g_object_ref (character));
486 g_hash_table_insert (instance->export_names, g_object_ref (character), g_strdup (name));
489 /*** RESOURC LOAD ***/
491 typedef struct _SwfdecResourceLoad SwfdecResourceLoad;
492 struct _SwfdecResourceLoad {
493 SwfdecSandbox * sandbox;
494 char * target_string;
495 SwfdecSpriteMovie * target_movie;
496 char * url;
497 SwfdecBuffer * buffer;
498 SwfdecMovieClipLoader * loader;
501 static void
502 swfdec_resource_load_free (gpointer loadp)
504 SwfdecResourceLoad *load = loadp;
506 g_free (load->url);
507 g_free (load->target_string);
508 if (load->buffer)
509 swfdec_buffer_unref (load->buffer);
510 g_slice_free (SwfdecResourceLoad, load);
513 static void
514 swfdec_resource_load_mark (gpointer loadp, gpointer playerp)
516 SwfdecResourceLoad *load = loadp;
518 swfdec_as_object_mark (SWFDEC_AS_OBJECT (load->sandbox));
519 if (load->loader)
520 swfdec_as_object_mark (SWFDEC_AS_OBJECT (load->loader));
521 if (load->target_movie)
522 swfdec_as_object_mark (SWFDEC_AS_OBJECT (load->target_movie));
525 static gboolean
526 swfdec_resource_create_movie (SwfdecResource *resource, SwfdecResourceLoad *load)
528 SwfdecPlayer *player;
529 SwfdecSpriteMovie *movie;
531 if (resource->movie)
532 return TRUE;
533 player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (resource)->context);
534 if (load->target_movie) {
535 movie = (SwfdecSpriteMovie *) swfdec_movie_resolve (SWFDEC_MOVIE (load->target_movie));
536 if (SWFDEC_IS_SPRITE_MOVIE (movie))
537 movie = swfdec_resource_replace_movie (movie, resource);
538 else
539 movie = NULL;
540 } else {
541 int level = swfdec_player_get_level (player, load->target_string);
542 if (level >= 0) {
543 movie = swfdec_player_get_movie_at_level (player, level);
544 if (movie)
545 swfdec_movie_remove (SWFDEC_MOVIE (movie));
546 movie = swfdec_player_create_movie_at_level (player, resource, level);
547 } else {
548 movie = NULL;
551 if (movie == NULL) {
552 SWFDEC_WARNING ("target does not reference a movie, not loading %s", load->url);
553 return FALSE;
555 /* FIXME: does this belong here? */
556 SWFDEC_ACTOR (movie)->focusrect = SWFDEC_FLASH_YES;
557 return TRUE;
560 static void
561 swfdec_resource_do_load (SwfdecPlayer *player, gboolean allowed, gpointer loadp)
563 SwfdecResourceLoad *load = loadp;
564 SwfdecResource *resource;
565 SwfdecLoader *loader;
567 if (!swfdec_as_context_use_mem (SWFDEC_AS_CONTEXT (player), sizeof (SwfdecResource))) {
568 swfdec_player_unroot (player, load);
569 return;
571 resource = g_object_new (SWFDEC_TYPE_RESOURCE, NULL);
572 swfdec_as_object_add (SWFDEC_AS_OBJECT (resource), SWFDEC_AS_CONTEXT (player), sizeof (SwfdecResource));
573 resource->version = 8;
574 if (load->loader) {
575 resource->clip_loader = load->loader;
576 resource->clip_loader_sandbox = load->sandbox;
578 resource->sandbox = load->sandbox;
579 if (!allowed) {
580 SWFDEC_WARNING ("SECURITY: no access to %s from %s",
581 load->url, swfdec_url_get_url (load->sandbox->url));
582 /* FIXME: is replacing correct? */
583 if (load->target_movie) {
584 resource->movie = SWFDEC_SPRITE_MOVIE (swfdec_movie_resolve (SWFDEC_MOVIE (load->target_movie)));
585 swfdec_resource_emit_error (resource, SWFDEC_AS_STR_IllegalRequest);
587 swfdec_player_unroot (player, load);
588 return;
591 /* FIXME: load nonetheless, even if there's no movie? */
592 if (swfdec_resource_create_movie (resource, load)) {
593 loader = swfdec_player_load (player, load->url, load->buffer);
594 swfdec_resource_set_loader (resource, loader);
595 g_object_unref (loader);
597 swfdec_player_unroot (player, load);
600 static const SwfdecAccessMatrix swfdec_resource_matrix = {
601 { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
602 { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES },
603 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
604 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_POLICY },
605 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_POLICY }
608 static void
609 swfdec_resource_load_request (gpointer loadp, gpointer playerp)
611 SwfdecResourceLoad *load = loadp;
612 SwfdecPlayer *player = playerp;
614 /* empty URL means unload (yay!) */
615 if (load->url[0] == '\0') {
616 SwfdecSpriteMovie *movie;
618 movie = load->target_movie ? (SwfdecSpriteMovie *) swfdec_movie_resolve (SWFDEC_MOVIE (load->target_movie)) : NULL;
619 if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
620 swfdec_resource_replace_movie (movie, SWFDEC_MOVIE (movie)->resource);
621 } else {
622 SWFDEC_DEBUG ("no movie, not unloading");
624 swfdec_player_unroot (player, load);
625 return;
628 /* fscommand? */
629 if (g_ascii_strncasecmp (load->url, "FSCommand:", 10) == 0) {
630 char *command = load->url + 10;
631 if (load->target_movie) {
632 char *target = swfdec_movie_get_path (SWFDEC_MOVIE (load->target_movie), TRUE);
633 SWFDEC_FIXME ("Adobe 9.0.124.0 and later don't emit fscommands here. "
634 "We just do for compatibility reasons with the testsuite.");
635 g_signal_emit_by_name (player, "fscommand", command, target);
636 g_free (target);
637 } else {
638 g_signal_emit_by_name (player, "fscommand", command, load->target_string);
640 swfdec_player_unroot (player, load);
641 return;
644 /* LAUNCH command (aka getURL) */
645 if (load->target_string && swfdec_player_get_level (player, load->target_string) < 0) {
646 swfdec_player_launch (player, load->url, load->target_string, load->buffer);
647 swfdec_player_unroot (player, load);
648 return;
651 swfdec_player_allow_by_matrix (player, load->sandbox, load->url,
652 swfdec_resource_matrix, swfdec_resource_do_load, load);
655 /* NB: must be called from a script */
656 /* FIXME: 6 arguments?! */
657 static void
658 swfdec_resource_load_internal (SwfdecPlayer *player,
659 SwfdecSpriteMovie *target_movie, const char *target_string,
660 const char *url, SwfdecBuffer *buffer, SwfdecMovieClipLoader *loader)
662 SwfdecResourceLoad *load;
664 g_assert (SWFDEC_AS_CONTEXT (player)->frame != NULL);
665 load = g_slice_new (SwfdecResourceLoad);
667 load->sandbox = SWFDEC_SANDBOX (SWFDEC_AS_CONTEXT (player)->global);
668 load->url = g_strdup (url);
669 load->target_movie = target_movie;
670 load->target_string = g_strdup (target_string);
671 load->buffer = buffer;
672 load->loader = loader;
674 swfdec_player_root_full (player, load, swfdec_resource_load_mark, swfdec_resource_load_free);
675 swfdec_player_request_resource (player, swfdec_resource_load_request, load, NULL);
678 gboolean
679 swfdec_resource_load_movie (SwfdecPlayer *player, const SwfdecAsValue *target,
680 const char *url, SwfdecBuffer *buffer, SwfdecMovieClipLoader *loader)
682 SwfdecMovie *movie;
683 const char *s;
685 g_return_val_if_fail (SWFDEC_IS_PLAYER (player), FALSE);
686 g_return_val_if_fail (target != NULL, FALSE);
687 g_return_val_if_fail (url != NULL, FALSE);
688 g_return_val_if_fail (loader == NULL || SWFDEC_IS_MOVIE_CLIP_LOADER (loader), FALSE);
690 if (SWFDEC_AS_VALUE_IS_OBJECT (target)) {
691 SwfdecAsObject *object = SWFDEC_AS_VALUE_GET_OBJECT (target);
692 if (SWFDEC_IS_SPRITE_MOVIE (object)) {
693 swfdec_resource_load_internal (player, SWFDEC_SPRITE_MOVIE (object),
694 NULL, url, buffer, loader);
695 return TRUE;
699 if (loader) {
700 if (SWFDEC_AS_VALUE_IS_NUMBER (target)) {
701 int i = swfdec_as_double_to_integer (SWFDEC_AS_VALUE_GET_NUMBER (target));
702 if (i < 0)
703 return FALSE;
704 s = swfdec_as_context_give_string (SWFDEC_AS_OBJECT (loader)->context,
705 g_strdup_printf ("_level%d", i));
706 swfdec_resource_load_internal (player, NULL, s, url, buffer, loader);
707 return TRUE;
708 } else if (SWFDEC_AS_VALUE_IS_STRING (target) ||
709 (SWFDEC_AS_VALUE_IS_OBJECT (target) && SWFDEC_IS_MOVIE (SWFDEC_AS_VALUE_GET_OBJECT (target)))) {
710 s = swfdec_as_value_to_string (SWFDEC_AS_CONTEXT (player), target);
711 } else {
712 SWFDEC_WARNING ("target does not reference a movie, not loading %s", url);
713 return FALSE;
715 } else {
716 s = swfdec_as_value_to_string (SWFDEC_AS_CONTEXT (player), target);
718 if (swfdec_player_get_level (player, s) >= 0) {
719 swfdec_resource_load_internal (player, NULL, s, url, buffer, NULL);
720 return TRUE;
722 movie = swfdec_player_get_movie_from_string (player, s);
723 if (SWFDEC_IS_SPRITE_MOVIE (movie)) {
724 swfdec_resource_load_internal (player, SWFDEC_SPRITE_MOVIE (movie),
725 NULL, url, buffer, loader);
726 return TRUE;
728 SWFDEC_WARNING ("%s does not reference a movie, not loading %s", s, url);
729 return FALSE;
732 void
733 swfdec_resource_load (SwfdecPlayer *player, const char *target,
734 const char *url, SwfdecBuffer *buffer)
736 g_return_if_fail (SWFDEC_IS_PLAYER (player));
737 g_return_if_fail (target != NULL);
738 g_return_if_fail (url != NULL);
740 swfdec_resource_load_internal (player, NULL, target, url, buffer, NULL);
743 gboolean
744 swfdec_resource_emit_on_load_init (SwfdecResource *resource)
746 g_return_val_if_fail (SWFDEC_IS_RESOURCE (resource), FALSE);
748 if (resource->state != SWFDEC_RESOURCE_COMPLETE)
749 return FALSE;
751 if (resource->movie && SWFDEC_IS_IMAGE_DECODER (resource->decoder)) {
752 SwfdecImage *image = SWFDEC_IMAGE_DECODER (resource->decoder)->image;
753 if (image) {
754 swfdec_movie_invalidate_next (SWFDEC_MOVIE (resource->movie));
755 swfdec_movie_queue_update (SWFDEC_MOVIE (resource->movie), SWFDEC_MOVIE_INVALID_EXTENTS);
756 SWFDEC_MOVIE (resource->movie)->image = g_object_ref (image);
759 swfdec_resource_emit_signal (resource, SWFDEC_AS_STR_onLoadInit, FALSE, NULL, 0);
760 resource->state = SWFDEC_RESOURCE_DONE;
761 /* free now unneeded resources */
762 resource->clip_loader = NULL;
763 resource->clip_loader_sandbox = NULL;
764 return TRUE;