| Flash (.swf) File Format - (Basics)by bkenwright@xbdev.net 
 
   There's a lot of cool things you'll come to love and hate about the flash swf 
format....I mean its data is stored using chunks or tokens...so as you read in 
each token descriptor, if you don't know what it is, or havn't wrote that bit of 
code yet, you can just skip over it :)  So as you continue to add 
additional functionality to your parser, well you can continue to add in the 
parts that you need :)   But it does have a few downsides as well, it has a lot of different token 
types...and I mean a lot...each new version they seem to add a dozen more 
types...and some of the tokens are recursive!...so some tokens store more tokens 
within themselves!....criky!...it can soon get whacky complicated!   But hey!..don't worry...I'll hold your hand through it....once you get past 
most of the quirks, you'll be okay...I mean I found it okay, but its can soon 
get very time consuming....might need to put the kettle on and make a strong 
black coffee :D   
  
    | To start the exploration of the swf file format, where going 
    to use a very simple swf file called simple.swf...and you can see a 
    screenshot of it on the right.  Its not compressed, and it only has a 
    single frame, so it doesn't animate...I suppose we could make it even more 
    simple...but I suppose this will do for now. |  |    The demo code is compiled using visual studio 2k5, and I tend to use sprintf(..) 
and other standard c/c++ librarys, because I'm writing a lot of the information 
to a debug output file, and adding lots of debug information, so you have to add 
in '_CRT_SECURE_NO_DEPRECATE' to the project define....as Microsoft doesn't like 
us using them anymore!   What we'll do first!....is read in the first 4 bytes!  Yup, nothing to 
extreme, we'll read them in, and write them out to a text file...and what you'll 
find is that the first 3 bytes will tell us what where dealing with.  I 
just read the 4th one in to show that its not a null terminated string ;)   
  
    | Source - Download Source Code |  
    | ////////////////////////////////////////////////////////////////////////////////////////
//                                                                                    //
// File:   main.cpp                                                                   //
// Date:   20-12-06 (xmas)                                                            //
// Author: bkenwright@xbdev.net                                                       //
// URL:    www.xbdev.net                                                              //
//                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////
/*
   Introduction to the flash swf file format
*/
////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>	// sprintf(..), fopen(..)
#include <stdarg.h>     // So we can use ... (in dprintf)
////////////////////////////////////////////////////////////////////////////////////////
//                                                                                    //
//  dprintf(..)                                                                       //
//  Debug function, so we can write various output information to a log file as we    //
//  read in new information - I usually prefair to write it to a txt file, so I can   //
//  later open it in notepad or something and take a careful look at it, instead      //
//  of dumping it to the command window.                                              //
//                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////
//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(..)
////////////////////////////////////////////////////////////////////////////////////////
//                                                                                    //
//  main(..)                                                                          //
//  Program entry point - its where we start and end                                  //
//                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////
void main()
{
	dprintf("Opening File: simple.swf\n");
	FILE * fp = fopen("simple.swf", "rb");
	char buf[4];
	fread (	buf,			// void * buffer,
		3 * sizeof(char),	// size
		1,			// count,
		fp );			// FILE * stream
	dprintf("Sig: '%c' '%c' '%c' '%c'\n",	buf[0], buf[1], buf[2], buf[3]);
	fclose(fp);
	dprintf("Closing File.\n Done\n");
}// End main(..)
/*
Opening File: simple.swf
Sig: 'F' 'W' 'S' '̧
Closing File.
Done
*/
 |    Not to bad eh?  Most of the code is just setup code, and things...so as 
