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
30 #include <liboil/liboil.h>
32 #include "swfdec_swf_decoder.h"
34 #include "swfdec_bits.h"
35 #include "swfdec_cached.h"
36 #include "swfdec_debug.h"
37 #include "swfdec_player_internal.h"
38 #include "swfdec_script.h"
39 #include "swfdec_script_internal.h"
40 #include "swfdec_sprite.h"
41 #include "swfdec_tag.h"
44 SWFDEC_STATE_INIT1
= 0,
46 SWFDEC_STATE_PARSE_FIRST_TAG
,
47 SWFDEC_STATE_PARSE_TAG
,
51 G_DEFINE_TYPE (SwfdecSwfDecoder
, swfdec_swf_decoder
, SWFDEC_TYPE_DECODER
)
54 swfdec_swf_decoder_dispose (GObject
*object
)
56 SwfdecSwfDecoder
*s
= SWFDEC_SWF_DECODER (object
);
58 g_hash_table_destroy (s
->characters
);
59 g_object_unref (s
->main_sprite
);
60 g_hash_table_destroy (s
->scripts
);
65 swfdec_buffer_unref (s
->buffer
);
70 swfdec_buffer_unref (s
->jpegtables
);
79 G_OBJECT_CLASS (swfdec_swf_decoder_parent_class
)->dispose (object
);
83 zalloc (void *opaque
, guint items
, guint size
)
85 return g_malloc (items
* size
);
89 zfree (void *opaque
, void *addr
)
95 swfdec_buffer_merge (const SwfdecBuffer
*front
, const SwfdecBuffer
*end
)
99 g_return_val_if_fail (front
!= NULL
, NULL
);
100 g_return_val_if_fail (end
!= NULL
, NULL
);
102 new = swfdec_buffer_new (front
->length
+ end
->length
);
104 memcpy (new->data
, front
->data
, front
->length
);
106 memcpy (new->data
+ front
->length
, end
->data
, end
->length
);
111 swfdec_swf_decoder_deflate (SwfdecSwfDecoder
* s
, SwfdecBuffer
*buffer
)
114 SwfdecDecoder
*dec
= SWFDEC_DECODER (s
);
116 if (s
->buffer
== NULL
) {
117 /* never written to */
118 g_assert (s
->state
== SWFDEC_STATE_INIT1
);
120 } else if (s
->state
== SWFDEC_STATE_INIT1
) {
121 /* not initialized yet */
122 SwfdecBuffer
*merge
= swfdec_buffer_merge (s
->buffer
, buffer
);
123 swfdec_buffer_unref (s
->buffer
);
124 swfdec_buffer_unref (buffer
);
126 } else if (s
->compressed
) {
127 s
->z
.next_in
= buffer
->data
;
128 s
->z
.avail_in
= buffer
->length
;
129 ret
= inflate (&s
->z
, Z_SYNC_FLUSH
);
131 SWFDEC_ERROR ("error uncompressing data: %s", s
->z
.msg
);
135 dec
->bytes_loaded
= s
->z
.total_out
+ 8;
136 swfdec_buffer_unref (buffer
);
138 guint max
= buffer
->length
;
140 if (dec
->bytes_loaded
+ max
> s
->buffer
->length
) {
141 SWFDEC_WARNING ("%"G_GSIZE_FORMAT
" bytes more than declared filesize",
142 dec
->bytes_loaded
+ max
- s
->buffer
->length
);
143 max
= s
->buffer
->length
- dec
->bytes_loaded
;
145 memcpy (s
->buffer
->data
+ dec
->bytes_loaded
, buffer
->data
, max
);
146 dec
->bytes_loaded
+= max
;
147 swfdec_buffer_unref (buffer
);
154 swf_inflate_init (SwfdecSwfDecoder
* s
)
161 ret
= inflateInit (z
);
162 SWFDEC_DEBUG ("inflateInit returned %d", ret
);
164 z
->next_out
= s
->buffer
->data
+ 8;
165 z
->avail_out
= s
->buffer
->length
- 8;
171 swfdec_swf_decoder_init_bits (SwfdecSwfDecoder
*dec
, SwfdecBits
*bits
)
173 swfdec_bits_init (bits
, dec
->buffer
);
174 bits
->end
= bits
->ptr
+ SWFDEC_DECODER (dec
)->bytes_loaded
;
175 bits
->ptr
+= dec
->bytes_parsed
;
176 g_assert (bits
->ptr
<= bits
->end
);
180 swfdec_swf_decoder_flush_bits (SwfdecSwfDecoder
*dec
, SwfdecBits
*bits
)
182 g_assert (bits
->idx
== 0);
183 g_assert (bits
->buffer
== dec
->buffer
);
185 dec
->bytes_parsed
= bits
->ptr
- dec
->buffer
->data
;
186 g_assert (dec
->bytes_parsed
<= SWFDEC_DECODER (dec
)->bytes_loaded
);
190 swf_parse_header1 (SwfdecSwfDecoder
* s
)
192 SwfdecDecoder
*dec
= SWFDEC_DECODER (s
);
193 int sig1
, sig2
, sig3
;
194 SwfdecBuffer
*buffer
, *rest
;
198 g_assert (s
->buffer
!= NULL
);
199 if (s
->buffer
->length
<= 8) {
200 return SWFDEC_STATUS_NEEDBITS
;
203 swfdec_bits_init (&bits
, s
->buffer
);
205 sig1
= swfdec_bits_get_u8 (&bits
);
206 sig2
= swfdec_bits_get_u8 (&bits
);
207 sig3
= swfdec_bits_get_u8 (&bits
);
208 if ((sig1
!= 'F' && sig1
!= 'C') || sig2
!= 'W' || sig3
!= 'S') {
209 return SWFDEC_STATUS_ERROR
;
212 s
->version
= swfdec_bits_get_u8 (&bits
);
213 dec
->bytes_total
= swfdec_bits_get_u32 (&bits
);
214 if (dec
->bytes_total
<= 8) {
215 SWFDEC_ERROR ("Joke? Flash files need to be bigger than %u bytes", dec
->bytes_total
);
216 dec
->bytes_total
= 0;
217 return SWFDEC_STATUS_ERROR
;
219 rest
= swfdec_bits_get_buffer (&bits
, -1);
221 data
= g_try_malloc (dec
->bytes_total
);
223 return SWFDEC_STATUS_ERROR
;
224 buffer
= swfdec_buffer_new_for_data (data
, dec
->bytes_total
);
225 memcpy (buffer
->data
, s
->buffer
->data
, 8);
226 swfdec_buffer_unref (s
->buffer
);
229 s
->compressed
= (sig1
== 'C');
231 SWFDEC_DEBUG ("compressed");
232 if (!swf_inflate_init (s
))
233 return SWFDEC_STATUS_ERROR
;
235 SWFDEC_DEBUG ("not compressed");
237 SWFDEC_DECODER (s
)->bytes_loaded
= 8;
239 s
->state
= SWFDEC_STATE_INIT2
;
240 swfdec_swf_decoder_deflate (s
, rest
);
241 dec
->data_type
= SWFDEC_LOADER_DATA_SWF
;
243 return SWFDEC_STATUS_OK
;
247 swf_parse_header2 (SwfdecSwfDecoder
* s
)
251 SwfdecDecoder
*dec
= SWFDEC_DECODER (s
);
253 swfdec_swf_decoder_init_bits (s
, &s
->b
);
254 n
= swfdec_bits_peekbits (&s
->b
, 5);
255 /* rect rate + total_frames */
256 n
= ((5 + 4 * n
+ 7) / 8 + (2 + 2)) * 8;
257 if (swfdec_bits_left (&s
->b
) < n
)
258 return SWFDEC_STATUS_NEEDBITS
;
260 swfdec_bits_get_rect (&s
->b
, &rect
);
261 if (rect
.x0
!= 0.0 || rect
.y0
!= 0.0)
262 SWFDEC_ERROR ("SWF window doesn't start at 0 0 but at %g %g", rect
.x0
, rect
.y0
);
263 SWFDEC_INFO ("SWF size: %g x %g pixels", rect
.x1
/ SWFDEC_TWIPS_SCALE_FACTOR
,
264 rect
.y1
/ SWFDEC_TWIPS_SCALE_FACTOR
);
265 dec
->width
= MAX (0, ceil (rect
.x1
/ SWFDEC_TWIPS_SCALE_FACTOR
));
266 dec
->height
= MAX (0, ceil (rect
.y1
/ SWFDEC_TWIPS_SCALE_FACTOR
));
267 swfdec_bits_syncbits (&s
->b
);
268 dec
->rate
= swfdec_bits_get_u16 (&s
->b
);
269 if (dec
->rate
== 0) {
270 SWFDEC_INFO ("rate is 0, setting to 65536");
273 SWFDEC_LOG ("rate = %g", dec
->rate
/ 256.0);
274 dec
->frames_total
= swfdec_bits_get_u16 (&s
->b
);
275 SWFDEC_LOG ("n_frames = %d", dec
->frames_total
);
276 swfdec_sprite_set_n_frames (s
->main_sprite
, dec
->frames_total
, dec
->rate
);
278 swfdec_swf_decoder_flush_bits (s
, &s
->b
);
280 s
->state
= SWFDEC_STATE_PARSE_FIRST_TAG
;
281 return SWFDEC_STATUS_INIT
;
285 swfdec_swf_decoder_parse_one (SwfdecSwfDecoder
*s
)
287 int ret
= SWFDEC_STATUS_OK
;
292 case SWFDEC_STATE_INIT1
:
293 ret
= swf_parse_header1 (s
);
295 case SWFDEC_STATE_INIT2
:
296 ret
= swf_parse_header2 (s
);
298 case SWFDEC_STATE_PARSE_FIRST_TAG
:
299 case SWFDEC_STATE_PARSE_TAG
:
308 /* we're parsing tags */
309 swfdec_swf_decoder_init_bits (s
, &bits
);
310 if (swfdec_bits_left (&bits
) < 2 * 8)
311 return SWFDEC_STATUS_NEEDBITS
;
313 x
= swfdec_bits_get_u16 (&bits
);
315 SWFDEC_DEBUG ("tag %d %s", tag
, swfdec_swf_decoder_get_tag_name (tag
));
317 if (tag_len
== 0x3f) {
318 if (swfdec_bits_left (&bits
) < 4 * 8)
319 return SWFDEC_STATUS_NEEDBITS
;
321 tag_len
= swfdec_bits_get_u32 (&bits
);
327 SWFDEC_INFO ("parsing at %d, tag %d %s, length %d",
328 s
->bytes_parsed
, tag
,
329 swfdec_swf_decoder_get_tag_name (tag
), tag_len
);
331 if (swfdec_bits_left (&bits
) / 8 < tag_len
)
332 return SWFDEC_STATUS_NEEDBITS
;
334 swfdec_bits_init_bits (&s
->b
, &bits
, tag_len
);
335 swfdec_swf_decoder_flush_bits (s
, &bits
);
337 func
= swfdec_swf_decoder_get_tag_func (tag
);
339 s
->state
= SWFDEC_STATE_EOF
;
340 } else if ((swfdec_swf_decoder_get_tag_flag (tag
) & SWFDEC_TAG_FIRST_ONLY
)
341 && s
->state
== SWFDEC_STATE_PARSE_TAG
) {
342 SWFDEC_WARNING ("tag %d %s must be first tag in file, ignoring",
343 tag
, swfdec_swf_decoder_get_tag_name (tag
));
344 } else if (func
== NULL
) {
345 SWFDEC_FIXME ("tag function not implemented for %d %s",
346 tag
, swfdec_swf_decoder_get_tag_name (tag
));
347 } else if (s
->main_sprite
->parse_frame
< s
->main_sprite
->n_frames
) {
348 s
->parse_sprite
= s
->main_sprite
;
350 s
->parse_sprite
= NULL
;
352 if (swfdec_bits_left (&s
->b
)) {
354 ("early finish (%d bytes) at %d, tag %d %s, length %d",
355 swfdec_bits_left (&s
->b
) / 8,
356 s
->bytes_parsed
, tag
,
357 swfdec_swf_decoder_get_tag_name (tag
), tag_len
);
360 ret
= SWFDEC_STATE_EOF
;
361 SWFDEC_ERROR ("data after last frame");
363 s
->state
= SWFDEC_STATE_PARSE_TAG
;
367 case SWFDEC_STATE_EOF
:
368 if (s
->bytes_parsed
< SWFDEC_DECODER (s
)->bytes_loaded
) {
369 SWFDEC_WARNING ("%u bytes after EOF", SWFDEC_DECODER (s
)->bytes_loaded
- s
->bytes_parsed
);
371 return SWFDEC_STATUS_EOF
;
373 g_assert_not_reached ();
377 SWFDEC_DECODER (s
)->frames_loaded
= s
->main_sprite
->parse_frame
;
383 swfdec_swf_decoder_parse (SwfdecDecoder
*dec
, SwfdecBuffer
*buffer
)
385 SwfdecSwfDecoder
*s
= SWFDEC_SWF_DECODER (dec
);
386 SwfdecStatus status
= 0;
388 swfdec_swf_decoder_deflate (s
, buffer
);
390 status
|= swfdec_swf_decoder_parse_one (s
);
391 } while ((status
& (SWFDEC_STATUS_EOF
| SWFDEC_STATUS_NEEDBITS
| SWFDEC_STATUS_ERROR
)) == 0);
396 swfdec_swf_decoder_eof (SwfdecDecoder
*dec
)
398 if (dec
->bytes_loaded
< dec
->bytes_total
) {
399 SWFDEC_ERROR ("only %u of %u bytes provided, broken transmission?",
400 dec
->bytes_loaded
, dec
->bytes_total
);
407 swfdec_swf_decoder_class_init (SwfdecSwfDecoderClass
*class)
409 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
410 SwfdecDecoderClass
*decoder_class
= SWFDEC_DECODER_CLASS (class);
412 object_class
->dispose
= swfdec_swf_decoder_dispose
;
414 decoder_class
->parse
= swfdec_swf_decoder_parse
;
415 decoder_class
->eof
= swfdec_swf_decoder_eof
;
419 swfdec_swf_decoder_init (SwfdecSwfDecoder
*s
)
421 s
->main_sprite
= g_object_new (SWFDEC_TYPE_SPRITE
, NULL
);
423 s
->characters
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
424 NULL
, g_object_unref
);
425 s
->scripts
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
426 NULL
, (GDestroyNotify
) swfdec_script_unref
);
430 swfdec_swf_decoder_get_character (SwfdecSwfDecoder
* s
, guint id
)
432 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (s
), NULL
);
434 return g_hash_table_lookup (s
->characters
, GUINT_TO_POINTER (id
));
438 * swfdec_swf_decoder_create_character:
439 * @s: a #SwfdecDecoder
440 * @id: id of the character
441 * @type: the required type for the character
443 * Gets the character of the requested @type and with the given @id from @s.
444 * If there is already a different character with the given id, return NULL.
445 * If the character doesn't exist yet, create it.
447 * Returns: The requested character or NULL on failure;
450 swfdec_swf_decoder_create_character (SwfdecSwfDecoder
* s
, guint id
, GType type
)
452 SwfdecCharacter
*result
;
454 g_return_val_if_fail (SWFDEC_IS_DECODER (s
), NULL
);
455 g_return_val_if_fail (g_type_is_a (type
, SWFDEC_TYPE_CHARACTER
), NULL
);
457 SWFDEC_INFO (" id = %d", id
);
458 result
= swfdec_swf_decoder_get_character (s
, id
);
460 SWFDEC_WARNING ("character with id %d already exists", id
);
463 result
= g_object_new (type
, NULL
);
465 g_hash_table_insert (s
->characters
, GUINT_TO_POINTER (id
), result
);
471 swfdec_swf_decoder_add_script (SwfdecSwfDecoder
*s
, SwfdecScript
*script
)
473 g_return_if_fail (SWFDEC_IS_SWF_DECODER (s
));
474 g_return_if_fail (script
!= NULL
);
475 g_return_if_fail (script
->buffer
!= NULL
);
477 g_hash_table_insert (s
->scripts
, (gpointer
) script
->main
, script
);
481 swfdec_swf_decoder_get_script (SwfdecSwfDecoder
*s
, guint8
*data
)
483 g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (s
), NULL
);
484 g_return_val_if_fail (data
!= NULL
, NULL
);
486 return g_hash_table_lookup (s
->scripts
, data
);