www.pudn.com > FlashFormat.rar > FSWFStream.cpp
// Copyright © 1999 Middlesoft, Inc. All rights reserved.
// First Created By Lee Thomason.
// First Created On 09/08/1999.
// Last Modified On 11/09/1999.
/****************************************************************************************
File Summary: FSWFStream.cpp
This source file contains the definition for all low-level SWF-stream functions:
Class Member Function
FSWFStream FSWFStream();
void WriteBits(U32, U32);
void WriteLargeData(U8*, U32);
void FlushBits();
void WriteDWord(U32);
void WriteWord(U32);
void WriteByte(U32);
U32 Size();
void Append(FSWFStream *);
void WriteToFile( FILE*);
void AppendTag(U16, U32, FSWFStream*);
U32 MinBits(U32, U16);
U32 MaxNum(S32, S32, S32, S32);
****************************************************************************************/
#pragma warning( disable : 4786 )
#include "FObj.h"
#include "FSWFStream.h"
//////////////////////////////////////////////////////////////////////////////////////
// -------- FSWFStream ------------------------------------------------------------
// FSWFStream is the object used to store a string of bytes, an SWF file "in memory"
// before being written to the disk. It handles bit packing and endian issues.
// SWF uses bit packing a lot to reduce the size of the data going over the Net.
// The issue here of course is how to pack and unpack the bits correctly.
FSWFStream::FSWFStream()
{
streamPos = 0; //the position in the FSWFStream(how many bytes you have put in)
bytePos = 8; //the number of bits left to fill in the current byte
currentByte = 0; //the value of the current byte being created
#ifndef DEBUG
stream.reserve( 1024 ); // start out at 1k to make faster -
// if it is a debug build, don't reserve, as we wish to stress the system
#endif
stream.push_back( 0 );
}
// Adds 'size' bits from 'data' to the stream FSWFStream. Data is in the form of
// a U32. Size indicates how many of the 32 bits are significant and should
// be output. It checks how many bits are available in the current output byte
// and works by repeatedly stuffing it with the next bits from 'data'
// and then adding currentByte to the stream until all "size" bits have been output.
void FSWFStream::WriteBits(U32 data, U32 size) //adds individual bits
{
FLASHASSERT( ( data <= (0x01< bytePos )
{
//if more bits left to write than shift out what will fit
currentByte |= data << (32 - size) >> (32 - bytePos);
// shift all the way left, then right to right
// justify the data to be or'ed in
stream[streamPos] = currentByte;
streamPos++;
stream.push_back( 0 );
size -= bytePos;
currentByte = 0;
bytePos = 8;
}
else if ( size <= bytePos )
{
currentByte |= data << (32 - size) >> (32 - bytePos);
bytePos -= size;
size = 0;
if ( !bytePos )
{ //if current byte is filled
stream[streamPos] = currentByte;
streamPos++;
stream.push_back( 0 );
currentByte = 0;
bytePos = 8;
}
}
}
}
// For adding large data that is pointed to by a pointer. The data is only
// integrated into the stream when it is actually written to disk.
// E. G. a large JPEG. This is to avoid storing it twice.
// Stores the current streamPos, data pointer and size in the OutDataList.
void FSWFStream::WriteLargeData( const U8 *data, U32 size )
{
LargeData large;
large.position = streamPos;
large.data = data;
large.size = size;
outDataList.push_back( large );
}
// Kick out the current partially filled byte to the stream.
// If there is a byte currently being built for addition to the stream, then the end of that
// byte is filled with zeroes and the byte is added to the stream.
void FSWFStream::FlushBits()
{
if ( bytePos != 8 )
{
stream[streamPos] = currentByte;
streamPos++;
stream.push_back( 0 );
currentByte = 0;
bytePos = 8;
}
}
//
// Writes a 32 bit stream of data to given FSWFStream in the proper form (reversed byte order),
// so B1B2B3B4 is written as B4B3B2B1. The function does this by sending a byte at a time
// of the data to the FSWFStream in the appropriate order.
void FSWFStream::WriteDWord(U32 data){
//declare variable used to output the bytes
U32 v;
//output the rightmost byte
v = data << 24 >> 24;
WriteBits(v, 8);
//output the center right byte
v = data << 16 >> 24;
WriteBits(v, 8);
//output the center left byte
v = data << 8 >> 24;
WriteBits(v, 8);
//output the leftmost byte
v = data >> 24;
WriteBits(v, 8);
}
// Writes a 16 bit stream of data to the FSWFStream in the proper form, so B1B2 is written as
// B2B1.
void FSWFStream::WriteWord(U32 data ){
//declare the variable used to output the bytes
U32 v;
//output the rightmost byte
v = data << 24 >> 24;
WriteBits(v, 8);
//output the leftmost byte
v = data << 16 >> 24;
WriteBits(v, 8);
}
// Writes an 8 bit stream of data to the FSWFStream. There is no bit swapping!! A byte is
// written as a byte.
void FSWFStream::WriteByte(U32 data ){
//declare the variable used to output the byte
U32 v = 0;
//output the byte
v = data << 24 >> 24;
WriteBits(v, 8);
}
// Returns the size of the FSWFStream. For purposes of denoting size in tags and headers.
U32 FSWFStream::Size(void)
{
int size = streamPos;
std::list::iterator it;
for ( it = outDataList.begin(); it != outDataList.end(); it++ )
{
LargeData& data = (*it);
size += data.size;
}
return size;
}
// Appends the stream FSWFStream to this. Doesn't actually write the bitmaps,
// jpegs ... Instead it just writes their file name with a note that the actual file
// should go there.
void FSWFStream::Append(FSWFStream *add)
{
int addStreamPos = 0; // this functions position in the "add" stream,
// remembering that add->streamPos is the END
// of the "add" stream.
// remove all the large data from the other stream
while( add->outDataList.size() )
{
LargeData data = add->outDataList.front();
add->outDataList.pop_front();
for ( ;addStreamPos < data.position; addStreamPos++ )
{
WriteBits( add->stream[addStreamPos], 8 );
}
//addStreamPos should now equal data.position
WriteLargeData( data.data, data.size );
}
// Write the remainder of the stream data, after the last outData.
for ( ;addStreamPos < add->streamPos; addStreamPos++ )
{
WriteBits( add->stream[addStreamPos], 8);
}
}
// Writes the stream FSWFStream to the given file.
void FSWFStream::WriteToFile( FILE* swfFile )
{
U32 currentStreamPos = 0; //the current position in the FSWFStream for writing
const U8* currentData;
U32 currentDataSize;
U32 currentDataPosition;
U32 outDataListSize = outDataList.size();
int wrote = 0;
if ( outDataListSize )
{
for ( U32 i=0; i= currentStreamPos );
if ( currentDataPosition - currentStreamPos > 0 )
{
fwrite( &stream[currentStreamPos], 1, ( currentDataPosition - currentStreamPos ), swfFile );
}
wrote += currentDataPosition - currentStreamPos;
currentStreamPos = currentDataPosition;
//currentStreamPos should now equal currentDataPosition
FLASHASSERT( currentDataSize > 0 );
fwrite( currentData, 1, currentDataSize, swfFile );
wrote += currentDataSize;
}
}
if ( streamPos > currentStreamPos )
{
fwrite( &stream[currentStreamPos], 1, streamPos - currentStreamPos, swfFile );
}
wrote += streamPos - currentStreamPos;
}
void FSWFStream::WriteToMemory( U8* memory )
{
U32 currentStreamPos = 0; //the current position in the FSWFStream for writing
const U8* currentData;
U32 currentDataSize;
U32 currentDataPosition;
U32 outDataListSize = outDataList.size();
int wrote = 0;
if ( outDataListSize )
{
for ( U32 i=0; i= currentStreamPos );
if ( currentDataPosition - currentStreamPos > 0 )
{
memcpy( memory, &stream[currentStreamPos], ( currentDataPosition - currentStreamPos ) );
memory += currentDataPosition - currentStreamPos;
}
wrote += currentDataPosition - currentStreamPos;
currentStreamPos = currentDataPosition;
//currentStreamPos should now equal currentDataPosition
FLASHASSERT( currentDataSize > 0 );
memcpy( memory, currentData, currentDataSize );
memory += currentDataSize;
wrote += currentDataSize;
}
}
if ( streamPos > currentStreamPos )
{
// fwrite( &stream[currentStreamPos], 1, streamPos - currentStreamPos, swfFile );
memcpy( memory, &stream[currentStreamPos], streamPos - currentStreamPos );
memory += streamPos - currentStreamPos;
}
wrote += streamPos - currentStreamPos;
}
void FSWFStream::AppendTag(U16 tagID, U32 length, FSWFStream* buffer )
{
U32 longLength = 0;
bool longHead = false;
if (length>62) //If long type tag:
{
longHead = true;
longLength = length; //The actual length is here.
length = 0x3f; //This field's length becomes 63 to indicate a long tag.
}
else
{ //Else short type tag:
longHead = false; //It is not a long header, so the length is valid.
}
U16 firstPartOfTag = (tagID<<6) | length; // Build up the first 2 bytes of the tag:
// 10bits for tag ID
// 6bits for tag length
WriteWord( (U32)firstPartOfTag );
if (longHead)
{
WriteDWord(longLength);
}
if ( buffer ) // If there is not a buffer, don't write any more.
{
Append( buffer ); // Copy the buffer passed in to this object.
}
}
// Calculates the minimum number of bits necessary to represent the given number. The
// number should be given in its unsigned form with the flag sign equal to 1 if it is
// signed. Repeatedly compares number to another unsigned int called x.
// x is initialized to 1. The value of x is shifted left i times until x is greater
// than number. Now i is equal to the number of bits the UNSIGNED value of number needs.
// The signed value will need one more bit for the sign so i+1 is returned if the number
// is signed, and i is returned if the number is unsigned.
U32 FSWFStream::MinBits(U32 number, U16 sign)
{
//If the number == 0, then 0 bits are necessary for unsigned, and 1 for signed.
//Sign should either have a value of 0 or 1.
if ( number == 0 )
{
return sign;
}
//declare and initialize the variable for comparison
U32 x = 1;
U32 i;
//keep increasing the value of x and i until s is greater than the given number
for(i = 1; i<33; i++){
x <<= 1;
if (x > number){
break;
}
}
FLASHASSERT( sign + i <= 32 );
//return the calculated value and account for the number being signed or not
return i + sign;
}
// Compares the absolute values of 4 signed integers and returns the unsigned magnitude of
// the number with the greatest absolute value.
U32 FSWFStream::MaxNum(S32 a, S32 b, S32 c, S32 d){
//take the absolute values of the given numbers
int aAbs = abs(a);
int bAbs = abs(b);
int cAbs = abs(c);
int dAbs = abs(d);
//compare the numbers and return the unsigned value of the one with the greatest magnitude
if (aAbs>bAbs){
if (aAbs>cAbs){
if (aAbs>dAbs){
return (U32) aAbs;
} else {
return (U32) dAbs;
}
} else
if (cAbs>dAbs){
return (U32) cAbs;
} else {
return (U32) dAbs;
}
} else {
if (bAbs>cAbs){
if (bAbs>dAbs){
return (U32) bAbs;
} else {
return (U32) dAbs;
}
} else
if (cAbs>dAbs){
return (U32) cAbs;
} else {
return (U32) dAbs;
}
}
}