www.xbdev.net xbdev - software development
Tuesday January 22, 2019
home | about | contact | Donations

     
 

Image Formats

A single picture is worth a thousand words...

 

Flash (.swf) File Format - (zlib compression)

by bkenwright@xbdev.net

 

I've had to add this section, as most of the time you'll find that your swf files are compressed!  I mean when you export an swf, by default the compression tick box is selected, so it will do it unless you untick it.  Also swf flash files are all over the internet, and theres nothing better than fast websites!  And by making your .swf files compressed they load faster :)  So I'll quickly go over how you can add in a few extra lines and plug in the zlib dll so you can unzip the contents.

 

When you read in the header for your swf, the first few bytes will determine if its compressed.  If its 'C' 'W' 'S', then you have a compressed file...so you read to where the compressed data starts, read in the whole file, pass it to the zlib uncompression algorithm, and it returns you the whole file uncompressed.  You can then start parsing it and doing what you want with it.

 

The great thing is you do the decompression once for the whole file at the start, and your ready to go :)

 

If you've not heard of zlib, then youv'e been missing out....its an open source library of compression algorithms, which you can download on the internet...just google, zlib and you'll find a ton of information on it.  I'm going to use the dll version, as I just downloaded it from the sourceforge website, and included it with the exe I build....I then just add in a few lines to use the dll, and the two functions in the dll....I say 2, but what I mean is one, as we don't use the compression function, just the decompression one.

 

Now for the demo code below, I used a dialog.swf, which is just an outline of a simple dialog you can create...uses compression...and its quiet large...takes about 30 seconds to dump all the data to the txt file :)  And you can open it up in notepad and see all the exciting information thats in there :)

 

Theres no error checking in the code, so it will just crash if you move the dialog.swf file in a different directory than the executable.....just to show how easy it is to sit down and write a small piece of code that can read in the swf flash data.

 

If someone reads this tutorial, could they email me to update the code later on when I get time, add more comments and things to it...

 

Source - Download Source Code (53kb)

// ref: http://www.gzip.org/zlib/

// http://edais.mvps.org/Tutorials/ZLib/index.html

#include <windows.h>
#include <stdio.h>
#include <stdarg.h>

// *IMPORTANT* needs -> zlib.dll, so we can decompress the swf

//------------------------------------------------------------------------------

#pragma pack(1)
struct stSWFHeader
{
    unsigned char sig[3];
    unsigned char version;
    unsigned int  uncompSize;

    enum rectSize
    {
        xmin = 0,        // X minimum position for rectangle in twips
        xmax,            // X maximum position for rectangle in twips
        ymin,            // Y minimum position for rectangle in twips
        ymax            // Y maximum position for rectangle in twips
    };

    int    rectBits;        // Bits used for each subsequent field
    int rectSizes[4];    // rectSize indexes

    unsigned short int frameRate;
    unsigned short int frameCount;
};
#pragma pack()


//------------------------------------------------------------------------------

//Saving debug information to a log file
void dprintf(const char *fmt, ...) 
{
    va_list parms;
    char buf[256];

    // Try to print in the allocated space.
    va_start(parms, fmt);
    vsprintf (buf, fmt, parms);
    va_end(parms);

    // Write the information out to a txt file
    FILE *fp = fopen("output.txt", "a+");
    fprintf(fp, "%s", buf);
    fclose(fp);
}// End dprintf(..)

//------------------------------------------------------------------------------

void ReadDataChunks(char * data, int lenData);

//------------------------------------------------------------------------------

