////////////////////////////////////////////////////////////////////////////////////////
// //
// File: main.cpp //
// Date: 13-11-07 (winter) //
// Author: bkenwright@xbdev.net //
// URL: www.xbdev.net //
// //
////////////////////////////////////////////////////////////////////////////////////////
/*
Introduction to the flash swf file format - dumping tag information
Jpg Data
Just for testing, this code creates a simple window and uses the directx api so we
can try and covert the jpg image data to a texture, also we dump out the jpg
encoding and image data to a jpg file
*/
////////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h> // sprintf(..), fopen(..)
#include <stdarg.h> // So we can use ... (in dprintf)
#include "loadjpg.h" // DecodeJpgFileData(...)
////////////////////////////////////////////////////////////////////////////////////////
// //
// Debug printf that writes to a txt file :) //
// //
////////////////////////////////////////////////////////////////////////////////////////
//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(..)
////////////////////////////////////////////////////////////////////////////////////////
// //
// Various Flash SWF Container Structure Defines //
// //
////////////////////////////////////////////////////////////////////////////////////////
#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()
////////////////////////////////////////////////////////////////////////////////////////
struct stTagType
{
int m_id;
char m_name[32];
};
stTagType Tags [] =
{
{ 0, "END" },
{ 1, "SHOWFRAME" },
{ 2, "DEFINESHAPE" },
{ 3, "FREECHARACTER" },
{ 4, "PLACEOBJECT" },
{ 5, "REMOVEOBJECT" },
{ 6, "DEFINEBITS" },
{ 7, "DEFINEBUTTON" },
{ 8, "JPEGTABLES" },
{ 9, "SETBACKGROUNDCOLOR" },
{ 10, "DEFINEFONT" },
{ 11, "DEFINETEXT" },
{ 12, "DOACTION" },
{ 13, "DEFINEFONTINFO" },
{ 14, "DEFINESOUND" },
{ 15, "STARTSOUND" },
{ 17, "DEFINEBUTTONSOUND" },
{ 18, "SOUNDSTREAMHEAD" },
{ 19, "SOUNDSTREAMBLOCK" },
{ 20, "DEFINELOSSLESS" },
{ 21, "DEFINEBITSJPEG2" },
{ 22, "DEFINESHAPE2" },
{ 23, "DEFINEBUTTONCXFORM" },
{ 24, "PROTECT" },
{ 25, "PATHSAREPOSTSCRIPT" },
{ 26, "PLACEOBJECT2" },
{ 28, "REMOVEOBJECT2" },
{ 29, "SYNCFRAME" },
{ 31, "FREEALL" },
{ 32, "DEFINESHAPE3" },
{ 33, "DEFINETEXT2" },
{ 34, "DEFINEBUTTON2" },
{ 35, "DEFINEBITSJPEG3" },
{ 36, "DEFINELOSSLESS2" },
{ 37, "DEFINEEDITTEXT" },
{ 38, "DEFINEVIDEO" },
{ 39, "DEFINESPRITE" },
{ 40, "NAMECHARACTER" },
{ 41, "SERIALNUMBER" },
{ 42, "DEFINETEXTFORMAT" },
{ 43, "FRAMELABEL" },
{ 45, "SOUNDSTREAMHEAD2" },
{ 46, "DEFINEMORPHSHAPE" },
{ 47, "FRAMETAG" },
{ 48, "DEFINEFONT2" },
{ 49, "GENCOMMAND" },
{ 50, "DEFINECOMMANDOBJ" },
{ 51, "CHARACTERSET" },
{ 52, "FONTREF" },
{ 56, "EXPORTASSETS" },
{ 57, "IMPORTASSETS" },
{ 58, "ENABLEDEBUGGER" },
{ 59, "INITACTION" },
{ 60, "DEFINEVIDEOSTREAM" },
{ 61, "VIDEOFRAME" },
{ 62, "DEFINEFONTINFO2" },
{ 1023,"DEFINEBITSPTR" },
};
struct stSmallTag
{
unsigned short Tag : 10; // UB[10] Tag id
unsigned short Length : 6; // UB[6] Length of tag
};
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
};
////////////////////////////////////////////////////////////////////////////////////////
void DebugRawDataFile(char* filename, char * data, int size)
{
FILE *fp = fopen(filename, "wb+");
fwrite(data, size, 1, fp);
fclose(fp);
}
////////////////////////////////////////////////////////////////////////////////////////
int ReadDefineBitsJPEG2(char * uncompData, int tagLen)
{
int characterID = *((unsigned short*)&uncompData[0]);
uncompData += 2;
tagLen -= 2;
dprintf("\tstDefineBitsJPEG2 : CharacterID: %d\n", characterID);
static int count = 0;
count++;
char buf[32];
sprintf(buf, "imageJPEG2_%d.jpg", count);
// ??? Not sure what this is about! Should start with the SOI jpg tag, but
// instead seems to start with 4 misc bytes...looks like EOI and SOI tags,
// back to front! But why would that be?
uncompData+=4;
tagLen -= 4;
dprintf("Dumping To File %s\n", buf);
DebugRawDataFile(buf, &uncompData[0], tagLen);
// Decompressing the jpg image data and write it to a bmp
const unsigned char* jpgRawData = (const unsigned char*)&uncompData[0];
unsigned char* rgbpix = NULL;
unsigned int width = 0;
unsigned int height = 0;
DecodeJpgFileData(jpgRawData, tagLen, &rgbpix, &width, &height);
// Dumping it to a bmp file
sprintf(buf, "imageJPEG2_to_BMP%d.bmp", count);
WriteBMP24(buf, width, height, rgbpix);
delete[] rgbpix;
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////
//--------------------------------------------------------------------------------------
int ReadDefineBitsJPEG3(char * uncompData, int tagLen)
{
int characterID = *((unsigned short*)&uncompData[0]);
uncompData += 2;
tagLen -= 2;
// Offset to the alpha component as well :)
int sizeJpgData = *((unsigned int*)&uncompData[0]);
uncompData += 4;
tagLen -= 4;
dprintf("\tstDefineBitsJPEG3 : CharacterID: %d\n", characterID);
static int count = 0;
count++;
char buf[32];
sprintf(buf, "imageJPEG3_%d.jpg", count);
dprintf("Dumping To File %s\n", buf);
DebugRawDataFile(buf, &uncompData[0], sizeJpgData);
// Decompressing the jpg image data and write it to a bmp
const unsigned char* jpgRawData = (const unsigned char*)&uncompData[0];
unsigned char* rgbpix = NULL;
unsigned int width = 0;
unsigned int height = 0;
DecodeJpgFileData(jpgRawData, sizeJpgData, &rgbpix, &width, &height);
// Dumping it to a bmp file
sprintf(buf, "imageJPEG3_to_BMP%d.bmp", count);
WriteBMP24(buf, width, height, rgbpix);
delete[] rgbpix;
// Lets do the alpha part on the end....
// Increment past the jpg data to the alpha part
int alphaSize = sizeJpgData;
char* alphaData = uncompData + sizeJpgData;
// -- Alpha part of grabbing the data ----
// The jpg3 alpha component is zlib compressed, so we have to use the zlib
// decompression algorithm again
int (*uncompress) (char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen);
HMODULE dll = LoadLibrary("zlib1.dll");
uncompress = (int (*) (char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen))GetProcAddress(dll, "uncompress");
// Just allocate a big junk of memory, read it all in, and uncompress it!
int outSize = 500000;
// This is where our uncompressed data will go
char * tmpOut = new char [outSize];
memset(tmpOut, 0, outSize);
// We have to set tmpOutLen to a val, as it modifies it to the actual size of
// the decompressed data
unsigned int tmpOutLen = outSize;
// go go go...do the uncompression
int error = uncompress(tmpOut, &tmpOutLen, alphaData, alphaSize);
/*
// Just for info, the zlib error codes
#define Z_OK 0
#define Z_STREAM_END 1
#define Z_NEED_DICT 2
#define Z_ERRNO (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR (-3)
#define Z_MEM_ERROR (-4)
#define Z_BUF_ERROR (-5)
#define Z_VERSION_ERROR (-6)
*/
if (error!=0)
{
dprintf("Error decompressing JPEG3 Alpha - zlib error: %d", error);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////
void ReadDataTag(int tagID, int tagLength, char * data)
{
char * tagName = "**Unknown** - Wierd";
for (int i=0; i<sizeof(Tags)/sizeof(stTagType); i++)
{
if (tagID == Tags[i].m_id)
{
tagName = Tags[i].m_name;
break;
}
}
dprintf("\tTag: %.2d", tagID);
dprintf(", Name: %21s", tagName);
dprintf(", Length: %4d", tagLength);
// Lets dump the first 2 raw data bytes for curiosity as well
dprintf(", Raw-Data:0x%.2X, 0x%.2X\n", data[0], data[1]);
// Parse any tags that we want
switch (tagID)
{
case 21: // DEFINEBITSJPEG2
{
ReadDefineBitsJPEG2(&data[0], tagLength);
}
break;
case 35: // DEFINEBITSJPEG3
{
ReadDefineBitsJPEG3(&data[0], tagLength);
}
break;
}
}// End ReadDataTag(..)
//--------------------------------------------------------------------------------------
void ReadDataChunks(char * data, int lenData)
{
char * tmpData = data;
int tmpLen = lenData;
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);
if (Length != 0x3F) // Small Tag Data
{
ReadDataTag(Tag, Length, tmpData);
tmpData+=Length;
tmpLen-=Length;
}
else //------------ // Large Tag Data
{
Length = *((unsigned int*)&tmpData[0]);
tmpData+=4;
tmpLen-=4;
ReadDataTag(Tag, Length, tmpData);
tmpData+=Length;
tmpLen-=Length;
}
}
dprintf("\nEnd Reading Tags\n");
}// End ReadDataChunks(..)
////////////////////////////////////////////////////////////////////////////////////////
// //
// Program Entry Point //
// //
////////////////////////////////////////////////////////////////////////////////////////
void main()
{
// For testing, we'll just read in a test flash swf file called dialog.swf
FILE * fp = fopen("dialog.swf", "rb");
// Basic error checking
if (fp==NULL)
{
dprintf("** Error - unable to open swf file, ejecting..exiting..goodbye\n");
}
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);
// Just for this simple example we'll just allocate a big chunk of memory
// to read in all our data
int outSize = 500000;
char * tmpIn = new char [20000];
char * tmpOut = new char [outSize];
memset(tmpIn, 0, 4000);
memset(tmpOut, 0, outSize);
// Okay read in all the file data into our temp buffer!
int done = 1;
int size = 0;
while (done)
{
done = (int)fread(tmpIn + size, 1, 1, fp);
if (done)
{
size += 1;
}
}
// Finished with the file now :)
fclose(fp);
// Now at this point we have all our data from the file in memory, so we
// have to determine if to just use as is, or uncompress it first, when
// we've made this decidion, we will set them to variables
char * uncompData = NULL; // Pointer to our swf data
int uncompDataSize = 0; // How many bytes or data is
// Do we have a compressed swf?
if (head.sig[0]=='C' &&
head.sig[1]=='W' &&
head.sig[2]=='S')
{
int (*uncompress) (char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen);
HMODULE dll = LoadLibrary("zlib1.dll");
uncompress = (int (*) (char *dest, unsigned int *destLen, const char *source, unsigned int sourceLen))GetProcAddress(dll, "uncompress");
unsigned int tmpOutLen = outSize;
int error = uncompress(tmpOut, &tmpOutLen, tmpIn, size);
uncompDataSize = tmpOutLen;
delete[] tmpIn;
tmpIn = NULL;
// Lets point to our uncompressed data
uncompData = tmpOut;
}
// Not compressed
else if (head.sig[0]=='F' &&
head.sig[1]=='W' &&
head.sig[2]=='S')
{
delete[] tmpOut;
tmpOut = NULL;
uncompData = tmpIn;
uncompDataSize = size;
}
// Its a mutant unknown file!...bale out
else
{
dprintf("*** Error, unknown file format! Ejecting, exiting..goodbye\n");
return;
}
// We made it!...we made it!...we actually have the data now, so we progress
// by now reading in the rest of the swf file format header...I think this is
// bad to mix the compression with part of the header..maybe divided the header
// into two parts...oh well...just the way it is.
// Seems messy, but the swf rect is bit packed, so we do all this messy bit
// fiddly stuff to get the data
// Header Rect
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;
uncompDataSize--; // 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("\tbuf: %d\n", buf);
head.rectSizes[i] = buf;
i++;
}
// Header FrameRate
unsigned short int *tmpInt = (unsigned short int*)&uncompData[0];
head.frameRate = *tmpInt;
uncompData+=2;
uncompDataSize-=2;
// Header FrameCount
tmpInt = (unsigned short int*)&uncompData[0];
head.frameCount = *tmpInt;
uncompData+=2;
uncompDataSize-=2;
dprintf("Head FrameRate: %d\n", head.frameRate);
dprintf("Head FrameCount: %d\n", head.frameCount);
////////////////////////////////////////////////////////////////////////////////////
// ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags //
// ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags //
// ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags ** Dump Tags //
////////////////////////////////////////////////////////////////////////////////////
// We are now at the start of the list of tags, so we go into this function, which
// basically iterates through all the tags and dumps its name and size, one by
// one to the debug text file..
ReadDataChunks(&uncompData[0], uncompDataSize);
////////////////////////////////////////////////////////////////////////////////////
// Well your mum always told you to tidy up before you leave!...
if (tmpOut)
{
delete[] tmpOut;
tmpOut = NULL;
}
if (tmpIn)
{
delete[] tmpIn;
tmpIn = NULL;
}
dprintf("Done Parsing SWF File...thank you, goodbye :)\n");
}// End main(..)
/* output.txt
---
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
Tag: 09, Name: SETBACKGROUNDCOLOR, Length: 3, Raw-Data:0xFFFFFFFF, 0x0A
Tag: 43, Name: FRAMELABEL, Length: 11, Raw-Data:0x7F, 0x05
Tag: 21, Name: DEFINEBITSJPEG2, Length: 722, Raw-Data:0xFFFFFFBF, 0x00
Tag: 02, Name: DEFINESHAPE, Length: 36, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 16, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 34, Raw-Data:0xFFFFFF93, 0x06
Tag: 26, Name: PLACEOBJECT2, Length: 19, Raw-Data:0xFFFFFFFF, 0x08
Tag: 35, Name: DEFINEBITSJPEG3, Length: 1550, Raw-Data:0xFFFFFFBF, 0x00
Tag: 02, Name: DEFINESHAPE, Length: 37, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 16, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 35, Raw-Data:0xFFFFFF93, 0x06
Tag: 26, Name: PLACEOBJECT2, Length: 19, Raw-Data:0xFFFFFFFF, 0x08
Tag: 35, Name: DEFINEBITSJPEG3, Length: 755, Raw-Data:0xFFFFFFBF, 0x00
Tag: 02, Name: DEFINESHAPE, Length: 33, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 16, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 35, Raw-Data:0xFFFFFF93, 0x06
Tag: 26, Name: PLACEOBJECT2, Length: 19, Raw-Data:0xFFFFFFFF, 0x08
Tag: 35, Name: DEFINEBITSJPEG3, Length: 1506, Raw-Data:0xFFFFFFBF, 0x00
Tag: 02, Name: DEFINESHAPE, Length: 34, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 16, Raw-Data:0xFFFFFFFF, 0x09
Tag: 39, Name: DEFINESPRITE, Length: 34, Raw-Data:0xFFFFFF93, 0x06
Tag: 26, Name: PLACEOBJECT2, Length: 19, Raw-Data:0x7F, 0x05
Tag: 21, Name: DEFINEBITSJPEG2, Length: 698, Raw-Data:0xFFFFFFBF, 0x00
Tag: 02, Name: DEFINESHAPE, Length: 33, Raw-Data:0xFFFFFFFF, 0x09
.. other same things...
Tag: 01, Name: SHOWFRAME, Length: 0, Raw-Data:0x00, 0x00
Tag: 00, Name: END, Length: 0, Raw-Data:0x00, 0x00
Tag: 00, Name: END, Length: 0, Raw-Data:0x00, 0x00
End Reading Tags
Done Parsing SWF File...thank you, goodbye :)
*/
|