root/src/blocks/fromswf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. writeSWFPrebuiltClipToMethod
  2. completeSWFPrebuiltClip
  3. SWFPrebuiltClipLength
  4. destroySWFPrebuiltClip
  5. newSWFPrebuiltClip
  6. writeSWFPrebuiltToMethod
  7. completeSWFPrebuilt
  8. destroySWFPrebuilt
  9. newSWFPrebuilt
  10. getbits
  11. getsbits
  12. rect
  13. matrix
  14. rgb
  15. rgba
  16. readint2
  17. readint4
  18. putint2
  19. putint4
  20. freadc
  21. r_readc
  22. swfseek
  23. openswf
  24. treadc
  25. readtag_common
  26. readtag_file
  27. readtag_sprite
  28. change_id
  29. drop_tag
  30. handle_tag
  31. definesprite
  32. shaperecord
  33. gradient
  34. fillstyle
  35. morphgradient
  36. morphfillstyle
  37. fillandlinestyles
  38. linestyle
  39. morphlinestyle
  40. morphlinestyle2
  41. defineshape
  42. shape
  43. definemorphshape
  44. definetext
  45. placeobject
  46. definebutton
  47. cxform
  48. definebutton2
  49. definetextfield
  50. exportassets
  51. soundinfo
  52. definebuttonsound
  53. newSWFPrebuiltClip_fromInput
  54. newSWFPrebuiltClip_fromFile

/*
    Ming, an SWF output library
    Copyright (C) 2002  Opaque Industries - http://www.opaque.net/

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/* $Id: fromswf.c,v 1.28 2009/02/16 17:40:41 krechert Exp $ */


#include "ming_config.h"

#include "libming.h"
#include "fromswf.h"
#include "method.h"
#include "input.h"
#include "output.h"
#include "error.h"

#ifndef __C2MAN__
#include <stdlib.h>
#include <string.h>
#endif

#if USE_ZLIB
#include <zlib.h>
#endif

static void
writeSWFPrebuiltClipToMethod(SWFBlock block, SWFByteOutputMethod method, void *data)
{
        SWFPrebuiltClip clip = (SWFPrebuiltClip) block;
        methodWriteUInt16(CHARACTERID(clip), method, data);
        methodWriteUInt16(clip->frames, method, data);
        
        SWFOutput_writeToMethod(clip->display, method, data);
}

static int
completeSWFPrebuiltClip(SWFBlock block)
{
        return 4 + SWFPrebuiltClipLength(block);
}

int
SWFPrebuiltClipLength(SWFBlock block)
{       SWFPrebuiltClip clip = (SWFPrebuiltClip)block;
        return SWFOutput_getLength(clip->display);
}

/*
 * destroys a SWFPrebuiltClip instance
 */
void
destroySWFPrebuiltClip(SWFPrebuiltClip clip)
{       destroySWFOutput(clip->display);
        destroySWFCharacter((SWFCharacter) clip);
}

SWFPrebuiltClip
newSWFPrebuiltClip()
{
        SWFPrebuiltClip clip = (SWFPrebuiltClip)malloc(sizeof(struct SWFPrebuiltClip_s));

        SWFCharacterInit((SWFCharacter)clip);

        BLOCK(clip)->type = SWF_PREBUILTCLIP;
        BLOCK(clip)->writeBlock = writeSWFPrebuiltClipToMethod;
        BLOCK(clip)->complete = completeSWFPrebuiltClip;
        BLOCK(clip)->dtor = (destroySWFBlockMethod) destroySWFPrebuiltClip;
        
        clip->frames = 0;
        clip->display = newSWFOutput();
        return clip;
}

static void
writeSWFPrebuiltToMethod(SWFBlock block, SWFByteOutputMethod method, void *data)
{
        SWFPrebuilt defines = (SWFPrebuilt) block;
        
        SWFOutput_writeToMethod(defines->defines, method, data);
}

static int
completeSWFPrebuilt(SWFBlock block)
{
        SWFPrebuilt defines = (SWFPrebuilt) block;
        return SWFOutput_getLength(defines->defines);
}

void
destroySWFPrebuilt(SWFPrebuilt defines)
{       destroySWFOutput(defines->defines);
        free((SWFBlock) defines);
}

SWFPrebuilt
newSWFPrebuilt()
{
        SWFPrebuilt data = (SWFPrebuilt)malloc(sizeof(struct SWFPrebuilt_s));
        
        SWFBlockInit((SWFBlock)data);
        BLOCK(data)->type = SWF_PREBUILT;
        BLOCK(data)->writeBlock = writeSWFPrebuiltToMethod;
        BLOCK(data)->complete = completeSWFPrebuilt;
        BLOCK(data)->dtor = (destroySWFBlockMethod) destroySWFPrebuilt;

        data->defines = newSWFOutput();
        return data;
}

// functions to read swf

static int verbose = {0};

struct bitstream
{       char lastch;
        char bitoff;
        unsigned char (*readc)(void *);
};
typedef struct bitstream *BITS;

#define alignbits(x) ((BITS)x)->bitoff = 0

static int
getbits(BITS bp, int nbits)
{       int res = 0, nb, db;
        for(nb = 0 ; nb < nbits ; nb += db)
        {       if(bp->bitoff == 0)
                {       bp->lastch = bp->readc(bp);
                        bp->bitoff = 8;
                }
                db = nbits - nb;
                if(db > bp->bitoff)
                        db = bp->bitoff;
                /* db bits von vorn wegnehmen */
                res <<= db;
                res |= (bp->lastch >> (bp->bitoff -= db)) & ((1 << db) - 1);
        }
        return res;
}
static int
getsbits(BITS bp, int nbits)
{       int res = getbits(bp, nbits);
        if(res & (1 << (nbits-1)))
                res |= (-1) << nbits;
        return(res);
}

