Coverage Report

Created: 2026-04-26 07:10

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