long as your familiar with standard c/c++ its not to bad.  So what you'll 
see from the output file is we have 'FWS' which means where dealing with a bog 
standard uncompressed .swf file.  If we'd have 'CWS' then it would be a 
compressed flash .swf file, and we'd have to uncompress it using zlib, which 
we'll go over later :)   So lets take a look at what the header file format looks like:   
  
    | Field | Type | Comment |  
    | Signature | UI8[3] | Signature byte 'F' 'W' 'S' or 'C' 'W' 'S' for compressed 
    with zlib |  
    | Version | UI8 | Single byte file version |  
    | File Length | UI32 | Length of entire file in bytes |  
    | Frame Size | RECT RECT format is:  UI5   - nBits, nBits - xMin nBits - xMax nBits - yMin nBits - yMax | Frame size in TWIPS |  
    | Frame Rate | UI16 | Frame delay in 8.8 fixed number of frames per second |  
    | Frame Count | UI16 | Total number of frames in movie |    Now the first thing that just shouted out at me when I first seen that header 
format was ' RECT'!  You just want to go, "Whats that all about"...well as 
I mentioned earlier, lots of the information in this file format is bitwise 
packed...so a lot of times you have to read in a few bits, to determine how many 
bits to read in next!...be clear I'm saying bits, not bytes!.   Seems clear though, we have a Signature, Version, FileLength, all seems nice 
and clear to me, so I think we can create a nice tidy header structure and read 
in all our header data :)   What your about to see might look like a lot!  And if your shaky on bit 
shifting, and all that boolean logic of ANDing and ORing data, well your in for 
fun now :)  As all where doing below is reading in the header file and 
storing it in a structure.  The biggest chunk is because of the RECT bounds 
part....which is messy I think...I did it all in the main so you could see how 
you do it....later on I create a ReadRect(..) function where you can just pass 
the start pointer to the data, and it returns how many bytes to increment along 
by to the next data you want.   
  
    | Source - Download Source Code |  
    | ////////////////////////////////////////////////////////////////////////////////////////