/* rectangle */
static void rect(BITS bp)
{       int nbits, xmin, xmax, ymin, ymax;
        nbits = getbits(bp, 5);
        xmin = getbits(bp, nbits);
        xmax = getbits(bp, nbits);
        ymin = getbits(bp, nbits);
        ymax = getbits(bp, nbits);
        if(verbose)
                printf("rect %.2f,%.2f %.2f,%.2f\n", xmin/Ming_scale, ymin/Ming_scale, xmax/Ming_scale, ymax/Ming_scale);
}
/* matrix */
static void matrix(BITS bp)
{       int hasscale, nscalebits, scalex, scaley;
        int hasrotate, nrotatebits, rotateskew0, rotateskew1;
        int ntranslatebits, translatex, translatey;
        if((hasscale = getbits(bp, 1)))
        {       nscalebits = getbits(bp, 5);
                scalex = getbits(bp, nscalebits);
                scaley = getbits(bp, nscalebits);
                if(verbose)
                        printf("scale %d %d\n", scalex, scaley);
        }
        if((hasrotate = getbits(bp, 1)))
        {       nrotatebits = getbits(bp, 5);
                rotateskew0 = getsbits(bp, nrotatebits);
                rotateskew1 = getsbits(bp, nrotatebits);
                if(verbose)
                        printf("skew %d %d\n", rotateskew0, rotateskew1);
        }
        ntranslatebits = getbits(bp, 5);
        translatex = getsbits(bp, ntranslatebits);
        translatey = getsbits(bp, ntranslatebits);
        if(verbose)
                printf("translate %d %d\n", translatex, translatey);
}
/* rgb */
static void rgb(BITS bp)
{       int r, g, b;
        alignbits(bp);
        r = bp->readc(bp); g = bp->readc(bp); b = bp->readc(bp);
        if(verbose)
                printf("rgb %x %x %x\n", r, g, b);
}
static void rgba(BITS bp)
{       int r, g, b, a;
        alignbits(bp);
        r = bp->readc(bp); g = bp->readc(bp); b = bp->readc(bp);
        a = bp->readc(bp);
        if(verbose)
                printf("rgba %x %x %x %x\n", r, g, b, a);
}
static int
readint2(BITS bp)
{       int res;
        res = bp->readc(bp);
        res |= bp->readc(bp) << 8;
        return res;
}
static int
readint4(BITS bp)
{       int res;
        res = bp->readc(bp);
        res |= bp->readc(bp) << 8;
        res |= bp->readc(bp) << 16;
        res |= bp->readc(bp) << 24;
        return res;
}
static void putint2(unsigned char *p, int val)
{       *p++ = val;
        *p++ = val >> 8;
}
static void putint4(unsigned char *p, int val)
{       *p++ = val;
        *p++ = val >> 8;
        *p++ = val >> 16;
        *p++ = val >> 24;
}

/* open a swf file as a stream */
struct swfile
{       char lastch;
        char bitoff;
        unsigned char (*readc)(struct swfile *);

        char *name;     
        unsigned char vers[4];
        int fsize;
        
        char rect[9];
        unsigned short rectlen;
        SWFInput input;
        short frames, rate;

        short compressed;
        unsigned char *zbuf, *zptr, *zend;
};
static unsigned char freadc(struct swfile *sp)
{       return SWFInput_getChar(sp->input);
}
static unsigned char r_readc(struct swfile *sp)
{       return sp->rect[sp->rectlen++] = freadc(sp);
}
static void swfseek(struct swfile *sp, int delta)
{       SWFInput_seek(sp->input, delta, 1);
}

static struct swfile *openswf(SWFInput input)
{       struct swfile *res = (struct swfile *)malloc(sizeof(struct swfile));
        SWFInput_read(input, res->vers, 4);
        if(memcmp(res->vers, "FWS", 3) && memcmp(res->vers, "CWS", 3))
                SWF_error("input not a SWF stream\n");
        res->fsize = SWFInput_getUInt32(input);
        res->compressed = res->vers[0] == 'C';
        if(res->compressed)
        {
#if USE_ZLIB
                static z_stream z = {0};
                int len = SWFInput_length(input);
                unsigned char *zbuf;

                z.next_in = (unsigned char *)malloc(z.avail_in = len - 8);
                SWFInput_read(input, z.next_in, z.avail_in);
                // caller will do, leave it here for double memory consumption
                //destroySWFInput(input);
                zbuf = z.next_out = (unsigned char *)malloc(z.avail_out = res->fsize - 8);
                inflateInit(&z);
                inflate(&z, Z_FINISH);
                inflateEnd(&z);
                input = newSWFInput_allocedBuffer(zbuf, z.next_out-zbuf);
#else
                SWF_error("The SWF to be opened is compressed, but we can't uncompress it (no zlib compiled into this version of Ming).\n");
                return NULL;
#endif
        }
        res->input = input;
        // setup to read that rect...
        alignbits(res);
        res->rectlen = 0;
        res->readc = r_readc;
        rect((BITS) res);
        res->readc = freadc;
        readint2((BITS) res);   // movie rate
        res->frames = readint2((BITS) res);
        return res;
}

/* tag */
struct swftag
{       char lastch;
        char bitoff;
        unsigned char (*readc)(struct swftag *sp);

        short type; int size;
        unsigned char hdr[6]; short hdrlen;
        unsigned char *datbuf, *datptr, *datend;
        short alloced;
};
typedef struct swftag *TAG;

static unsigned char treadc(TAG tp)
{       return *tp->datptr++;
}

static TAG readtag_common(BITS bp)
{       TAG res = (TAG) malloc(sizeof(struct swftag));
        res->type = readint2(bp);
        res->size = res->type & 63;
        putint2(res->hdr, res->type);
        res->type >>= 6;
        res->hdrlen = 2;
        if(res->size == 63)
        {       res->size = readint4(bp);
                putint4(res->hdr+2, res->size);
                res->hdrlen = 6;
        }
        res->bitoff = 0;
        res->readc = treadc;
        res->alloced = 0;
        return res;
}
static TAG readtag_file(struct swfile *sp)
{       TAG res = (TAG) readtag_common((BITS) sp);
        if(res->size)
        {       res->datbuf = res->datptr = (unsigned char *)malloc(res->size);
                res->datend = res->datbuf + res->size;
                SWFInput_read(sp->input, res->datbuf, res->size);
                res->alloced = 1;
        }
        return res;
}
static TAG readtag_sprite(TAG tp)
{       TAG res = readtag_common((BITS) tp);
        if(res->size)
        {       res->datbuf = res->datptr = tp->datptr;
                res->datend = res->datbuf + res->size;
                tp->datptr += res->size;
        }
        return res;
}

