add test for frames and bytes properties of empty movies
[swfdec.git] / test / swfedit_file.c
blobe257010f4cdf1e9c94ebd096f1497a187db8e320
1 /* Swfedit
2 * Copyright (C) 2007 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 <zlib.h>
26 #include "libswfdec/swfdec_bits.h"
27 #include "libswfdec/swfdec_buffer.h"
28 #include "libswfdec/swfdec_debug.h"
29 #include "libswfdec/swfdec_swf_decoder.h"
30 #include "swfdec_out.h"
31 #include "swfedit_file.h"
32 #include "swfedit_tag.h"
34 G_DEFINE_TYPE (SwfeditFile, swfedit_file, SWFEDIT_TYPE_TOKEN)
36 static void
37 swfedit_file_dispose (GObject *object)
39 SwfeditFile *file = SWFEDIT_FILE (object);
41 g_free (file->filename);
43 G_OBJECT_CLASS (swfedit_file_parent_class)->dispose (object);
46 static void *
47 zalloc (void *opaque, unsigned int items, unsigned int size)
49 return g_malloc (items * size);
52 static void
53 zfree (void *opaque, void *addr)
55 g_free (addr);
58 static SwfdecBuffer *
59 swfenc_file_inflate (SwfdecBits *bits, guint size)
61 SwfdecBuffer *decoded, *encoded;
62 z_stream z;
63 int ret;
65 encoded = swfdec_bits_get_buffer (bits, -1);
66 if (encoded == NULL)
67 return NULL;
68 decoded = swfdec_buffer_new_and_alloc (size);
69 z.zalloc = zalloc;
70 z.zfree = zfree;
71 z.opaque = NULL;
72 z.next_in = encoded->data;
73 z.avail_in = encoded->length;
74 z.next_out = decoded->data;
75 z.avail_out = decoded->length;
76 ret = inflateInit (&z);
77 SWFDEC_DEBUG ("inflateInit returned %d", ret);
78 if (ret >= Z_OK) {
79 ret = inflate (&z, Z_SYNC_FLUSH);
80 SWFDEC_DEBUG ("inflate returned %d", ret);
82 inflateEnd (&z);
83 swfdec_buffer_unref (encoded);
84 if (ret < Z_OK) {
85 swfdec_buffer_unref (decoded);
86 return NULL;
88 return decoded;
91 static SwfdecBuffer *
92 swf_parse_header1 (SwfeditFile *file, SwfdecBits *bits, GError **error)
94 guint sig1, sig2, sig3, bytes_total;
96 sig1 = swfdec_bits_get_u8 (bits);
97 sig2 = swfdec_bits_get_u8 (bits);
98 sig3 = swfdec_bits_get_u8 (bits);
99 if ((sig1 != 'F' && sig1 != 'C') || sig2 != 'W' || sig3 != 'S') {
100 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
101 "This is not a SWF file");
102 return NULL;
105 swfedit_token_add (SWFEDIT_TOKEN (file), "version", SWFEDIT_TOKEN_UINT8,
106 GUINT_TO_POINTER (swfdec_bits_get_u8 (bits)));
107 bytes_total = swfdec_bits_get_u32 (bits) - 8;
109 if (sig1 == 'C') {
110 /* compressed */
111 SwfdecBuffer *ret = swfenc_file_inflate (bits, bytes_total);
112 if (ret == NULL)
113 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
114 "Unable to uncompress file");
115 return ret;
116 } else {
117 SwfdecBuffer *ret = swfdec_bits_get_buffer (bits, bytes_total);
118 if (ret == NULL)
119 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
120 "File too small");
121 return ret;
125 static void
126 swf_parse_header2 (SwfeditFile *file, SwfdecBits *bits)
128 swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rect", SWFEDIT_TOKEN_RECT, NULL);
129 swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "rate", SWFEDIT_TOKEN_UINT16, NULL);
130 swfedit_tag_read_token (SWFEDIT_TOKEN (file), bits, "frames", SWFEDIT_TOKEN_UINT16, NULL);
133 static gboolean
134 swfedit_file_parse (SwfeditFile *file, SwfdecBits *bits, GError **error)
136 SwfdecBuffer *next;
138 next = swf_parse_header1 (file, bits, error);
139 if (next == NULL)
140 return FALSE;
141 swfdec_bits_init (bits, next);
142 swf_parse_header2 (file, bits);
144 while (swfdec_bits_left (bits)) {
145 guint x = swfdec_bits_get_u16 (bits);
146 G_GNUC_UNUSED guint tag = (x >> 6) & 0x3ff;
147 guint tag_len = x & 0x3f;
148 SwfdecBuffer *buffer;
149 SwfeditTag *item;
151 if (tag_len == 0x3f)
152 tag_len = swfdec_bits_get_u32 (bits);
153 if (tag == 0)
154 break;
155 if (tag_len > 0)
156 buffer = swfdec_bits_get_buffer (bits, tag_len);
157 else
158 buffer = swfdec_buffer_new ();
159 if (buffer == NULL) {
160 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
161 "Invalid contents in file");
162 return FALSE;
164 item = swfedit_tag_new (SWFEDIT_TOKEN (file), tag, buffer);
165 swfedit_token_add (SWFEDIT_TOKEN (file),
166 swfdec_swf_decoder_get_tag_name (tag),
167 SWFEDIT_TOKEN_OBJECT, item);
169 swfdec_buffer_unref (next);
170 return TRUE;
173 static void
174 swfedit_file_class_init (SwfeditFileClass *class)
176 GObjectClass *object_class = G_OBJECT_CLASS (class);
178 object_class->dispose = swfedit_file_dispose;
181 static void
182 swfedit_file_init (SwfeditFile *s)
186 SwfeditFile *
187 swfedit_file_new (const char *filename, GError **error)
189 SwfeditFile *file;
190 SwfdecBuffer *buffer;
191 SwfdecBits bits;
192 char *absolute;
194 if (g_path_is_absolute (filename)) {
195 absolute = g_strdup (filename);
196 } else {
197 char *dir = g_get_current_dir ();
198 absolute = g_build_filename (dir, filename, NULL);
199 g_free (dir);
201 buffer = swfdec_buffer_new_from_file (filename, error);
202 if (buffer == NULL)
203 return NULL;
204 swfdec_bits_init (&bits, buffer);
205 file = g_object_new (SWFEDIT_TYPE_FILE, NULL);
206 file->filename = absolute;
207 if (!swfedit_file_parse (file, &bits, error)) {
208 swfdec_buffer_unref (buffer);
209 g_object_unref (file);
210 return NULL;
212 swfdec_buffer_unref (buffer);
213 return file;
216 static SwfdecBuffer *
217 swfedit_file_write (SwfeditFile *file)
219 guint i;
220 SwfeditToken *token = SWFEDIT_TOKEN (file);
221 SwfdecBufferQueue *queue;
222 SwfdecBuffer *buffer;
223 SwfdecOut *out;
225 queue = swfdec_buffer_queue_new ();
226 /* write second part of header */
227 out = swfdec_out_open ();
228 swfedit_tag_write_token (token, out, 1);
229 swfedit_tag_write_token (token, out, 2);
230 swfedit_tag_write_token (token, out, 3);
231 swfdec_buffer_queue_push (queue, swfdec_out_close (out));
233 for (i = 4; i < token->tokens->len; i++) {
234 SwfeditTokenEntry *entry = &g_array_index (token->tokens, SwfeditTokenEntry, i);
235 g_assert (entry->type == SWFEDIT_TOKEN_OBJECT);
237 buffer = swfedit_tag_write (entry->value);
238 out = swfdec_out_open ();
239 swfdec_out_put_u16 (out, SWFEDIT_TAG (entry->value)->tag << 6 |
240 MIN (buffer->length, 0x3f));
241 if (buffer->length >= 0x3f) {
242 swfdec_out_put_u32 (out, buffer->length);
244 swfdec_buffer_queue_push (queue, swfdec_out_close (out));
245 swfdec_buffer_queue_push (queue, buffer);
247 /* write closing tag */
248 buffer = swfdec_buffer_new_and_alloc0 (2);
249 swfdec_buffer_queue_push (queue, buffer);
251 /* FIXME: implement compression */
252 out = swfdec_out_open ();
253 swfdec_out_put_u8 (out, 'F');
254 swfdec_out_put_u8 (out, 'W');
255 swfdec_out_put_u8 (out, 'S');
256 swfedit_tag_write_token (token, out, 0);
257 swfdec_out_put_u32 (out, swfdec_buffer_queue_get_depth (queue) + 8);
258 swfdec_out_prepare_bytes (out, swfdec_buffer_queue_get_depth (queue));
259 while ((buffer = swfdec_buffer_queue_pull_buffer (queue))) {
260 swfdec_out_put_buffer (out, buffer);
261 swfdec_buffer_unref (buffer);
263 swfdec_buffer_queue_unref (queue);
264 return swfdec_out_close (out);
267 gboolean
268 swfedit_file_save (SwfeditFile *file, GError **error)
270 SwfdecBuffer *buffer;
271 gboolean ret;
273 g_return_val_if_fail (SWFEDIT_IS_FILE (file), FALSE);
275 buffer = swfedit_file_write (file);
276 if (buffer == NULL) {
277 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
278 "Failed to render file");
279 return FALSE;
281 ret = g_file_set_contents (file->filename, (char *) buffer->data,
282 buffer->length, error);
283 swfdec_buffer_unref (buffer);
284 return ret;
287 guint
288 swfedit_file_get_version (SwfeditFile *file)
290 SwfeditTokenEntry *entry;
292 g_return_val_if_fail (SWFEDIT_FILE (file), 3);
294 entry = &g_array_index (SWFEDIT_TOKEN (file)->tokens, SwfeditTokenEntry, 0);
295 return GPOINTER_TO_UINT (entry->value);