//                                                                                    //
// File:   main.cpp                                                                   //
// Date:   20-12-06 (xmas)                                                            //
// Author: bkenwright@xbdev.net                                                       //
// URL:    www.xbdev.net                                                              //
//                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////
/*
   Introduction to the flash swf file format
*/
////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>	// sprintf(..), fopen(..)
#include <stdarg.h>     // So we can use ... (in dprintf)
////////////////////////////////////////////////////////////////////////////////////////
//                                                                                    //
//  SWF Header Container Structures                                                   //
//                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////
struct stRect
{
	int m_Nbits;		// nBits = UB[5] Bits in each rect value field 
	int m_Xmin;		// SB[nBits] X minimum position for rect 
	int m_Xmax;		// SB[nBits] X maximum position for rect 
	int m_Ymin;		// SB[nBits] Y minimum position for rect 
	int m_Ymax;		// SB[nBits] Y maximum position for rect 
};
struct stSWFHeader
{
	char		m_Sig[3];	// UI8[3] Signature byte 1 - 'FWS' or 'CWS'
	unsigned int	m_Version;	// UI8 Single byte file version 
	unsigned int	m_FileLength;	// UI32 Length of entire file in bytes 
	stRect		m_FrameSize;	// RECT Frame size in TWIPS 
	unsigned short  m_FrameRate;	// UI16 Frame delay in 8.8 fixed number of fps
	unsigned short  m_FrameCount;	// UI16 Total number of frames in movie 
};
//Saving debug information to a log file
void dprintf(const char *fmt, ...) 
{
	.... (as above)
}// End dprintf(..)
////////////////////////////////////////////////////////////////////////////////////////
//                                                                                    //
//  main(..)                                                                          //
//  Program entry point - its where we start and end                                  //
//                                                                                    //
////////////////////////////////////////////////////////////////////////////////////////
void main()
{
	dprintf("Reading in simple.swf\n");
	// Open the file, and read in all its contents int a large buffer
	FILE * fp = fopen("simple.swf", "rb");
	// Large temporary buffer which we'll use to read in the file to
	char fileData[20000];
	int size = 0;
	while (true)
	{
		int done = (int)fread(fileData + size, 1, 1, fp);
		if (done)
		{
			size += 1;
		}
		else
		{
			break;
		}
	}// End while(..)
	// Close file
	fclose(fp);
	// Pointer to the start of the file data, which we can increment as 
	// we go along and determine what each byte is for
	char* data = fileData;
	// At this point, we have read in the whole file, and its stored
	// in our temporary buffer.
	dprintf("Sig: '%c' '%c' '%c' \n",	data[0], data[1], data[2]);
	// Create a temp instance of our header structure, and read data 
	// into it
	stSWFHeader head;
	head.m_Sig[0] = data[0];
	head.m_Sig[1] = data[1];
	head.m_Sig[2] = data[2];
	// Increment data offset by 3 bytes
	data += 3;
	head.m_Version = data[0];
	dprintf("Version: %d\n", head.m_Version);
	// Increment data offset by 1 byte
	data += 1;
	
	head.m_FileLength = ((unsigned int*)data)[0];
	dprintf("FileLength: %d\n", head.m_FileLength);
	// Increment data offset by 4 bytes (unsigned int is 4 bytes)
	data += 4;
	// Get a pointer to the rect from the header, easier to reference then
	stRect* rect = &head.m_FrameSize;
	// Need to get the first 5 bits!
	int nBits = data[0] >> 3;
	rect->m_Nbits = nBits;
	dprintf("Rect: nBits: %d\n", rect->m_Nbits);
	// Now this is where it gets tricky, as we have some of our data
	// in this byte, and some in the next bytes..so we have
	// to do lots of bit manipulation
	// Temp variable which we will use to store the value in as we
	// get each bit, as we go from byte to byte
	int buf = 0;
	// Current number of bits left in the byte where working with, as
	// remember the first 5 bytes where use to hold the number of bits
	// for the other size
	int numBits = 3;
	// Byte data, which we change as we go from byte to byte
	unsigned char byte = data[0] & 0x7;
	// Read 4 rect values into here, i.e. xMin, xMax etc
	int val[4];
	// Loop around the 4 values
	for (int i=0; i<4; i++)
	{
		buf = 0;
		for (int j=0; j<nBits; j++) // Go bit by bit along the byte
		{
			if (byte & 0x80)		
			{
				buf = buf | 1;	// We have a 1 at this bit
			}
			buf = buf << 1;		// Defaults to 0, so we have 0 at this bit
			byte = byte<<1;
			numBits--;
			if (numBits==0)		// Reached the last bit, we get the next byte
			{			// along
				data++;
				byte = data[0];
				numBits=8;	// Just got a new byte, so we now have 8
						// bits to work with
			}
		}
		buf = buf>>1;			// Took me a while to track this down, but we need
						// to go back one as we have found our value
		val[i] = buf;
	}
	// Just to note, we always start on a fresh aligned byte after readin
	// in a rect!  So there could be padding/unused bits on the end :)
	if (numBits>0)
	{
		data++;
	}
	// Store the values and write them out to our debug log
	rect->m_Xmin = val[0];
	rect->m_Xmax = val[1];
	rect->m_Ymin = val[2];
	rect->m_Ymax = val[3];
	dprintf("Rect Xmin: %d\n", rect->m_Xmin);
	dprintf("Rect Xmax: %d\n", rect->m_Xmax);
	dprintf("Rect Ymin: %d\n", rect->m_Ymin);
	dprintf("Rect Ymax: %d\n", rect->m_Ymax);
	head.m_FrameRate = ((unsigned short*)data)[0];
	dprintf("FrameRate: %d\n", head.m_FrameRate);
	data+=2;
	head.m_FrameCount = ((unsigned short*)data)[0];
	dprintf("FrameCount: %d\n", head.m_FrameCount);
	data+=2;
}// End main(..)
/*
Reading in simple.swf
Sig: 'F' 'W' 'S' 
Version: 3
FileLength: 151
Rect: nBits: 15
Rect Xmin: 0
Rect Xmax: 12000
Rect Ymin: 0
Rect Ymax: 8000
FrameRate: 3072
FrameCount: 1
*/
 |      Doesn't look like much?  Well its pretty good I think...as after the 
header, its just tags!  Well some people call them chunks...basically, you 
have 6 bytes which say what type and how long...and you just keep going like 
that...and any chunks we arn't interested in, we can just get its type, and skip 
over its contents :)                                                       |