static int idoffset = {0}, maxid = {0};
static int change_id(TAG tp)
{       int val = readint2((BITS) tp);
        if(val != 0 && val != 65535)
        {       val += idoffset;
                if(val > maxid)
                        maxid = val;
                putint2(tp->datptr-2, val);
        }
        return val;
}

// processing functions for handle()
static void defineshape(TAG tp, int lev);
static void definetext(TAG tp, int lev);
static void placeobject(TAG tp, int lv);
static void definebutton(TAG tp);
static void definebutton2(TAG tp);
static void definetextfield(TAG tp);
static void definesprite(TAG tp);
static void definemorphshape(TAG tp,int lev);
static void exportassets(TAG tp);
static void definebuttonsound(TAG tp);
static void fillandlinestyles(TAG tp, int lev);
static void linestyle(TAG tp, int lev);
static void shape(TAG tp, int lev);
static void morphlinestyle2(TAG tp);

static int drop_tag(TAG tp)
{
        switch(tp->type)
        {
                case SWF_FILEATTRIBUTES:
                case SWF_METADATA:
                case SWF_DEFINESCENEANDFRAMEDATA: // only allowed in main timeline -> merge ?
                        return 1;
                default:
                        return 0;
        }
}

static int handle_tag(TAG tp)
{       int id;
        int displaylist = 0;
        if(verbose)
        {       char *tagnam = "inknown";
                switch(tp->type)
                {
                        case SWF_END:
                                tagnam = "stagEnd"; break;
                        case SWF_SHOWFRAME:
                                tagnam = "stagShowFrame"; break;
                        case SWF_DEFINESHAPE:
                                tagnam = "stagDefineShape"; break;
                        case SWF_FREECHARACTER:
                                tagnam = "stagFreeCharacter"; break;
                        case SWF_PLACEOBJECT:
                                tagnam = "stagPlaceObject"; break;
                        case SWF_REMOVEOBJECT:
                                tagnam = "stagRemoveObject"; break;
                        case SWF_DEFINEBITS:
                                tagnam = "stagDefineBits"; break;
                        case SWF_DEFINEBUTTON:
                                tagnam = "stagDefineButton"; break;
                        case SWF_JPEGTABLES:
                                tagnam = "stagJPEGTables"; break;
                        case SWF_SETBACKGROUNDCOLOR:
                                tagnam = "stagSetBackgroundColor"; break;
                        case SWF_DEFINEFONT:
                                tagnam = "stagDefineFont"; break;
                        case SWF_DEFINETEXT:
                                tagnam = "stagDefineText"; break;
                        case SWF_DOACTION:
                                tagnam = "stagDoAction"; break;
                        case SWF_DEFINEFONTINFO:
                                tagnam = "stagDefineFontInfo"; break;
                        case SWF_DEFINESOUND:
                                tagnam = "stagDefineSound"; break;
                        case SWF_STARTSOUND:
                                tagnam = "stagStartSound"; break;
                        case SWF_DEFINEBUTTONSOUND:
                                tagnam = "stagDefineButtonSound"; break;
                        case SWF_SOUNDSTREAMHEAD:
                                tagnam = "stagSoundStreamHead"; break;
                        case SWF_SOUNDSTREAMBLOCK:
                                tagnam = "stagSoundStreamBlock"; break;
                        case SWF_DEFINELOSSLESS:
                                tagnam = "stagDefineBitsLossless"; break;
                        case SWF_DEFINEBITSJPEG2:
                                tagnam = "stagDefineBitsJPEG2"; break;
                        case SWF_DEFINESHAPE2:
                                tagnam = "stagDefineShape2"; break;
                        case SWF_DEFINEBUTTONCXFORM:
                                tagnam = "stagDefineButtonCxform"; break;
                        case SWF_PROTECT:
                                tagnam = "stagProtect"; break;
                        case SWF_PLACEOBJECT2:
                                tagnam = "stagPlaceObject2"; break;
                        case SWF_PLACEOBJECT3:
                                tagnam = "stagPlaceObject3"; break;
                        case SWF_REMOVEOBJECT2:
                                tagnam = "stagRemoveObject2"; break;
                        case SWF_DEFINESHAPE3:
                                tagnam = "stagDefineShape3"; break;
                        case SWF_DEFINESHAPE4:
                                tagnam = "stagDefineShape4"; break;
                        case SWF_DEFINETEXT2:
                                tagnam = "stagDefineText2"; break;
                        case SWF_DEFINEBUTTON2:
                                tagnam = "stagDefineButton2"; break;
                        case SWF_DEFINEBITSJPEG3:
                                tagnam = "stagDefineBitsJPEG3"; break;
                        case SWF_DEFINELOSSLESS2:
                                tagnam = "stagDefineBitsLossless2"; break;
                        case SWF_DEFINEEDITTEXT:
                                tagnam = "stagDefineTextField"; break;
                        case SWF_DEFINESPRITE:
                                tagnam = "stagDefineSprite"; break;
                        case SWF_NAMECHARACTER:
                                tagnam = "stagNameCharacter"; break;
                        case SWF_FRAMELABEL:
                                tagnam = "stagFrameLabel"; break;
                        case SWF_SOUNDSTREAMHEAD2:
                                tagnam = "stagSoundStreamHead2"; break;
                        case SWF_DEFINEMORPHSHAPE:
                                tagnam = "stagDefineMorphShape"; break;
                        case SWF_DEFINEMORPHSHAPE2:
                                tagnam = "stagDefineMorphShape2"; break;
                        case SWF_DEFINEFONT2:
                                tagnam = "stagDefineFont2"; break;
                        case SWF_DEFINEFONT3:
                                tagnam = "stagDefineFont3"; break;
                        case SWF_DEFINEFONTALIGNZONES:
                                tagnam = "stagDefineFontAlignZones"; break;
                        case SWF_EXPORTASSETS:
                                tagnam = "stagExportAssets"; break;
                        /*case stagClipInit:    
                                tagnam = "stagClipInit"; break;*/
                        /*case stagNewFontInfo:
                                tagnam = "stagNewFontInfo"; break;*/
                        case SWF_DEFINEVIDEOSTREAM:
                                tagnam = "stagDefineVideoStrem"; break;
                        case SWF_VIDEOFRAME:
                                tagnam = "stagVideoFrame"; break;
                        case SWF_INITACTION:
                                tagnam = "stagInitAction"; break;
                }
                printf("tag %d %s\n", tp->type, tagnam);
        }
        switch(tp->type)
        {       /* tags without an id */
                case SWF_END:
                case SWF_SHOWFRAME:
                case SWF_SETBACKGROUNDCOLOR:
                case SWF_DOACTION:
                case SWF_PROTECT:
                case SWF_REMOVEOBJECT2:
                case SWF_FRAMELABEL:
                case SWF_SOUNDSTREAMHEAD:
                case SWF_SOUNDSTREAMHEAD2:
                case SWF_SOUNDSTREAMBLOCK:
                case SWF_JPEGTABLES:
                case SWF_SYMBOLCLASS:
                case SWF_DOABC:
                case SWF_DEFINEFONTNAME:
                /*case stagClipInit:*/
                        break;
                /* simple tags - one id at beginning */
                case SWF_FREECHARACTER:
                case SWF_PLACEOBJECT:
                case SWF_REMOVEOBJECT:
                case SWF_DEFINEBITS:
                case SWF_DEFINEBITSJPEG2:
                case SWF_DEFINEBITSJPEG3:
                case SWF_DEFINELOSSLESS:
                case SWF_DEFINELOSSLESS2:
                case SWF_DEFINEFONT:
                case SWF_DEFINEFONTINFO:
                case SWF_DEFINESOUND:
                case SWF_STARTSOUND:
                case SWF_NAMECHARACTER:
                case SWF_DEFINEFONT2:
                case SWF_DEFINEFONT3:
                case SWF_DEFINEFONTALIGNZONES:
                case SWF_DEFINEBUTTONCXFORM:
                case SWF_DEFINEVIDEOSTREAM:
                case SWF_VIDEOFRAME:
                case SWF_INITACTION:
                case SWF_DEFINEBINARYDATA:
                /*case SWF_NEWFONTINFO:*/
                        id = change_id(tp);
                        if(verbose)
                                printf("id %d offset %d\n", id, idoffset);
                        break;
                /* to be processed specially */
                case SWF_DEFINESHAPE:
                        defineshape(tp, 1);
                        break;
                case SWF_DEFINETEXT:
                        definetext(tp, 1);
                        break;
                case SWF_DEFINESHAPE2:
                        defineshape(tp, 2);
                        break;
                case SWF_PLACEOBJECT2:
                        placeobject(tp, 2);
                        break;
                case SWF_PLACEOBJECT3:
                        placeobject(tp, 3);
                        break;
                case SWF_DEFINESHAPE3:
                        defineshape(tp, 3);
                        break;
                case SWF_DEFINESHAPE4:
                        defineshape(tp, 4);
                        break;
                case SWF_DEFINETEXT2:
                        definetext(tp, 2);
                        break;
                case SWF_DEFINEBUTTON:
                        definebutton(tp);
                        break;
                case SWF_DEFINEBUTTON2:
                        definebutton2(tp);
                        break;
                case SWF_DEFINEEDITTEXT:
                        definetextfield(tp);
                        break;
                case SWF_DEFINESPRITE:
                        definesprite(tp);
                        break;
                case SWF_DEFINEMORPHSHAPE:
                        definemorphshape(tp, 1);
                        break;
                case SWF_DEFINEMORPHSHAPE2:
                        definemorphshape(tp, 2);
                        break;
                case SWF_EXPORTASSETS:
                        exportassets(tp);
                        break;
                case SWF_DEFINEBUTTONSOUND:
                        definebuttonsound(tp);
                        break;
                default:
                        SWF_error("unknown tag %d\n", tp->type);
        }
        switch(tp->type)
        {       case SWF_END:
                case SWF_SHOWFRAME:
                case SWF_DOACTION:
                case SWF_REMOVEOBJECT2:
                case SWF_FRAMELABEL:
                case SWF_SOUNDSTREAMHEAD:
                case SWF_SOUNDSTREAMHEAD2:
                case SWF_SOUNDSTREAMBLOCK:
                case SWF_DEFINEVIDEOSTREAM:
                case SWF_VIDEOFRAME:
                case SWF_INITACTION:
                case SWF_FREECHARACTER:
                case SWF_PLACEOBJECT:
                case SWF_REMOVEOBJECT:
                case SWF_STARTSOUND:
                case SWF_NAMECHARACTER:
                case SWF_PLACEOBJECT2:
                case SWF_PLACEOBJECT3:
                        displaylist = 1;
        }
        return displaylist;
}

