2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2007 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
32 #include <glib-object.h>
33 #include <libswfdec/swfdec.h>
34 #include <libswfdec/swfdec_button.h>
35 #include <libswfdec/swfdec_text_field.h>
36 #include <libswfdec/swfdec_font.h>
37 #include <libswfdec/swfdec_image.h>
38 #include <libswfdec/swfdec_movie.h>
39 #include <libswfdec/swfdec_player_internal.h>
40 #include <libswfdec/swfdec_sprite.h>
41 #include <libswfdec/swfdec_shape.h>
42 #include <libswfdec/swfdec_sound.h>
43 #include <libswfdec/swfdec_swf_decoder.h>
44 #include <libswfdec/swfdec_resource.h>
45 #include <libswfdec/swfdec_tag.h>
46 #include <libswfdec/swfdec_text.h>
48 static gboolean verbose
= FALSE
;
51 get_audio_format_name (guint codec
)
54 case SWFDEC_AUDIO_CODEC_ADPCM
:
56 case SWFDEC_AUDIO_CODEC_MP3
:
58 case SWFDEC_AUDIO_CODEC_UNCOMPRESSED
:
59 return "uncompressed";
60 case SWFDEC_AUDIO_CODEC_NELLYMOSER
:
68 dump_sound (SwfdecSound
*sound
)
70 g_print (" codec: %s\n", get_audio_format_name (sound
->codec
));
72 g_print (" format: %s\n", swfdec_audio_format_to_string (sound
->format
));
73 g_print (" samples: %u (%gs)\n", sound
->n_samples
,
74 (double) sound
->n_samples
/ swfdec_audio_format_get_rate (sound
->format
));
79 dump_sprite (SwfdecSwfDecoder
*dec
, SwfdecSprite
*s
)
82 g_print (" %u frames\n", s
->n_frames
);
86 SwfdecSound
*sound
= NULL
;
88 for (i
= 0; i
< s
->n_frames
; i
++) {
89 SwfdecSpriteFrame
*frame
= &s
->frames
[i
];
90 if (frame
->sound_head
!= sound
&&
91 frame
->sound_block
!= NULL
) {
92 sound
= frame
->sound_head
;
93 for (j
= i
; j
< s
->n_frames
; j
++) {
94 SwfdecSpriteFrame
*cur
= &s
->frames
[i
];
95 if (cur
->sound_head
!= sound
)
99 g_print (" %4u -%4u sound: %s %s\n", i
, j
,
100 get_audio_format_name (sound
->codec
),
101 swfdec_audio_format_to_string (sound
->format
));
107 if (!swfdec_sprite_get_action (s
, i
, &tag
, &buffer
))
110 case SWFDEC_TAG_DOACTION
:
111 g_print (" %4u script\n", j
);
113 case SWFDEC_TAG_PLACEOBJECT2
:
114 case SWFDEC_TAG_PLACEOBJECT3
:
117 gboolean has_char
, is_move
;
120 swfdec_bits_init (&bits
, buffer
);
121 swfdec_bits_getbits (&bits
, 6);
122 has_char
= swfdec_bits_getbit (&bits
);
123 is_move
= swfdec_bits_getbit (&bits
);
124 if (tag
== SWFDEC_TAG_PLACEOBJECT3
)
125 swfdec_bits_get_u8 (&bits
);
126 depth
= swfdec_bits_get_u16 (&bits
);
127 g_print (" %4u %5u %s", j
, depth
, is_move
? "move" : "place");
130 c
= swfdec_swf_decoder_get_character (dec
, swfdec_bits_get_u16 (&bits
));
132 g_print (" %s %u", G_OBJECT_TYPE_NAME (c
), c
->id
);
137 case SWFDEC_TAG_REMOVEOBJECT
:
138 case SWFDEC_TAG_REMOVEOBJECT2
:
141 swfdec_bits_init (&bits
, buffer
);
142 if (tag
== SWFDEC_TAG_REMOVEOBJECT
)
143 swfdec_bits_get_u16 (&bits
);
144 g_print (" %4u %5u remove\n", j
, swfdec_bits_get_u16 (&bits
));
147 case SWFDEC_TAG_SHOWFRAME
:
150 case SWFDEC_TAG_STARTSOUND
:
151 /* FIXME add info about what sound etc */
152 g_print (" %4u start sound\n", j
);
155 g_assert_not_reached ();
162 dump_path (cairo_path_t
*path
)
165 cairo_path_data_t
*data
= path
->data
;
168 for (i
= 0; i
< path
->num_data
; i
++) {
170 switch (data
[i
].header
.type
) {
171 case CAIRO_PATH_CURVE_TO
:
172 g_print (" curve %g %g (%g %g . %g %g)\n",
173 data
[i
+ 3].point
.x
, data
[i
+ 3].point
.y
,
174 data
[i
+ 1].point
.x
, data
[i
+ 1].point
.y
,
175 data
[i
+ 2].point
.x
, data
[i
+ 2].point
.y
);
178 case CAIRO_PATH_LINE_TO
:
180 case CAIRO_PATH_MOVE_TO
:
184 g_print (" %s %g %g\n", name
, data
[i
].point
.x
, data
[i
].point
.y
);
186 case CAIRO_PATH_CLOSE_PATH
:
187 g_print (" close\n");
190 g_assert_not_reached ();
197 dump_shape (SwfdecShape
*shape
)
201 for (walk
= shape
->draws
; walk
; walk
= walk
->next
) {
202 if (SWFDEC_IS_PATTERN (walk
->data
)) {
203 SwfdecPattern
*pattern
= walk
->data
;
204 char *str
= swfdec_pattern_to_string (pattern
);
205 g_print ("%s\n", str
);
208 g_print (" %g %g %g %g %g %g\n",
209 pattern
->start_transform
.xx
, pattern
->start_transform
.xy
,
210 pattern
->start_transform
.yx
, pattern
->start_transform
.yy
,
211 pattern
->start_transform
.x0
, pattern
->start_transform
.y0
);
213 } else if (SWFDEC_IS_STROKE (walk
->data
)) {
214 SwfdecStroke
*line
= walk
->data
;
215 g_print ("line (width %u, color #%08X)\n", line
->start_width
, line
->start_color
);
217 g_print ("not filled\n");
220 dump_path (&SWFDEC_DRAW (walk
->data
)->path
);
226 dump_text_field (SwfdecTextField
*text
)
228 g_print (" %s\n", text
->input
? text
->input
: "");
231 g_print (" variable %s\n", text
->variable
);
233 g_print (" no variable\n");
238 dump_text (SwfdecText
*text
)
241 gunichar2 uni
[text
->glyphs
->len
];
244 for (i
= 0; i
< text
->glyphs
->len
; i
++) {
245 SwfdecTextGlyph
*glyph
= &g_array_index (text
->glyphs
, SwfdecTextGlyph
, i
);
246 uni
[i
] = g_array_index (glyph
->font
->glyphs
, SwfdecFontEntry
, glyph
->glyph
).value
;
250 s
= g_utf16_to_utf8 (uni
, text
->glyphs
->len
, NULL
, NULL
, NULL
);
253 g_print (" text: %s\n", s
);
258 g_print (" %u characters\n", text
->glyphs
->len
);
262 dump_font (SwfdecFont
*font
)
266 g_print (" %s\n", font
->name
);
267 g_print (" %u characters\n", font
->glyphs
->len
);
269 for (i
= 0; i
< font
->glyphs
->len
; i
++) {
270 gunichar2 c
= g_array_index (font
->glyphs
, SwfdecFontEntry
, i
).value
;
272 if (c
== 0 || (s
= g_utf16_to_utf8 (&c
, 1, NULL
, NULL
, NULL
)) == NULL
) {
284 dump_button (SwfdecButton
*button
)
288 #define SWFDEC_CONTENT_IN_STATE(content, state) \
289 ((content)->sequence->start <= state && \
290 (content)->sequence->end > state)
292 for (walk
= button
->records
; walk
; walk
= walk
->next
) {
293 SwfdecContent
*content
= walk
->data
;
295 g_print (" %s %s %s %s %s %d\n",
296 SWFDEC_CONTENT_IN_STATE (content
, SWFDEC_BUTTON_UP
) ? "U" : " ",
297 SWFDEC_CONTENT_IN_STATE (content
, SWFDEC_BUTTON_OVER
) ? "O" : " ",
298 SWFDEC_CONTENT_IN_STATE (content
, SWFDEC_BUTTON_DOWN
) ? "D" : " ",
299 SWFDEC_CONTENT_IN_STATE (content
, SWFDEC_BUTTON_HIT
) ? "H" : " ",
300 G_OBJECT_TYPE_NAME (content
->graphic
), SWFDEC_CHARACTER (content
->graphic
)->id
);
306 get_image_type_name (SwfdecImageType type
)
309 case SWFDEC_IMAGE_TYPE_JPEG
:
310 return "JPEG with global table";
311 case SWFDEC_IMAGE_TYPE_JPEG2
:
313 case SWFDEC_IMAGE_TYPE_JPEG3
:
314 return "JPEG with alpha";
315 case SWFDEC_IMAGE_TYPE_LOSSLESS
:
317 case SWFDEC_IMAGE_TYPE_LOSSLESS2
:
318 return "lossless with alpha";
319 case SWFDEC_IMAGE_TYPE_PNG
:
321 case SWFDEC_IMAGE_TYPE_UNKNOWN
:
323 g_assert_not_reached ();
329 dump_image (SwfdecImage
*image
)
331 cairo_surface_destroy (swfdec_image_create_surface (image
));
332 g_print (" %s %u x %u\n", get_image_type_name (image
->type
),
333 image
->width
, image
->height
);
337 dump_object (gpointer value
, gpointer dec
)
339 SwfdecCharacter
*c
= value
;
341 g_print ("%d: %s\n", c
->id
, G_OBJECT_TYPE_NAME (c
));
342 if (verbose
&& SWFDEC_IS_GRAPHIC (c
)) {
343 SwfdecGraphic
*graphic
= SWFDEC_GRAPHIC (c
);
344 g_print (" extents: %g %g %g %g\n", graphic
->extents
.x0
, graphic
->extents
.y0
,
345 graphic
->extents
.x1
, graphic
->extents
.y1
);
347 if (SWFDEC_IS_IMAGE (c
)) {
348 dump_image (SWFDEC_IMAGE (c
));
350 if (SWFDEC_IS_SPRITE (c
)) {
351 dump_sprite (dec
, SWFDEC_SPRITE (c
));
353 if (SWFDEC_IS_SHAPE(c
)) {
354 dump_shape(SWFDEC_SHAPE(c
));
356 if (SWFDEC_IS_TEXT (c
)) {
357 dump_text (SWFDEC_TEXT (c
));
359 if (SWFDEC_IS_TEXT_FIELD (c
)) {
360 dump_text_field (SWFDEC_TEXT_FIELD (c
));
362 if (SWFDEC_IS_FONT (c
)) {
363 dump_font (SWFDEC_FONT (c
));
365 if (SWFDEC_IS_BUTTON (c
)) {
366 dump_button (SWFDEC_BUTTON (c
));
368 if (SWFDEC_IS_SOUND (c
)) {
369 dump_sound (SWFDEC_SOUND (c
));
374 enqueue (gpointer key
, gpointer value
, gpointer listp
)
376 GList
**list
= listp
;
378 *list
= g_list_prepend (*list
, value
);
382 sort_by_id (gconstpointer a
, gconstpointer b
)
384 if (SWFDEC_CHARACTER (a
)->id
< SWFDEC_CHARACTER (b
)->id
)
390 main (int argc
, char *argv
[])
393 SwfdecPlayer
*player
;
394 GError
*error
= NULL
;
395 GOptionEntry options
[] = {
396 { "verbose", 'v', 0, G_OPTION_ARG_NONE
, &verbose
, "bew verbose", NULL
},
402 ctx
= g_option_context_new ("");
403 g_option_context_add_main_entries (ctx
, options
, "options");
404 g_option_context_parse (ctx
, &argc
, &argv
, &error
);
405 g_option_context_free (ctx
);
407 g_printerr ("Error parsing command line arguments: %s\n", error
->message
);
408 g_error_free (error
);
415 g_print ("usage: %s [OPTIONS] file\n", argv
[0]);
419 player
= swfdec_player_new_from_file (argv
[1]);
420 if (player
->resource
->loader
->error
) {
421 g_printerr ("Couldn't open file \"%s\": %s\n", argv
[1], player
->resource
->loader
->error
);
422 g_object_unref (player
);
426 swfdec_player_advance (player
, 0);
427 if (!swfdec_player_is_initialized (player
)) {
428 g_printerr ("File \"%s\" is not a SWF file\n", argv
[1]);
429 g_object_unref (player
);
433 s
= (SwfdecSwfDecoder
*) SWFDEC_MOVIE (player
->roots
->data
)->resource
->decoder
;
434 /* FIXME: can happen after a _root.loadMovie() call */
435 if (!SWFDEC_IS_SWF_DECODER (s
)) {
436 g_printerr ("Movie already unloaded from \"%s\"\n", argv
[1]);
437 g_object_unref (player
);
443 g_print (" version: %d\n", s
->version
);
444 g_print (" rate : %g fps\n", SWFDEC_DECODER (s
)->rate
/ 256.0);
445 g_print (" size : %ux%u pixels\n", SWFDEC_DECODER (s
)->width
, SWFDEC_DECODER (s
)->height
);
446 g_print ("objects:\n");
447 g_hash_table_foreach (s
->characters
, enqueue
, &list
);
448 list
= g_list_sort (list
, sort_by_id
);
449 g_list_foreach (list
, dump_object
, s
);
452 g_print ("main sprite:\n");
453 dump_sprite (s
, s
->main_sprite
);
454 g_object_unref (player
);