Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2020
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Management sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : #include <gpac/nodes_mpeg4.h>
28 : #include <gpac/internal/swf_dev.h>
29 : #include <gpac/avparse.h>
30 :
31 : #ifndef GPAC_DISABLE_SWF_IMPORT
32 :
33 :
34 : #include <zlib.h>
35 :
36 : enum
37 : {
38 : SWF_END = 0,
39 : SWF_SHOWFRAME = 1,
40 : SWF_DEFINESHAPE = 2,
41 : SWF_FREECHARACTER = 3,
42 : SWF_PLACEOBJECT = 4,
43 : SWF_REMOVEOBJECT = 5,
44 : SWF_DEFINEBITS = 6,
45 : SWF_DEFINEBITSJPEG = 6,
46 : SWF_DEFINEBUTTON = 7,
47 : SWF_JPEGTABLES = 8,
48 : SWF_SETBACKGROUNDCOLOR = 9,
49 : SWF_DEFINEFONT = 10,
50 : SWF_DEFINETEXT = 11,
51 : SWF_DOACTION = 12,
52 : SWF_DEFINEFONTINFO = 13,
53 : SWF_DEFINESOUND = 14,
54 : SWF_STARTSOUND = 15,
55 : SWF_DEFINEBUTTONSOUND = 17,
56 : SWF_SOUNDSTREAMHEAD = 18,
57 : SWF_SOUNDSTREAMBLOCK = 19,
58 : SWF_DEFINEBITSLOSSLESS = 20,
59 : SWF_DEFINEBITSJPEG2 = 21,
60 : SWF_DEFINESHAPE2 = 22,
61 : SWF_DEFINEBUTTONCXFORM = 23,
62 : SWF_PROTECT = 24,
63 : SWF_PLACEOBJECT2 = 26,
64 : SWF_REMOVEOBJECT2 = 28,
65 : SWF_DEFINESHAPE3 = 32,
66 : SWF_DEFINETEXT2 = 33,
67 : SWF_DEFINEBUTTON2 = 34,
68 : SWF_DEFINEBITSJPEG3 = 35,
69 : SWF_DEFINEBITSLOSSLESS2 = 36,
70 : SWF_DEFINEEDITTEXT = 37,
71 : SWF_DEFINEMOVIE = 38,
72 : SWF_DEFINESPRITE = 39,
73 : SWF_NAMECHARACTER = 40,
74 : SWF_SERIALNUMBER = 41,
75 : SWF_GENERATORTEXT = 42,
76 : SWF_FRAMELABEL = 43,
77 : SWF_SOUNDSTREAMHEAD2 = 45,
78 : SWF_DEFINEMORPHSHAPE = 46,
79 : SWF_DEFINEFONT2 = 48,
80 : SWF_TEMPLATECOMMAND = 49,
81 : SWF_GENERATOR3 = 51,
82 : SWF_EXTERNALFONT = 52,
83 : SWF_EXPORTASSETS = 56,
84 : SWF_IMPORTASSETS = 57,
85 : SWF_ENABLEDEBUGGER = 58,
86 : SWF_MX0 = 59,
87 : SWF_MX1 = 60,
88 : SWF_MX2 = 61,
89 : SWF_MX3 = 62,
90 : SWF_MX4 = 63,
91 : SWF_REFLEX = 777
92 : };
93 :
94 :
95 6 : static void swf_init_decompress(SWFReader *read)
96 : {
97 : u32 size, dst_size;
98 : uLongf destLen;
99 : char *src, *dst;
100 :
101 : assert(gf_bs_get_size(read->bs)-8 < (u64)1<<31); /*must fit within 32 bits*/
102 6 : size = (u32) gf_bs_get_size(read->bs)-8;
103 6 : dst_size = read->length;
104 6 : src = gf_malloc(sizeof(char)*size);
105 6 : dst = gf_malloc(sizeof(char)*dst_size);
106 : memset(dst, 0, sizeof(char)*8);
107 6 : gf_bs_read_data(read->bs, src, size);
108 6 : dst_size -= 8;
109 6 : destLen = (uLongf)dst_size;
110 6 : uncompress((Bytef *) dst+8, &destLen, (Bytef *) src, size);
111 : dst_size += 8;
112 6 : gf_free(src);
113 6 : read->mem = dst;
114 6 : gf_bs_del(read->bs);
115 6 : read->bs = gf_bs_new(read->mem, dst_size, GF_BITSTREAM_READ);
116 6 : gf_bs_skip_bytes(read->bs, 8);
117 6 : }
118 :
119 :
120 : static GF_Err swf_seek_file_to(SWFReader *read, u32 size)
121 : {
122 407 : return gf_bs_seek(read->bs, size);
123 : }
124 :
125 : static u32 swf_get_file_pos(SWFReader *read)
126 : {
127 21883 : return (u32) gf_bs_get_position(read->bs);
128 : }
129 :
130 : static u32 swf_read_data(SWFReader *read, char *data, u32 data_size)
131 : {
132 630 : return gf_bs_read_data(read->bs, data, data_size);
133 : }
134 :
135 : static u32 swf_read_int(SWFReader *read, u32 nbBits)
136 : {
137 1605118 : return gf_bs_read_int(read->bs, nbBits);
138 : }
139 :
140 146637 : static s32 swf_read_sint(SWFReader *read, u32 nbBits)
141 : {
142 : u32 r = 0;
143 : u32 i;
144 146637 : if (!nbBits)return 0;
145 292250 : r = swf_read_int(read, 1) ? 0xFFFFFFFF : 0;
146 1045924 : for (i=1; i<nbBits; i++) {
147 1045924 : r <<= 1;
148 2091848 : r |= swf_read_int(read, 1);
149 : }
150 146125 : return (s32) r;
151 : }
152 :
153 : static u32 swf_align(SWFReader *read)
154 : {
155 31587 : return gf_bs_align(read->bs);
156 : }
157 :
158 : static void swf_skip_data(SWFReader *read, u32 size)
159 : {
160 196 : while (size && !read->ioerr) {
161 182 : swf_read_int(read, 8);
162 182 : size --;
163 : }
164 : }
165 :
166 1324 : static void swf_get_rec(SWFReader *read, SWFRec *rc)
167 : {
168 : u32 nbbits;
169 1324 : swf_align(read);
170 1324 : nbbits = swf_read_int(read, 5);
171 1324 : rc->x = FLT2FIX( swf_read_sint(read, nbbits) * SWF_TWIP_SCALE );
172 1324 : rc->w = FLT2FIX( swf_read_sint(read, nbbits) * SWF_TWIP_SCALE );
173 1324 : rc->w -= rc->x;
174 1324 : rc->y = FLT2FIX( swf_read_sint(read, nbbits) * SWF_TWIP_SCALE );
175 1324 : rc->h = FLT2FIX( swf_read_sint(read, nbbits) * SWF_TWIP_SCALE );
176 1324 : rc->h -= rc->y;
177 1324 : }
178 :
179 1590 : static u32 swf_get_32(SWFReader *read)
180 : {
181 : u32 val, res;
182 1590 : val = swf_read_int(read, 32);
183 : res = (val&0xFF);
184 1590 : res <<=8;
185 1590 : res |= ((val>>8)&0xFF);
186 1590 : res<<=8;
187 1590 : res |= ((val>>16)&0xFF);
188 1590 : res<<=8;
189 1590 : res|= ((val>>24)&0xFF);
190 1590 : return res;
191 : }
192 :
193 : static u16 swf_get_16(SWFReader *read)
194 : {
195 : u16 val, res;
196 45200 : val = swf_read_int(read, 16);
197 : res = (val&0xFF);
198 : res <<=8;
199 22419 : res |= ((val>>8)&0xFF);
200 : return res;
201 : }
202 :
203 320 : static s16 swf_get_s16(SWFReader *read)
204 : {
205 : s16 val;
206 : u8 v1;
207 640 : v1 = swf_read_int(read, 8);
208 320 : val = swf_read_sint(read, 8);
209 320 : val = (val<<8)&0xFF00;
210 320 : val |= (v1&0xFF);
211 320 : return val;
212 : }
213 :
214 3006 : static u32 swf_get_color(SWFReader *read)
215 : {
216 : u32 res;
217 : res = 0xFF00;
218 3006 : res |= swf_read_int(read, 8);
219 3006 : res<<=8;
220 6012 : res |= swf_read_int(read, 8);
221 3006 : res<<=8;
222 6012 : res |= swf_read_int(read, 8);
223 3006 : return res;
224 : }
225 :
226 61 : static u32 swf_get_argb(SWFReader *read)
227 : {
228 : u32 res, al;
229 61 : res = swf_read_int(read, 8);
230 61 : res<<=8;
231 122 : res |= swf_read_int(read, 8);
232 61 : res<<=8;
233 122 : res |= swf_read_int(read, 8);
234 61 : al = swf_read_int(read, 8);
235 61 : return ((al<<24) | res);
236 : }
237 :
238 4835 : static u32 swf_get_matrix(SWFReader *read, GF_Matrix2D *mat)
239 : {
240 : u32 bits_read;
241 : u32 flag, nb_bits;
242 :
243 : memset(mat, 0, sizeof(GF_Matrix2D));
244 4835 : mat->m[0] = mat->m[4] = FIX_ONE;
245 :
246 4835 : bits_read = swf_align(read);
247 :
248 4835 : flag = swf_read_int(read, 1);
249 4835 : bits_read += 1;
250 4835 : if (flag) {
251 3714 : nb_bits = swf_read_int(read, 5);
252 : #ifdef GPAC_FIXED_POINT
253 : mat->m[0] = swf_read_sint(read, nb_bits);
254 : mat->m[4] = swf_read_sint(read, nb_bits);
255 : #else
256 3714 : mat->m[0] = (Float) swf_read_sint(read, nb_bits);
257 3714 : mat->m[0] /= 0x10000;
258 3714 : mat->m[4] = (Float) swf_read_sint(read, nb_bits);
259 3714 : mat->m[4] /= 0x10000;
260 : #endif
261 3714 : bits_read += 5 + 2*nb_bits;
262 : }
263 4835 : flag = swf_read_int(read, 1);
264 4835 : bits_read += 1;
265 4835 : if (flag) {
266 2061 : nb_bits = swf_read_int(read, 5);
267 : /*WATCHOUT FOR ORDER*/
268 : #ifdef GPAC_FIXED_POINT
269 : mat->m[3] = swf_read_sint(read, nb_bits);
270 : mat->m[1] = swf_read_sint(read, nb_bits);
271 : #else
272 2061 : mat->m[3] = (Float) swf_read_sint(read, nb_bits);
273 2061 : mat->m[3] /= 0x10000;
274 2061 : mat->m[1] = (Float) swf_read_sint(read, nb_bits);
275 2061 : mat->m[1] /= 0x10000;
276 : #endif
277 2061 : bits_read += 5 + 2*nb_bits;
278 : }
279 4835 : nb_bits = swf_read_int(read, 5);
280 4835 : bits_read += 5 + 2*nb_bits;
281 4835 : if (nb_bits) {
282 4676 : mat->m[2] = FLT2FIX( swf_read_sint(read, nb_bits) * SWF_TWIP_SCALE );
283 4676 : mat->m[5] = FLT2FIX( swf_read_sint(read, nb_bits) * SWF_TWIP_SCALE );
284 : }
285 4835 : return bits_read;
286 : }
287 :
288 : #define SWF_COLOR_SCALE (1/256.0f)
289 :
290 180 : static void swf_get_colormatrix(SWFReader *read, GF_ColorMatrix *cmat)
291 : {
292 : Bool has_add, has_mul;
293 : u32 nbbits;
294 : memset(cmat, 0, sizeof(GF_ColorMatrix));
295 180 : cmat->m[0] = cmat->m[6] = cmat->m[12] = cmat->m[18] = FIX_ONE;
296 :
297 180 : has_add = swf_read_int(read, 1);
298 180 : has_mul = swf_read_int(read, 1);
299 180 : nbbits = swf_read_int(read, 4);
300 180 : if (has_mul) {
301 32 : cmat->m[0] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
302 32 : cmat->m[6] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
303 32 : cmat->m[12] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
304 32 : cmat->m[18] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
305 : }
306 180 : if (has_add) {
307 104 : cmat->m[4] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
308 104 : cmat->m[9] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
309 104 : cmat->m[14] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
310 104 : cmat->m[19] = FLT2FIX( swf_read_sint(read, nbbits) * SWF_COLOR_SCALE );
311 : }
312 180 : cmat->identity = 0;
313 180 : if ((cmat->m[0] == cmat->m[6])
314 180 : && (cmat->m[0] == cmat->m[12])
315 180 : && (cmat->m[0] == cmat->m[18])
316 148 : && (cmat->m[0] == FIX_ONE)
317 148 : && (cmat->m[4] == cmat->m[9])
318 146 : && (cmat->m[4] == cmat->m[14])
319 146 : && (cmat->m[4] == cmat->m[19])
320 48 : && (cmat->m[4] == 0))
321 48 : cmat->identity = 1;
322 180 : }
323 :
324 15 : static char *swf_get_string(SWFReader *read)
325 : {
326 : char szName[1024];
327 : char *name;
328 : u32 i = 0;
329 :
330 15 : if (read->size>1024) {
331 0 : name = gf_malloc(sizeof(char)*read->size);
332 : } else {
333 : name = szName;
334 : }
335 : while (1) {
336 444 : name[i] = swf_read_int(read, 8);
337 153 : if (!name[i]) break;
338 138 : i++;
339 : }
340 15 : if (read->size>1024) {
341 0 : return gf_realloc(name, sizeof(char)*(strlen(name)+1));
342 : } else {
343 15 : return gf_strdup(szName);
344 : }
345 : }
346 :
347 3175 : static SWFShapeRec *swf_new_shape_rec()
348 : {
349 : SWFShapeRec *style;
350 3175 : GF_SAFEALLOC(style, SWFShapeRec);
351 3175 : if (!style) return NULL;
352 3175 : GF_SAFEALLOC(style->path, SWFPath);
353 3175 : if (!style->path) {
354 0 : gf_free(style);
355 0 : return NULL;
356 : }
357 : return style;
358 : }
359 :
360 1515 : static SWFShapeRec *swf_clone_shape_rec(SWFShapeRec *old_sr)
361 : {
362 1515 : SWFShapeRec *new_sr = (SWFShapeRec *)gf_malloc(sizeof(SWFShapeRec));
363 : memcpy(new_sr, old_sr, sizeof(SWFShapeRec));
364 1515 : new_sr->path = (SWFPath*)gf_malloc(sizeof(SWFPath));
365 : memset(new_sr->path, 0, sizeof(SWFPath));
366 :
367 1515 : if (old_sr->nbGrad) {
368 206 : new_sr->grad_col = (u32*)gf_malloc(sizeof(u32) * old_sr->nbGrad);
369 206 : memcpy(new_sr->grad_col, old_sr->grad_col, sizeof(u32) * old_sr->nbGrad);
370 206 : new_sr->grad_ratio = (u8*)gf_malloc(sizeof(u8) * old_sr->nbGrad);
371 206 : memcpy(new_sr->grad_ratio, old_sr->grad_ratio, sizeof(u8) * old_sr->nbGrad);
372 : }
373 1515 : return new_sr;
374 : }
375 :
376 : /*parse/append fill and line styles*/
377 1427 : static void swf_parse_styles(SWFReader *read, u32 revision, SWFShape *shape, u32 *bits_fill, u32 *bits_line)
378 : {
379 : u32 i, j, count;
380 : SWFShapeRec *style;
381 :
382 1427 : swf_align(read);
383 :
384 : /*get fill styles*/
385 1427 : count = swf_read_int(read, 8);
386 1427 : if (revision && (count== 0xFF)) count = swf_get_16(read);
387 1427 : if (count) {
388 1515 : for (i=0; i<count; i++) {
389 1515 : style = swf_new_shape_rec();
390 :
391 1515 : style->solid_col = 0xFF00FF00;
392 3030 : style->type = swf_read_int(read, 8);
393 :
394 : /*gradient fill*/
395 1515 : if (style->type & 0x10) {
396 206 : swf_get_matrix(read, &style->mat);
397 206 : swf_align(read);
398 412 : style->nbGrad = swf_read_int(read, 8);
399 206 : if (style->nbGrad) {
400 206 : style->grad_col = (u32 *) gf_malloc(sizeof(u32) * style->nbGrad);
401 206 : style->grad_ratio = (u8 *) gf_malloc(sizeof(u8) * style->nbGrad);
402 1022 : for (j=0; j<style->nbGrad; j++) {
403 1632 : style->grad_ratio[j] = swf_read_int(read, 8);
404 816 : if (revision==2) style->grad_col[j] = swf_get_argb(read);
405 804 : else style->grad_col[j] = swf_get_color(read);
406 : }
407 206 : style->solid_col = style->grad_col[0];
408 :
409 : /*make sure we have keys between 0 and 1.0 for BIFS (0 and 255 in swf)*/
410 206 : if (style->grad_ratio[0] != 0) {
411 : u32 *grad_col;
412 : u8 *grad_ratio;
413 0 : grad_ratio = (u8 *) gf_malloc(sizeof(u8) * (style->nbGrad+1));
414 0 : grad_col = (u32 *) gf_malloc(sizeof(u32) * (style->nbGrad+1));
415 0 : grad_col[0] = style->grad_col[0];
416 0 : grad_ratio[0] = 0;
417 0 : for (j=0; j<style->nbGrad; j++) {
418 0 : grad_col[j+1] = style->grad_col[j];
419 0 : grad_ratio[j+1] = style->grad_ratio[j];
420 : }
421 0 : gf_free(style->grad_col);
422 0 : style->grad_col = grad_col;
423 0 : gf_free(style->grad_ratio);
424 0 : style->grad_ratio = grad_ratio;
425 0 : style->nbGrad++;
426 : }
427 206 : if (style->grad_ratio[style->nbGrad-1] != 255) {
428 0 : u32 *grad_col = (u32*)gf_malloc(sizeof(u32) * (style->nbGrad+1));
429 0 : u8 *grad_ratio = (u8*)gf_malloc(sizeof(u8) * (style->nbGrad+1));
430 0 : memcpy(grad_col, style->grad_col, sizeof(u32) * style->nbGrad);
431 0 : memcpy(grad_ratio, style->grad_ratio, sizeof(u8) * style->nbGrad);
432 0 : grad_col[style->nbGrad] = style->grad_col[style->nbGrad-1];
433 0 : grad_ratio[style->nbGrad] = 255;
434 0 : gf_free(style->grad_col);
435 0 : style->grad_col = grad_col;
436 0 : gf_free(style->grad_ratio);
437 0 : style->grad_ratio = grad_ratio;
438 0 : style->nbGrad++;
439 : }
440 :
441 : } else {
442 0 : style->solid_col = 0xFF;
443 : }
444 : }
445 : /*bitmap fill*/
446 1309 : else if (style->type & 0x40) {
447 2 : style->img_id = swf_get_16(read);
448 2 : if (style->img_id == 65535) {
449 0 : style->img_id = 0;
450 0 : style->type = 0;
451 0 : style->solid_col = 0xFF00FFFF;
452 : }
453 2 : swf_get_matrix(read, &style->mat);
454 : }
455 : /*solid fill*/
456 : else {
457 1307 : if (revision==2) style->solid_col = swf_get_argb(read);
458 1262 : else style->solid_col = swf_get_color(read);
459 : }
460 1515 : gf_list_add(shape->fill_right, style);
461 1515 : style = swf_clone_shape_rec(style);
462 1515 : gf_list_add(shape->fill_left, style);
463 : }
464 : }
465 :
466 1427 : swf_align(read);
467 : /*get line styles*/
468 1427 : count = swf_read_int(read, 8);
469 1427 : if (revision && (count==0xFF)) count = swf_get_16(read);
470 1427 : if (count) {
471 846 : for (i=0; i<count; i++) {
472 846 : style = swf_new_shape_rec();
473 846 : gf_list_add(shape->lines, style);
474 846 : style->width = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
475 846 : if (revision==2) style->solid_col = swf_get_argb(read);
476 846 : else style->solid_col = swf_get_color(read);
477 : }
478 : }
479 :
480 1427 : swf_align(read);
481 2854 : *bits_fill = swf_read_int(read, 4);
482 2854 : *bits_line = swf_read_int(read, 4);
483 1427 : }
484 :
485 206915 : static void swf_path_realloc_pts(SWFPath *path, u32 nbPts)
486 : {
487 206915 : if (path)
488 206915 : path->pts = (SFVec2f*)gf_realloc(path->pts, sizeof(SFVec2f) * (path->nbPts + nbPts));
489 206915 : }
490 :
491 175934 : static void swf_path_add_com(SWFShapeRec *sr, SFVec2f pt, SFVec2f ctr, u32 type)
492 : {
493 : /*not an error*/
494 175934 : if (!sr) return;
495 :
496 83509 : sr->path->types = (u32*)gf_realloc(sr->path->types, sizeof(u32) * (sr->path->nbType+1));
497 :
498 83509 : sr->path->types[sr->path->nbType] = type;
499 83509 : switch (type) {
500 17170 : case 2:
501 17170 : swf_path_realloc_pts(sr->path, 2);
502 17170 : sr->path->pts[sr->path->nbPts] = ctr;
503 17170 : sr->path->pts[sr->path->nbPts+1] = pt;
504 17170 : sr->path->nbPts+=2;
505 17170 : break;
506 66339 : case 1:
507 : default:
508 66339 : swf_path_realloc_pts(sr->path, 1);
509 66339 : sr->path->pts[sr->path->nbPts] = pt;
510 66339 : sr->path->nbPts++;
511 66339 : break;
512 : }
513 83509 : sr->path->nbType++;
514 : }
515 :
516 1911 : static void swf_referse_path(SWFPath *path)
517 : {
518 : u32 i, j, pti, ptj;
519 : u32 *types;
520 : SFVec2f *pts;
521 :
522 1911 : if (path->nbType<=1) return;
523 :
524 1739 : types = (u32 *) gf_malloc(sizeof(u32) * path->nbType);
525 1739 : pts = (SFVec2f *) gf_malloc(sizeof(SFVec2f) * path->nbPts);
526 :
527 :
528 : /*need first moveTo*/
529 1739 : types[0] = 0;
530 1739 : pts[0] = path->pts[path->nbPts - 1];
531 1739 : pti = path->nbPts - 2;
532 : ptj = 1;
533 : j=1;
534 :
535 45253 : for (i=0; i<path->nbType-1; i++) {
536 43514 : types[j] = path->types[path->nbType - i - 1];
537 43514 : switch (types[j]) {
538 8809 : case 2:
539 : assert(ptj<=path->nbPts-2);
540 8809 : pts[ptj] = path->pts[pti];
541 8809 : pts[ptj+1] = path->pts[pti-1];
542 8809 : pti-=2;
543 8809 : ptj+=2;
544 8809 : break;
545 32519 : case 1:
546 : assert(ptj<=path->nbPts-1);
547 32519 : pts[ptj] = path->pts[pti];
548 32519 : pti--;
549 32519 : ptj++;
550 32519 : break;
551 2186 : case 0:
552 : assert(ptj<=path->nbPts-1);
553 2186 : pts[ptj] = path->pts[pti];
554 2186 : pti--;
555 2186 : ptj++;
556 2186 : break;
557 : }
558 43514 : j++;
559 : }
560 1739 : gf_free(path->pts);
561 1739 : path->pts = pts;
562 1739 : gf_free(path->types);
563 1739 : path->types = types;
564 : }
565 :
566 4690 : static void swf_free_shape_rec(SWFShapeRec *ptr)
567 : {
568 4690 : if (ptr->grad_col) gf_free(ptr->grad_col);
569 4690 : if (ptr->grad_ratio) gf_free(ptr->grad_ratio);
570 4690 : if (ptr->path) {
571 4690 : if (ptr->path->pts) gf_free(ptr->path->pts);
572 4690 : if (ptr->path->types) gf_free(ptr->path->types);
573 4690 : if (ptr->path->idx) gf_free(ptr->path->idx);
574 4690 : gf_free(ptr->path);
575 : }
576 4690 : gf_free(ptr);
577 4690 : }
578 :
579 10068 : static void swf_reset_rec_list(GF_List *recs)
580 : {
581 24820 : while (gf_list_count(recs)) {
582 4684 : SWFShapeRec *tmp = (SWFShapeRec *)gf_list_get(recs, 0);
583 4684 : gf_list_rem(recs, 0);
584 4684 : swf_free_shape_rec(tmp);
585 : }
586 10068 : }
587 :
588 7044 : static void swf_append_path(SWFPath *a, SWFPath *b)
589 : {
590 7044 : if (b->nbType<=1) return;
591 :
592 6872 : a->pts = (SFVec2f*)gf_realloc(a->pts, sizeof(SFVec2f) * (a->nbPts + b->nbPts));
593 6872 : memcpy(&a->pts[a->nbPts], b->pts, sizeof(SFVec2f)*b->nbPts);
594 6872 : a->nbPts += b->nbPts;
595 :
596 6872 : a->types = (u32*)gf_realloc(a->types, sizeof(u32)*(a->nbType+ b->nbType));
597 6872 : memcpy(&a->types[a->nbType], b->types, sizeof(u32)*b->nbType);
598 6872 : a->nbType += b->nbType;
599 : }
600 :
601 123406 : static void swf_path_add_type(SWFPath *path, u32 val)
602 : {
603 123406 : path->types = (u32*)gf_realloc(path->types, sizeof(u32) * (path->nbType + 1));
604 123406 : path->types[path->nbType] = val;
605 123406 : path->nbType++;
606 123406 : }
607 :
608 2757 : static void swf_resort_path(SWFPath *a, SWFReader *read)
609 : {
610 : u32 idx, i, j;
611 : GF_List *paths;
612 : SWFPath *sorted, *p, *np;
613 :
614 2757 : if (!a->nbType) return;
615 :
616 2751 : paths = gf_list_new();
617 2751 : GF_SAFEALLOC(sorted, SWFPath);
618 2751 : if (!sorted) {
619 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SWF Parsing] Fail to allocate path for resorting\n"));
620 : return;
621 : }
622 2751 : swf_path_realloc_pts(sorted, 1);
623 2751 : sorted->pts[sorted->nbPts] = a->pts[0];
624 2751 : sorted->nbPts++;
625 2751 : swf_path_add_type(sorted, 0);
626 2751 : gf_list_add(paths, sorted);
627 :
628 : /*1- split all paths*/
629 : idx = 1;
630 80752 : for (i=1; i<a->nbType; i++) {
631 80752 : switch (a->types[i]) {
632 17170 : case 2:
633 17170 : swf_path_realloc_pts(sorted, 2);
634 17170 : sorted->pts[sorted->nbPts] = a->pts[idx];
635 17170 : sorted->pts[sorted->nbPts+1] = a->pts[idx+1];
636 17170 : sorted->nbPts+=2;
637 17170 : swf_path_add_type(sorted, 2);
638 17170 : idx += 2;
639 : break;
640 58491 : case 1:
641 58491 : swf_path_realloc_pts(sorted, 1);
642 58491 : sorted->pts[sorted->nbPts] = a->pts[idx];
643 58491 : sorted->nbPts+=1;
644 58491 : swf_path_add_type(sorted, 1);
645 58491 : idx += 1;
646 : break;
647 5091 : case 0:
648 5091 : GF_SAFEALLOC(sorted , SWFPath);
649 5091 : if (!sorted) return;
650 5091 : swf_path_realloc_pts(sorted, 1);
651 5091 : sorted->pts[sorted->nbPts] = a->pts[idx];
652 5091 : sorted->nbPts++;
653 5091 : swf_path_add_type(sorted, 0);
654 5091 : gf_list_add(paths, sorted);
655 5091 : idx += 1;
656 : break;
657 : }
658 : }
659 :
660 5004 : restart:
661 11865 : for (i=0; i<gf_list_count(paths); i++) {
662 9114 : p = (SWFPath*)gf_list_get(paths, i);
663 :
664 37605 : for (j=i+1; j < gf_list_count(paths); j++) {
665 30744 : np = (SWFPath*)gf_list_get(paths, j);
666 :
667 : /*check if any next subpath ends at the same place we're starting*/
668 30744 : if ((np->pts[np->nbPts-1].x == p->pts[0].x) && (np->pts[np->nbPts-1].y == p->pts[0].y)) {
669 : u32 k;
670 : idx = 1;
671 32036 : for (k=1; k<p->nbType; k++) {
672 32036 : switch (p->types[k]) {
673 2206 : case 2:
674 2206 : swf_path_realloc_pts(np, 2);
675 2206 : np->pts[np->nbPts] = p->pts[idx];
676 2206 : np->pts[np->nbPts+1] = p->pts[idx+1];
677 2206 : np->nbPts+=2;
678 2206 : swf_path_add_type(np, 2);
679 2206 : idx += 2;
680 : break;
681 29830 : case 1:
682 29830 : swf_path_realloc_pts(np, 1);
683 29830 : np->pts[np->nbPts] = p->pts[idx];
684 29830 : np->nbPts+=1;
685 29830 : swf_path_add_type(np, 1);
686 29830 : idx += 1;
687 : break;
688 : default:
689 : assert(0);
690 : break;
691 : }
692 : }
693 2253 : gf_free(p->pts);
694 2253 : gf_free(p->types);
695 2253 : gf_free(p);
696 2253 : gf_list_rem(paths, i);
697 : goto restart;
698 : }
699 : /*check if any next subpath starts at the same place we're ending*/
700 28491 : else if ((p->pts[p->nbPts-1].x == np->pts[0].x) && (p->pts[p->nbPts-1].y == np->pts[0].y)) {
701 : u32 k;
702 : idx = 1;
703 7867 : for (k=1; k<np->nbType; k++) {
704 7867 : switch (np->types[k]) {
705 242 : case 2:
706 242 : swf_path_realloc_pts(p, 2);
707 242 : p->pts[p->nbPts] = np->pts[idx];
708 242 : p->pts[p->nbPts+1] = np->pts[idx+1];
709 242 : p->nbPts+=2;
710 242 : swf_path_add_type(p, 2);
711 242 : idx += 2;
712 : break;
713 7625 : case 1:
714 7625 : swf_path_realloc_pts(p, 1);
715 7625 : p->pts[p->nbPts] = np->pts[idx];
716 7625 : p->nbPts+=1;
717 7625 : swf_path_add_type(p, 1);
718 7625 : idx += 1;
719 : break;
720 : default:
721 : assert(0);
722 : break;
723 : }
724 : }
725 456 : gf_free(np->pts);
726 456 : gf_free(np->types);
727 456 : gf_free(np);
728 456 : gf_list_rem(paths, j);
729 456 : j--;
730 : }
731 : }
732 : }
733 :
734 : /*reassemble path*/
735 2751 : gf_free(a->pts);
736 2751 : gf_free(a->types);
737 : memset(a, 0, sizeof(SWFPath));
738 :
739 7884 : while (gf_list_count(paths)) {
740 5133 : sorted = (SWFPath*)gf_list_get(paths, 0);
741 5133 : if (read->flat_limit==0) {
742 5133 : swf_append_path(a, sorted);
743 : } else {
744 : Bool prev_is_line_to = 0;
745 : idx = 0;
746 0 : for (i=0; i<sorted->nbType; i++) {
747 0 : switch (sorted->types[i]) {
748 0 : case 2:
749 0 : swf_path_realloc_pts(a, 2);
750 0 : a->pts[a->nbPts] = sorted->pts[idx];
751 0 : a->pts[a->nbPts+1] = sorted->pts[idx+1];
752 0 : a->nbPts+=2;
753 0 : swf_path_add_type(a, 2);
754 0 : idx += 2;
755 : prev_is_line_to = 0;
756 : break;
757 0 : case 1:
758 0 : if (prev_is_line_to) {
759 : Fixed angle;
760 : Bool flatten = 0;
761 : SFVec2f v1, v2;
762 0 : v1.x = a->pts[a->nbPts-1].x - a->pts[a->nbPts-2].x;
763 0 : v1.y = a->pts[a->nbPts-1].y - a->pts[a->nbPts-2].y;
764 0 : v2.x = a->pts[a->nbPts-1].x - sorted->pts[idx].x;
765 0 : v2.y = a->pts[a->nbPts-1].y - sorted->pts[idx].y;
766 :
767 0 : angle = gf_mulfix(v1.x,v2.x) + gf_mulfix(v1.y,v2.y);
768 : /*get magnitudes*/
769 0 : v1.x = gf_v2d_len(&v1);
770 0 : v2.x = gf_v2d_len(&v2);
771 0 : if (!v1.x || !v2.x) flatten = 1;
772 : else {
773 : Fixed h_pi = GF_PI / 2;
774 0 : angle = gf_divfix(angle, gf_mulfix(v1.x, v2.x));
775 0 : if (angle + FIX_EPSILON >= FIX_ONE) angle = 0;
776 0 : else if (angle - FIX_EPSILON <= -FIX_ONE) angle = GF_PI;
777 0 : else angle = gf_acos(angle);
778 :
779 : if (angle<0) angle += h_pi;
780 0 : angle = ABSDIFF(angle, h_pi);
781 0 : if (angle < read->flat_limit) flatten = 1;
782 : }
783 : if (flatten) {
784 0 : a->pts[a->nbPts-1] = sorted->pts[idx];
785 0 : idx++;
786 0 : read->flatten_points++;
787 0 : break;
788 : }
789 : }
790 0 : swf_path_realloc_pts(a, 1);
791 0 : a->pts[a->nbPts] = sorted->pts[idx];
792 0 : a->nbPts+=1;
793 0 : swf_path_add_type(a, 1);
794 0 : idx += 1;
795 : prev_is_line_to = 1;
796 : break;
797 0 : case 0:
798 0 : swf_path_realloc_pts(a, 1);
799 0 : a->pts[a->nbPts] = sorted->pts[idx];
800 0 : a->nbPts+=1;
801 0 : swf_path_add_type(a, 0);
802 0 : idx += 1;
803 : prev_is_line_to = 0;
804 : break;
805 : }
806 : }
807 : }
808 5133 : gf_free(sorted->pts);
809 5133 : gf_free(sorted->types);
810 5133 : gf_free(sorted);
811 5133 : gf_list_rem(paths, 0);
812 : }
813 2751 : gf_list_del(paths);
814 : }
815 :
816 : /*
817 : Notes on SWF->BIFS conversion - some ideas taken from libswfdec
818 : A single fillStyle has 2 associated path, one used for left fill, one for right fill
819 : This is then a 4 step process:
820 : 1- blindly parse swf shape, and add point/lines to the proper left/right path
821 : 2- for each fillStyles, revert the right path so that it becomes a left path
822 : 3- concatenate left and right paths
823 : 4- resort all subelements of the final path, making sure moveTo introduced by the SWF coding (due to style changes)
824 : are removed.
825 : Ex: if path is
826 : A->C, B->A, C->B = moveTo(A), lineTo(C), moveTo(B), lineTo (A), moveTo(C), lineTo(B)
827 : we restort and remove unneeded moves to get
828 : A->C->B = moveTo(A), lineTo(C), lineTo(B), lineTo(A)
829 : */
830 1834 : static GF_Err swf_flush_shape(SWFReader *read, SWFShape *shape, SWFFont *font, Bool last_shape)
831 : {
832 : GF_Err e;
833 : SWFShapeRec *sf0;
834 : u32 i, count;
835 1834 : count = gf_list_count(shape->fill_left);
836 3745 : for (i=0; i<count; i++) {
837 : SWFShapeRec *sf1;
838 1911 : sf0 = (SWFShapeRec*)gf_list_get(shape->fill_left, i);
839 1911 : sf1 = (SWFShapeRec*)gf_list_get(shape->fill_right, i);
840 : /*reverse right path*/
841 1911 : swf_referse_path(sf1->path);
842 : /*concatenate with left path*/
843 1911 : swf_append_path(sf0->path, sf1->path);
844 : /*resort all path curves*/
845 1911 : swf_resort_path(sf0->path, read);
846 : }
847 : /*remove dummy fill_left*/
848 1911 : for (i=0; i<gf_list_count(shape->fill_left); i++) {
849 1911 : sf0 = (SWFShapeRec*)gf_list_get(shape->fill_left, i);
850 1911 : if (sf0->path->nbType<=1) {
851 6 : gf_list_rem(shape->fill_left, i);
852 6 : swf_free_shape_rec(sf0);
853 6 : i--;
854 : }
855 : }
856 : /*remove dummy lines*/
857 846 : for (i=0; i<gf_list_count(shape->lines); i++) {
858 846 : SWFShapeRec *sl = (SWFShapeRec*)gf_list_get(shape->lines, i);
859 846 : if (sl->path->nbType<1) {
860 0 : gf_list_rem(shape->lines, i);
861 0 : swf_free_shape_rec(sl);
862 0 : i--;
863 : } else {
864 846 : swf_resort_path(sl->path, read);
865 : }
866 : }
867 :
868 : /*now translate a flash shape record into BIFS*/
869 1834 : e = read->define_shape(read, shape, font, last_shape);
870 :
871 : /*delete shape*/
872 1834 : swf_reset_rec_list(shape->fill_left);
873 1834 : swf_reset_rec_list(shape->fill_right);
874 1834 : swf_reset_rec_list(shape->lines);
875 1834 : return e;
876 : }
877 :
878 1511 : static GF_Err swf_parse_shape_def(SWFReader *read, SWFFont *font, u32 revision)
879 : {
880 : u32 nbBits, comType;
881 : s32 x, y;
882 : SFVec2f orig, ctrl, end;
883 : Bool flag;
884 : u32 fill0, fill1, strike;
885 : u32 bits_fill, bits_line;
886 : SWFShape shape;
887 : Bool is_empty;
888 : SWFShapeRec *sf0, *sf1, *sl;
889 :
890 : memset(&shape, 0, sizeof(SWFShape));
891 1511 : shape.fill_left = gf_list_new();
892 1511 : shape.fill_right = gf_list_new();
893 1511 : shape.lines = gf_list_new();
894 1511 : ctrl.x = ctrl.y = 0;
895 1511 : swf_align(read);
896 :
897 : /*regular shape - get initial styles*/
898 1511 : if (!font) {
899 1104 : shape.ID = swf_get_16(read);
900 1104 : swf_get_rec(read, &shape.rc);
901 1104 : swf_parse_styles(read, revision, &shape, &bits_fill, &bits_line);
902 : }
903 : /*glyph*/
904 : else {
905 814 : bits_fill = swf_read_int(read, 4);
906 814 : bits_line = swf_read_int(read, 4);
907 :
908 : /*fonts are usually defined without styles*/
909 407 : if ((read->tag == SWF_DEFINEFONT) || (read->tag==SWF_DEFINEFONT2)) {
910 407 : sf0 = swf_new_shape_rec();
911 407 : gf_list_add(shape.fill_right, sf0);
912 407 : sf0 = swf_new_shape_rec();
913 407 : gf_list_add(shape.fill_left, sf0);
914 407 : sf0->solid_col = 0xFF000000;
915 407 : sf0->type = 0;
916 : }
917 : }
918 :
919 : is_empty = 1;
920 :
921 : /*parse all points*/
922 : fill0 = fill1 = strike = 0;
923 : sf0 = sf1 = sl = NULL;
924 : x = y = 0;
925 : while (1) {
926 61736 : flag = swf_read_int(read, 1);
927 61736 : if (!flag) {
928 8586 : Bool new_style = swf_read_int(read, 1);
929 8586 : Bool set_strike = swf_read_int(read, 1);
930 8586 : Bool set_fill1 = swf_read_int(read, 1);
931 8586 : Bool set_fill0 = swf_read_int(read, 1);
932 8586 : Bool move_to = swf_read_int(read, 1);
933 : /*end of shape*/
934 8586 : if (!new_style && !set_strike && !set_fill0 && !set_fill1 && !move_to) break;
935 :
936 : is_empty = 0;
937 :
938 7075 : if (move_to) {
939 4512 : nbBits = swf_read_int(read, 5);
940 4512 : x = swf_read_sint(read, nbBits);
941 4512 : y = swf_read_sint(read, nbBits);
942 : }
943 7075 : if (set_fill0) fill0 = swf_read_int(read, bits_fill);
944 7075 : if (set_fill1) fill1 = swf_read_int(read, bits_fill);
945 7075 : if (set_strike) strike = swf_read_int(read, bits_line);
946 : /*looks like newStyle does not append styles but define a new set - old styles can no
947 : longer be referenced*/
948 7075 : if (new_style) {
949 : /*flush current shape record into BIFS*/
950 323 : swf_flush_shape(read, &shape, font, 0);
951 323 : swf_parse_styles(read, revision, &shape, &bits_fill, &bits_line);
952 : }
953 :
954 7075 : if (read->flags & GF_SM_SWF_NO_LINE) strike = 0;
955 :
956 : /*moveto*/
957 7075 : orig.x = FLT2FIX( x * SWF_TWIP_SCALE );
958 7075 : orig.y = FLT2FIX( y * SWF_TWIP_SCALE );
959 7075 : end = orig;
960 :
961 7075 : sf0 = fill0 ? (SWFShapeRec*)gf_list_get(shape.fill_left, fill0 - 1) : NULL;
962 7075 : sf1 = fill1 ? (SWFShapeRec*)gf_list_get(shape.fill_right, fill1 - 1) : NULL;
963 7075 : sl = strike ? (SWFShapeRec*)gf_list_get(shape.lines, strike - 1) : NULL;
964 :
965 7075 : if (move_to) {
966 4512 : swf_path_add_com(sf0, end, ctrl, 0);
967 4512 : swf_path_add_com(sf1, end, ctrl, 0);
968 4512 : swf_path_add_com(sl, end, ctrl, 0);
969 : } else {
970 2563 : if (set_fill0) swf_path_add_com(sf0, end, ctrl, 0);
971 2563 : if (set_fill1) swf_path_add_com(sf1, end, ctrl, 0);
972 2563 : if (set_strike) swf_path_add_com(sl, end, ctrl, 0);
973 : }
974 :
975 : } else {
976 53150 : flag = swf_read_int(read, 1);
977 : /*quadratic curve*/
978 53150 : if (!flag) {
979 25426 : nbBits = 2 + swf_read_int(read, 4);
980 12713 : x += swf_read_sint(read, nbBits);
981 12713 : y += swf_read_sint(read, nbBits);
982 12713 : ctrl.x = FLT2FIX( x * SWF_TWIP_SCALE );
983 12713 : ctrl.y = FLT2FIX( y * SWF_TWIP_SCALE );
984 12713 : x += swf_read_sint(read, nbBits);
985 12713 : y += swf_read_sint(read, nbBits);
986 12713 : end.x = FLT2FIX( x * SWF_TWIP_SCALE );
987 12713 : end.y = FLT2FIX( y * SWF_TWIP_SCALE );
988 : /*curveTo*/
989 : comType = 2;
990 : }
991 : /*straight line*/
992 : else {
993 80874 : nbBits = 2 + swf_read_int(read, 4);
994 40437 : flag = swf_read_int(read, 1);
995 40437 : if (flag) {
996 19262 : x += swf_read_sint(read, nbBits);
997 19262 : y += swf_read_sint(read, nbBits);
998 : } else {
999 21175 : flag = swf_read_int(read, 1);
1000 21175 : if (flag) {
1001 11321 : y += swf_read_sint(read, nbBits);
1002 : } else {
1003 9854 : x += swf_read_sint(read, nbBits);
1004 : }
1005 : }
1006 : /*lineTo*/
1007 : comType = 1;
1008 40437 : end.x = FLT2FIX( x * SWF_TWIP_SCALE );
1009 40437 : end.y = FLT2FIX( y * SWF_TWIP_SCALE );
1010 : }
1011 53150 : swf_path_add_com(sf0, end, ctrl, comType);
1012 53150 : swf_path_add_com(sf1, end, ctrl, comType);
1013 53150 : swf_path_add_com(sl, end, ctrl, comType);
1014 : }
1015 : }
1016 :
1017 1511 : if (is_empty) {
1018 11 : swf_reset_rec_list(shape.fill_left);
1019 11 : swf_reset_rec_list(shape.fill_right);
1020 11 : swf_reset_rec_list(shape.lines);
1021 : }
1022 :
1023 1511 : swf_align(read);
1024 :
1025 : /*now translate a flash shape record*/
1026 1511 : swf_flush_shape(read, &shape, font, 1);
1027 :
1028 : /*delete shape*/
1029 1511 : swf_reset_rec_list(shape.fill_left);
1030 1511 : swf_reset_rec_list(shape.fill_right);
1031 1511 : swf_reset_rec_list(shape.lines);
1032 1511 : gf_list_del(shape.fill_left);
1033 1511 : gf_list_del(shape.fill_right);
1034 1511 : gf_list_del(shape.lines);
1035 :
1036 1511 : return GF_OK;
1037 : }
1038 :
1039 384 : SWFFont *swf_find_font(SWFReader *read, u32 ID)
1040 : {
1041 : u32 i, count;
1042 384 : count = gf_list_count(read->fonts);
1043 462 : for (i=0; i<count; i++) {
1044 462 : SWFFont *ft = (SWFFont *)gf_list_get(read->fonts, i);
1045 462 : if (ft->fontID==ID) return ft;
1046 : }
1047 : return NULL;
1048 : }
1049 :
1050 10673 : static DispShape *swf_get_depth_entry(SWFReader *read, u32 Depth, Bool create)
1051 : {
1052 : u32 i;
1053 : DispShape *tmp;
1054 10673 : i=0;
1055 106363 : while ((tmp = (DispShape *)gf_list_enum(read->display_list, &i))) {
1056 106187 : if (tmp->depth == Depth) return tmp;
1057 : }
1058 176 : if (!create) return NULL;
1059 172 : GF_SAFEALLOC(tmp , DispShape);
1060 172 : if (!tmp) return NULL;
1061 172 : tmp->depth = Depth;
1062 172 : tmp->char_id = 0;
1063 172 : gf_list_add(read->display_list, tmp);
1064 :
1065 172 : memset(&tmp->mat, 0, sizeof(GF_Matrix2D));
1066 172 : tmp->mat.m[0] = tmp->mat.m[4] = FIX_ONE;
1067 :
1068 172 : memset(&tmp->cmat, 0, sizeof(GF_ColorMatrix));
1069 172 : tmp->cmat.m[0] = tmp->cmat.m[6] = tmp->cmat.m[12] = tmp->cmat.m[18] = FIX_ONE;
1070 172 : tmp->cmat.identity = 1;
1071 : return tmp;
1072 : }
1073 :
1074 :
1075 0 : static GF_Err swf_func_skip(SWFReader *read)
1076 : {
1077 0 : if (!read) return GF_OK;
1078 0 : swf_skip_data(read, read->size);
1079 0 : return read->ioerr;
1080 : }
1081 :
1082 : static GF_Err swf_set_backcol(SWFReader *read)
1083 : {
1084 13 : u32 col = swf_get_color(read);
1085 13 : return read->set_backcol(read, col);
1086 : }
1087 :
1088 18 : static GF_Err swf_actions(SWFReader *read, u32 mask, u32 key)
1089 : {
1090 : u32 skip_actions = 0;
1091 36 : u8 action_code = swf_read_int(read, 8);
1092 18 : read->has_interact = 1;
1093 :
1094 :
1095 : #define DO_ACT(_code) { act.type = _code; read->action(read, &act); break; }
1096 :
1097 105 : while (action_code) {
1098 : u16 length;
1099 69 : if (action_code > 0x80) length = swf_get_16(read);
1100 : else length = 0;
1101 :
1102 69 : if (read->no_as || skip_actions) {
1103 0 : swf_skip_data(read, length);
1104 0 : if (skip_actions) skip_actions--;
1105 : } else {
1106 : SWFAction act;
1107 : memset(&act, 0, sizeof(SWFAction));
1108 69 : act.button_mask = mask;
1109 69 : act.button_key = key;
1110 :
1111 69 : switch (action_code) {
1112 : /* SWF 3 Action Model */
1113 7 : case 0x81: /* goto frame */
1114 : assert (length == 2);
1115 : act.type = GF_SWF_AS3_GOTO_FRAME;
1116 7 : act.frame_number = swf_get_16(read);
1117 7 : read->action(read, &act);
1118 7 : break;
1119 2 : case 0x83: /* get URL */
1120 2 : act.type = GF_SWF_AS3_GET_URL;
1121 2 : act.url = swf_get_string(read);
1122 2 : act.target = swf_get_string(read);
1123 2 : read->action(read, &act);
1124 2 : gf_free(act.url);
1125 2 : gf_free(act.target);
1126 2 : break;
1127 : /* next frame */
1128 0 : case 0x04:
1129 0 : DO_ACT(GF_SWF_AS3_NEXT_FRAME)
1130 : /* previous frame */
1131 0 : case 0x05:
1132 0 : DO_ACT(GF_SWF_AS3_PREV_FRAME)
1133 : /* play */
1134 7 : case 0x06:
1135 7 : DO_ACT(GF_SWF_AS3_PLAY)
1136 : /* stop */
1137 5 : case 0x07:
1138 5 : DO_ACT(GF_SWF_AS3_STOP)
1139 : /* toggle quality */
1140 0 : case 0x08:
1141 0 : DO_ACT(GF_SWF_AS3_TOGGLE_QUALITY)
1142 : /* stop sounds*/
1143 0 : case 0x09:
1144 0 : DO_ACT(GF_SWF_AS3_STOP_SOUNDS)
1145 : /* wait for frame */
1146 2 : case 0x8A:
1147 : assert (length == 3);
1148 2 : act.type = GF_SWF_AS3_WAIT_FOR_FRAME;
1149 2 : act.frame_number = swf_get_16(read);
1150 2 : skip_actions = swf_read_int(read, 8);
1151 2 : if (read->action(read, &act)) skip_actions = 0;
1152 : break;
1153 : /* set target */
1154 0 : case 0x8B:
1155 0 : act.type = GF_SWF_AS3_SET_TARGET;
1156 0 : act.target = swf_get_string(read);
1157 0 : read->action(read, &act);
1158 0 : gf_free(act.target);
1159 0 : break;
1160 : /* goto label */
1161 0 : case 0x8C:
1162 0 : act.type = GF_SWF_AS3_GOTO_LABEL;
1163 0 : act.target = swf_get_string(read);
1164 0 : read->action(read, &act);
1165 0 : gf_free(act.target);
1166 0 : break;
1167 46 : default:
1168 : // swf_report(read, GF_OK, "Skipping unsupported action %x", action_code);
1169 46 : if (length) swf_skip_data(read, length);
1170 : break;
1171 : }
1172 : }
1173 138 : action_code = swf_read_int(read, 8);
1174 : }
1175 : #undef DO_ACT
1176 :
1177 18 : return GF_OK;
1178 : }
1179 :
1180 8 : static GF_Err swf_def_button(SWFReader *read, u32 revision)
1181 : {
1182 : SWF_Button button;
1183 : Bool has_actions;
1184 :
1185 : memset(&button, 0, sizeof(SWF_Button));
1186 : has_actions = 0;
1187 : button.count = 0;
1188 8 : button.ID = swf_get_16(read);
1189 8 : if (revision==1) {
1190 8 : gf_bs_read_int(read->bs, 7);
1191 8 : gf_bs_read_int(read->bs, 1);
1192 8 : has_actions = swf_get_16(read);
1193 : }
1194 44 : while (1) {
1195 52 : SWF_ButtonRecord *rec = &button.buttons[button.count];
1196 52 : gf_bs_read_int(read->bs, 4);
1197 52 : rec->hitTest = gf_bs_read_int(read->bs, 1);
1198 52 : rec->down = gf_bs_read_int(read->bs, 1);
1199 52 : rec->over = gf_bs_read_int(read->bs, 1);
1200 52 : rec->up = gf_bs_read_int(read->bs, 1);
1201 52 : if (!rec->hitTest && !rec->up && !rec->over && !rec->down) break;
1202 44 : rec->character_id = swf_get_16(read);
1203 44 : rec->depth = swf_get_16(read);
1204 44 : swf_get_matrix(read, &rec->mx);
1205 44 : if (revision==1) {
1206 44 : swf_align(read);
1207 44 : swf_get_colormatrix(read, &rec->cmx);
1208 : }
1209 0 : else gf_cmx_init(&rec->cmx);
1210 44 : gf_bs_align(read->bs);
1211 44 : button.count++;
1212 : }
1213 8 : read->define_button(read, &button);
1214 8 : if (revision==0) {
1215 0 : swf_actions(read, GF_SWF_COND_OVERUP_TO_OVERDOWN, 0);
1216 : } else {
1217 14 : while (has_actions) {
1218 : u32 i, mask, key;
1219 6 : has_actions = swf_get_16(read);
1220 : mask = 0;
1221 54 : for (i=0; i<8; i++) {
1222 96 : if (swf_read_int(read, 1))
1223 6 : mask |= 1<<i;
1224 : }
1225 6 : key = swf_read_int(read, 7);
1226 12 : if (swf_read_int(read, 1))
1227 0 : mask |= GF_SWF_COND_OVERDOWN_TO_IDLE;
1228 :
1229 6 : swf_actions(read, mask, key);
1230 : }
1231 : }
1232 8 : read->define_button(read, NULL);
1233 8 : return GF_OK;
1234 : }
1235 :
1236 : static Bool swf_mat_is_identity(GF_Matrix2D *mat)
1237 : {
1238 10718 : if (mat->m[0] != FIX_ONE) return 0;
1239 2433 : if (mat->m[4] != FIX_ONE) return 0;
1240 2415 : if (mat->m[1]) return 0;
1241 2415 : if (mat->m[2]) return 0;
1242 461 : if (mat->m[3]) return 0;
1243 461 : if (mat->m[5]) return 0;
1244 : return 1;
1245 : }
1246 :
1247 5388 : static GF_Err swf_place_obj(SWFReader *read, u32 revision)
1248 : {
1249 : GF_Err e;
1250 : u32 shape_id;
1251 : u32 ID, bitsize;
1252 : u32 clip_depth;
1253 : GF_Matrix2D mat;
1254 : GF_ColorMatrix cmat;
1255 : DispShape *ds;
1256 : char *name;
1257 : u32 depth, type;
1258 : Bool had_depth;
1259 : /*SWF flags*/
1260 : Bool has_clip_actions, has_clip, has_name, has_ratio, has_cmat, has_mat, has_id, has_move;
1261 :
1262 : name = NULL;
1263 : clip_depth = 0;
1264 : ID = 0;
1265 : depth = 0;
1266 : has_cmat = has_mat = has_move = 0;
1267 :
1268 5388 : gf_cmx_init(&cmat);
1269 5388 : gf_mx2d_init(mat);
1270 : /*place*/
1271 : type = SWF_PLACE;
1272 :
1273 : /*SWF 1.0*/
1274 5388 : if (revision==0) {
1275 0 : ID = swf_get_16(read);
1276 0 : depth = swf_get_16(read);
1277 : bitsize = 32;
1278 0 : bitsize += swf_get_matrix(read, &mat);
1279 : has_mat = 1;
1280 0 : bitsize += swf_align(read);
1281 : /*size exceeds matrix, parse col mat*/
1282 0 : if (bitsize < read->size*8) {
1283 0 : swf_get_colormatrix(read, &cmat);
1284 : has_cmat = 1;
1285 0 : swf_align(read);
1286 : }
1287 : }
1288 : /*SWF 3.0*/
1289 5388 : else if (revision==1) {
1290 : /*reserved*/
1291 5388 : has_clip_actions = swf_read_int(read, 1);
1292 5388 : has_clip = swf_read_int(read, 1);
1293 5388 : has_name = swf_read_int(read, 1);
1294 5388 : has_ratio = swf_read_int(read, 1);
1295 5388 : has_cmat = swf_read_int(read, 1);
1296 5388 : has_mat = swf_read_int(read, 1);
1297 5388 : has_id = swf_read_int(read, 1);
1298 5388 : has_move = swf_read_int(read, 1);
1299 :
1300 5388 : depth = swf_get_16(read);
1301 7575 : if (has_id) ID = swf_get_16(read);
1302 5388 : if (has_mat) {
1303 4502 : swf_get_matrix(read, &mat);
1304 4502 : swf_align(read);
1305 : }
1306 5388 : if (has_cmat) {
1307 136 : swf_align(read);
1308 136 : swf_get_colormatrix(read, &cmat);
1309 136 : swf_align(read);
1310 : }
1311 5388 : if (has_ratio) /*ratio = */swf_get_16(read);
1312 5388 : if (has_clip) clip_depth = swf_get_16(read);
1313 :
1314 5388 : if (has_name) {
1315 3 : name = swf_get_string(read);
1316 3 : gf_free(name);
1317 : }
1318 5388 : if (has_clip_actions) {
1319 : swf_get_16(read);
1320 : swf_get_16(read);
1321 : }
1322 : /*replace*/
1323 5388 : if (has_id && has_move) type = SWF_REPLACE;
1324 : /*move*/
1325 3897 : else if (!has_id && has_move) type = SWF_MOVE;
1326 : /*place*/
1327 : else type = SWF_PLACE;
1328 : }
1329 :
1330 5388 : if (clip_depth) {
1331 0 : swf_report(read, GF_NOT_SUPPORTED, "Clipping not supported - ignoring");
1332 0 : return GF_OK;
1333 : }
1334 :
1335 : /*1: check depth of display list*/
1336 5388 : had_depth = read->allocate_depth(read, depth);
1337 : /*check validity*/
1338 5388 : if ((type==SWF_MOVE) && !had_depth) swf_report(read, GF_BAD_PARAM, "Accessing empty depth level %d", depth);
1339 :
1340 : ds = NULL;
1341 :
1342 : /*usual case: (re)place depth level*/
1343 5388 : switch (type) {
1344 3201 : case SWF_MOVE:
1345 3201 : ds = swf_get_depth_entry(read, depth, 0);
1346 3201 : shape_id = ds ? ds->char_id : 0;
1347 : break;
1348 : case SWF_REPLACE:
1349 : case SWF_PLACE:
1350 : default:
1351 : shape_id = ID;
1352 : break;
1353 : }
1354 :
1355 5388 : if (!shape_id) {
1356 0 : swf_report(read, GF_BAD_PARAM, "%s unfound object (ID %d)", (type==SWF_MOVE) ? "Moving" : ((type==SWF_PLACE) ? "Placing" : "Replacing"), ID);
1357 0 : return GF_OK;
1358 : }
1359 : /*restore prev matrix if needed*/
1360 5388 : if (type==SWF_REPLACE) {
1361 1491 : if (!ds) ds = swf_get_depth_entry(read, depth, 0);
1362 1491 : if (ds) {
1363 1487 : if (!has_mat) {
1364 828 : memcpy(&mat, &ds->mat, sizeof(GF_Matrix2D));
1365 : has_mat = 1;
1366 : }
1367 1487 : if (!has_cmat) {
1368 1391 : memcpy(&cmat, &ds->cmat, sizeof(GF_ColorMatrix));
1369 : has_cmat = 1;
1370 : }
1371 : }
1372 : }
1373 :
1374 : /*check for identity matrices*/
1375 3997 : if (has_cmat && cmat.identity) has_cmat = 0;
1376 5388 : if (has_mat && swf_mat_is_identity(&mat)) has_mat = 0;
1377 :
1378 : /*store in display list*/
1379 5388 : ds = swf_get_depth_entry(read, depth, 1);
1380 15833 : e = read->place_obj(read, depth, shape_id, ds->char_id, type,
1381 : has_mat ? &mat : NULL,
1382 : has_cmat ? &cmat : NULL,
1383 : swf_mat_is_identity(&ds->mat) ? NULL : &ds->mat,
1384 5388 : ds->cmat.identity ? NULL : &ds->cmat);
1385 :
1386 : /*remember matrices*/
1387 5388 : memcpy(&ds->mat, &mat, sizeof(GF_Matrix2D));
1388 5388 : memcpy(&ds->cmat, &cmat, sizeof(GF_ColorMatrix));
1389 5388 : ds->char_id = shape_id;
1390 :
1391 5388 : if (e) swf_report(read, e, "Error %s object ID %d", (type==SWF_MOVE) ? "Moving" : ((type==SWF_PLACE) ? "Placing" : "Replacing"), shape_id);
1392 : return GF_OK;
1393 : }
1394 :
1395 593 : static GF_Err swf_remove_obj(SWFReader *read, u32 revision)
1396 : {
1397 : GF_Err e;
1398 : DispShape *ds;
1399 : u32 depth;
1400 593 : if (revision==0) swf_get_16(read);
1401 593 : depth = swf_get_16(read);
1402 593 : ds = swf_get_depth_entry(read, depth, 0);
1403 : /*this happens if a placeObject has failed*/
1404 593 : if (!ds) return GF_OK;
1405 593 : e = read->remove_obj(read, depth, ds->char_id);
1406 593 : ds->char_id = 0;
1407 593 : return e;
1408 : }
1409 :
1410 : static GF_Err swf_show_frame(SWFReader *read)
1411 : {
1412 : GF_Err e;
1413 3302 : e = read->show_frame(read);
1414 3302 : read->current_frame ++;
1415 : return e;
1416 : }
1417 :
1418 25 : static GF_Err swf_def_font(SWFReader *read, u32 revision)
1419 : {
1420 : u32 i, count;
1421 : GF_Err e;
1422 : SWFFont *ft;
1423 : u32 *offset_table = NULL;
1424 : u32 start;
1425 :
1426 25 : GF_SAFEALLOC(ft, SWFFont);
1427 25 : if (!ft) return GF_OUT_OF_MEM;
1428 :
1429 25 : ft->glyphs = gf_list_new();
1430 25 : ft->fontID = swf_get_16(read);
1431 : e = GF_OK;
1432 :
1433 :
1434 25 : if (revision==0) {
1435 11 : start = swf_get_file_pos(read);
1436 :
1437 11 : count = swf_get_16(read);
1438 11 : ft->nbGlyphs = count / 2;
1439 11 : offset_table = (u32*)gf_malloc(sizeof(u32) * ft->nbGlyphs);
1440 11 : offset_table[0] = 0;
1441 285 : for (i=1; i<ft->nbGlyphs; i++) offset_table[i] = swf_get_16(read);
1442 :
1443 285 : for (i=0; i<ft->nbGlyphs; i++) {
1444 285 : swf_align(read);
1445 285 : e = swf_seek_file_to(read, start + offset_table[i]);
1446 285 : if (e) break;
1447 285 : swf_parse_shape_def(read, ft, 0);
1448 : }
1449 11 : gf_free(offset_table);
1450 11 : if (e) return e;
1451 14 : } else if (revision==1) {
1452 : SWFRec rc;
1453 : Bool wide_offset, wide_codes;
1454 : u32 code_offset, checkpos;
1455 28 : ft->has_layout = swf_read_int(read, 1);
1456 28 : ft->has_shiftJIS = swf_read_int(read, 1);
1457 28 : ft->is_unicode = swf_read_int(read, 1);
1458 28 : ft->is_ansi = swf_read_int(read, 1);
1459 14 : wide_offset = swf_read_int(read, 1);
1460 14 : wide_codes = swf_read_int(read, 1);
1461 28 : ft->is_italic = swf_read_int(read, 1);
1462 28 : ft->is_bold = swf_read_int(read, 1);
1463 14 : swf_read_int(read, 8);
1464 14 : count = swf_read_int(read, 8);
1465 14 : ft->fontName = (char*)gf_malloc(sizeof(u8)*count+1);
1466 14 : ft->fontName[count] = 0;
1467 84 : for (i=0; i<count; i++) ft->fontName[i] = swf_read_int(read, 8);
1468 :
1469 14 : ft->nbGlyphs = swf_get_16(read);
1470 14 : start = swf_get_file_pos(read);
1471 :
1472 14 : if (ft->nbGlyphs) {
1473 8 : offset_table = (u32*)gf_malloc(sizeof(u32) * ft->nbGlyphs);
1474 130 : for (i=0; i<ft->nbGlyphs; i++) {
1475 122 : if (wide_offset) offset_table[i] = swf_get_32(read);
1476 122 : else offset_table[i] = swf_get_16(read);
1477 : }
1478 : }
1479 :
1480 14 : if (wide_offset) {
1481 0 : code_offset = swf_get_32(read);
1482 : } else {
1483 14 : code_offset = swf_get_16(read);
1484 : }
1485 :
1486 14 : if (ft->nbGlyphs) {
1487 122 : for (i=0; i<ft->nbGlyphs; i++) {
1488 122 : swf_align(read);
1489 122 : e = swf_seek_file_to(read, start + offset_table[i]);
1490 122 : if (e) break;
1491 :
1492 122 : swf_parse_shape_def(read, ft, 0);
1493 : }
1494 8 : gf_free(offset_table);
1495 8 : if (e) return e;
1496 :
1497 8 : checkpos = swf_get_file_pos(read);
1498 8 : if (checkpos != start + code_offset) {
1499 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[SWF Parsing] bad code offset in font\n"));
1500 : return GF_NON_COMPLIANT_BITSTREAM;
1501 : }
1502 :
1503 8 : ft->glyph_codes = (u16*)gf_malloc(sizeof(u16) * ft->nbGlyphs);
1504 130 : for (i=0; i<ft->nbGlyphs; i++) {
1505 204 : if (wide_codes) ft->glyph_codes[i] = swf_get_16(read);
1506 80 : else ft->glyph_codes[i] = swf_read_int(read, 8);
1507 : }
1508 : }
1509 14 : if (ft->has_layout) {
1510 10 : ft->ascent = swf_get_s16(read);
1511 10 : ft->descent = swf_get_s16(read);
1512 10 : ft->leading = swf_get_s16(read);
1513 10 : if (ft->nbGlyphs) {
1514 8 : ft->glyph_adv = (s16*)gf_malloc(sizeof(s16) * ft->nbGlyphs);
1515 8 : for (i=0; i<ft->nbGlyphs; i++) ft->glyph_adv[i] = swf_get_s16(read);
1516 122 : for (i=0; i<ft->nbGlyphs; i++) swf_get_rec(read, &rc);
1517 : }
1518 : /*kerning info*/
1519 10 : count = swf_get_16(read);
1520 10 : for (i=0; i<count; i++) {
1521 0 : if (wide_codes) {
1522 : swf_get_16(read);
1523 : swf_get_16(read);
1524 : } else {
1525 0 : swf_read_int(read, 8);
1526 0 : swf_read_int(read, 8);
1527 : }
1528 0 : swf_get_s16(read);
1529 : }
1530 : }
1531 : }
1532 :
1533 25 : gf_list_add(read->fonts, ft);
1534 25 : return GF_OK;
1535 : }
1536 :
1537 11 : static GF_Err swf_def_font_info(SWFReader *read)
1538 : {
1539 : SWFFont *ft;
1540 : Bool wide_chars;
1541 : u32 i, count;
1542 :
1543 11 : i = swf_get_16(read);
1544 11 : ft = swf_find_font(read, i);
1545 11 : if (!ft) {
1546 0 : swf_report(read, GF_BAD_PARAM, "Cannot locate font ID %d", i);
1547 0 : return GF_BAD_PARAM;
1548 : }
1549 : /*overwrite font info*/
1550 11 : if (ft->fontName) gf_free(ft->fontName);
1551 11 : count = swf_read_int(read, 8);
1552 11 : ft->fontName = (char*)gf_malloc(sizeof(char) * (count+1));
1553 11 : ft->fontName[count] = 0;
1554 158 : for (i=0; i<count; i++) ft->fontName[i] = swf_read_int(read, 8);
1555 11 : swf_read_int(read, 2);
1556 22 : ft->is_unicode = swf_read_int(read, 1);
1557 22 : ft->has_shiftJIS = swf_read_int(read, 1);
1558 22 : ft->is_ansi = swf_read_int(read, 1);
1559 22 : ft->is_italic = swf_read_int(read, 1);
1560 22 : ft->is_bold = swf_read_int(read, 1);
1561 : /*TODO - this should be remapped to a font data stream, we currently only assume the glyph code
1562 : table is the same as the original font file...*/
1563 11 : wide_chars = swf_read_int(read, 1);
1564 11 : if (ft->glyph_codes) gf_free(ft->glyph_codes);
1565 11 : ft->glyph_codes = (u16*)gf_malloc(sizeof(u16) * ft->nbGlyphs);
1566 :
1567 296 : for (i=0; i<ft->nbGlyphs; i++) {
1568 285 : if (wide_chars) ft->glyph_codes[i] = swf_get_16(read);
1569 570 : else ft->glyph_codes[i] = swf_read_int(read, 8);
1570 : }
1571 : return GF_OK;
1572 : }
1573 :
1574 81 : static GF_Err swf_def_text(SWFReader *read, u32 revision)
1575 : {
1576 : SWFRec rc;
1577 : SWFText txt;
1578 : Bool flag;
1579 : u32 nbits_adv, nbits_glyph, i, col, fontID, count, font_height;
1580 : Fixed offX, offY;
1581 : GF_Err e;
1582 :
1583 81 : txt.ID = swf_get_16(read);
1584 81 : swf_get_rec(read, &rc);
1585 81 : swf_get_matrix(read, &txt.mat);
1586 81 : txt.text = gf_list_new();
1587 :
1588 81 : swf_align(read);
1589 81 : nbits_glyph = swf_read_int(read, 8);
1590 81 : nbits_adv = swf_read_int(read, 8);
1591 : fontID = 0;
1592 : offX = offY = 0;
1593 : font_height = 0;
1594 : col = 0xFF000000;
1595 : e = GF_OK;
1596 :
1597 : while (1) {
1598 273 : flag = swf_read_int(read, 1);
1599 : /*regular glyph record*/
1600 273 : if (!flag) {
1601 : SWFGlyphRec *gr;
1602 177 : count = swf_read_int(read, 7);
1603 177 : if (!count) break;
1604 :
1605 96 : if (!fontID) {
1606 : e = GF_BAD_PARAM;
1607 0 : swf_report(read, GF_BAD_PARAM, "Defining text %d without assigning font", fontID);
1608 : break;
1609 : }
1610 :
1611 96 : GF_SAFEALLOC(gr, SWFGlyphRec);
1612 96 : if (!gr) return GF_OUT_OF_MEM;
1613 :
1614 96 : gf_list_add(txt.text, gr);
1615 96 : gr->fontID = fontID;
1616 96 : gr->fontSize = font_height;
1617 96 : gr->col = col;
1618 96 : gr->orig_x = offX;
1619 96 : gr->orig_y = offY;
1620 96 : gr->nbGlyphs = count;
1621 96 : gr->indexes = (u32*)gf_malloc(sizeof(u32) * gr->nbGlyphs);
1622 96 : gr->dx = (Fixed*)gf_malloc(sizeof(Fixed) * gr->nbGlyphs);
1623 1857 : for (i=0; i<gr->nbGlyphs; i++) {
1624 3522 : gr->indexes[i] = swf_read_int(read, nbits_glyph);
1625 3522 : gr->dx[i] = FLT2FIX( swf_read_int(read, nbits_adv) * SWF_TWIP_SCALE );
1626 : }
1627 96 : swf_align(read);
1628 : }
1629 : /*text state change*/
1630 : else {
1631 : Bool has_font, has_col, has_y_off, has_x_off;
1632 : /*reserved*/
1633 96 : swf_read_int(read, 3);
1634 96 : has_font = swf_read_int(read, 1);
1635 96 : has_col = swf_read_int(read, 1);
1636 96 : has_y_off = swf_read_int(read, 1);
1637 96 : has_x_off = swf_read_int(read, 1);
1638 :
1639 : /*end of rec*/
1640 96 : if (!has_font && !has_col && !has_y_off && !has_x_off) break;
1641 177 : if (has_font) fontID = swf_get_16(read);
1642 96 : if (has_col) {
1643 81 : if (revision==0) col = swf_get_color(read);
1644 0 : else col = swf_get_argb(read);
1645 : }
1646 : /*openSWF spec seems to have wrong order here*/
1647 96 : if (has_x_off) offX = FLT2FIX( swf_get_s16(read) * SWF_TWIP_SCALE );
1648 96 : if (has_y_off) offY = FLT2FIX( swf_get_s16(read) * SWF_TWIP_SCALE );
1649 177 : if (has_font) font_height = swf_get_16(read);
1650 : }
1651 : }
1652 :
1653 : if (e) goto exit;
1654 :
1655 81 : if (! (read->flags & GF_SM_SWF_NO_TEXT) ) {
1656 81 : e = read->define_text(read, &txt);
1657 : }
1658 :
1659 0 : exit:
1660 177 : while (gf_list_count(txt.text)) {
1661 96 : SWFGlyphRec *gr = (SWFGlyphRec *)gf_list_get(txt.text, 0);
1662 96 : gf_list_rem(txt.text, 0);
1663 96 : if (gr->indexes) gf_free(gr->indexes);
1664 96 : if (gr->dx) gf_free(gr->dx);
1665 96 : gf_free(gr);
1666 : }
1667 81 : gf_list_del(txt.text);
1668 :
1669 81 : return e;
1670 : }
1671 :
1672 :
1673 4 : static GF_Err swf_def_edit_text(SWFReader *read)
1674 : {
1675 : GF_Err e;
1676 : SWFEditText txt;
1677 : char *var_name;
1678 : Bool has_text, has_text_color, has_max_length, has_font;
1679 :
1680 : memset(&txt, 0, sizeof(SWFEditText));
1681 4 : txt.color = 0xFF000000;
1682 :
1683 4 : txt.ID = swf_get_16(read);
1684 4 : swf_get_rec(read, &txt.bounds);
1685 4 : swf_align(read);
1686 :
1687 4 : has_text = swf_read_int(read, 1);
1688 8 : txt.word_wrap = swf_read_int(read, 1);
1689 8 : txt.multiline = swf_read_int(read, 1);
1690 8 : txt.password = swf_read_int(read, 1);
1691 8 : txt.read_only = swf_read_int(read, 1);
1692 4 : has_text_color = swf_read_int(read, 1);
1693 4 : has_max_length = swf_read_int(read, 1);
1694 4 : has_font = swf_read_int(read, 1);
1695 4 : /*reserved*/swf_read_int(read, 1);
1696 8 : txt.auto_size = swf_read_int(read, 1);
1697 8 : txt.has_layout = swf_read_int(read, 1);
1698 8 : txt.no_select = swf_read_int(read, 1);
1699 8 : txt.border = swf_read_int(read, 1);
1700 4 : /*reserved*/swf_read_int(read, 1);
1701 8 : txt.html = swf_read_int(read, 1);
1702 8 : txt.outlines = swf_read_int(read, 1);
1703 :
1704 4 : if (has_font) {
1705 4 : txt.fontID = swf_get_16(read);
1706 4 : txt.font_height = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
1707 : }
1708 4 : if (has_text_color) txt.color = swf_get_argb(read);
1709 4 : if (has_max_length) txt.max_length = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
1710 :
1711 4 : if (txt.has_layout) {
1712 4 : txt.align = swf_read_int(read, 8);
1713 2 : txt.left = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
1714 2 : txt.right = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
1715 2 : txt.indent = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
1716 2 : txt.leading = FLT2FIX( swf_get_16(read) * SWF_TWIP_SCALE );
1717 : }
1718 4 : var_name = swf_get_string(read);
1719 4 : if (has_text) txt.init_value = swf_get_string(read);
1720 :
1721 : e = GF_OK;
1722 4 : if (! (read->flags & GF_SM_SWF_NO_TEXT) ) {
1723 4 : e = read->define_edit_text(read, &txt);
1724 : }
1725 4 : gf_free(var_name);
1726 4 : if (txt.init_value) gf_free(txt.init_value);
1727 :
1728 4 : return e;
1729 : }
1730 :
1731 31 : static void swf_delete_sound_stream(SWFReader *read)
1732 : {
1733 31 : if (!read->sound_stream) return;
1734 2 : if (read->sound_stream->output) gf_fclose(read->sound_stream->output);
1735 2 : if (read->sound_stream->szFileName) gf_free(read->sound_stream->szFileName);
1736 2 : gf_free(read->sound_stream);
1737 2 : read->sound_stream = NULL;
1738 : }
1739 :
1740 18 : static GF_Err swf_def_sprite(SWFReader *read)
1741 : {
1742 : GF_Err e;
1743 : GF_List *prev_dlist;
1744 : u32 frame_count;
1745 : Bool prev_sprite;
1746 : u32 prev_frame, prev_depth;
1747 : SWFSound *snd;
1748 :
1749 18 : prev_sprite = read->current_sprite_id;
1750 18 : read->current_sprite_id = swf_get_16(read);
1751 18 : frame_count = swf_get_16(read);
1752 :
1753 : /*store frame state*/
1754 18 : prev_frame = read->current_frame;
1755 18 : read->current_frame = 0;
1756 : /*store soundStream state*/
1757 18 : snd = read->sound_stream;
1758 18 : read->sound_stream = NULL;
1759 : /*store depth state*/
1760 18 : prev_depth = read->max_depth;
1761 18 : read->max_depth = 0;
1762 :
1763 18 : prev_dlist = read->display_list;
1764 18 : read->display_list = gf_list_new();
1765 :
1766 18 : e = read->define_sprite(read, frame_count);
1767 18 : if (e) return e;
1768 :
1769 : /*close sprite soundStream*/
1770 18 : swf_delete_sound_stream(read);
1771 : /*restore sound stream*/
1772 18 : read->sound_stream = snd;
1773 18 : read->max_depth = prev_depth;
1774 :
1775 51 : while (gf_list_count(read->display_list)) {
1776 15 : DispShape *s = (DispShape *)gf_list_get(read->display_list, 0);
1777 15 : gf_list_rem(read->display_list, 0);
1778 15 : gf_free(s);
1779 : }
1780 18 : gf_list_del(read->display_list);
1781 18 : read->display_list = prev_dlist;
1782 :
1783 18 : read->current_frame = prev_frame;
1784 18 : read->current_sprite_id = prev_sprite;
1785 :
1786 18 : read->tag = SWF_DEFINESPRITE;
1787 18 : return GF_OK;
1788 : }
1789 :
1790 2 : static GF_Err swf_def_sound(SWFReader *read)
1791 : {
1792 : SWFSound *snd;
1793 2 : GF_SAFEALLOC(snd , SWFSound);
1794 2 : if (!snd) return GF_OUT_OF_MEM;
1795 2 : snd->ID = swf_get_16(read);
1796 4 : snd->format = swf_read_int(read, 4);
1797 4 : snd->sound_rate = swf_read_int(read, 2);
1798 4 : snd->bits_per_sample = swf_read_int(read, 1) ? 16 : 8;
1799 4 : snd->stereo = swf_read_int(read, 1);
1800 2 : snd->sample_count = swf_get_32(read);
1801 :
1802 2 : switch (snd->format) {
1803 : /*raw PCM*/
1804 0 : case 0:
1805 0 : swf_report(read, GF_NOT_SUPPORTED, "Raw PCM Audio not supported");
1806 0 : gf_free(snd);
1807 0 : break;
1808 : /*ADPCM*/
1809 0 : case 1:
1810 0 : swf_report(read, GF_NOT_SUPPORTED, "AD-PCM Audio not supported");
1811 0 : gf_free(snd);
1812 0 : break;
1813 : /*MP3*/
1814 2 : case 2:
1815 : {
1816 : char szName[1024];
1817 : u32 alloc_size, tot_size;
1818 : char *frame;
1819 :
1820 2 : sprintf(szName, "swf_sound_%d.mp3", snd->ID);
1821 2 : if (read->localPath) {
1822 2 : snd->szFileName = (char*)gf_malloc(sizeof(char)*GF_MAX_PATH);
1823 2 : strcpy(snd->szFileName, read->localPath);
1824 2 : strcat(snd->szFileName, szName);
1825 : } else {
1826 0 : snd->szFileName = gf_strdup(szName);
1827 : }
1828 2 : snd->output = gf_fopen(snd->szFileName, "wb");
1829 :
1830 : alloc_size = 4096;
1831 2 : frame = (char*)gf_malloc(sizeof(char)*4096);
1832 : /*snd->frame_delay_ms =*/ swf_get_16(read);
1833 2 : snd->frame_delay_ms = read->current_frame*1000;
1834 2 : snd->frame_delay_ms /= read->frame_rate;
1835 : tot_size = 9;
1836 : /*parse all frames*/
1837 96 : while (tot_size<read->size) {
1838 92 : u32 toread = read->size - tot_size;
1839 92 : if (toread>alloc_size) toread = alloc_size;
1840 92 : swf_read_data(read, frame, toread);
1841 92 : gf_fwrite(frame, sizeof(char)*toread, snd->output);
1842 92 : tot_size += toread;
1843 : }
1844 :
1845 2 : gf_free(frame);
1846 2 : return gf_list_add(read->sounds, snd);
1847 : }
1848 0 : case 3:
1849 0 : swf_report(read, GF_NOT_SUPPORTED, "Unrecognized sound format");
1850 0 : gf_free(snd);
1851 0 : break;
1852 : }
1853 : return GF_OK;
1854 : }
1855 :
1856 :
1857 : typedef struct
1858 : {
1859 : u32 sync_flags;
1860 : u32 in_point, out_point;
1861 : u32 nb_loops;
1862 : } SoundInfo;
1863 :
1864 2 : static SoundInfo swf_skip_soundinfo(SWFReader *read)
1865 : {
1866 : SoundInfo si;
1867 2 : u32 sync_flags = swf_read_int(read, 4);
1868 2 : Bool has_env = swf_read_int(read, 1);
1869 2 : Bool has_loops = swf_read_int(read, 1);
1870 2 : Bool has_out_pt = swf_read_int(read, 1);
1871 2 : Bool has_in_pt = swf_read_int(read, 1);
1872 :
1873 : memset(&si, 0, sizeof(SoundInfo));
1874 2 : si.sync_flags = sync_flags;
1875 2 : if (has_in_pt) si.in_point = swf_get_32(read);
1876 2 : if (has_out_pt) si.out_point = swf_get_32(read);
1877 2 : if (has_loops) si.nb_loops = swf_get_16(read);
1878 : /*we ignore the envelope*/
1879 2 : if (has_env) {
1880 : u32 i;
1881 0 : u32 nb_ctrl = swf_read_int(read, 8);
1882 0 : for (i=0; i<nb_ctrl; i++) {
1883 0 : swf_read_int(read, 32); /*mark44*/
1884 0 : swf_read_int(read, 16); /*l0*/
1885 0 : swf_read_int(read, 16); /*l1*/
1886 : }
1887 : }
1888 2 : return si;
1889 : }
1890 :
1891 : static SWFSound *sndswf_get_sound(SWFReader *read, u32 ID)
1892 : {
1893 : u32 i;
1894 : SWFSound *snd;
1895 2 : i=0;
1896 2 : while ((snd = (SWFSound *)gf_list_enum(read->sounds, &i))) {
1897 2 : if (snd->ID==ID) return snd;
1898 : }
1899 : return NULL;
1900 : }
1901 :
1902 2 : static GF_Err swf_start_sound(SWFReader *read)
1903 : {
1904 : SWFSound *snd;
1905 2 : u32 ID = swf_get_16(read);
1906 : SoundInfo si;
1907 2 : si = swf_skip_soundinfo(read);
1908 :
1909 : snd = sndswf_get_sound(read, ID);
1910 2 : if (!snd) {
1911 0 : swf_report(read, GF_BAD_PARAM, "Cannot find sound with ID %d", ID);
1912 0 : return GF_OK;
1913 : }
1914 2 : if (!snd->is_setup) {
1915 2 : GF_Err e = read->setup_sound(read, snd, 0);
1916 2 : if (e) return e;
1917 2 : snd->is_setup = 1;
1918 : }
1919 2 : return read->start_sound(read, snd, (si.sync_flags & 0x2) ? 1 : 0);
1920 : }
1921 :
1922 2 : static GF_Err swf_soundstream_hdr(SWFReader *read)
1923 : {
1924 : char szName[1024];
1925 : SWFSound *snd;
1926 :
1927 2 : if (read->sound_stream) {
1928 0 : swf_report(read, GF_BAD_PARAM, "More than one sound stream for current timeline!!");
1929 0 : return swf_func_skip(read);
1930 : }
1931 :
1932 2 : GF_SAFEALLOC(snd, SWFSound);
1933 2 : if (!snd) return GF_OUT_OF_MEM;
1934 :
1935 2 : /*rec_mix = */swf_read_int(read, 8);
1936 : /*0: uncompressed, 1: ADPCM, 2: MP3*/
1937 4 : snd->format = swf_read_int(read, 4);
1938 : /*0: 5.5k, 1: 11k, 2: 2: 22k, 3: 44k*/
1939 4 : snd->sound_rate = swf_read_int(read, 2);
1940 : /*0: 8 bit, 1: 16 bit*/
1941 4 : snd->bits_per_sample = swf_read_int(read, 1) ? 16 : 8;
1942 : /*0: mono, 8 1: stereo*/
1943 4 : snd->stereo = swf_read_int(read, 1);
1944 : /*samplesperframe hint*/
1945 2 : swf_read_int(read, 16);
1946 :
1947 2 : switch (snd->format) {
1948 : /*raw PCM*/
1949 0 : case 0:
1950 0 : swf_report(read, GF_NOT_SUPPORTED, "Raw PCM Audio not supported");
1951 0 : gf_free(snd);
1952 0 : break;
1953 : /*ADPCM*/
1954 0 : case 1:
1955 0 : swf_report(read, GF_NOT_SUPPORTED, "AD-PCM Audio not supported");
1956 0 : gf_free(snd);
1957 0 : break;
1958 : /*MP3*/
1959 2 : case 2:
1960 2 : read->sound_stream = snd;
1961 2 : if (read->localPath) {
1962 2 : sprintf(szName, "%s/swf_soundstream_%d.mp3", read->localPath, read->current_sprite_id);
1963 : } else {
1964 0 : sprintf(szName, "swf_soundstream_%d.mp3", read->current_sprite_id);
1965 : }
1966 2 : read->sound_stream->szFileName = gf_strdup(szName);
1967 2 : read->setup_sound(read, read->sound_stream, 0);
1968 2 : break;
1969 0 : case 3:
1970 0 : swf_report(read, GF_NOT_SUPPORTED, "Unrecognized sound format");
1971 0 : gf_free(snd);
1972 0 : break;
1973 : }
1974 : return GF_OK;
1975 : }
1976 :
1977 336 : static GF_Err swf_soundstream_block(SWFReader *read)
1978 : {
1979 : #ifdef GPAC_DISABLE_AV_PARSERS
1980 : return swf_func_skip(read);
1981 : #else
1982 : unsigned char bytes[4];
1983 : u32 hdr, alloc_size, size, tot_size, samplesPerFrame;
1984 : char *frame;
1985 :
1986 : /*note we're doing only MP3*/
1987 336 : if (!read->sound_stream) return swf_func_skip(read);
1988 :
1989 : samplesPerFrame = swf_get_16(read);
1990 : /*delay = */swf_get_16(read);
1991 :
1992 336 : if (!read->sound_stream->is_setup) {
1993 :
1994 : /*error at setup*/
1995 2 : if (!read->sound_stream->output) {
1996 2 : read->sound_stream->output = gf_fopen(read->sound_stream->szFileName, "wb");
1997 2 : if (!read->sound_stream->output)
1998 0 : return swf_func_skip(read);
1999 : }
2000 : /*store TS of first AU*/
2001 2 : read->sound_stream->frame_delay_ms = read->current_frame*1000;
2002 2 : read->sound_stream->frame_delay_ms /= read->frame_rate;
2003 2 : read->setup_sound(read, read->sound_stream, 1);
2004 2 : read->sound_stream->is_setup = 1;
2005 : }
2006 :
2007 336 : if (!samplesPerFrame) return GF_OK;
2008 :
2009 : alloc_size = 1;
2010 334 : frame = (char*)gf_malloc(sizeof(char));
2011 : tot_size = 4;
2012 : /*parse all frames*/
2013 : while (1) {
2014 1072 : bytes[0] = swf_read_int(read, 8);
2015 1072 : bytes[1] = swf_read_int(read, 8);
2016 1072 : bytes[2] = swf_read_int(read, 8);
2017 1072 : bytes[3] = swf_read_int(read, 8);
2018 536 : hdr = GF_4CC(bytes[0], bytes[1], bytes[2], bytes[3]);
2019 536 : size = gf_mp3_frame_size(hdr);
2020 536 : if (alloc_size<size-4) {
2021 334 : frame = (char*)gf_realloc(frame, sizeof(char)*(size-4));
2022 : alloc_size = size-4;
2023 : }
2024 : /*watchout for truncated framesif */
2025 536 : if (tot_size + size >= read->size) size = read->size - tot_size;
2026 :
2027 536 : swf_read_data(read, frame, size-4);
2028 536 : gf_fwrite(bytes, sizeof(char)*4, read->sound_stream->output);
2029 536 : gf_fwrite(frame, sizeof(char)*(size-4), read->sound_stream->output);
2030 536 : if (tot_size + size >= read->size) break;
2031 : tot_size += size;
2032 : }
2033 334 : gf_free(frame);
2034 334 : return GF_OK;
2035 : #endif
2036 : }
2037 :
2038 0 : static GF_Err swf_def_hdr_jpeg(SWFReader *read)
2039 : {
2040 0 : if (!read) return GF_OK;
2041 0 : if (read->jpeg_hdr) {
2042 0 : swf_report(read, GF_NON_COMPLIANT_BITSTREAM, "JPEG Table already defined in file");
2043 0 : return GF_NON_COMPLIANT_BITSTREAM;
2044 : }
2045 0 : read->jpeg_hdr_size = read->size;
2046 0 : if (read->size) {
2047 0 : read->jpeg_hdr = gf_malloc(sizeof(char)*read->size);
2048 0 : swf_read_data(read, (char *) read->jpeg_hdr, read->size);
2049 : }
2050 : return GF_OK;
2051 : }
2052 :
2053 :
2054 2 : static GF_Err swf_def_bits_jpeg(SWFReader *read, u32 version)
2055 : {
2056 : u32 ID;
2057 : FILE *file = NULL;
2058 : char szName[1024];
2059 : u8 *buf;
2060 : u32 skip = 0;
2061 : #ifndef GPAC_DISABLE_AV_PARSERS
2062 : u32 AlphaPlaneSize = 0;
2063 : #endif
2064 2 : u32 size = read->size;
2065 :
2066 2 : ID = swf_get_16(read);
2067 2 : size -= 2;
2068 2 : if (version==3) {
2069 0 : u32 offset = swf_get_32(read);
2070 : #ifndef GPAC_DISABLE_AV_PARSERS
2071 0 : size -= 4;
2072 0 : AlphaPlaneSize = size - offset;
2073 : #endif
2074 : size = offset;
2075 : }
2076 :
2077 : /*dump file*/
2078 2 : if (read->localPath) {
2079 : sprintf(szName, "%s/swf_jpeg_%d.jpg", read->localPath, ID);
2080 : } else {
2081 : sprintf(szName, "swf_jpeg_%d.jpg", ID);
2082 : }
2083 :
2084 2 : if (version!=3)
2085 2 : file = gf_fopen(szName, "wb");
2086 :
2087 2 : if (version==1 && read->jpeg_hdr_size) {
2088 : /*remove JPEG EOI*/
2089 0 : gf_fwrite(read->jpeg_hdr, read->jpeg_hdr_size-2, file);
2090 : /*remove JPEG SOI*/
2091 : swf_get_16(read);
2092 0 : size-=2;
2093 : }
2094 2 : buf = gf_malloc(sizeof(u8)*size);
2095 2 : swf_read_data(read, (char *) buf, size);
2096 2 : if (version==1) {
2097 0 : gf_fwrite(buf, size, file);
2098 : } else {
2099 : u32 i;
2100 12648 : for (i=0; i<size; i++) {
2101 12648 : if ((i+4<size)
2102 12640 : && (buf[i]==0xFF) && (buf[i+1]==0xD9)
2103 0 : && (buf[i+2]==0xFF) && (buf[i+3]==0xD8)
2104 : ) {
2105 0 : memmove(buf+i, buf+i+4, sizeof(char)*(size-i-4));
2106 0 : size -= 4;
2107 0 : break;
2108 : }
2109 : }
2110 2 : if ((buf[0]==0xFF) && (buf[1]==0xD8) && (buf[2]==0xFF) && (buf[3]==0xD8)) {
2111 : skip = 2;
2112 : }
2113 2 : if (version==2)
2114 2 : gf_fwrite(buf+skip, size-skip, file);
2115 : }
2116 2 : if (version!=3)
2117 2 : gf_fclose(file);
2118 :
2119 2 : if (version==3) {
2120 : #ifndef GPAC_DISABLE_AV_PARSERS
2121 : char *dst, *raw;
2122 : GF_Err e;
2123 : u32 codecid;
2124 : u32 osize, w, h, j, pf;
2125 : GF_BitStream *bs;
2126 :
2127 : /*decompress jpeg*/
2128 0 : bs = gf_bs_new( (char *) buf+skip, size-skip, GF_BITSTREAM_READ);
2129 0 : gf_img_parse(bs, &codecid, &w, &h, NULL, NULL);
2130 0 : gf_bs_del(bs);
2131 :
2132 0 : osize = w*h*4;
2133 0 : raw = gf_malloc(sizeof(char)*osize);
2134 0 : memset(raw, 0, sizeof(char)*osize);
2135 0 : e = gf_img_jpeg_dec(buf+skip, size-skip, &w, &h, &pf, raw, &osize, 4);
2136 0 : if (e != GF_OK) {
2137 0 : swf_report(read, e, "Cannopt decode JPEG image");
2138 : }
2139 :
2140 : /*read alpha map and decompress it*/
2141 0 : if (size<AlphaPlaneSize) buf = gf_realloc(buf, sizeof(u8)*AlphaPlaneSize);
2142 0 : swf_read_data(read, (char *) buf, AlphaPlaneSize);
2143 :
2144 0 : osize = w*h;
2145 0 : dst = gf_malloc(sizeof(char)*osize);
2146 0 : uncompress((Bytef *) dst, (uLongf *) &osize, buf, AlphaPlaneSize);
2147 : /*write alpha channel*/
2148 0 : for (j=0; j<osize; j++) {
2149 0 : raw[4*j + 3] = dst[j];
2150 : }
2151 0 : gf_free(dst);
2152 :
2153 : /*write png*/
2154 0 : if (read->localPath) {
2155 : sprintf(szName, "%s/swf_png_%d.png", read->localPath, ID);
2156 : } else {
2157 : sprintf(szName, "swf_png_%d.png", ID);
2158 : }
2159 :
2160 0 : osize = w*h*4;
2161 0 : buf = gf_realloc(buf, sizeof(char)*osize);
2162 0 : gf_img_png_enc(raw, w, h, h*4, GF_PIXEL_RGBA, (char *)buf, &osize);
2163 :
2164 0 : file = gf_fopen(szName, "wb");
2165 0 : gf_fwrite(buf, osize, file);
2166 0 : gf_fclose(file);
2167 :
2168 0 : gf_free(raw);
2169 : #endif //GPAC_DISABLE_AV_PARSERS
2170 : }
2171 2 : gf_free(buf);
2172 :
2173 2 : return read->setup_image(read, ID, szName);
2174 : }
2175 :
2176 :
2177 0 : static const char *swf_get_tag_name(u32 tag)
2178 : {
2179 0 : switch (tag) {
2180 : case SWF_END:
2181 : return "End";
2182 0 : case SWF_SHOWFRAME:
2183 0 : return "ShowFrame";
2184 0 : case SWF_DEFINESHAPE:
2185 0 : return "DefineShape";
2186 0 : case SWF_FREECHARACTER:
2187 0 : return "FreeCharacter";
2188 0 : case SWF_PLACEOBJECT:
2189 0 : return "PlaceObject";
2190 0 : case SWF_REMOVEOBJECT:
2191 0 : return "RemoveObject";
2192 0 : case SWF_DEFINEBITSJPEG:
2193 0 : return "DefineBitsJPEG";
2194 0 : case SWF_DEFINEBUTTON:
2195 0 : return "DefineButton";
2196 0 : case SWF_JPEGTABLES:
2197 0 : return "JPEGTables";
2198 0 : case SWF_SETBACKGROUNDCOLOR:
2199 0 : return "SetBackgroundColor";
2200 0 : case SWF_DEFINEFONT:
2201 0 : return "DefineFont";
2202 0 : case SWF_DEFINETEXT:
2203 0 : return "DefineText";
2204 0 : case SWF_DOACTION:
2205 0 : return "DoAction";
2206 0 : case SWF_DEFINEFONTINFO:
2207 0 : return "DefineFontInfo";
2208 0 : case SWF_DEFINESOUND:
2209 0 : return "DefineSound";
2210 0 : case SWF_STARTSOUND:
2211 0 : return "StartSound";
2212 0 : case SWF_DEFINEBUTTONSOUND:
2213 0 : return "DefineButtonSound";
2214 0 : case SWF_SOUNDSTREAMHEAD:
2215 0 : return "SoundStreamHead";
2216 0 : case SWF_SOUNDSTREAMBLOCK:
2217 0 : return "SoundStreamBlock";
2218 0 : case SWF_DEFINEBITSLOSSLESS:
2219 0 : return "DefineBitsLossless";
2220 0 : case SWF_DEFINEBITSJPEG2:
2221 0 : return "DefineBitsJPEG2";
2222 0 : case SWF_DEFINESHAPE2:
2223 0 : return "DefineShape2";
2224 0 : case SWF_DEFINEBUTTONCXFORM:
2225 0 : return "DefineButtonCXForm";
2226 0 : case SWF_PROTECT:
2227 0 : return "Protect";
2228 0 : case SWF_PLACEOBJECT2:
2229 0 : return "PlaceObject2";
2230 0 : case SWF_REMOVEOBJECT2:
2231 0 : return "RemoveObject2";
2232 0 : case SWF_DEFINESHAPE3:
2233 0 : return "DefineShape3";
2234 0 : case SWF_DEFINETEXT2:
2235 0 : return "DefineText2";
2236 0 : case SWF_DEFINEBUTTON2:
2237 0 : return "DefineButton2";
2238 0 : case SWF_DEFINEBITSJPEG3:
2239 0 : return "DefineBitsJPEG3";
2240 0 : case SWF_DEFINEBITSLOSSLESS2:
2241 0 : return "DefineBitsLossless2";
2242 0 : case SWF_DEFINEEDITTEXT:
2243 0 : return "DefineEditText";
2244 0 : case SWF_DEFINEMOVIE:
2245 0 : return "DefineMovie";
2246 0 : case SWF_DEFINESPRITE:
2247 0 : return "DefineSprite";
2248 0 : case SWF_NAMECHARACTER:
2249 0 : return "NameCharacter";
2250 0 : case SWF_SERIALNUMBER:
2251 0 : return "SerialNumber";
2252 0 : case SWF_GENERATORTEXT:
2253 0 : return "GeneratorText";
2254 0 : case SWF_FRAMELABEL:
2255 0 : return "FrameLabel";
2256 0 : case SWF_SOUNDSTREAMHEAD2:
2257 0 : return "SoundStreamHead2";
2258 0 : case SWF_DEFINEMORPHSHAPE:
2259 0 : return "DefineMorphShape";
2260 0 : case SWF_DEFINEFONT2:
2261 0 : return "DefineFont2";
2262 0 : case SWF_TEMPLATECOMMAND:
2263 0 : return "TemplateCommand";
2264 0 : case SWF_GENERATOR3:
2265 0 : return "Generator3";
2266 0 : case SWF_EXTERNALFONT:
2267 0 : return "ExternalFont";
2268 0 : case SWF_EXPORTASSETS:
2269 0 : return "ExportAssets";
2270 0 : case SWF_IMPORTASSETS:
2271 0 : return "ImportAssets";
2272 0 : case SWF_ENABLEDEBUGGER:
2273 0 : return "EnableDebugger";
2274 0 : case SWF_MX0:
2275 0 : return "MX0";
2276 0 : case SWF_MX1:
2277 0 : return "MX1";
2278 0 : case SWF_MX2:
2279 0 : return "MX2";
2280 0 : case SWF_MX3:
2281 0 : return "MX3";
2282 0 : case SWF_MX4:
2283 0 : return "MX4";
2284 0 : default:
2285 0 : return "UnknownTag";
2286 : }
2287 : }
2288 :
2289 0 : static GF_Err swf_unknown_tag(SWFReader *read)
2290 : {
2291 0 : if (!read) return GF_OK;
2292 0 : swf_report(read, GF_NOT_SUPPORTED, "Tag %s (0x%2x) not implemented - skipping", swf_get_tag_name(read->tag), read->tag);
2293 0 : return swf_func_skip(read);
2294 : }
2295 :
2296 10925 : static GF_Err swf_process_tag(SWFReader *read)
2297 : {
2298 10925 : switch (read->tag) {
2299 : case SWF_END:
2300 : return GF_OK;
2301 : case SWF_PROTECT:
2302 : return GF_OK;
2303 : case SWF_SETBACKGROUNDCOLOR:
2304 13 : return swf_set_backcol(read);
2305 751 : case SWF_DEFINESHAPE:
2306 751 : return swf_parse_shape_def(read, NULL, 0);
2307 304 : case SWF_DEFINESHAPE2:
2308 304 : return swf_parse_shape_def(read, NULL, 1);
2309 49 : case SWF_DEFINESHAPE3:
2310 49 : return swf_parse_shape_def(read, NULL, 2);
2311 0 : case SWF_PLACEOBJECT:
2312 0 : return swf_place_obj(read, 0);
2313 5388 : case SWF_PLACEOBJECT2:
2314 5388 : return swf_place_obj(read, 1);
2315 0 : case SWF_REMOVEOBJECT:
2316 0 : return swf_remove_obj(read, 0);
2317 593 : case SWF_REMOVEOBJECT2:
2318 593 : return swf_remove_obj(read, 1);
2319 : case SWF_SHOWFRAME:
2320 3302 : return swf_show_frame(read);
2321 11 : case SWF_DEFINEFONT:
2322 11 : return swf_def_font(read, 0);
2323 14 : case SWF_DEFINEFONT2:
2324 14 : return swf_def_font(read, 1);
2325 11 : case SWF_DEFINEFONTINFO:
2326 11 : return swf_def_font_info(read);
2327 81 : case SWF_DEFINETEXT:
2328 81 : return swf_def_text(read, 0);
2329 0 : case SWF_DEFINETEXT2:
2330 0 : return swf_def_text(read, 1);
2331 4 : case SWF_DEFINEEDITTEXT:
2332 4 : return swf_def_edit_text(read);
2333 18 : case SWF_DEFINESPRITE:
2334 18 : return swf_def_sprite(read);
2335 : /*no revision needed*/
2336 2 : case SWF_SOUNDSTREAMHEAD:
2337 : case SWF_SOUNDSTREAMHEAD2:
2338 2 : return swf_soundstream_hdr(read);
2339 2 : case SWF_DEFINESOUND:
2340 2 : return swf_def_sound(read);
2341 2 : case SWF_STARTSOUND:
2342 2 : return swf_start_sound(read);
2343 336 : case SWF_SOUNDSTREAMBLOCK:
2344 336 : return swf_soundstream_block(read);
2345 :
2346 0 : case SWF_DEFINEBUTTON:
2347 0 : return swf_def_button(read, 0);
2348 8 : case SWF_DEFINEBUTTON2:
2349 8 : return swf_def_button(read, 1);
2350 : // case SWF_DEFINEBUTTONSOUND:
2351 12 : case SWF_DOACTION:
2352 12 : return swf_actions(read, 0, 0);
2353 0 : case SWF_FRAMELABEL:
2354 : {
2355 0 : char *framelabel = swf_get_string(read);
2356 0 : gf_free(framelabel);
2357 0 : return GF_OK;
2358 : }
2359 :
2360 0 : case SWF_JPEGTABLES:
2361 0 : return swf_def_hdr_jpeg(read);
2362 0 : case SWF_DEFINEBITSJPEG:
2363 0 : return swf_def_bits_jpeg(read, 1);
2364 2 : case SWF_DEFINEBITSJPEG2:
2365 2 : return swf_def_bits_jpeg(read, 2);
2366 0 : case SWF_DEFINEBITSJPEG3:
2367 0 : return swf_def_bits_jpeg(read, 3);
2368 :
2369 0 : default:
2370 0 : return swf_unknown_tag(read);
2371 : }
2372 : }
2373 :
2374 10925 : GF_Err swf_parse_tag(SWFReader *read)
2375 : {
2376 : GF_Err e;
2377 : s32 diff;
2378 : u16 hdr;
2379 : u32 pos;
2380 :
2381 :
2382 : hdr = swf_get_16(read);
2383 10925 : read->tag = hdr>>6;
2384 10925 : read->size = hdr & 0x3f;
2385 10925 : if (read->size == 0x3f) {
2386 1575 : swf_align(read);
2387 1575 : read->size = swf_get_32(read);
2388 : }
2389 10925 : pos = swf_get_file_pos(read);
2390 10925 : diff = pos + read->size;
2391 10925 : gf_set_progress("SWF Parsing", pos, read->length);
2392 :
2393 10925 : e = swf_process_tag(read);
2394 10925 : swf_align(read);
2395 :
2396 21850 : diff -= swf_get_file_pos(read);
2397 10925 : if (diff<0) {
2398 0 : swf_report(read, GF_IO_ERR, "tag %s over-read of %d bytes (size %d)", swf_get_tag_name(read->tag), -1*diff, read->size);
2399 0 : return GF_IO_ERR;
2400 : } else {
2401 10925 : swf_read_int(read, diff*8);
2402 : }
2403 :
2404 :
2405 10925 : if (!e && !read->tag) {
2406 : return GF_EOS;
2407 : }
2408 :
2409 10903 : if (read->ioerr) {
2410 0 : swf_report(read, GF_IO_ERR, "bitstream IO err (tag size %d)", read->size);
2411 0 : return read->ioerr;
2412 : }
2413 : return e;
2414 : }
2415 :
2416 :
2417 :
2418 9 : GF_Err swf_parse_sprite(SWFReader *read)
2419 : {
2420 : /*parse*/
2421 : while (1) {
2422 137 : GF_Err e = swf_parse_tag(read);
2423 137 : if (e<0) {
2424 0 : swf_report(read, e, "Error parsing tag %s", swf_get_tag_name(read->tag));
2425 0 : return e;
2426 : }
2427 : /*done with sprite*/
2428 137 : if (read->tag==SWF_END) break;
2429 : }
2430 : return GF_OK;
2431 : }
2432 :
2433 :
2434 1482 : void swf_report(SWFReader *read, GF_Err e, char *format, ...)
2435 : {
2436 : #ifndef GPAC_DISABLE_LOG
2437 1482 : if (gf_log_tool_level_on(GF_LOG_PARSER, e ? GF_LOG_ERROR : GF_LOG_WARNING)) {
2438 : char szMsg[2048];
2439 : va_list args;
2440 1482 : va_start(args, format);
2441 : vsnprintf(szMsg, 2048, format, args);
2442 1482 : va_end(args);
2443 1482 : GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_PARSER, ("[SWF Parsing] %s (frame %d)\n", szMsg, read->current_frame+1) );
2444 : }
2445 : #endif
2446 1482 : }
2447 :
2448 :
2449 0 : static void swf_io_error(void *par)
2450 : {
2451 : SWFReader *read = (SWFReader *)par;
2452 0 : if (read) read->ioerr = GF_IO_ERR;
2453 0 : }
2454 :
2455 8 : GF_Err gf_sm_load_run_swf(GF_SceneLoader *load)
2456 : {
2457 : GF_Err e;
2458 8 : SWFReader *read = (SWFReader *)load->loader_priv;
2459 8 : if (!read) return GF_BAD_PARAM;
2460 :
2461 : /*parse all tags*/
2462 : while (1) {
2463 7734 : e = swf_parse_tag(read);
2464 7734 : if (e) break;
2465 : }
2466 8 : gf_set_progress("SWF Parsing", read->length, read->length);
2467 :
2468 8 : if (e==GF_EOS) {
2469 8 : if (read->finalize)
2470 8 : read->finalize(read);
2471 : e = GF_OK;
2472 : }
2473 : if (!e) {
2474 8 : if (read->flat_limit != 0)
2475 0 : swf_report(read, GF_OK, "%d points removed while parsing shapes (Flattening limit %.4f)", read->flatten_points, read->flat_limit);
2476 :
2477 8 : if (read->no_as && read->has_interact) swf_report(read, GF_OK, "ActionScripts and interactions have been removed");
2478 : } else
2479 0 : swf_report(read, e, "Error parsing tag %s", swf_get_tag_name(read->tag));
2480 :
2481 :
2482 : return e;
2483 : }
2484 :
2485 119 : void gf_swf_reader_del(SWFReader *read)
2486 : {
2487 119 : if (!read) return;
2488 13 : gf_bs_del(read->bs);
2489 13 : if (read->mem) gf_free(read->mem);
2490 :
2491 170 : while (gf_list_count(read->display_list)) {
2492 157 : DispShape *s = (DispShape *)gf_list_get(read->display_list, 0);
2493 157 : gf_list_rem(read->display_list, 0);
2494 157 : gf_free(s);
2495 : }
2496 13 : gf_list_del(read->display_list);
2497 51 : while (gf_list_count(read->fonts)) {
2498 25 : SWFFont *ft = (SWFFont *)gf_list_get(read->fonts, 0);
2499 25 : gf_list_rem(read->fonts, 0);
2500 25 : if (ft->glyph_adv) gf_free(ft->glyph_adv);
2501 25 : if (ft->glyph_codes) gf_free(ft->glyph_codes);
2502 25 : if (ft->fontName) gf_free(ft->fontName);
2503 25 : gf_list_del(ft->glyphs);
2504 25 : gf_free(ft);
2505 : }
2506 13 : gf_list_del(read->fonts);
2507 13 : gf_list_del(read->apps);
2508 :
2509 28 : while (gf_list_count(read->sounds)) {
2510 2 : SWFSound *snd = (SWFSound *)gf_list_get(read->sounds, 0);
2511 2 : gf_list_rem(read->sounds, 0);
2512 2 : if (snd->output) gf_fclose(snd->output);
2513 2 : if (snd->szFileName) gf_free(snd->szFileName);
2514 2 : gf_free(snd);
2515 : }
2516 13 : gf_list_del(read->sounds);
2517 13 : swf_delete_sound_stream(read);
2518 :
2519 13 : if (read->jpeg_hdr) gf_free(read->jpeg_hdr);
2520 13 : if (read->localPath) gf_free(read->localPath);
2521 13 : gf_fclose(read->input);
2522 13 : gf_free(read->inputName);
2523 13 : gf_free(read);
2524 : }
2525 :
2526 8 : void gf_sm_load_done_swf(GF_SceneLoader *load)
2527 : {
2528 8 : SWFReader *read = (SWFReader *) load->loader_priv;
2529 8 : if (!read) return;
2530 8 : if (read->svg_file) {
2531 1 : gf_fclose(read->svg_file);
2532 1 : read->svg_file = NULL;
2533 : }
2534 8 : gf_swf_reader_del(read);
2535 8 : load->loader_priv = NULL;
2536 : }
2537 :
2538 13 : SWFReader *gf_swf_reader_new(const char *localPath, const char *inputName)
2539 : {
2540 : SWFReader *read;
2541 : FILE *input;
2542 13 : input = gf_fopen(inputName, "rb");
2543 13 : if (!input) return NULL;
2544 :
2545 13 : GF_SAFEALLOC(read, SWFReader);
2546 13 : if (!read) return NULL;
2547 13 : read->inputName = gf_strdup(inputName);
2548 13 : read->input = input;
2549 13 : read->bs = gf_bs_from_file(input, GF_BITSTREAM_READ);
2550 13 : gf_bs_set_eos_callback(read->bs, swf_io_error, &read);
2551 13 : read->display_list = gf_list_new();
2552 13 : read->fonts = gf_list_new();
2553 13 : read->apps = gf_list_new();
2554 13 : read->sounds = gf_list_new();
2555 :
2556 13 : if (localPath) {
2557 0 : read->localPath = gf_strdup(localPath);
2558 : } else {
2559 : char *c;
2560 13 : read->localPath = gf_strdup(inputName);
2561 13 : c = strrchr(read->localPath, GF_PATH_SEPARATOR);
2562 13 : if (c) c[1] = 0;
2563 : else {
2564 0 : gf_free(read->localPath);
2565 0 : read->localPath = NULL;
2566 : }
2567 : }
2568 :
2569 13 : return read;
2570 : }
2571 :
2572 5 : GF_Err gf_swf_reader_set_user_mode(SWFReader *read, void *user,
2573 : GF_Err (*add_sample)(void *user, const u8 *data, u32 length, u64 timestamp, Bool isRap),
2574 : GF_Err (*add_header)(void *user, const u8 *data, u32 length, Bool isHeader))
2575 : {
2576 5 : if (!read) return GF_BAD_PARAM;
2577 6 : read->user = user;
2578 6 : read->add_header = add_header;
2579 6 : read->add_sample = add_sample;
2580 5 : return GF_OK;
2581 : }
2582 :
2583 13 : GF_Err gf_swf_read_header(SWFReader *read)
2584 : {
2585 : SWFRec rc;
2586 : u8 sig[3];
2587 :
2588 : /*get signature*/
2589 13 : sig[0] = gf_bs_read_u8(read->bs);
2590 13 : sig[1] = gf_bs_read_u8(read->bs);
2591 13 : sig[2] = gf_bs_read_u8(read->bs);
2592 : /*"FWS" or "CWS"*/
2593 13 : if ( ((sig[0] != 'F') && (sig[0] != 'C')) || (sig[1] != 'W') || (sig[2] != 'S') ) {
2594 : return GF_URL_ERROR;
2595 : }
2596 13 : /*version = */gf_bs_read_u8(read->bs);
2597 13 : read->length = swf_get_32(read);
2598 :
2599 : /*if compressed decompress the whole file*/
2600 13 : if (sig[0] == 'C') {
2601 6 : swf_init_decompress(read);
2602 : }
2603 :
2604 13 : swf_get_rec(read, &rc);
2605 13 : read->width = rc.w;
2606 13 : read->height = rc.h;
2607 :
2608 13 : swf_align(read);
2609 13 : read->frame_rate = swf_get_16(read)>>8;
2610 13 : read->frame_count = swf_get_16(read);
2611 13 : GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("SWF Import - Scene Size %gx%g - %d frames @ %d FPS\n", read->width, read->height, read->frame_count, read->frame_rate));
2612 : return GF_OK;
2613 : }
2614 :
2615 5 : GF_Err gf_swf_get_duration(SWFReader *read, u32 *frame_rate, u32 *frame_count)
2616 : {
2617 5 : *frame_rate = read->frame_rate;
2618 5 : *frame_count = read->frame_count;
2619 5 : return GF_OK;
2620 : }
2621 :
2622 8 : GF_Err gf_sm_load_init_swf(GF_SceneLoader *load)
2623 : {
2624 : SWFReader *read;
2625 : GF_Err e;
2626 :
2627 8 : if (!load->ctx || !load->scene_graph || !load->fileName) return GF_BAD_PARAM;
2628 :
2629 : #ifdef GPAC_ENABLE_COVERAGE
2630 8 : if (gf_sys_is_cov_mode()) {
2631 : swf_func_skip(NULL);
2632 : swf_def_hdr_jpeg(NULL);
2633 : swf_get_tag_name(SWF_FREECHARACTER);
2634 : swf_unknown_tag(NULL);
2635 : swf_io_error(NULL);
2636 : }
2637 : #endif
2638 :
2639 8 : read = gf_swf_reader_new(load->localPath, load->fileName);
2640 8 : read->load = load;
2641 8 : read->flags = load->swf_import_flags;
2642 8 : read->flat_limit = FLT2FIX(load->swf_flatten_limit);
2643 8 : load->loader_priv = read;
2644 :
2645 8 : gf_swf_read_header(read);
2646 8 : load->ctx->scene_width = FIX2INT(read->width);
2647 8 : load->ctx->scene_height = FIX2INT(read->height);
2648 8 : load->ctx->is_pixel_metrics = 1;
2649 :
2650 8 : if (!(load->swf_import_flags & GF_SM_SWF_SPLIT_TIMELINE) ) {
2651 2 : swf_report(read, GF_OK, "ActionScript disabled");
2652 2 : read->no_as = 1;
2653 : }
2654 :
2655 8 : if (!(load->swf_import_flags & GF_SM_SWF_USE_SVG)) {
2656 : #ifndef GPAC_DISABLE_VRML
2657 7 : e = swf_to_bifs_init(read);
2658 : #else
2659 : e = GF_NOT_SUPPORTED;
2660 : #endif
2661 : } else {
2662 : #ifndef GPAC_DISABLE_SVG
2663 : FILE *svgFile;
2664 1 : if (load->svgOutFile) {
2665 : char svgFileName[GF_MAX_PATH];
2666 1 : if (load->localPath) {
2667 : sprintf(svgFileName, "%s%c%s.svg", load->localPath, GF_PATH_SEPARATOR, load->svgOutFile);
2668 : } else {
2669 : sprintf(svgFileName, "%s.svg", load->svgOutFile);
2670 : }
2671 1 : svgFile = gf_fopen(svgFileName, "wt");
2672 1 : if (!svgFile) return GF_BAD_PARAM;
2673 1 : read->svg_file = svgFile;
2674 : } else {
2675 0 : svgFile = stdout;
2676 : }
2677 : gf_swf_reader_set_user_mode(read, svgFile, swf_svg_write_text_sample, swf_svg_write_text_header);
2678 1 : e = swf_to_svg_init(read, read->flags, load->swf_flatten_limit);
2679 : #else
2680 : e = GF_NOT_SUPPORTED;
2681 : #endif
2682 : }
2683 8 : if (e) goto exit;
2684 :
2685 : /*parse all tags*/
2686 138 : while (e == GF_OK) {
2687 138 : e = swf_parse_tag(read);
2688 138 : if (read->current_frame==1) break;
2689 : }
2690 8 : if (e==GF_EOS) e = GF_OK;
2691 :
2692 8 : load->done = gf_sm_load_done_swf;
2693 8 : load->process = gf_sm_load_run_swf;
2694 :
2695 8 : exit:
2696 8 : if (e) gf_sm_load_done_swf(load);
2697 : return e;
2698 : }
2699 :
2700 : #endif /*GPAC_DISABLE_SWF_IMPORT*/
|