static void definesprite(TAG sp)
{       TAG tp;
        int type;
        int id, frames;
        id = change_id(sp);
        frames = readint2((BITS) sp);
        if(verbose)
                printf("sprite %d, %d frames\n", id, frames);
        do
        {       tp = readtag_sprite(sp);
                handle_tag(tp);
                type = tp->type;
                free(tp);
        } while(type);
        if(sp->datptr != sp->datend)
                SWF_error("consistency check: file size wrong in sprite\n");
}

/* shape */
static void shaperecord(TAG tp, int nfillbits, int nlinebits, int lev)
{       int type, statenewstyles, statelinestyle, statefillstyle1, statefillstyle0;
        int statemoveto, movebits, movex, movey, fill0style, fill1style, linestyle;
        int edgeflag, nbits, genlineflag, dx, dy, vertlineflag;
        int cdx, cdy, adx, ady;
        
        while(1)
        {       type = getbits((BITS) tp, 1);
                
                if(!type)
                {       statenewstyles = getbits((BITS) tp, 1);
                        statelinestyle = getbits((BITS) tp, 1);
                        statefillstyle1 = getbits((BITS) tp, 1);
                        statefillstyle0 = getbits((BITS) tp, 1);
                        if((statemoveto = getbits((BITS) tp, 1)))
                        {       movebits = getbits((BITS) tp, 5);
                                movex = getsbits((BITS) tp, movebits);
                                movey = getsbits((BITS) tp, movebits);
                                if(verbose)
                                        printf("move %d %d\n", movex, movey);
                        }
                        if(statenewstyles == 0 && statelinestyle == 0 && statefillstyle1 == 0&& statefillstyle0 == 0 && statemoveto == 0)
                                break;
                        if(statefillstyle0)
                        {       fill0style = getbits((BITS) tp, nfillbits);
                                if(verbose)
                                        printf("fillstyle0 %d\n", fill0style);
                        }
                        if(statefillstyle1)
                        {       fill1style = getbits((BITS) tp, nfillbits);
                                if(verbose)
                                        printf("fillstyle1 %d\n", fill1style);
                        }
                        if(statelinestyle)
                        {       linestyle = getbits((BITS) tp, nlinebits);
                                if(verbose)
                                        printf("linestyle %d\n", linestyle);
                        }
/* contrary to document, but
 ... seems to work AND make sense
 */
                        if(statefillstyle0 || statefillstyle1 || statelinestyle)
                                ;
                        else
                        if(statenewstyles)
                                fillandlinestyles(tp, lev);
                }
                else
                {       edgeflag = getbits((BITS) tp, 1);
                        if(!edgeflag)   /* curve */
                        {       nbits = getbits((BITS) tp, 4)+2;
                                cdx = getsbits((BITS) tp, nbits);
                                cdy = getsbits((BITS) tp, nbits);
                                adx = getsbits((BITS) tp, nbits);
                                ady = getsbits((BITS) tp, nbits);
                                if(verbose)
                                        printf("curve %d,%d %d,%d\n", cdx, cdy, adx, ady);
                        }
                        else
                        {       nbits = getbits((BITS) tp, 4)+2;
                                if((genlineflag = getbits((BITS) tp, 1)))
                                {       dx = getsbits((BITS) tp, nbits);
                                        dy = getsbits((BITS) tp, nbits);
                                }
                                else if((vertlineflag = getbits((BITS) tp, 1)))
                                {       dx = 0;
                                        dy = getsbits((BITS) tp, nbits);
                                }
                                else
                                {       dx = getsbits((BITS) tp, nbits);
                                        dy = 0;
                                }
                                if(verbose)
                                        printf("line %d,%d\n", dx, dy);
                        }
                }
        }
}

