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