/* swf.c Low-level swf format handling. */ #include #include #include #include #include #include #include "swf.h" struct _SWFWriter { FILE* fp; int swf_version; float framerate; int compression; int width, height; unsigned long filesize_pos; unsigned long framecount_pos; int framecount; int bpos; int buff; int objid; int tag; int tag_len; int tag_lenpos; unsigned char tag_buff[62]; }; /* byte oprations */ void SWFWriter_write_bytes(SWFWriter* writer, unsigned char* s, unsigned long len) { if (writer->tag != -1) { int buflen = 62-writer->tag_len; if (0 <= buflen) { if (len <= buflen) { buflen = len; } memcpy(writer->tag_buff+writer->tag_len, s, buflen); writer->tag_len += buflen; len -= buflen; s += buflen; if (len == 0) return; /* 62bytes exceeded */ { unsigned int tag = (writer->tag << 6) | 63; unsigned char buf[4]; buf[0] = tag & 0xff; buf[1] = (tag >> 8) & 0xff; fwrite(buf, 1, 2, writer->fp); writer->tag_lenpos = ftell(writer->fp); fwrite(buf, 1, 4, writer->fp); fwrite(writer->tag_buff, 1, 62, writer->fp); } } writer->tag_len += len; } fwrite(s, 1, len, writer->fp); } void SWFWriter_write_ui8(SWFWriter* writer, unsigned char x) { SWFWriter_write_bytes(writer, &x, 1); } void SWFWriter_write_si8(SWFWriter* writer, signed char x) { SWFWriter_write_bytes(writer, &x, 1); } void SWFWriter_write_ui16(SWFWriter* writer, unsigned int x) { /* little endian */ unsigned char buf[2]; buf[0] = x & 0xff; buf[1] = (x >> 8) & 0xff; SWFWriter_write_bytes(writer, buf, 2); } void SWFWriter_write_ub16(SWFWriter* writer, unsigned int x) { /* big endian */ unsigned char buf[2]; buf[1] = (x >> 8) & 0xff; buf[1] = x & 0xff; SWFWriter_write_bytes(writer, buf, 2); } void SWFWriter_write_si16(SWFWriter* writer, signed int x) { /* little endian */ unsigned char buf[2]; buf[0] = x & 0xff; buf[1] = (x >> 8) & 0xff; SWFWriter_write_bytes(writer, buf, 2); } void SWFWriter_write_ui32(SWFWriter* writer, unsigned int x) { /* little endian */ unsigned char buf[4]; buf[0] = x & 0xff; buf[1] = (x >> 8) & 0xff; buf[2] = (x >> 16) & 0xff; buf[3] = (x >> 24) & 0xff; SWFWriter_write_bytes(writer, buf, 4); } void SWFWriter_write_si32(SWFWriter* writer, signed int x) { /* little endian */ unsigned char buf[4]; buf[0] = x & 0xff; buf[1] = (x >> 8) & 0xff; buf[2] = (x >> 16) & 0xff; buf[3] = (x >> 24) & 0xff; SWFWriter_write_bytes(writer, buf, 4); } void SWFWriter_write_rgb(SWFWriter* writer, int r, int g, int b) { SWFWriter_write_ui8(writer, r); SWFWriter_write_ui8(writer, g); SWFWriter_write_ui8(writer, b); } void SWFWriter_write_rgba(SWFWriter* writer, int r, int g, int b, int a) { SWFWriter_write_ui8(writer, r); SWFWriter_write_ui8(writer, g); SWFWriter_write_ui8(writer, b); SWFWriter_write_ui8(writer, a); } /* bit operations */ #if 0 static int needbits_unsigned(int bits, unsigned int x) { int n = 0; if (x != 0) { while (1) { n += 1; x >>= 1; if (x == 0) break; } } if (n < bits) { return bits; } return n; } #endif static int needbits_signed(int bits, signed int x) { int n = 0; if (x != 0) { n++; if (x < 0) { x = -x-1; } while (1) { n += 1; x >>= 1; if (x == 0) break; } } if (n < bits) { return bits; } return n; } static void writebits_unsigned(SWFWriter* writer, int bits, unsigned int x) { while (1) { /* r: the number of remaining bits we can write into the current buffer. */ int r = 8 - writer->bpos; if (bits <= r) { /* |-----8-bits-----| |-bpos-|-bits-| | | |----r----| */ writer->buff |= x << (r-bits); writer->bpos += bits; break; } else { /* |-----8-bits-----| |-bpos-|---bits----... | |----r----| */ SWFWriter_write_ui8(writer, writer->buff | (x >> (bits-r))); /* r < bits */ writer->buff = 0; writer->bpos = 0; bits -= r; /* trim the upper r bits */ x &= (1<bpos) { SWFWriter_write_ui8(writer, writer->buff); writer->buff = 0; writer->bpos = 0; } } /* various length structure */ void SWFWriter_write_cstring(SWFWriter* writer, unsigned char* s) { SWFWriter_write_bytes(writer, s, strlen(s)+1); } void SWFWriter_write_rect(SWFWriter* writer, int xmin, int ymin, int xmax, int ymax) { int n = 0; n = needbits_signed(n, xmin); n = needbits_signed(n, xmax); n = needbits_signed(n, ymin); n = needbits_signed(n, ymax); writebits_unsigned(writer, 5, n); writebits_signed(writer, n, xmin); writebits_signed(writer, n, xmax); writebits_signed(writer, n, ymin); writebits_signed(writer, n, ymax); finishbits(writer); } void SWFWriter_write_matrix(SWFWriter* writer, int scale, float scalex, float scaley, int rot, float rot0, float rot1, int transx, int transy) { if (scale) { int sx = scalex*65536, sy = scaley*65536; int n = 0; n = needbits_signed(n, sx); n = needbits_signed(n, sy); writebits_unsigned(writer, 1, 1); writebits_unsigned(writer, 5, n); writebits_signed(writer, n, sx); writebits_signed(writer, n, sy); } else { writebits_unsigned(writer, 1, 0); } if (rot) { int r0 = rot0*65536, r1 = rot1*65536; int n = 0; n = needbits_signed(n, r0); n = needbits_signed(n, r1); writebits_unsigned(writer, 1, 1); writebits_unsigned(writer, 5, n); writebits_signed(writer, n, r0); writebits_signed(writer, n, r1); } else { writebits_unsigned(writer, 1, 0); } { int n = 0; n = needbits_signed(n, transx); n = needbits_signed(n, transy); writebits_unsigned(writer, 5, n); writebits_signed(writer, n, transx); writebits_signed(writer, n, transy); } finishbits(writer); } void SWFWriter_write_style_solid_fill(SWFWriter* writer, int r, int g, int b, int a) { SWFWriter_write_ui8(writer, 1); /* fillstyles */ SWFWriter_write_ui8(writer, 0x00); /* FillStyleType: solid */ if (a != -1) { /* DefineShape3 */ SWFWriter_write_rgba(writer, r, g, b, a); } else { /* DefineShape or DefineShape2 */ SWFWriter_write_rgb(writer, r, g, b); } SWFWriter_write_ui8(writer, 0); /* linestyles */ } void SWFWriter_write_style_clipped_bitmap_fill(SWFWriter* writer, int bitmapid, int dx, int dy) { SWFWriter_write_ui8(writer, 1); /* fillstyles */ SWFWriter_write_ui8(writer, 0x43); /* FillStyleType: non-smoothed clipped bitmap */ SWFWriter_write_ui16(writer, bitmapid); SWFWriter_write_matrix(writer, 1,20,20, 0,0,0, dx,dy); /* bitmap matrix */ SWFWriter_write_ui8(writer, 0); /* linestyles */ } void SWFWriter_write_rectshape(SWFWriter* writer, int x, int y, int w, int h) { int n; writebits_unsigned(writer, 4, 1); /* fillbits=1 */ writebits_unsigned(writer, 4, 0); /* linebits=0 */ writebits_unsigned(writer, 1, 0); /* TypeFlag: styletype(0) */ writebits_unsigned(writer, 4, 2); /* Fillstyle */ writebits_unsigned(writer, 1, 1); /* StateMoveTo */ n = 0; n = needbits_signed(n, x); n = needbits_signed(n, y); writebits_unsigned(writer, 5, n); writebits_signed(writer, n, x); writebits_signed(writer, n, y); writebits_unsigned(writer, 1, 1); /* set fillstyle1: 1 */ writebits_unsigned(writer, 1, 1); /* TypeFlag: edgetype(1) */ writebits_unsigned(writer, 1, 1); /* StraightEdgeRecord */ n = needbits_signed(2, w); writebits_unsigned(writer, 4, n-2); writebits_unsigned(writer, 1, 0); /* vert/horiz only */ writebits_unsigned(writer, 1, 0); /* dx */ writebits_signed(writer, n, w); writebits_unsigned(writer, 1, 1); /* TypeFlag: edgetype(1) */ writebits_unsigned(writer, 1, 1); /* StraightEdgeRecord */ n = needbits_signed(2, h); writebits_unsigned(writer, 4, n-2); writebits_unsigned(writer, 1, 0); /* vert/horiz only */ writebits_unsigned(writer, 1, 1); /* dy */ writebits_signed(writer, n, h); writebits_unsigned(writer, 1, 1); /* TypeFlag: edgetype(1) */ writebits_unsigned(writer, 1, 1); /* StraightEdgeRecord */ n = needbits_signed(2, -w); writebits_unsigned(writer, 4, n-2); writebits_unsigned(writer, 1, 0); /* vert/horiz only */ writebits_unsigned(writer, 1, 0); /* dx */ writebits_signed(writer, n, -w); writebits_unsigned(writer, 1, 1); /* TypeFlag: edgetype(1) */ writebits_unsigned(writer, 1, 1); /* StraightEdgeRecord */ n = needbits_signed(2, -h); writebits_unsigned(writer, 4, n-2); writebits_unsigned(writer, 1, 0); /* vert/horiz only */ writebits_unsigned(writer, 1, 1); /* dy */ writebits_signed(writer, n, -h); writebits_unsigned(writer, 1, 0); /* styletype */ writebits_unsigned(writer, 5, 0); /* EOS */ finishbits(writer); } /* tag */ void SWFWriter_start_tag(SWFWriter* writer, int tag) { writer->tag = tag; writer->tag_len = 0; } void SWFWriter_end_tag2(SWFWriter* writer, int forcelong) { unsigned char buf[4]; if (writer->tag_len <= 62) { unsigned int tag = (writer->tag << 6) | (forcelong? 63 : writer->tag_len); buf[0] = tag & 0xff; buf[1] = (tag >> 8) & 0xff; fwrite(buf, 1, 2, writer->fp); if (forcelong) { buf[0] = writer->tag_len & 0xff; buf[1] = (writer->tag_len >> 8) & 0xff; buf[2] = (writer->tag_len >> 16) & 0xff; buf[3] = (writer->tag_len >> 24) & 0xff; fwrite(buf, 1, 4, writer->fp); } fwrite(writer->tag_buff, 1, writer->tag_len, writer->fp); } else { unsigned long pos = ftell(writer->fp); fseek(writer->fp, writer->tag_lenpos, SEEK_SET); buf[0] = writer->tag_len & 0xff; buf[1] = (writer->tag_len >> 8) & 0xff; buf[2] = (writer->tag_len >> 16) & 0xff; buf[3] = (writer->tag_len >> 24) & 0xff; fwrite(buf, 1, 4, writer->fp); fseek(writer->fp, pos, SEEK_SET); } writer->tag = -1; } void SWFWriter_end_tag(SWFWriter* writer) { SWFWriter_end_tag2(writer, 0); } void SWFWriter_end_tag_forcelong(SWFWriter* writer) { SWFWriter_end_tag2(writer, 1); } int SWFWriter_new_objid(SWFWriter* writer) { writer->objid++; return writer->objid; } /* open/close fp: output file (FILE*) swf_version: swf version width, height: size (in twip) compression: currently ignored */ SWFWriter* SWFWriter_open(FILE* fp, int swf_version, int width, int height, float framerate, int compression) { SWFWriter* writer = (SWFWriter*) malloc(sizeof(SWFWriter)); if (!writer) return NULL; assert(ftell(fp) != -1); writer->fp = fp; writer->swf_version = swf_version; writer->width = width; writer->height = height; writer->framerate = framerate; writer->compression = compression; SWFWriter_initialize(writer); return writer; } void SWFWriter_initialize(SWFWriter* writer) { writer->bpos = 0; writer->buff = 0; writer->objid = 0; writer->framecount = 0; writer->tag = -1; /* header */ fseek(writer->fp, 0, SEEK_SET); SWFWriter_write_bytes(writer, "FWS", 3); SWFWriter_write_ui8(writer, writer->swf_version); writer->filesize_pos = ftell(writer->fp); SWFWriter_write_ui32(writer, 0); /* dummy length */ SWFWriter_write_rect(writer, 0, 0, writer->width*20, writer->height*20); SWFWriter_write_ui16(writer, writer->framerate * 256); writer->framecount_pos = ftell(writer->fp); SWFWriter_write_ui16(writer, 0); /* dummy framecount */ } void SWFWriter_next_frame(SWFWriter* writer) { SWFWriter_start_tag(writer, 1); /* ShowFrame */ SWFWriter_end_tag(writer); writer->framecount++; } unsigned long SWFWriter_close(SWFWriter* writer) { unsigned long filesize; SWFWriter_start_tag(writer, 0); /* write eof */ SWFWriter_end_tag(writer); filesize = ftell(writer->fp); fseek(writer->fp, writer->filesize_pos, SEEK_SET); SWFWriter_write_ui32(writer, filesize); /* modify the filesize */ fseek(writer->fp, writer->framecount_pos, SEEK_SET); SWFWriter_write_ui16(writer, writer->framecount); /* modify the framecount */ fflush(writer->fp); free((char*) writer); return filesize; } /* Predefined tags */ int SWFWriter_define_rect_shape_rgb(SWFWriter* writer, int r, int g, int b, int w, int h) { int shapeid = SWFWriter_new_objid(writer); SWFWriter_start_tag(writer, 32); /* DefineShape3 */ SWFWriter_write_ui16(writer, shapeid); SWFWriter_write_rect(writer, 0, 0, w*20, h*20); SWFWriter_write_style_solid_fill(writer, r, g, b, 255); SWFWriter_write_rectshape(writer, 0, 0, w*20, h*20); SWFWriter_end_tag(writer); return shapeid; } int SWFWriter_define_rect_shape_bitmap(SWFWriter* writer, unsigned char* buf, unsigned long len, int w, int h) { int bitmapid = SWFWriter_new_objid(writer); int shapeid = SWFWriter_new_objid(writer); SWFWriter_start_tag(writer, 20); /* DefineBitsLossless */ SWFWriter_write_ui16(writer, bitmapid); SWFWriter_write_ui8(writer, 5); /* 24bit RGB */ SWFWriter_write_ui16(writer, w); SWFWriter_write_ui16(writer, h); SWFWriter_write_bytes(writer, buf, len); SWFWriter_end_tag_forcelong(writer); /* Flashplayer bug */ SWFWriter_start_tag(writer, 32); /* DefineShape3 */ SWFWriter_write_ui16(writer, shapeid); SWFWriter_write_rect(writer, 20, 20, w*20, h*20); /* Macromedia Hack */ SWFWriter_write_style_clipped_bitmap_fill(writer, bitmapid, 0, 0); SWFWriter_write_rectshape(writer, 20, 20, w*20, h*20); SWFWriter_end_tag(writer); return shapeid; } void SWFWriter_place_object(SWFWriter* writer, int cid, int depth, int x, int y) { SWFWriter_start_tag(writer, 26); /* PlaceObject2 */ SWFWriter_write_ui8(writer, 0x06); /* character+matrix */ SWFWriter_write_ui16(writer, depth); SWFWriter_write_ui16(writer, cid); SWFWriter_write_matrix(writer, 0,0,0, 0,0,0, x*20,y*20); SWFWriter_end_tag(writer); } void SWFWriter_remove_object(SWFWriter* writer, int depth) { SWFWriter_start_tag(writer, 28); /* RemoveObject2 */ SWFWriter_write_ui16(writer, depth); SWFWriter_end_tag(writer); } #ifdef TEST_SWF int main(int argc, char* argv[]) { int i, cid; char foo[65536]; SWFWriter* writer = SWFWriter_open(stdout, 5, 100, 100, 12.0, 0); cid = SWFWriter_define_rect_shape_rgb(writer, 0,0,255, 20, 20); for (i = 0; i < 50; i++) { if (0 < i) { SWFWriter_remove_object(writer, 1); } SWFWriter_place_object(writer, cid, 1, i, i*2); SWFWriter_next_frame(writer); } SWFWriter_close(writer); return 0; } #endif