static void gradient(TAG tp, int alpha, int cod)
{       int n, ngrad, r1;
        
        alignbits(tp);
        ngrad = tp->readc(tp);
        for(n = 0 ; n < ngrad ; n++)
        {       r1 = tp->readc(tp);
                if(verbose)
                        printf("ratio %d\n", r1);
                if(alpha) rgba((BITS) tp); else rgb((BITS) tp);
        }
        if (cod == 0x13)
                readint2((BITS) tp);
}

static void fillstyle(TAG tp, int lev)
{       unsigned short id;
        char cod;

        alignbits(tp);
        cod = tp->readc(tp);
        switch(cod)
        {       case 0:
                        if(verbose) printf("solid fill:\n"); break;
                case 0x10:
                        if(verbose) printf("linear gradient fill\n"); break;
                case 0x12:
                        if(verbose) printf("radial gradient fill:\n"); break;
                case 0x13:
                        if(verbose) printf("focal gradient fill:\n"); break;
                case 0x40:
                        if(verbose) printf("tiled bitmap fill:\n"); break;
                case 0x41:
                        if(verbose) printf("clipped bitmap fill\n"); break;
                case 0x42:
                        if(verbose) printf("tilled bitmap fill with hard edges\n"); break;
                case 0x43:
                        if(verbose) printf("clipped bitmap fill with hard edges\n"); break;
        }
        if(cod == 0)
                if(lev >= 3) rgba((BITS) tp); else rgb((BITS) tp);
        else if(cod == 0x10 || cod == 0x12 || cod == 0x13)
        {       matrix((BITS) tp);
                gradient(tp, lev >= 3, cod);
        }
        else if(cod == 0x40 || cod == 0x41 || cod == 0x42 || cod == 0x43)
        {       id = change_id(tp);
                if(verbose)
                        printf("fill with id %d\n", id);
                matrix((BITS) tp);
        }
        else
                printf("%s:%d: UNEXPEDCED %x\n", __FILE__, __LINE__, cod);
}

static void morphgradient(TAG tp)
{       int n, ngrad, r1, r2;
        
        alignbits(tp);
        ngrad = tp->readc(tp);
        for(n = 0 ; n < ngrad ; n++)
        {       r1 = tp->readc(tp);
                if(verbose)
                        printf("ratio %d\n", r1);
                rgba((BITS) tp);
                r2 = tp->readc(tp);
                if(verbose)
                        printf("ratio %d\n", r2);
                rgba((BITS) tp);
        }
}

