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.
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
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
)
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
);
47 zalloc (void *opaque
, unsigned int items
, unsigned int size
)
49 return g_malloc (items
* size
);
53 zfree (void *opaque
, void *addr
)
59 swfenc_file_inflate (SwfdecBits
*bits
, guint size
)
61 SwfdecBuffer
*decoded
, *encoded
;
65 encoded
= swfdec_bits_get_buffer (bits
, -1);
68 decoded
= swfdec_buffer_new_and_alloc (size
);
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
);
79 ret
= inflate (&z
, Z_SYNC_FLUSH
);
80 SWFDEC_DEBUG ("inflate returned %d", ret
);
83 swfdec_buffer_unref (encoded
);
85 swfdec_buffer_unref (decoded
);
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");
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;
111 SwfdecBuffer
*ret
= swfenc_file_inflate (bits
, bytes_total
);
113 g_set_error (error
, G_FILE_ERROR
, G_FILE_ERROR_FAILED
,
114 "Unable to uncompress file");
117 SwfdecBuffer
*ret
= swfdec_bits_get_buffer (bits
, bytes_total
);
119 g_set_error (error
, G_FILE_ERROR
, G_FILE_ERROR_FAILED
,
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
);
134 swfedit_file_parse (SwfeditFile
*file
, SwfdecBits
*bits
, GError
**error
)
138 next
= swf_parse_header1 (file
, bits
, error
);
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
;
152 tag_len
= swfdec_bits_get_u32 (bits
);
156 buffer
= swfdec_bits_get_buffer (bits
, tag_len
);
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");
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
);
174 swfedit_file_class_init (SwfeditFileClass
*class)
176 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
178 object_class
->dispose
= swfedit_file_dispose
;
182 swfedit_file_init (SwfeditFile
*s
)
187 swfedit_file_new (const char *filename
, GError
**error
)
190 SwfdecBuffer
*buffer
;
194 if (g_path_is_absolute (filename
)) {
195 absolute
= g_strdup (filename
);
197 char *dir
= g_get_current_dir ();
198 absolute
= g_build_filename (dir
, filename
, NULL
);
201 buffer
= swfdec_buffer_new_from_file (filename
, error
);
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
);
212 swfdec_buffer_unref (buffer
);
216 static SwfdecBuffer
*
217 swfedit_file_write (SwfeditFile
*file
)
220 SwfeditToken
*token
= SWFEDIT_TOKEN (file
);
221 SwfdecBufferQueue
*queue
;
222 SwfdecBuffer
*buffer
;
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
);
268 swfedit_file_save (SwfeditFile
*file
, GError
**error
)
270 SwfdecBuffer
*buffer
;
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");
281 ret
= g_file_set_contents (file
->filename
, (char *) buffer
->data
,
282 buffer
->length
, error
);
283 swfdec_buffer_unref (buffer
);
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
);