Decode whole buffers
[swfdec.git] / tools / dump.c
blobd70f9f7d5535cd1a89c2fd798ffe7cef9135969b
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2008 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
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <stdio.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/stat.h>
30 #include <glib.h>
31 #include <glib-object.h>
32 #include <swfdec/swfdec.h>
33 #include <swfdec/swfdec_audio_decoder.h>
34 #include <swfdec/swfdec_button.h>
35 #include <swfdec/swfdec_text_field.h>
36 #include <swfdec/swfdec_font.h>
37 #include <swfdec/swfdec_image.h>
38 #include <swfdec/swfdec_movie.h>
39 #include <swfdec/swfdec_player_internal.h>
40 #include <swfdec/swfdec_sprite.h>
41 #include <swfdec/swfdec_shape.h>
42 #include <swfdec/swfdec_sound.h>
43 #include <swfdec/swfdec_swf_decoder.h>
44 #include <swfdec/swfdec_resource.h>
45 #include <swfdec/swfdec_tag.h>
46 #include <swfdec/swfdec_text.h>
48 static gboolean verbose = FALSE;
50 static const char *
51 get_audio_format_name (guint codec)
53 switch (codec) {
54 case SWFDEC_AUDIO_CODEC_UNDEFINED:
55 return "Undefined";
56 case SWFDEC_AUDIO_CODEC_ADPCM:
57 return "ADPCM";
58 case SWFDEC_AUDIO_CODEC_MP3:
59 return "MP3";
60 case SWFDEC_AUDIO_CODEC_UNCOMPRESSED:
61 return "Uncompressed";
62 case SWFDEC_AUDIO_CODEC_NELLYMOSER_16KHZ:
63 return "Nellymoser 16kHz";
64 case SWFDEC_AUDIO_CODEC_NELLYMOSER_8KHZ:
65 return "Nellymoser 8kHz";
66 case SWFDEC_AUDIO_CODEC_NELLYMOSER:
67 return "Nellymoser";
68 case SWFDEC_AUDIO_CODEC_ALAW:
69 return "a-law";
70 case SWFDEC_AUDIO_CODEC_MULAW:
71 return "u-law";
72 case SWFDEC_AUDIO_CODEC_AAC:
73 return "AAC";
74 case SWFDEC_AUDIO_CODEC_SPEEX:
75 return "Speex";
76 case SWFDEC_AUDIO_CODEC_MP3_8KHZ:
77 return "MP3 8kHz";
78 default:
79 return "Unknown";
83 static void
84 dump_sound (SwfdecSound *sound)
86 g_print (" codec: %s\n", get_audio_format_name (sound->codec));
87 if (verbose) {
88 g_print (" format: %s\n", swfdec_audio_format_to_string (sound->format));
89 g_print (" samples: %u (%gs)\n", sound->n_samples,
90 (double) sound->n_samples / swfdec_audio_format_get_rate (sound->format));
94 static void
95 dump_sprite (SwfdecSwfDecoder *dec, SwfdecSprite *s)
97 if (!verbose) {
98 g_print (" %u frames\n", s->n_frames);
99 } else {
100 guint i, j, tag;
101 SwfdecBuffer *buffer;
103 j = 0;
104 for (i = 0; ; i++) {
105 if (!swfdec_sprite_get_action (s, i, &tag, &buffer))
106 break;
107 switch (tag) {
108 case SWFDEC_TAG_DOACTION:
109 g_print (" %4u script\n", j);
110 break;
111 case SWFDEC_TAG_PLACEOBJECT2:
112 case SWFDEC_TAG_PLACEOBJECT3:
114 SwfdecBits bits;
115 gboolean has_char, is_move;
116 guint depth;
118 swfdec_bits_init (&bits, buffer);
119 swfdec_bits_getbits (&bits, 6);
120 has_char = swfdec_bits_getbit (&bits);
121 is_move = swfdec_bits_getbit (&bits);
122 if (tag == SWFDEC_TAG_PLACEOBJECT3)
123 swfdec_bits_get_u8 (&bits);
124 depth = swfdec_bits_get_u16 (&bits);
125 g_print (" %4u %5u %s", j, depth, is_move ? "move" : "place");
126 if (has_char) {
127 SwfdecCharacter *c;
128 c = swfdec_swf_decoder_get_character (dec, swfdec_bits_get_u16 (&bits));
129 if (c)
130 g_print (" %s %u", G_OBJECT_TYPE_NAME (c), c->id);
132 g_print ("\n");
134 break;
135 case SWFDEC_TAG_REMOVEOBJECT:
136 case SWFDEC_TAG_REMOVEOBJECT2:
138 SwfdecBits bits;
139 swfdec_bits_init (&bits, buffer);
140 if (tag == SWFDEC_TAG_REMOVEOBJECT)
141 swfdec_bits_get_u16 (&bits);
142 g_print (" %4u %5u remove\n", j, swfdec_bits_get_u16 (&bits));
144 break;
145 case SWFDEC_TAG_SHOWFRAME:
146 j++;
147 break;
148 case SWFDEC_TAG_STARTSOUND:
149 /* FIXME add info about what sound etc */
150 g_print (" %4u start sound\n", j);
151 break;
152 case SWFDEC_TAG_EXPORTASSETS:
153 g_print (" %4u export\n", j);
154 break;
155 case SWFDEC_TAG_DOINITACTION:
156 g_print (" %4u init action\n", j);
157 break;
158 case SWFDEC_TAG_SETBACKGROUNDCOLOR:
159 g_print (" %4u background color\n", j);
160 break;
161 case SWFDEC_TAG_SOUNDSTREAMHEAD:
162 /* FIXME */
163 g_print (" %4u sound stream\n", j);
164 break;
165 case SWFDEC_TAG_SOUNDSTREAMHEAD2:
166 case SWFDEC_TAG_SOUNDSTREAMBLOCK:
167 break;
168 default:
169 g_assert_not_reached ();
175 static void
176 dump_path (cairo_path_t *path)
178 int i;
179 cairo_path_data_t *data = path->data;
180 const char *name;
182 for (i = 0; i < path->num_data; i++) {
183 name = NULL;
184 switch (data[i].header.type) {
185 case CAIRO_PATH_CURVE_TO:
186 g_print (" curve %g %g (%g %g . %g %g)\n",
187 data[i + 3].point.x, data[i + 3].point.y,
188 data[i + 1].point.x, data[i + 1].point.y,
189 data[i + 2].point.x, data[i + 2].point.y);
190 i += 3;
191 break;
192 case CAIRO_PATH_LINE_TO:
193 name = "line ";
194 case CAIRO_PATH_MOVE_TO:
195 if (!name)
196 name = "move ";
197 i++;
198 g_print (" %s %g %g\n", name, data[i].point.x, data[i].point.y);
199 break;
200 case CAIRO_PATH_CLOSE_PATH:
201 g_print (" close\n");
202 break;
203 default:
204 g_assert_not_reached ();
205 break;
210 static void
211 dump_shape (SwfdecShape *shape)
213 GSList *walk;
215 for (walk = shape->draws; walk; walk = walk->next) {
216 if (SWFDEC_IS_PATTERN (walk->data)) {
217 SwfdecPattern *pattern = walk->data;
218 char *str = swfdec_pattern_to_string (pattern);
219 g_print ("%s\n", str);
220 g_free (str);
221 if (verbose) {
222 g_print (" %g %g %g %g %g %g\n",
223 pattern->start_transform.xx, pattern->start_transform.xy,
224 pattern->start_transform.yx, pattern->start_transform.yy,
225 pattern->start_transform.x0, pattern->start_transform.y0);
227 } else if (SWFDEC_IS_STROKE (walk->data)) {
228 SwfdecStroke *line = walk->data;
229 g_print ("line (width %u, color #%08X)\n", line->start_width, line->start_color);
230 } else {
231 g_print ("not filled\n");
233 if (verbose) {
234 dump_path (&SWFDEC_DRAW (walk->data)->path);
239 static void
240 dump_text_field (SwfdecTextField *text)
242 g_print (" %s\n", text->input ? text->input : "");
243 if (verbose) {
244 if (text->variable)
245 g_print (" variable %s\n", text->variable);
246 else
247 g_print (" no variable\n");
251 static void
252 dump_text (SwfdecText *text)
254 guint i;
255 gunichar2 uni[text->glyphs->len];
256 char *s;
258 for (i = 0; i < text->glyphs->len; i++) {
259 SwfdecTextGlyph *glyph = &g_array_index (text->glyphs, SwfdecTextGlyph, i);
260 uni[i] = g_array_index (glyph->font->glyphs, SwfdecFontEntry, glyph->glyph).value;
261 if (uni[i] == 0)
262 goto fallback;
264 s = g_utf16_to_utf8 (uni, text->glyphs->len, NULL, NULL, NULL);
265 if (s == NULL)
266 goto fallback;
267 g_print (" text: %s\n", s);
268 g_free (s);
269 return;
271 fallback:
272 g_print (" %u characters\n", text->glyphs->len);
275 static void
276 dump_font (SwfdecFont *font)
278 unsigned int i;
279 if (font->name)
280 g_print (" %s\n", font->name);
281 g_print (" %u characters\n", font->glyphs->len);
282 if (verbose) {
283 for (i = 0; i < font->glyphs->len; i++) {
284 gunichar2 c = g_array_index (font->glyphs, SwfdecFontEntry, i).value;
285 char *s;
286 if (c == 0 || (s = g_utf16_to_utf8 (&c, 1, NULL, NULL, NULL)) == NULL) {
287 g_print (" ");
288 } else {
289 g_print ("%s ", s);
290 g_free (s);
293 g_print ("\n");
297 static void
298 dump_button (SwfdecButton *button)
302 static const char *
303 get_image_type_name (SwfdecImageType type)
305 switch (type) {
306 case SWFDEC_IMAGE_TYPE_JPEG:
307 return "JPEG with global table";
308 case SWFDEC_IMAGE_TYPE_JPEG2:
309 return "JPEG";
310 case SWFDEC_IMAGE_TYPE_JPEG3:
311 return "JPEG with alpha";
312 case SWFDEC_IMAGE_TYPE_LOSSLESS:
313 return "lossless";
314 case SWFDEC_IMAGE_TYPE_LOSSLESS2:
315 return "lossless with alpha";
316 case SWFDEC_IMAGE_TYPE_PNG:
317 return "PNG";
318 case SWFDEC_IMAGE_TYPE_UNKNOWN:
319 default:
320 g_assert_not_reached ();
321 return "Unknown";
325 static void
326 dump_image (SwfdecImage *image)
328 cairo_surface_destroy (swfdec_image_create_surface (image, NULL));
329 g_print (" %s %u x %u\n", get_image_type_name (image->type),
330 image->width, image->height);
333 static void
334 dump_object (gpointer value, gpointer dec)
336 SwfdecCharacter *c = value;
338 g_print ("%d: %s\n", c->id, G_OBJECT_TYPE_NAME (c));
339 if (verbose && SWFDEC_IS_GRAPHIC (c)) {
340 SwfdecGraphic *graphic = SWFDEC_GRAPHIC (c);
341 g_print (" extents: %g %g %g %g\n", graphic->extents.x0, graphic->extents.y0,
342 graphic->extents.x1, graphic->extents.y1);
344 if (SWFDEC_IS_IMAGE (c)) {
345 dump_image (SWFDEC_IMAGE (c));
347 if (SWFDEC_IS_SPRITE (c)) {
348 dump_sprite (dec, SWFDEC_SPRITE (c));
350 if (SWFDEC_IS_SHAPE(c)) {
351 dump_shape(SWFDEC_SHAPE(c));
353 if (SWFDEC_IS_TEXT (c)) {
354 dump_text (SWFDEC_TEXT (c));
356 if (SWFDEC_IS_TEXT_FIELD (c)) {
357 dump_text_field (SWFDEC_TEXT_FIELD (c));
359 if (SWFDEC_IS_FONT (c)) {
360 dump_font (SWFDEC_FONT (c));
362 if (SWFDEC_IS_BUTTON (c)) {
363 dump_button (SWFDEC_BUTTON (c));
365 if (SWFDEC_IS_SOUND (c)) {
366 dump_sound (SWFDEC_SOUND (c));
370 static void
371 enqueue (gpointer key, gpointer value, gpointer listp)
373 GList **list = listp;
375 *list = g_list_prepend (*list, value);
378 static int
379 sort_by_id (gconstpointer a, gconstpointer b)
381 if (SWFDEC_CHARACTER (a)->id < SWFDEC_CHARACTER (b)->id)
382 return -1;
383 return 1;
387 main (int argc, char *argv[])
389 SwfdecSwfDecoder *s;
390 SwfdecPlayer *player;
391 GError *error = NULL;
392 GOptionEntry options[] = {
393 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "bew verbose", NULL },
394 { NULL }
396 GOptionContext *ctx;
397 GList *list = NULL;
398 SwfdecURL *url;
400 ctx = g_option_context_new ("");
401 g_option_context_add_main_entries (ctx, options, "options");
402 g_option_context_parse (ctx, &argc, &argv, &error);
403 g_option_context_free (ctx);
404 if (error) {
405 g_printerr ("Error parsing command line arguments: %s\n", error->message);
406 g_error_free (error);
407 return 1;
410 swfdec_init();
412 if(argc < 2){
413 g_print ("usage: %s [OPTIONS] file\n", argv[0]);
414 return 0;
417 player = swfdec_player_new (NULL);
418 url = swfdec_url_new_from_input (argv[1]);
419 swfdec_player_set_url (player, url);
420 swfdec_url_free (url);
421 /* FIXME: HACK! */
422 swfdec_player_advance (player, 0);
423 if (!swfdec_player_is_initialized (player)) {
424 g_printerr ("File \"%s\" is not a SWF file\n", argv[1]);
425 g_object_unref (player);
426 player = NULL;
427 return 1;
429 s = (SwfdecSwfDecoder *) SWFDEC_MOVIE (player->priv->roots->data)->resource->decoder;
430 /* FIXME: can happen after a _root.loadMovie() call */
431 if (!SWFDEC_IS_SWF_DECODER (s)) {
432 g_printerr ("Movie already unloaded from \"%s\"\n", argv[1]);
433 g_object_unref (player);
434 player = NULL;
435 return 1;
438 g_print ("file:\n");
439 g_print (" version: %d\n", s->version);
440 g_print (" rate : %g fps\n", SWFDEC_DECODER (s)->rate / 256.0);
441 g_print (" size : %ux%u pixels\n", SWFDEC_DECODER (s)->width, SWFDEC_DECODER (s)->height);
442 g_print ("objects:\n");
443 g_hash_table_foreach (s->characters, enqueue, &list);
444 list = g_list_sort (list, sort_by_id);
445 g_list_foreach (list, dump_object, s);
446 g_list_free (list);
448 g_print ("main sprite:\n");
449 dump_sprite (s, s->main_sprite);
450 g_object_unref (player);
451 s = NULL;
452 player = NULL;
454 return 0;