static void morphfillstyle(TAG tp)
{       unsigned short id;
        char cod;

        alignbits(tp);
        cod = tp->readc(tp);
        switch(cod)
        {       case 0:
                        if(verbose) printf("solid fill:\n"); break;
                case 0x10:
                        if(verbose) printf("linear gradient fill\n"); break;
                case 0x12:
                        if(verbose) printf("radial gradient fill:\n"); break;
                case 0x13:
                        if(verbose) printf("focal gradient fill:\n"); break;
                case 0x40:
                        if(verbose) printf("tiled bitmap fill:\n"); break;
                case 0x41:
                        if(verbose) printf("clipped bitmap fill\n"); break;
                case 0x42:
                        if(verbose) printf("tilled bitmap fill with hard edges\n"); break;
                case 0x43:
                        if(verbose) printf("clipped bitmap fill with hard edges\n"); break;
        }
        if(cod == 0)
        {       rgba((BITS) tp);
                rgba((BITS) tp);
        }
        else if(cod == 0x10 || cod == 0x12 || cod == 0x13)
        {       matrix((BITS) tp);
                alignbits(tp);
                matrix((BITS) tp);
                morphgradient(tp);
        }
        else if(cod == 0x40 || cod == 0x41 || cod == 0x42 || cod == 0x43)
        {       id = change_id(tp);
                if(verbose) printf("fill with id %d\n", id);
                matrix((BITS) tp);
                alignbits(tp);
                matrix((BITS) tp);
        }
        else
                printf("%s:%d: UNEXPEDCED %x\n", __FILE__, __LINE__, cod);
}

static void fillandlinestyles(TAG tp, int lev)
{       int n, nfill, nline;

        alignbits(tp);
        nfill = tp->readc(tp);
        if(nfill == 0xff)
                nfill = readint2((BITS) tp);
        if(verbose)     
                printf ("%d fill styles\n", nfill);
        for(n = 0 ; n < nfill ; n++)
                fillstyle(tp, lev);
        alignbits(tp);
        nline = tp->readc(tp);
        if(nline == 0xff)
                nline = readint2((BITS) tp);
        if(verbose)
                printf ("%d line styles\n", nline);
        for(n = 0 ; n < nline ; n++)
                if (lev == 4)
                        morphlinestyle2(tp);
                else
                        linestyle(tp, lev);
}

static void linestyle(TAG tp, int lev)
{       unsigned short w;
        w = readint2((BITS) tp);
        if(verbose)
                printf ("w %d\n", w);
        if(lev >= 3) rgba((BITS) tp); else rgb((BITS) tp);
}

static void morphlinestyle(TAG tp)
{       unsigned short w1, w2;
        w1 = readint2((BITS) tp);
        w2 = readint2((BITS) tp);
        if(verbose)
                printf("w %d => %d\n", w1, w2);
        rgba((BITS) tp); rgba((BITS) tp);
}

static void morphlinestyle2(TAG tp)
{       unsigned short w1;
        int join_style;
        int has_fill;
        int is_morph = (tp->type == SWF_DEFINEMORPHSHAPE2);
        w1 = readint2((BITS) tp);
        if (is_morph) {
                unsigned short w2;
                w2 = readint2((BITS) tp);
                if(verbose)
                        printf("w %d => %d\n", w1, w2);
        } else {
                if(verbose)
                        printf("w %d\n", w1);
        }
        getbits((BITS) tp, 2);
        join_style = getbits((BITS) tp, 2);
        has_fill = getbits((BITS) tp, 1);
        getbits((BITS) tp, 11);
        if (join_style == 2) {
                readint2((BITS) tp);
        } else {
                if (has_fill) {
                        if (is_morph)
                                morphfillstyle(tp);
                        else
                                fillstyle(tp, 4);
                } else {
                        rgba((BITS) tp);
                        if (is_morph)
                                rgba((BITS) tp);
                }
        }
}

static void defineshape(TAG tp, int lev)
{       unsigned short id;

        id = change_id(tp);
        if(verbose)
                printf("shape %d\n", id);
        alignbits(tp);
        rect((BITS) tp);
        if(lev == 4) {
                alignbits(tp);
                rect((BITS) tp);
                alignbits(tp);
                tp->readc(tp);
        }
        fillandlinestyles(tp, lev);
        shape(tp, lev);
}

static void shape(TAG tp, int lev)
{       int nfillbits, nlinebits;
        alignbits(tp);
        nfillbits = getbits((BITS) tp, 4);
        nlinebits = getbits((BITS) tp, 4);
        shaperecord(tp, nfillbits, nlinebits,lev);
}

static void definemorphshape(TAG tp, int lev)
{       unsigned short id, fcnt, lcnt;
        unsigned long loff;
        unsigned char *endp;
        int n;

        id = change_id(tp);
        if(verbose)
                printf("morph %d\n", id);
        rect((BITS) tp);
        alignbits(tp);
        rect((BITS) tp);
        if (lev == 2) {
                rect((BITS) tp);
                rect((BITS) tp);
                tp->readc(tp);
        }
        loff = readint4((BITS) tp);
        endp = tp->datptr + loff;
        fcnt = tp->readc(tp);
        if(fcnt == 0xff)
                fcnt = readint2((BITS) tp);
        if(verbose)
                printf ("%d fill styles\n", fcnt);
        for(n = 0 ; n < fcnt ; n++)
        {       alignbits(tp);
                morphfillstyle(tp);
        }
        lcnt = tp->readc(tp);
        if(lcnt == 0xff)
                lcnt = readint2((BITS) tp);
        if(verbose)
                printf ("%d line styles\n", lcnt);
        for(n = 0 ; n < lcnt ; n++)
        {       alignbits(tp);
                if (lev == 2)
                        morphlinestyle2(tp);
                else
                        morphlinestyle(tp);
        }
/*      for(n = 0 ; tp->datptr < endp ; n++)
        {       alignbits(tp);
                shaperecord(tp, bits_req(fcnt), bits_req(lcnt), 3);
        }
        for( ; n > 0 ; --n)
        {       alignbits(tp);
                shaperecord(tp, bits_req(fcnt), bits_req(lcnt), 3);
        }*/
        shape(tp, 3);
}

