📄 swfdec_swf_decoder.c
字号:
/* Swfdec * Copyright (C) 2003-2006 David Schleef <ds@schleef.org> * 2005-2006 Eric Anholt <eric@anholt.net> * 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <zlib.h>#include <math.h>#include <string.h>#include <stdlib.h>#include <liboil/liboil.h>#include "swfdec_swf_decoder.h"#include "swfdec.h"#include "swfdec_bits.h"#include "swfdec_cached.h"#include "swfdec_debug.h"#include "swfdec_player_internal.h"#include "swfdec_script.h"#include "swfdec_script_internal.h"#include "swfdec_sprite.h"enum { SWFDEC_STATE_INIT1 = 0, SWFDEC_STATE_INIT2, SWFDEC_STATE_PARSETAG, SWFDEC_STATE_EOF,};G_DEFINE_TYPE (SwfdecSwfDecoder, swfdec_swf_decoder, SWFDEC_TYPE_DECODER)static voidswfdec_swf_decoder_dispose (GObject *object){ SwfdecSwfDecoder *s = SWFDEC_SWF_DECODER (object); guint i,j; if (s->root_actions) { for (i = 0; i < s->main_sprite->n_frames; i++) { GArray *array = s->root_actions[i]; if (array) { for (j = 0; j < array->len; j++) { SwfdecRootAction *action = &g_array_index (array, SwfdecRootAction, j); switch (action->type) { case SWFDEC_ROOT_ACTION_EXPORT: { SwfdecRootExportData *data = action->data; g_free (data->name); g_object_unref (data->character); g_free (data); } break; case SWFDEC_ROOT_ACTION_INIT_SCRIPT: swfdec_script_unref (action->data); break; default: g_assert_not_reached (); break; } } g_array_free (array, TRUE); } } g_free (s->root_actions); s->root_actions = NULL; } g_hash_table_destroy (s->characters); g_object_unref (s->main_sprite); g_hash_table_destroy (s->scripts); if (s->uncompressed_buffer) { inflateEnd (&s->z); swfdec_buffer_unref (s->uncompressed_buffer); s->uncompressed_buffer = NULL; } swfdec_buffer_queue_unref (s->input_queue); if (s->jpegtables) { swfdec_buffer_unref (s->jpegtables); } g_free (s->password); G_OBJECT_CLASS (swfdec_swf_decoder_parent_class)->dispose (object);}static void *zalloc (void *opaque, guint items, guint size){ return g_malloc (items * size);}static voidzfree (void *opaque, void *addr){ g_free (addr);}static gbooleanswfdec_swf_decoder_deflate_all (SwfdecSwfDecoder * s){ int ret; SwfdecBuffer *buffer; SwfdecDecoder *dec = SWFDEC_DECODER (s); while ((buffer = swfdec_buffer_queue_pull_buffer (SWFDEC_DECODER (s)->queue))) { if (s->compressed) { int offset = s->z.total_out; s->z.next_in = buffer->data; s->z.avail_in = buffer->length; ret = inflate (&s->z, Z_SYNC_FLUSH); if (ret < Z_OK) { SWFDEC_ERROR ("error uncompressing data: %s", s->z.msg); return FALSE; } swfdec_buffer_unref (buffer); buffer = swfdec_buffer_new_subbuffer (s->uncompressed_buffer, offset, s->z.total_out - offset); } dec->bytes_loaded += buffer->length; swfdec_buffer_queue_push (s->input_queue, buffer); } return TRUE;}static gbooleanswf_inflate_init (SwfdecSwfDecoder * s){ SwfdecDecoder *dec = SWFDEC_DECODER (s); z_stream *z; int ret; guint8 *data; data = g_try_malloc (dec->bytes_total - 8); if (data == NULL) return FALSE; s->uncompressed_buffer = swfdec_buffer_new_for_data (data, dec->bytes_total - 8); z = &s->z; z->zalloc = zalloc; z->zfree = zfree; ret = inflateInit (z); SWFDEC_DEBUG ("inflateInit returned %d", ret); z->next_out = s->uncompressed_buffer->data; z->avail_out = s->uncompressed_buffer->length; z->opaque = NULL; return TRUE;}static intswf_parse_header1 (SwfdecSwfDecoder * s){ SwfdecDecoder *dec = SWFDEC_DECODER (s); int sig1, sig2, sig3; SwfdecBuffer *buffer; /* NB: we're still reading from the original queue, since deflating is not initialized yet */ buffer = swfdec_buffer_queue_pull (dec->queue, 8); if (buffer == NULL) { return SWFDEC_STATUS_NEEDBITS; } s->b.buffer = buffer; s->b.ptr = buffer->data; s->b.idx = 0; s->b.end = buffer->data + buffer->length; sig1 = swfdec_bits_get_u8 (&s->b); sig2 = swfdec_bits_get_u8 (&s->b); sig3 = swfdec_bits_get_u8 (&s->b); s->version = swfdec_bits_get_u8 (&s->b); dec->bytes_total = swfdec_bits_get_u32 (&s->b); swfdec_buffer_unref (buffer); SWFDEC_DECODER (s)->bytes_loaded = 8; if ((sig1 != 'F' && sig1 != 'C') || sig2 != 'W' || sig3 != 'S') { return SWFDEC_STATUS_ERROR; } s->compressed = (sig1 == 'C'); if (s->compressed) { SWFDEC_DEBUG ("compressed"); if (!swf_inflate_init (s)) return SWFDEC_STATUS_ERROR; } else { SWFDEC_DEBUG ("not compressed"); } s->state = SWFDEC_STATE_INIT2; return SWFDEC_STATUS_OK;}static intswf_parse_header2 (SwfdecSwfDecoder * s){ int n; SwfdecBuffer *buffer; SwfdecRect rect; SwfdecDecoder *dec = SWFDEC_DECODER (s); buffer = swfdec_buffer_queue_peek (s->input_queue, 32); if (buffer == NULL) { return SWFDEC_STATUS_NEEDBITS; } swfdec_bits_init (&s->b, buffer); swfdec_bits_get_rect (&s->b, &rect); if (rect.x0 != 0.0 || rect.y0 != 0.0) SWFDEC_ERROR ("SWF window doesn't start at 0 0 but at %g %g", rect.x0, rect.y0); SWFDEC_INFO ("SWF size: %g x %g pixels", rect.x1 / SWFDEC_TWIPS_SCALE_FACTOR, rect.y1 / SWFDEC_TWIPS_SCALE_FACTOR); dec->width = MAX (0, ceil (rect.x1 / SWFDEC_TWIPS_SCALE_FACTOR)); dec->height = MAX (0, ceil (rect.y1 / SWFDEC_TWIPS_SCALE_FACTOR)); swfdec_bits_syncbits (&s->b); dec->rate = swfdec_bits_get_u16 (&s->b); if (dec->rate == 0) { SWFDEC_INFO ("rate is 0, setting to 1"); dec->rate = 1; } SWFDEC_LOG ("rate = %g", dec->rate / 256.0); dec->frames_total = swfdec_bits_get_u16 (&s->b); SWFDEC_LOG ("n_frames = %d", dec->frames_total); n = s->b.ptr - s->b.buffer->data; swfdec_buffer_unref (buffer); buffer = swfdec_buffer_queue_pull (s->input_queue, n); swfdec_buffer_unref (buffer); swfdec_sprite_set_n_frames (s->main_sprite, dec->frames_total, dec->rate); s->state = SWFDEC_STATE_PARSETAG; return SWFDEC_STATUS_INIT;}static SwfdecStatusswfdec_swf_decoder_parse (SwfdecDecoder *dec){ SwfdecSwfDecoder *s = SWFDEC_SWF_DECODER (dec); int ret = SWFDEC_STATUS_OK; SwfdecBuffer *buffer; s->b = s->parse; g_assert (dec->player); switch (s->state) { case SWFDEC_STATE_INIT1: ret = swf_parse_header1 (s); break; case SWFDEC_STATE_INIT2: if (!swfdec_swf_decoder_deflate_all (s)) return SWFDEC_STATUS_ERROR; ret = swf_parse_header2 (s); break; case SWFDEC_STATE_PARSETAG: { guint header_length; guint x; SwfdecTagFunc func; guint tag; guint tag_len; if (!swfdec_swf_decoder_deflate_all (s)) return SWFDEC_STATUS_ERROR; /* we're parsing tags */ buffer = swfdec_buffer_queue_peek (s->input_queue, 2); if (buffer == NULL) { return SWFDEC_STATUS_NEEDBITS; } swfdec_bits_init (&s->b, buffer); x = swfdec_bits_get_u16 (&s->b); tag = (x >> 6) & 0x3ff; SWFDEC_DEBUG ("tag %d %s", tag, swfdec_swf_decoder_get_tag_name (tag)); tag_len = x & 0x3f; if (tag_len == 0x3f) { swfdec_buffer_unref (buffer); buffer = swfdec_buffer_queue_peek (s->input_queue, 6); if (buffer == NULL) { return SWFDEC_STATUS_NEEDBITS; } swfdec_bits_init (&s->b, buffer); swfdec_bits_get_u16 (&s->b); tag_len = swfdec_bits_get_u32 (&s->b); header_length = 6; } else { header_length = 2; } swfdec_buffer_unref (buffer); SWFDEC_INFO ("parsing at %d, tag %d %s, length %d", swfdec_buffer_queue_get_offset (s->input_queue), tag, swfdec_swf_decoder_get_tag_name (tag), tag_len); if (swfdec_buffer_queue_get_depth (s->input_queue) < tag_len + header_length) { return SWFDEC_STATUS_NEEDBITS; } buffer = swfdec_buffer_queue_pull (s->input_queue, header_length); swfdec_buffer_unref (buffer); if (tag_len > 0) buffer = swfdec_buffer_queue_pull (s->input_queue, tag_len); else buffer = NULL; swfdec_bits_init (&s->b, buffer); func = swfdec_swf_decoder_get_tag_func (tag); if (tag == 0) { s->state = SWFDEC_STATE_EOF; } else if (func == NULL) { SWFDEC_WARNING ("tag function not implemented for %d %s", tag, swfdec_swf_decoder_get_tag_name (tag)); } else if (s->main_sprite->parse_frame < s->main_sprite->n_frames) { s->parse_sprite = s->main_sprite; ret = func (s, tag); s->parse_sprite = NULL; swfdec_bits_syncbits (&s->b); if (swfdec_bits_left (&s->b)) { SWFDEC_WARNING ("early finish (%d bytes) at %d, tag %d %s, length %d", swfdec_bits_left (&s->b) / 8, swfdec_buffer_queue_get_offset (s->input_queue), tag, swfdec_swf_decoder_get_tag_name (tag), tag_len); } } else { ret = SWFDEC_STATE_EOF; SWFDEC_ERROR ("data after last frame"); } if (buffer) swfdec_buffer_unref (buffer); } break; case SWFDEC_STATE_EOF: if (swfdec_buffer_queue_get_depth (s->input_queue) > 0) { SWFDEC_WARNING ("%u bytes after EOF", swfdec_buffer_queue_get_depth (s->input_queue)); swfdec_buffer_queue_clear (s->input_queue); } return SWFDEC_STATUS_EOF; } /* copy state */ dec->frames_loaded = s->main_sprite->parse_frame; return ret;}static voidswfdec_swf_decoder_class_init (SwfdecSwfDecoderClass *class){ GObjectClass *object_class = G_OBJECT_CLASS (class); SwfdecDecoderClass *decoder_class = SWFDEC_DECODER_CLASS (class); object_class->dispose = swfdec_swf_decoder_dispose; decoder_class->parse = swfdec_swf_decoder_parse;}static voidswfdec_swf_decoder_init (SwfdecSwfDecoder *s){ s->main_sprite = g_object_new (SWFDEC_TYPE_SPRITE, NULL); s->characters = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); s->input_queue = swfdec_buffer_queue_new (); s->scripts = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) swfdec_script_unref);}gpointerswfdec_swf_decoder_get_character (SwfdecSwfDecoder * s, guint id){ g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (s), NULL); return g_hash_table_lookup (s->characters, GUINT_TO_POINTER (id));}/** * swfdec_swf_decoder_create_character: * @s: a #SwfdecDecoder * @id: id of the character * @type: the required type for the character * * Gets the character of the requested @type and with the given @id from @s. * If there is already a different character with the given id, return NULL. * If the character doesn't exist yet, create it. * * Returns: The requested character or NULL on failure; **/gpointerswfdec_swf_decoder_create_character (SwfdecSwfDecoder * s, guint id, GType type){ SwfdecCharacter *result; g_return_val_if_fail (SWFDEC_IS_DECODER (s), NULL); g_return_val_if_fail (g_type_is_a (type, SWFDEC_TYPE_CHARACTER), NULL); SWFDEC_INFO (" id = %d", id); result = swfdec_swf_decoder_get_character (s, id); if (result) { SWFDEC_WARNING ("character with id %d already exists", id); return NULL; } result = g_object_new (type, NULL); result->id = id; g_hash_table_insert (s->characters, GUINT_TO_POINTER (id), result); if (SWFDEC_IS_CACHED (result)) { swfdec_cached_set_cache (SWFDEC_CACHED (result), SWFDEC_DECODER (s)->player->cache); } return result;}voidswfdec_swf_decoder_add_root_action (SwfdecSwfDecoder *s, SwfdecRootActionType type, gpointer data){ SwfdecSprite *sprite; GArray *array; SwfdecRootAction action; g_return_if_fail (SWFDEC_IS_SWF_DECODER (s)); sprite = s->main_sprite; g_return_if_fail (sprite->parse_frame < sprite->n_frames); if (s->root_actions == NULL) s->root_actions = g_new0 (GArray *, sprite->n_frames); array = s->root_actions[sprite->parse_frame]; if (array == NULL) { s->root_actions[sprite->parse_frame] = g_array_new (FALSE, FALSE, sizeof (SwfdecRootAction)); array = s->root_actions[sprite->parse_frame]; } action.type = type; action.data = data; g_array_append_val (array, action);}voidswfdec_swf_decoder_add_script (SwfdecSwfDecoder *s, SwfdecScript *script){ g_return_if_fail (SWFDEC_IS_SWF_DECODER (s)); g_return_if_fail (script != NULL); g_return_if_fail (script->buffer != NULL); g_hash_table_insert (s->scripts, script->buffer->data, script);}SwfdecScript *swfdec_swf_decoder_get_script (SwfdecSwfDecoder *s, guint8 *data){ g_return_val_if_fail (SWFDEC_IS_SWF_DECODER (s), NULL); g_return_val_if_fail (data != NULL, NULL); return g_hash_table_lookup (s->scripts, data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -