+#ifdef _ZLIB_INCLUDED_
+static U32 mycrc32;
+
+static U32*crc32_table = 0;
+static void make_crc32_table(void)
+{
+ int t;
+ if(crc32_table)
+ return;
+ crc32_table = (U32*)malloc(1024);
+
+ for (t = 0; t < 256; t++) {
+ U32 c = t;
+ int s;
+ for (s = 0; s < 8; s++) {
+ c = (0xedb88320L*(c&1)) ^ (c >> 1);
+ }
+ crc32_table[t] = c;
+ }
+}
+static inline void png_write_byte(FILE*fi, U8 byte)
+{
+ fwrite(&byte,1,1,fi);
+ mycrc32 = crc32_table[(mycrc32 ^ byte) & 0xff] ^ (mycrc32 >> 8);
+}
+static void png_start_chunk(FILE*fi, char*type, int len)
+{
+ U8 mytype[4]={0,0,0,0};
+ U32 mylen = REVERSESWAP32(len);
+ memcpy(mytype,type,strlen(type));
+ fwrite(&mylen, 4, 1, fi);
+ mycrc32=0xffffffff;
+ png_write_byte(fi,mytype[0]);
+ png_write_byte(fi,mytype[1]);
+ png_write_byte(fi,mytype[2]);
+ png_write_byte(fi,mytype[3]);
+}
+static void png_write_bytes(FILE*fi, U8*bytes, int len)
+{
+ int t;
+ for(t=0;t<len;t++)
+ png_write_byte(fi,bytes[t]);
+}
+static void png_write_dword(FILE*fi, U32 dword)
+{
+ png_write_byte(fi,dword>>24);
+ png_write_byte(fi,dword>>16);
+ png_write_byte(fi,dword>>8);
+ png_write_byte(fi,dword);
+}
+static void png_end_chunk(FILE*fi)
+{
+ U32 tmp = REVERSESWAP32((mycrc32^0xffffffff));
+ fwrite(&tmp,4,1,fi);
+}
+
+
+/* extract a lossless image (png) out of a tag
+ This routine was originally meant to be a one-pager. I just
+ didn't know png is _that_ much fun. :) -mk
+ */
+void handlelossless(TAG*tag)
+{
+ char name[80];
+ char*filename = name;
+ FILE*fi;
+ int width, height;
+ int crc;
+ int id;
+ int t;
+ U8 bpp = 1;
+ U8 format;
+ U8 tmp;
+ Bytef* data=0;
+ U8* data2=0;
+ U8* data3=0;
+ uLongf datalen;
+ uLongf datalen2;
+ U32 datalen3;
+ U8 head[] = {137,80,78,71,13,10,26,10};
+ int cols;
+ char alpha = tag->id == ST_DEFINEBITSLOSSLESS2;
+ RGBA* palette;
+ int pos;
+ int error;
+ U32 tmp32;
+
+ make_crc32_table();
+
+ if(tag->id != ST_DEFINEBITSLOSSLESS &&
+ tag->id != ST_DEFINEBITSLOSSLESS2) {
+ int id = GET16(tag->data);
+ fprintf(stderr, "Object %d is not a PNG picture!\n",id);
+ exit(1);
+ }
+
+ id =swf_GetU16(tag);
+ format = swf_GetU8(tag);
+ if(format == 3) bpp = 8;
+ if(format == 4) bpp = 16;
+ if(format == 5) bpp = 32;
+ if(format!=3 && format!=5) {
+ if(format==4)
+ fprintf(stderr, "Can't handle 16-bit palette images yet (image %d)\n",id);
+ else
+ fprintf(stderr, "Unknown image type %d in image %d\n", format, id);
+ return;
+ }
+ width = swf_GetU16(tag);
+ height = swf_GetU16(tag);
+ if(format == 3) cols = swf_GetU8(tag) + 1;
+// this is what format means according to the flash specification. (which is
+// clearly wrong)
+// if(format == 4) cols = swf_GetU16(tag) + 1;
+// if(format == 5) cols = swf_GetU32(tag) + 1;
+ else cols = 0;
+
+ msg("<verbose> Width %d", width);
+ msg("<verbose> Height %d", height);
+ msg("<verbose> Format %d", format);
+ msg("<verbose> Cols %d", cols);
+ msg("<verbose> Bpp %d", bpp);
+
+ datalen = (width*height*bpp/8+cols*8);
+ do {
+ if(data)
+ free(data);
+ datalen+=4096;
+ data = malloc(datalen);
+ error = uncompress (data, &datalen, &tag->data[tag->pos], tag->len-tag->pos);
+ } while(error == Z_BUF_ERROR);
+ if(error != Z_OK) {
+ fprintf(stderr, "Zlib error %d (image %d)\n", error, id);
+ return;
+ }
+ msg("<verbose> Uncompressed image is %d bytes (%d colormap)", datalen, (3+alpha)*cols);
+ pos = 0;
+ datalen2 = datalen;
+ data2 = malloc(datalen2);
+ palette = (RGBA*)malloc(cols*sizeof(RGBA));
+
+ for(t=0;t<cols;t++) {
+ palette[t].r = data[pos++];
+ palette[t].g = data[pos++];
+ palette[t].b = data[pos++];
+ if(alpha) {
+ palette[t].a = data[pos++];
+ }
+ }
+
+ sprintf(name, "pic%d.png", id);
+ if(numextracts==1) {
+ filename = destfilename;
+ if(!strcmp(filename,"output.swf"))
+ filename = "output.png";
+ }
+ fi = save_fopen(filename, "wb");
+ fwrite(head,sizeof(head),1,fi);
+
+ png_start_chunk(fi, "IHDR", 13);
+ png_write_dword(fi,width);
+ png_write_dword(fi,height);
+ png_write_byte(fi,8);
+ if(format == 3)
+ png_write_byte(fi,3); //indexed
+ else if(format == 5 && alpha==0)
+ png_write_byte(fi,2); //rgb
+ else if(format == 5 && alpha==1)
+ png_write_byte(fi,6); //rgba
+ else return;
+
+ png_write_byte(fi,0); //compression mode
+ png_write_byte(fi,0); //filter mode
+ png_write_byte(fi,0); //interlace mode
+ png_end_chunk(fi);
+
+ if(format == 3) {
+ png_start_chunk(fi, "PLTE", 768);
+
+ for(t=0;t<256;t++) {
+ png_write_byte(fi,palette[t].r);
+ png_write_byte(fi,palette[t].g);
+ png_write_byte(fi,palette[t].b);
+ }
+ png_end_chunk(fi);
+
+ if(alpha) {
+ /* write alpha palette */
+ png_start_chunk(fi, "tRNS", 256);
+ for(t=0;t<256;t++) {
+ png_write_byte(fi,palette[t].a);
+ }
+ png_end_chunk(fi);
+ }
+ }
+ {
+ int pos2 = 0;
+ int x,y;
+ int srcwidth = width * (bpp/8);
+ datalen3 = (width*4+5)*height;
+ data3 = (U8*)malloc(datalen3);
+ for(y=0;y<height;y++)
+ {
+ data3[pos2++]=0; //filter type
+ if(bpp==32) {
+ if(!alpha) {
+ // 32 bit to 24 bit "conversion"
+ for(x=0;x<width;x++) {
+ data3[pos2++]=data[pos+1];
+ data3[pos2++]=data[pos+2];
+ data3[pos2++]=data[pos+3];
+ pos+=4; //ignore padding byte
+ }
+ } else {
+ for(x=0;x<width;x++) {
+ data3[pos2++]=data[pos+1];
+ data3[pos2++]=data[pos+2];
+ data3[pos2++]=data[pos+3];
+ data3[pos2++]=data[pos+0]; //alpha
+ pos+=4;
+ }
+ }
+ }
+ else {
+ for(x=0;x<srcwidth;x++)
+ data3[pos2++]=data[pos++];
+ }
+
+ pos+=((srcwidth+3)&~3)-srcwidth; //align
+ }
+ datalen3=pos2;
+ }
+
+ if(compress (data2, &datalen2, data3, datalen3) != Z_OK) {
+ fprintf(stderr, "zlib error in pic %d\n", id);
+ return;
+ }
+ msg("<verbose> Compressed data is %d bytes", datalen2);
+ png_start_chunk(fi, "IDAT", datalen2);
+ png_write_bytes(fi,data2,datalen2);
+ png_end_chunk(fi);
+ png_start_chunk(fi, "IEND", 0);
+ png_end_chunk(fi);
+
+ free(data);
+ free(data2);
+ free(data3);
+}
+#endif
+
+static FILE*mp3file=0;
+void handlesoundstream(TAG*tag)
+{
+ char*filename = "output.mp3";
+ if(numextracts==1) {
+ filename = destfilename;
+ if(!strcmp(filename,"output.swf"))
+ filename = "output.mp3";
+ }
+ switch(tag->id) {
+ case ST_SOUNDSTREAMHEAD:
+ if((tag->data[1]&0x30) == 0x20) { //mp3 compression
+ mp3file = fopen(filename, "wb");
+ msg("<notice> Writing mp3 data to %s",filename);
+ }
+ else
+ msg("<error> Soundstream is not mp3");
+ break;
+ case ST_SOUNDSTREAMHEAD2:
+ if((tag->data[1]&0x30) == 0x20) {//mp3 compression
+ mp3file = fopen(filename, "wb");
+ msg("<notice> Writing mp3 data to %s",filename);
+ }
+ else
+ msg("<error> Soundstream is not mp3 (2)");
+ break;
+ case ST_SOUNDSTREAMBLOCK:
+ if(mp3file)
+ fwrite(&tag->data[4],tag->len-4,1,mp3file);
+ break;
+ }
+}
+
+void handledefinesound(TAG*tag)
+{
+ U8 flags;
+ U32 samples;
+ char buf[128];
+ char*filename = buf;
+ FILE*fi;
+ char*extension = 0;
+ int format;
+ U16 id;
+ int rate,bits,stereo;
+ char*rates[] = {"5500","11025","22050","44100"};
+ id = swf_GetU16(tag); //id
+
+ flags = swf_GetU8(tag);
+ format = flags>>4;
+ rate = (flags>>2)&3;
+ bits = flags&2?16:8;
+ stereo = flags&1;
+
+ samples = swf_GetU32(tag);
+
+ extension = "raw";
+
+ if(format == 2) { // mp3
+ swf_GetU16(tag); //numsamples_seek
+ extension = "mp3";
+ } else if(format == 0) { // raw
+ printf("Sound is RAW, format: %s samples/sec, %d bit, %s\n", rates[rate], bits, stereo?"stereo":"mono");
+ // TODO: convert to WAV
+ extension = "raw";
+ } else if(format == 1) { // adpcm
+ printf("Sound is ADPCM, format: %s samples/sec, %d bit, %s\n", rates[rate], bits, stereo?"stereo":"mono");
+ extension = "adpcm";
+ }
+ sprintf(buf, "sound%d.%s", id, extension);
+ if(numextracts==1) {
+ filename = destfilename;
+ if(!strcmp(filename,"output.swf")) {
+ sprintf(buf, "output.%s", extension);
+ filename = buf;
+ }
+ }
+ fi = save_fopen(filename, "wb");
+ fwrite(&tag->data[tag->pos], tag->len - tag->pos, 1, fi);
+ fclose(fi);
+}
+