static void definetext(TAG tp, int lev)
{       unsigned short textid;
        int nglyphbits, nadvancebits;
        int n, nglyphs, chcode, dx;
        int hasfont, hascolor, hasyoffset, hasxoffset;
        unsigned short font=0, height;
        signed short xoffs, yoffs;
                        
        textid = change_id(tp);
        if(verbose) printf("text %d\n", textid);
        rect((BITS) tp);
        alignbits(tp);
        matrix((BITS) tp);
        nglyphbits = tp->readc(tp);
        nadvancebits = tp->readc(tp);
        alignbits(tp);
        while(1)
        {       if(!getbits((BITS) tp, 1))
                {       nglyphs = getbits((BITS) tp, 7);
                        if(!nglyphs)
                                break;
                        if(verbose) printf("%d chars:\n", nglyphs);
                        for(n = 0 ; n < nglyphs ; n++)
                        {       chcode = getbits((BITS) tp, nglyphbits);
                                dx = getsbits((BITS) tp, nadvancebits);
                                if(verbose) printf("code %d dx %d\n", chcode, dx);
                        }
                }
                else
                {       getbits((BITS) tp, 3);
                        hasfont = getbits((BITS) tp, 1);
                        hascolor = getbits((BITS) tp, 1);
                        hasyoffset = getbits((BITS) tp, 1);
                        hasxoffset = getbits((BITS) tp, 1);
                        if(hasfont)
                                font = change_id(tp);
                        if(hascolor)
                        {       if(lev == 2) rgba((BITS) tp);
                                else rgb((BITS) tp);
                        }
                        if(hasxoffset)
                        {       xoffs = readint2((BITS) tp);
                                if(verbose) printf("dx %d\n", xoffs);
                        }
                        if(hasyoffset)
                        {       yoffs = readint2((BITS) tp);
                                if(verbose) printf("dy %d\n", yoffs);
                        }
                        if(hasfont)
                        {       height = readint2((BITS) tp);
                                if(verbose) printf("font %d size %d\n", font, height);
                        }
                }
                alignbits(tp);
        }
}

static void placeobject(TAG tp, int lv)
{       int hasname, hasratio, hascxform, hasmatrix, haschar, hasmove, hasactions, hasmask;
        short depth, charid;
        int hasfilters, hasbitmapcaching, hasblendmode;
        if (lv == 3) {
                getbits((BITS)tp, 5);
                hasbitmapcaching = getbits((BITS)tp, 1);
                hasblendmode = getbits((BITS)tp, 1);
                hasfilters = getbits((BITS)tp, 1);
        }
        hasactions = getbits((BITS)tp, 1);
        hasmask = getbits((BITS)tp, 1);
        hasname = getbits((BITS)tp, 1);
        hasratio = getbits((BITS)tp, 1);
        hascxform = getbits((BITS)tp, 1);
        hasmatrix = getbits((BITS)tp, 1);
        haschar = getbits((BITS)tp, 1);
        hasmove = getbits((BITS)tp, 1);
        depth = readint2((BITS) tp);
        if(haschar)
        {       charid = change_id(tp);
                if(verbose) printf("char %d depth %d\n", charid, depth);
        }
}

static void definebutton(TAG tp)
{       short butid, charid, layer;
        unsigned char bstate;

        butid = change_id(tp);
        if(verbose)
                printf("char %d:\n", butid);
        while((bstate = tp->readc(tp)))
        {       if(bstate & 8)
                        if(verbose) printf("hit test ");
                if(bstate & 4)
                        if(verbose) printf("down ");
                if(bstate & 2)
                        if(verbose) printf("over ");
                if(bstate & 1)
                        if(verbose) printf("up");
                if(verbose) printf("\n");
                charid = change_id(tp);
                layer = readint2((BITS) tp);
                if(verbose) printf("char %d layer %d\n", charid, layer);
                alignbits(tp);
                matrix((BITS) tp);
        }
}

static void cxform(TAG tp, int alpha)
{       int hasadd, hasmult, nbits;
        int ra, ga, ba, aa, rm, gm, bm, am=0;
        hasadd = getbits((BITS) tp, 1);
        hasmult = getbits((BITS) tp, 1);
        nbits = getbits((BITS) tp, 4);
        if(verbose) printf("cxform ");
        if(hasmult)
        {       rm = getsbits((BITS) tp, nbits);
                gm = getsbits((BITS) tp, nbits);
                bm = getsbits((BITS) tp, nbits);
                if(alpha) am  = getsbits((BITS) tp, nbits);
                if(verbose) printf("mul %d %d %d ", rm, gm, bm);
                if(verbose) if(alpha) printf("%d ", am);
        }
        if(hasadd)
        {       ra = getsbits((BITS) tp, nbits);
                ga = getsbits((BITS) tp, nbits);
                ba = getsbits((BITS) tp, nbits);
                if(alpha) aa = getsbits((BITS) tp, nbits);
                if(verbose) printf("add %d %d %d", ra, ga, ba);
                if(verbose) if(alpha) printf(" %d", am);
        }
        if(verbose) printf("\n");
}

static void definebutton2(TAG tp)
{       short id, charid, offs, layer;
        unsigned char ch, bstate;

        id = change_id(tp);
        ch = tp->readc(tp);
        offs = readint2((BITS) tp);
        if(verbose)
                printf("id %d %s action offset %d\n", id, ch ? "menu" : "button", offs);
        while((bstate = tp->readc(tp)))
        {       if(bstate & 8)
                        if(verbose) printf("hit test ");
                if(bstate & 4)
                        if(verbose) printf("down ");
                if(bstate & 2)
                        if(verbose) printf("over ");
                if(bstate & 1)
                        if(verbose) printf("up");
                if(verbose) printf("\n");
                charid = change_id(tp);
                layer = readint2((BITS) tp);
                if(verbose) printf("char %d layer %d\n", charid, layer);
                alignbits(tp);
                matrix((BITS) tp);
                alignbits(tp);
                cxform(tp, 1);
        }
}

