7c733979c0eebbbd8bc3ca78f90e6f60468f0e88
[swftools.git] / src / flash.c
1 /* flash.c
2    Various routines for reading and writing swf files and tags.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org> 
7
8    This file is distributed under the GPL, see file COPYING for details */
9
10 #include "flash.h"
11 #include "bitio.h"
12
13 void swf_init(struct reader_t*r, uchar*newdata, int newlength)
14 {
15     reader_init (r, &newdata[3], newlength - 3);
16 }
17
18 struct flash_header swf_read_header(struct reader_t*r)
19 {
20     struct flash_header head;
21     u16 rate;
22     u16 count;
23     char version;
24     int length;
25     u8* oldpos = reader_getinputpos(r);
26
27     reader_input1(r,&version);
28     head.version = version;
29     reader_input4(r,&length);
30     head.length = length;
31     
32     reader_resetbits(r);
33     head.boundingBox = readRECT(r);
34     reader_input2(r,&rate);
35     head.rate = rate;
36     reader_input2(r,&count);
37     head.count = count;
38
39     head.headerlength = reader_getinputpos(r) - oldpos;
40     head.headerdata = oldpos;
41
42     return head;
43 }
44
45 void swf_write_header(struct writer_t*w, struct flash_header*head)
46 {
47     writer_writeu8(w, head->version);
48     writer_writeu32(w, head->length);
49     
50     writer_writebits(w, 31, 5); 
51     writer_writebits(w, head->boundingBox.x1, 31);
52     writer_writebits(w, head->boundingBox.x2, 31);
53     writer_writebits(w, head->boundingBox.y1, 31);
54     writer_writebits(w, head->boundingBox.y2, 31);
55     writer_resetbits(w);
56     writer_writeu16(w, head->rate);
57     writer_writeu16(w, head->count);
58 }
59
60 struct RGB readRGB(struct reader_t*r)
61 {
62     struct RGB rgb;
63     reader_input1(r,&rgb.r);
64     reader_input1(r,&rgb.g);
65     reader_input1(r,&rgb.b);
66     return rgb;
67 }
68
69 struct RGBA readRGBA(struct reader_t*r)
70 {
71     struct RGBA rgba;
72     reader_input1(r,&rgba.r);
73     reader_input1(r,&rgba.g);
74     reader_input1(r,&rgba.b);
75     reader_input1(r,&rgba.a);
76     return rgba;
77 }
78
79 struct GRADIENT readGRADIENT(struct reader_t*r, int shape)
80 {
81     struct GRADIENT gradient;
82     int t;
83     gradient.num = reader_readu8(r);
84     for(t=0;t<gradient.num;t++)
85     {
86         gradient.ratios[t] = reader_readu8(r);
87         if(shape<3)
88             gradient.rgb[t] = readRGB(r);
89         else
90             gradient.rgba[t] = readRGBA(r);
91     }
92     return gradient;
93 }
94
95 struct RECT readRECT(struct reader_t*reader)
96 {
97     u32 a;
98     struct RECT r;
99     s32 b;
100     reader_readbits(reader,&a,5);
101     reader_readsbits(reader,&b,a);
102     r.x1=b;
103     reader_readsbits(reader,&b,a);
104     r.x2=b;
105     reader_readsbits(reader,&b,a);
106     r.y1=b;
107     reader_readsbits(reader,&b,a);
108     r.y2=b;
109     return r;
110 }
111
112
113 void writeRECT(u8**pos, struct RECT*r)
114 {
115     struct writer_t w;
116     int t=0;
117     writer_init(&w, *pos, 256);
118     writer_writebits(&w, 31, 5); //FIXME:count
119     writer_writebits(&w, r->x1, 31);
120     writer_writebits(&w, r->x2, 31);
121     writer_writebits(&w, r->y1, 31);
122     writer_writebits(&w, r->y2, 31);
123     writer_resetbits(&w);
124     *pos = writer_getpos(&w);
125 }
126
127 struct CXFORM readCXFORM(struct reader_t*r, char alpha)
128 {
129     struct CXFORM c;
130     int bits;
131     c.hasadd=reader_readbit(r);
132     c.hasmult=reader_readbit(r);
133     bits=reader_getbits(r,4);
134     c.alpha = alpha;
135
136     if (c.hasmult)
137     {
138         c.rmult=reader_getsbits(r,bits)/65536.0;
139         c.gmult=reader_getsbits(r,bits)/65536.0;
140         c.bmult=reader_getsbits(r,bits)/65536.0;
141         if(c.alpha)
142             c.amult=reader_getsbits(r,bits)/65536.0;
143     }
144     if (c.hasadd)
145     {
146         c.radd=reader_getsbits(r,bits)/65536.0;
147         c.gadd=reader_getsbits(r,bits)/65536.0;
148         c.badd=reader_getsbits(r,bits)/65536.0;
149         if(c.alpha)
150             c.aadd=reader_getsbits(r,bits)/65536.0;
151     }
152     return c;
153 }
154
155 void CXFORM_write(struct CXFORM *obj, struct writer_t*w)
156 {
157     int bits = 15;
158     writer_writebit(w,obj->hasadd);
159     writer_writebit(w,obj->hasmult);
160     writer_writebits(w, bits, 4);
161     if (obj->hasmult)
162     {
163         writer_writebits(w, obj->rmult, bits);
164         writer_writebits(w, obj->gmult, bits);
165         writer_writebits(w, obj->bmult, bits);
166         if(obj->alpha)
167             writer_writebits(w, obj->amult, 4);
168     }
169     if (obj->hasadd)
170     {
171         writer_writebits(w, obj->radd, bits);
172         writer_writebits(w, obj->gadd, bits);
173         writer_writebits(w, obj->badd, bits);
174         if(obj->alpha)
175             writer_writebits(w, obj->aadd, 4);
176     }
177 }
178
179 unsigned char* readSTRING(struct reader_t*r)
180 {
181     unsigned char*now = reader_getinputpos(r);
182     char a;
183     do
184     {
185         reader_input1(r,&a);
186     }
187     while(a);
188     return now;
189 }
190 void MATRIX_init(struct MATRIX*m)
191 {
192     m->hasrotate = 0;
193     m->hasscale = 0;
194     m->b[0] = 0; 
195     m->b[1] = 0; 
196     m->a[0][0] = 1;
197     m->a[1][1] = 1;
198     m->a[1][0] = 0;
199     m->a[0][1] = 0;
200 }
201 struct MATRIX readMATRIX(struct reader_t*r)
202 {
203     struct MATRIX m;
204     u8 hasrotate;
205     u8 translatebits;
206     u32 translatex;
207     u32 translatey;
208
209     m.a[0][0] = m.a[1][1] = 1;
210     m.a[0][1] = m.a[1][0] = 0;
211     m.hasscale=reader_readbit(r);
212     if(m.hasscale)
213     {
214         u8 scalebits=reader_getbits(r,5);
215         s32 scalex=reader_getsbits(r,scalebits);
216         s32 scaley=reader_getsbits(r,scalebits);
217         m.a[0][0]=scalex/65536.0;
218         m.a[1][1]=scaley/65536.0;
219     }
220     m.hasrotate=reader_readbit(r);
221     if(m.hasrotate)
222     {
223         u8 rotbits=reader_getbits(r,5);
224         s32 rotateskew0=reader_getsbits(r,rotbits);
225         s32 rotateskew1=reader_getsbits(r,rotbits);
226         m.a[0][1]=rotateskew0/65536.0;
227         m.a[1][0]=rotateskew1/65536.0;
228     }
229
230     translatebits=reader_getbits(r,5);
231     translatex=reader_getsbits(r,translatebits);
232     translatey=reader_getsbits(r,translatebits);
233     m.b[0]=translatex;
234     m.b[1]=translatey;
235
236     return m;
237 }
238
239 void MATRIX_write(struct MATRIX * m , struct writer_t*w)
240 {
241     writer_writebit (w, m->hasscale);
242     if(m->hasscale)
243     {
244         int bits = 31;
245         writer_writebits(w, bits, 5);
246         writer_writebits(w, (u32)(m->a[0][0]*65536.0), bits);
247         writer_writebits(w, (u32)(m->a[1][1]*65536.0), bits);
248     }
249     writer_writebit (w, m->hasrotate);
250     if(m->hasrotate)
251     {
252         int bits = 31;
253         writer_writebits(w, bits, 5);
254         writer_writebits(w, (u32)(m->a[0][1]*65536.0), bits);
255         writer_writebits(w, (u32)(m->a[1][0]*65536.0), bits);
256     }
257
258     //translate
259     {
260         int bits = 31;
261         writer_writebits(w, bits, 5);
262         writer_writebits(w, (u32)(m->b[0]), bits);
263         writer_writebits(w, (u32)(m->b[1]), bits);
264     }
265 }
266
267
268 int swf_read_tag(struct reader_t*r, struct swf_tag* swftag)
269 {
270     u8*pos2,*pos = reader_getinputpos(r);
271     u16 tag;
272     u32 taglength;
273     u32 tagid;
274     int t;
275
276     reader_input2(r, &tag);
277
278     taglength = tag & 0x3f;
279     if (taglength == 0x3f)
280     {
281         reader_input4(r, &taglength);
282     }
283
284     swftag->id=tag>>6;
285     swftag->length = taglength;
286     swftag->data = reader_getinputpos(r);
287     reader_skip(r,taglength);
288     pos2 = reader_getinputpos(r);
289     swftag->fulllength = pos2 - pos;
290     swftag->fulldata = pos;
291     return 1;
292 }
293
294 int swf_count_tags(struct reader_t*r)
295 {
296     u8*pos = reader_getinputpos(r);
297     int t=0;
298     struct swf_tag tag;
299
300     while(1)
301     {
302         swf_read_tag(r,&tag);
303         t++;
304         if (tag.id == 0)
305             break;
306     }
307     
308     reader_setinputpos(r,pos);
309     return t;
310 }
311
312 void placeobject_init (struct PlaceObject*obj, struct swf_tag*tag)
313 {
314     struct reader_t r;
315     reader_init (&r, tag->data, tag->length);
316     obj -> id = reader_readu16(&r);
317     obj -> depth = reader_readu16(&r);
318     obj -> matrix = readMATRIX(&r);
319     obj -> hascxform = (reader_getinputpos(&r) < &tag->data[tag->length]);
320     if(obj -> hascxform)
321         obj -> cxform = readCXFORM(&r, 0);
322 }
323
324 void placeobject_write (struct PlaceObject*obj, struct writer_t*w)
325 {
326     u16 taghead = 0x3f | TAGID_PLACEOBJECT<<6;
327     u8*pos;
328     u8*lenpos;
329     U32 len;
330     writer_resetbits(w);
331     writer_write(w, &taghead, 2);
332     lenpos = writer_getpos(w);
333
334     writer_write(w, &taghead, 2);
335     writer_write(w, &taghead, 2);
336
337     pos = writer_getpos(w);
338
339     writer_write(w, &obj->id, 2);
340     writer_write(w, &obj->depth, 2);
341     MATRIX_write(&obj->matrix, w);
342
343     if(obj->hascxform)
344     {
345         CXFORM_write(&obj->cxform, w);
346     }
347     writer_resetbits(w);
348    
349     len = (u8*)writer_getpos(w) - pos;
350     lenpos[0] = len;
351     lenpos[1] = len>>8;
352     lenpos[2] = len>>16;
353     lenpos[3] = len>>24;
354 }
355
356 void placeobject2_init (struct PlaceObject2*obj,struct swf_tag*tag)
357 {    
358     struct reader_t r;
359     u8 b;
360     reader_init (&r, tag->data, tag->length);
361     b=reader_readu8(&r);
362     obj->reserved=         (b>>7)&1;
363     obj->hasclipactions=   (b>>6)&1;
364     obj->hasname=          (b>>5)&1;
365     obj->hasratio=         (b>>4)&1;
366     obj->hascolortransform=(b>>3)&1;
367     obj->hasmatrix=        (b>>2)&1;
368     obj->hascharacter=     (b>>1)&1;
369     obj->hasmove=          (b>>0)&1;
370
371     obj->depth = reader_readu16(&r);
372     obj->id = -1;
373     if(obj->hascharacter) {
374         obj->id = reader_readu16(&r);
375     }
376     if(obj->hasmatrix) { 
377         obj->matrix = readMATRIX(&r);
378     } 
379     if(obj->hascolortransform) {
380         obj->cxform = readCXFORM(&r,0);
381     }
382     if(obj->hasratio) {
383         obj->ratio=reader_readu16(&r);
384     }
385     obj->name = 0;
386     if(obj->hasname) {
387         obj->name=readSTRING(&r);
388     }
389     if(obj->hasclipactions) {
390         obj->clipactions=reader_readu16(&r);
391     }
392 }
393
394 void placeobject2_write (struct PlaceObject2*obj, struct writer_t*w)
395 {
396     u8 flags = obj->reserved<<7 | obj->hasclipactions<<6 | obj->hasname<<5 | obj->hasratio<<4 |
397                obj->hascolortransform<<3 | obj->hasmatrix<<2 | obj->hascharacter<<1 | obj->hasmove;
398     u16 taghead = SWAP16(0x3f | TAGID_PLACEOBJECT2<<6);
399     u8*pos;
400     u8*lenpos;
401     U32 len;
402     writer_resetbits(w);
403     writer_write(w, &taghead, 2);
404     lenpos = writer_getpos(w);
405     writer_write(w, &taghead, 2);
406     writer_write(w, &taghead, 2);
407
408     pos = writer_getpos(w);
409
410     writer_writeu8(w, flags);
411     writer_writeu16(w, obj->depth);
412     if(obj->hascharacter)
413         writer_writeu16(w, obj->id);
414     if(obj->hasmatrix)
415         MATRIX_write(&obj->matrix, w);
416     if(obj->hascolortransform)
417         CXFORM_write(&obj->cxform, w);
418     if(obj->hasratio)
419         writer_writeu16(w, obj->ratio);
420     writer_resetbits(w);
421     if(obj->hasname)
422         writer_write(w, obj->name, strlen(obj->name) + 1);
423     if(obj->hasclipactions)
424         writer_writeu16(w, obj->clipactions);
425     writer_resetbits(w);
426     
427     len = (u8*)writer_getpos(w) - pos;
428     lenpos[0] = len;
429     lenpos[1] = len>>8;
430     lenpos[2] = len>>16;
431     lenpos[3] = len>>24;
432 }
433
434 void read_swf(struct swffile*swf, uchar*data, int length)
435 {
436     int pos;
437     struct flash_header head;
438     int tagnum;
439     struct reader_t r;
440     swf_init(&r, data, length);
441     head = swf_read_header(&r);
442     logf("<debug> [HEADER] the version is %d", head.version);
443     logf("<debug> [HEADER] the length is %d", head.length);
444     logf("<debug> [HEADER] the boundingBox is %d:%d:%d:%d", 
445             head.boundingBox.x1,head.boundingBox.y1,
446             head.boundingBox.x2,head.boundingBox.y2);
447     logf("<debug> [HEADER] the rate (frames/second) is %d", head.rate);
448     logf("<debug> [HEADER] the count (frame number) is %d", head.count);
449
450     tagnum = swf_count_tags(&r);
451     swf->tags = (struct swf_tag*)malloc(sizeof(struct swf_tag)*tagnum);
452     
453     logf("<debug> [HEADER] the file consists of %d tags", tagnum);
454
455     pos = 0;
456     while(1)
457     {
458         struct swf_tag tag;
459         swf_read_tag(&r, &tag);
460         logf("<debug> read tag %02x (%d bytes)", tag.id, tag.length);
461         swf->tags[pos] = tag;
462         pos++;
463         if(tag.id == TAGID_END)
464             break;
465     }
466     swf->tagnum = tagnum;
467     swf->header = head;
468 }
469
470 int definingtagids[] =
471 {TAGID_DEFINESHAPE,
472  TAGID_DEFINESHAPE2,
473  TAGID_DEFINESHAPE3,
474  TAGID_DEFINEMORPHSHAPE,
475  TAGID_DEFINEFONT,
476  TAGID_DEFINEFONT2,
477  TAGID_DEFINETEXT,
478  TAGID_DEFINETEXT2,
479  TAGID_DEFINEEDITTEXT,
480  TAGID_DEFINEBITS,
481  TAGID_DEFINEBITSJPEG2,
482  TAGID_DEFINEBITSJPEG3,
483  TAGID_DEFINEBITSLOSSLESS,
484  TAGID_DEFINEBITSLOSSLESS2,
485  TAGID_DEFINEMOVIE,
486  TAGID_DEFINESPRITE,
487  TAGID_DEFINEBUTTON,
488  TAGID_DEFINEBUTTON2,
489  TAGID_DEFINESOUND,
490  -1
491 };
492
493 // tags which may be used inside a sprite definition
494 int spritetagids[] =
495 {TAGID_SHOWFRAME,
496  TAGID_PLACEOBJECT,
497  TAGID_PLACEOBJECT2,
498  TAGID_REMOVEOBJECT,
499  TAGID_REMOVEOBJECT2, //?
500  TAGID_DOACTION,
501  TAGID_STARTSOUND,
502  TAGID_FRAMELABEL,
503  TAGID_SOUNDSTREAMHEAD,
504  TAGID_SOUNDSTREAMHEAD2,
505  TAGID_SOUNDSTREAMBLOCK,
506  TAGID_END,
507  -1
508 };
509
510 int getidfromtag(struct swf_tag* tag)
511 {
512     int num = 1;
513     switch(tag->id) {
514         case TAGID_PLACEOBJECT2:
515             num++;
516         case TAGID_PLACEOBJECT: {
517            struct reader_t r;
518            reader_init (&r, tag->data, tag->length);
519            if(num>=2) {
520                 char b = reader_readu8(&r);
521                 if(!(b&2))
522                     return -1;
523            }
524            reader_readu16(&r);
525            return reader_readu16(&r);
526         }
527         break;
528         case TAGID_REMOVEOBJECT:
529            return tag->data[0]+tag->data[1]*256;
530         break;
531         case TAGID_REMOVEOBJECT2:
532            return -1;
533         break;
534     }
535
536     return tag->data[0]+tag->data[1]*256;
537 }
538
539 void setidintag(struct swf_tag* tag, int id)
540 {
541     tag->data[0] = id;
542     tag->data[1] = id>>8;
543 }
544
545 char is_sprite_tag (int id)
546 {
547     int t=0;
548     while(spritetagids[t]>=0)
549     {
550         if(spritetagids[t] == id) 
551             return 1;
552         t++;
553     }
554     return 0; 
555 }
556
557 char is_defining_tag (int id)
558 {
559     int t=0;
560     while(definingtagids[t]>=0)
561     {
562         if(definingtagids[t] == id) 
563             return 1;
564         t++;
565     }
566     return 0; 
567 }
568
569 struct swf_tag* duptag(struct swf_tag*tag)
570 {
571     struct swf_tag* newtag = (struct swf_tag*)malloc(sizeof(struct swf_tag));
572     newtag->id = tag->id;
573     newtag->fulldata = (u8*)malloc(tag->fulllength);
574     newtag->fulllength = tag->fulllength;
575     newtag->data = newtag->fulldata + (tag->data - tag->fulldata);
576     newtag->length = tag->length;
577     memcpy(newtag->fulldata, tag->fulldata, tag->fulllength);
578     return newtag;
579 }
580