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.
|