static void definetextfield(TAG tp)
{
        short textid, fontid=0;
        int haslength, noedit, password, multiline, wordwrap, drawbox, noselect, html, usefont;
        int hascolor, haslayout, hastext, hasfont;
        
        textid = change_id(tp);
        if(verbose) printf("textfield %d\n", textid);
        rect((BITS) tp);
        alignbits(tp);
        hastext = getbits((BITS) tp, 1);
        wordwrap = getbits((BITS) tp, 1);
        multiline = getbits((BITS) tp, 1);
        password = getbits((BITS) tp, 1);
        noedit = getbits((BITS) tp, 1);
        hascolor = getbits((BITS) tp, 1);
        haslength = getbits((BITS) tp, 1);
        hasfont = getbits((BITS) tp, 1);
        getbits((BITS) tp, 2);
        haslayout = getbits((BITS) tp, 1);
        noselect = getbits((BITS) tp, 1);
        drawbox = getbits((BITS) tp, 1);
        getbits((BITS) tp, 1);
        html = getbits((BITS) tp, 1);
        usefont = getbits((BITS) tp, 1);
        if(hasfont)
                fontid = change_id(tp);
        if(verbose)
        {       if ( fontid ) printf("font %d ", fontid);
                if(noedit) printf("noedit ");
                if(password) printf("password ");
                if(multiline) printf("multiline ");
                if(wordwrap) printf("wordwrap ");
                if(drawbox) printf("drawbox ");
                if(noselect) printf("noselect ");
                if(html) printf("html ");
                if(usefont) printf("usefont ");
                if(hascolor) rgba((BITS) tp);
                putchar('\n');
        }
}

static void exportassets(TAG tp)
{       short n, nobj, id;
        char ch;
        nobj = readint2((BITS) tp);
        for(n = 0 ; n < nobj ; n++)
        {       id = change_id(tp);
                if(verbose) printf("%d ", id);
                while((ch = tp->readc(tp)))
                        if(verbose) putchar(ch);
                if(verbose)
                        putchar((n < nobj-1) ? ' ' : '\n');
        }
}

static void soundinfo(TAG tp)
{       char flags, hasenvelope, hasloops, hasoutpoint, hasinpoint, npoints;
        signed short loops, lev0, lev1;
        int soundpoint, n;
        flags = getbits((BITS) tp, 4);
        hasenvelope = getbits((BITS) tp, 1);
        hasloops = getbits((BITS) tp, 1);
        hasoutpoint = getbits((BITS) tp, 1);
        hasinpoint = getbits((BITS) tp, 1);
        if(flags & 1)
                if(verbose) printf("no multiple ");
        if(flags & 2)
                if(verbose) printf("stop");
        if(flags & 3)
                if(verbose) putchar('\n');
        if(hasinpoint)
        {       soundpoint = readint4((BITS) tp);
                if(verbose) printf("inpoint %d\n", soundpoint);
        }
        if(hasoutpoint)
        {       soundpoint = readint4((BITS) tp);
                if(verbose) printf("outpoint %d\n", soundpoint);
        }
        if(hasloops)
        {       loops = readint2((BITS) tp);
                if(verbose) printf("%d loops\n", loops);
        }
        if(hasenvelope)
        {       npoints = tp->readc(tp);
                for(n = 0 ; n < npoints ; n++)
                {       soundpoint = readint4((BITS) tp);
                        lev0 = readint2((BITS) tp);
                        lev1 = readint2((BITS) tp);
                        if(verbose) printf("%d: %d %d\n", soundpoint, lev0, lev1);
                }
        }
}

static void definebuttonsound(TAG tp)
{       int id, n, snds[4];
        id = change_id(tp);
        if(verbose)
                printf("id %d\n", id);
        for(n = 0 ; n < 4 ; n++)
        {       snds[n] = change_id(tp);
                if(verbose)
                        printf("sound %d:\n", snds[n]);
                alignbits(tp);
                if(snds[n]) soundinfo(tp);
        }
}

extern int SWF_gNumCharacters;

/* 
 * load and create a SWF File as MovieClip 
 */
SWFPrebuiltClip
newSWFPrebuiltClip_fromInput(SWFInput input)
{       SWFPrebuiltClip clip;
        SWFOutput display, defines, out;
        SWFPrebuilt deps;
        TAG tp;
        struct swfile *swf;
        int type = 0, todisplay;
        
        swf = openswf(input);
        if ( ! swf ) return NULL;
        clip = newSWFPrebuiltClip();
        clip->frames = swf->frames;
        display = clip->display;
        deps = newSWFPrebuilt();
        SWFCharacter_addDependency((SWFCharacter)clip, (SWFCharacter)deps);
        defines = deps->defines;
        idoffset = SWF_gNumCharacters;
        maxid = SWF_gNumCharacters;
        // read the swf file here
        tp = readtag_file(swf);
                if(tp->type != SWF_SETBACKGROUNDCOLOR)
                        swfseek(swf, -(tp->hdrlen + tp->size));
        if(tp->alloced)
                free(tp->datbuf);
        free(tp);
        do
        {       tp = readtag_file(swf);
                type = tp->type;
                if(drop_tag(tp))
                {
                        if(tp->alloced)
                                free(tp->datbuf);
                        free(tp);
                        continue;
                }
                todisplay = handle_tag(tp);
                out = todisplay ? display : defines;
                SWFOutput_writeBuffer(out, tp->hdr, tp->hdrlen);
                if(tp->size)
                        SWFOutput_writeBuffer(out, tp->datbuf, tp->size);
                if(tp->alloced)
                        free(tp->datbuf);
                free(tp);
        } while(type);
        if(swf->compressed)
                destroySWFInput(swf->input);
        SWF_gNumCharacters = maxid + 1;
        CHARACTERID(clip) = SWF_gNumCharacters++;
        return clip;
}

/* 
 * load SWF file which can be used as a MovieClip
 */
SWFPrebuiltClip
newSWFPrebuiltClip_fromFile(const char *filename)
{       FILE *fp;
        SWFPrebuiltClip clip;
        SWFInput input;
        if(!(fp = fopen(filename, "rb")))
                return NULL;
        input = newSWFInput_file(fp);
        clip = newSWFPrebuiltClip_fromInput(input);
        destroySWFInput(input);
        fclose(fp);
        return clip;
}

/* [<][>][^][v][top][bottom][index][help] */