void main()
{
    FILE * fp = fopen("dialog.swf", "rb");

    stSWFHeader head;

    dprintf("---\n");

    fread (    &head.sig,                    // void * buffer,
            3 * sizeof(char),            // size
            1,                            // count,
            fp );                        // FILE * stream

    fread (    &head.version,                // void * buffer,
            sizeof(head.version),        // size
            1,                            // count,
            fp );                        // FILE * stream

    fread (    &head.uncompSize,            // void * buffer,
            sizeof(head.uncompSize),    // size
            1,                            // count,
            fp );                        // FILE * stream

    dprintf("sig: %c %c %c\n",    head.sig[0], head.sig[1], head.sig[2]);
    dprintf("version: %d\n",    head.version);
    dprintf("uncom size: %d\n", head.uncompSize);


    // If its compressed!

    // First we do the function declaration, of what the decompressoin function
    // looks like in the dll
    int (*uncompress) ( char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen);

    // Load the dll, which is with our exe
    HMODULE dll = LoadLibrary("zlib1.dll");

    // Setup the function, so it uses the one from the dll
    uncompress = (int (*) (char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen))GetProcAddress(dll, "uncompress");


    // Just some temp large value for our buffer
    int outSize = 500000;
    char * tmpIn  = new char [20000];
    char * tmpOut = new char [outSize];


    memset(tmpIn,  0, 4000);
    memset(tmpOut, 0, outSize);

    // Read in the whole file
    int done = 1;
    int size = 0;
    while (done)
    {
        done = (int)fread(tmpIn + size, 1, 1, fp);
        if (done)
        {
            size += 1;
        }
    }
    
    // Call uncompress on our data
    unsigned int tmpOutLen = outSize;
    int error = uncompress(tmpOut, &tmpOutLen, tmpIn, size);


    delete[] tmpIn;
    tmpIn = NULL;


    char * uncompData = tmpOut;
    //-----------------------------

    // NOW, take our uncompressed data, and start parsing it, read in
    // the tags


    dprintf("---\n");
    unsigned char rectFirstByte = *uncompData;
    uncompData++;
    
    int nbits = rectFirstByte >> 3;
    head.rectBits = nbits;

    dprintf("Rect No: nbits: %d\n", nbits);

    int buf = 0;
    int numBits = 3;
    int data = rectFirstByte & 0x7;

    int i=0;
    while (i<4)
    {
        buf = 0;
        for (int j=0; j<nbits; j++)
        {
            if (data & 0x80)
            {
                buf = buf | 1;        // We have a 1 at this bit
            }
            buf = buf << 1;            // Defaults to 0, so we have 0 at this bit
            data = data<<1;

            numBits--;
            if (numBits==0)
            {
                data = *uncompData;
                uncompData++;
                numBits=8;

                tmpOutLen--;        // Total bytes left in our data
            }
        }
        buf = buf>>1;                // Took me a while to track this down, but we need
                                    // to go back one as we have found our value
        dprintf("\buf: %d\n", buf);                                                                            

        head.rectSizes[i] = buf;

        i++;
    }

    unsigned short int *tmpInt = (unsigned short int*)&uncompData[0];
    head.frameRate = *tmpInt;
    uncompData+=2;
    tmpOutLen-=2;

    tmpInt = (unsigned short int*)&uncompData[0];
    head.frameCount = *tmpInt;
    uncompData+=2;
    tmpOutLen-=2;

    dprintf("Head FrameRate: %d\n", head.frameRate);
    dprintf("Head FrameCount: %d\n", head.frameCount);

    //-----------------------------

    ReadDataChunks(&uncompData[0], tmpOutLen);

    //-----------------------------
    

    delete[] tmpOut;
    tmpOut = NULL;

    fclose(fp);


    dprintf("done\n");

}


//------------------------------------------------------------------------------

#pragma pack(1)
struct stSmallTag
{
    unsigned short Tag    : 10;    // UB[10] Tag id 
    unsigned short Length : 6;    // UB[6] Length of tag 
};
#pragma pack()

#pragma pack(1)
struct stLargeTag
{
    unsigned short int Tag        : 10;    // UB[10] Tag id 
    unsigned short int LengthID    : 6;    // Long Header Flag UB[6] Always 0x3F  
    int                   Length;            // UI32 Length of tag 
};
#pragma pack()

//------------------------------------------------------------------------------


void ReadDataChunks(char * data, int lenData)
{
    char * tmpData = data;
    int    tmpLen  = lenData;


    dprintf("stSmallTag : size: %d\n",   sizeof(stSmallTag));
    dprintf("stLargeTag : size: %d\n\n", sizeof(stLargeTag));

    //stSmallTag * tmpSmall;
    //stLargeTag * tmpLarge;

    while (tmpLen > 0)
    {
        unsigned short int tmpx = tmpData[1] | (tmpData[0]<<8);
        unsigned short int *tmp0 = (unsigned short int*)&tmpData[0];
        tmpData+=2;
        tmpLen-=2;

        int Tag = (*tmp0 >> 6);
        int Length = (*tmp0 & 0x3F);

        //tmpSmall = (stSmallTag*)tmp0;
        //tmpLarge = (stLargeTag*)tmp0;

        if (Length != 0x3F)
        {
            // Small Tag Data
            dprintf("Tag (Small) ID: 0x%X\n", Tag);
            dprintf("\tLength: 0x%X\n", Length);

            tmpData+=Length;
            tmpLen-=Length;
        }
        else
        {
            // Large Tag Data
            dprintf("Tag (Large) ID: 0x%X\n", Tag);

            Length =  *((unsigned int*)&tmpData[0]);
            tmpData+=4;
            tmpLen-=4;


            dprintf("\tLength: 0x%X\n", Length);

            tmpData+=Length;
            tmpLen-=Length;

        }
    }

    dprintf("\nEnd Reading Tags\n");
}



/*
---
sig: C W S
version: 6
uncom size: 62352
---
Rect No: nbits: 15
buf: 0
buf: 12800
buf: 0
buf: 9600
Head FrameRate: 15360
Head FrameCount: 722
stSmallTag : size: 2
stLargeTag : size: 6

Tag (Small) ID: 0x9
    Length: 0x3
Tag (Large) ID: 0x2B
    Length: 0xB
Tag (Large) ID: 0x15
    Length: 0x2D2
Tag (Large) ID: 0x2
    Length: 0x24
Tag (Large) ID: 0x27
    Length: 0x10
Tag (Large) ID: 0x27
    Length: 0x22
Tag (Small) ID: 0x1A
    Length: 0x13
Tag (Large) ID: 0x23
    Length: 0x60E
Tag (Large) ID: 0x2
    Length: 0x25
Tag (Large) ID: 0x27

... more of the same


End Reading Tags
done
*/

 

You'll find if you run the demo code, it will generate a large 120kb txt file, which you can look at, and gives you all the chunk id's....these id's are just numbers for now, but its good to see that you can actually just cycle through the whole contents of the file, and pick out bits of data that we want ...compressed and uncompressed.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 
 Visitor: 9534626  { 209.237.238.175 } Copyright (c) 2002-2017 xbdev.net - All rights reserved.
Designated tutorial and software are the property of their respective owners.