Removed changes by Nicholas. These will need to be re-submitted through Trac and manually validated.

Added BMP (24-bit uncompressed, 8-bit uncompressed, and RLE8) and PNG support to File::ReadImageFile(). So far everything in FileHandler is presumed to be safe with any input file except UTK decompression.

Also started making use of the static keyword in various places to aid the compiler in optimization.
This commit is contained in:
Fatbag 2012-04-06 13:27:40 -05:00
parent 7442579090
commit cb751c0bb8
29 changed files with 692 additions and 1291 deletions

View file

@ -2,13 +2,8 @@ cmake_minimum_required(VERSION 2.6)
project(iff)
set(IFF_SOURCES
bhav.c
stbl.c
sprite.c
chunks.c
iff.c
)
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler/libpng)
add_executable(iffexport iffexport.c ${IFF_SOURCES})

View file

@ -1,53 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "iff.h"
int iff_parse_bhav(IFFChunk * ChunkInfo, const uint8_t * Buffer)
{
IFF_TREETABLE * TreeTableData;
if(ChunkInfo->Size < 12)
return 0;
ChunkInfo->FormattedData = malloc(17);
if(ChunkInfo->FormattedData == NULL)
return 0;
memset(ChunkInfo->FormattedData, 0, 17);
TreeTableData = (IFF_TREETABLE *)ChunkInfo->FormattedData;
memcpy (TreeTableData, Buffer, 2);
int nodeCount = 0;
if (TreeTableData->StreamVersion == 0x8003)
{
memcpy (((char *)TreeTableData)+2, Buffer+2, 7);
memcpy (&nodeCount, Buffer+9, 4);
}
else if ((TreeTableData->StreamVersion == 0x8000) || (TreeTableData->StreamVersion == 0x8001) || (TreeTableData->StreamVersion == 0x8002))
{
memcpy (&nodeCount, Buffer+2, 2);
memcpy (((char *)TreeTableData)+2, Buffer+4, 3);
memcpy (((char *)TreeTableData)+5, Buffer+8, 4);
switch (TreeTableData->StreamVersion)
{
case 0x8002:
break;
case 0x8001:
if (TreeTableData->NumParams > 4) { TreeTableData->NumParams = 4; }
if (TreeTableData->NumLocals > 4) { TreeTableData->NumLocals = 4; }
break;
case 0x8000:
TreeTableData->NumParams = 4;
TreeTableData->NumLocals = 0;
break;
default:
break;
}
}
printf("Node Count: %d", nodeCount);
TreeTableData->NodesBegin = (IFF_TREETABLENODE *)malloc(12 * nodeCount);
TreeTableData->NodesEnd = TreeTableData->NodesBegin + nodeCount;
memcpy(TreeTableData->NodesBegin, Buffer+((TreeTableData->StreamVersion == 0x8003) ? 13 : 12), 12 * nodeCount);
return 1;
}

View file

@ -1,29 +0,0 @@
/* BHAV chunk */
typedef struct TreeNodeParams
{
uint16_t Param0;
uint16_t Param1;
uint16_t Param2;
uint16_t Param3;
} IFF_TRETABLENODEPARAMS;
typedef struct TreeTableNode
{
uint16_t PrimitiveNumber;
uint8_t TransitionTrue;
uint8_t TransitionFalse;
IFF_TRETABLENODEPARAMS Parameters;
} IFF_TREETABLENODE;
typedef struct TreeTable
{
uint16_t StreamVersion;
uint8_t Type;
uint8_t NumParams;
uint8_t NumLocals;
uint32_t TreeVersion;
IFF_TREETABLENODE *NodesBegin;
IFF_TREETABLENODE *NodesEnd;
} IFF_TREETABLE;

View file

@ -19,19 +19,242 @@
#include <stdint.h>
#include "iff.h"
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile){
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer){
if( !strcmp(ChunkInfo->Type, "STR#") ||
!strcmp(ChunkInfo->Type, "CTSS") ||
!strcmp(ChunkInfo->Type, "FAMs") ||
!strcmp(ChunkInfo->Type, "TTAs") )
!strcmp(ChunkInfo->Type, "TTAs") )
return iff_parse_str(ChunkInfo, Buffer);
else if (!strcmp(ChunkInfo->Type, "BHAV"))
return iff_parse_bhav(ChunkInfo, Buffer);
else if (!strcmp(ChunkInfo->Type, "SPR#") || !strcmp(ChunkInfo->Type, "SPR2"))
return iff_parse_sprite(ChunkInfo, Buffer, SourceFile);
else if (!strcmp(ChunkInfo->Type, "PALT"))
return iff_parse_pmap(ChunkInfo, Buffer);
return 0;
}
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
/* No bounds checking yet */
IFF_STR * StringData;
unsigned Size = ChunkInfo->Size - 76;
if(Size < 2)
return 0;
ChunkInfo->FormattedData = malloc(sizeof(IFF_STR));
if(ChunkInfo->FormattedData == NULL)
return 0;
memset(ChunkInfo->FormattedData, 0, sizeof(IFF_STR));
StringData = (IFF_STR*) ChunkInfo->FormattedData;
StringData->Format = read_int16le(Buffer);
Buffer += 2;
if(Size-2 < 2) /* TSO allows this; as seen in the animations chunk in personglobals.iff */
return 1;
switch(StringData->Format){
case 0: {
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[0].PairCount == 0)
return 1;
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
/* Key */
length = read_uint8le(Buffer);
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
CurrentPair->Pair.Key[length] = 0x00;
}
Buffer += length+1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[0].LastPair = PrevPair;
} return 1;
case -1: {
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[0].PairCount == 0)
return 1;
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
/* Key */
length = strlen((char*)Buffer);
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
}
Buffer += length+1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[0].LastPair = PrevPair;
} return 1;
case -2: {
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[0].PairCount == 0)
return 1;
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
/* Key */
length = strlen((char*)Buffer);
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
}
Buffer += length+1;
/* Value */
length = strlen((char*)Buffer);
if(length != 0){
CurrentPair->Pair.Value = malloc(length+1);
strcpy(CurrentPair->Pair.Value, (char*)Buffer);
}
Buffer += length+1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[0].LastPair = PrevPair;
} return 1;
case -3: {
unsigned i, TotalPairCount;
TotalPairCount = read_uint16le(Buffer);
Buffer += 2;
if(TotalPairCount == 0)
return 1;
for(i=0; i<TotalPairCount; i++){
IFFStringPairNode * Pair;
unsigned length;
Pair = malloc(sizeof(IFFStringPairNode));
memset(Pair, 0, sizeof(IFFStringPairNode));
Pair->Pair.LanguageSet = read_uint8le(Buffer) - 1;
Buffer++;
/* Key */
length = strlen((char*)Buffer);
if(length != 0){
Pair->Pair.Key = malloc(length+1);
strcpy(Pair->Pair.Key, (char*)Buffer);
}
Buffer += length+1;
/* Value */
length = strlen((char*)Buffer);
if(length != 0){
Pair->Pair.Value = malloc(length+1);
strcpy(Pair->Pair.Value, (char*)Buffer);
}
Buffer += length+1;
/* Add the pair to the end of the associated language set */
Pair->PrevPair = StringData->LanguageSets[0].LastPair;
if(StringData->LanguageSets[0].PairCount == 0)
StringData->LanguageSets[0].FirstPair = Pair;
else
StringData->LanguageSets[0].LastPair->NextPair = Pair;
StringData->LanguageSets[0].PairCount++;
StringData->LanguageSets[0].LastPair = Pair;
}
} return 1;
case -4: {
unsigned LanguageSet;
unsigned LanguageSetCount = read_uint8le(Buffer);
Buffer++;
if(LanguageSetCount > 20) LanguageSetCount = 20;
for(LanguageSet=0; LanguageSet<LanguageSetCount; LanguageSet++){
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[LanguageSet].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[LanguageSet].PairCount == 0)
continue;
for(i=0; i<StringData->LanguageSets[LanguageSet].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[LanguageSet].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
Buffer++; /* Skip over LanguageSet */
/* Key */
length = read_uint8le(Buffer);
if(length > 127){
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
Buffer++;
}
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
CurrentPair->Pair.Key[length] = 0x00;
}
Buffer += length + 1;
/* Value */
length = read_uint8le(Buffer);
if(length > 127){
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
Buffer++;
}
if(length != 0){
CurrentPair->Pair.Value = malloc(length+1);
memcpy(CurrentPair->Pair.Value, Buffer+1, length);
CurrentPair->Pair.Value[length] = 0x00;
}
Buffer += length + 1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[LanguageSet].LastPair = PrevPair;
}
} return 1;
}
return 0;
}
int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize){

View file

@ -17,7 +17,6 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "iff.h"
#ifndef __inline
@ -37,11 +36,10 @@ IFFFile * iff_create()
return ptr;
}
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize, char *FileName)
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize)
{
unsigned offset;
if(!FileSize) FileSize = ~0;
else if(FileSize < 64)
return 0;
@ -49,8 +47,6 @@ int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned File
if(memcmp(Buffer, Header_IFF, 60))
return 0;
memcpy(IFFFileInfo->Header, Buffer, 60);
IFFFileInfo->FileName = FileName;
offset = read_uint32be(Buffer+60);
if(offset > FileSize - 28)
@ -105,8 +101,7 @@ IFFChunkNode * iff_add_chunk(IFFFile * IFFFileInfo, int Position)
node->NextChunk = ptr;
}
}
IFFFileInfo->ChunkCount++;
return ptr;
}
@ -152,20 +147,4 @@ int iff_enumerate_chunks(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned
BufferSize -= chunk->Chunk.Size;
}
return 1;
}
IFFChunk *iff_find_first_chunk(IFFFile *IFFFileInfo, const char *type, uint16_t id)
{
IFFChunkNode *currentNode = IFFFileInfo->FirstChunk;
do
{
if (type == NULL || !memcmp(type, currentNode->Chunk.Type, 4) &&
(id == 0 || id == currentNode->Chunk.ChunkID))
return &currentNode->Chunk;
currentNode = currentNode->NextChunk;
}
while (currentNode != IFFFileInfo->LastChunk && currentNode != NULL);
return NULL;
}

View file

@ -13,9 +13,6 @@
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "stbl.h"
#include "bhav.h"
#include "sprite.h"
#ifndef read_uint32be
#define read_int32be(x) (signed)(((x)[0]<<(8*3)) | ((x)[1]<<(8*2)) | ((x)[2]<<(8*1)) | ((x)[3]<<(8*0)))
@ -61,8 +58,6 @@ typedef struct IFFChunkNode_struct
typedef struct IFFFile_struct
{
uint8_t Header[64];
char *FileName;
uint32_t ChunkCount;
IFFChunkNode * FirstChunk;
@ -76,6 +71,59 @@ static const uint8_t Header_IFF[] = "IFF FILE 2.5:TYPE FOLLOWED BY SIZE\0 JAMIE
** IFF chunk structs
*/
/* STR# chunk */
enum IFFLanguage {
IFFLANG_DEFAULT = 0,
IFFLANG_EN_US = 1,
IFFLANG_EN_INTERNATIONAL = 2,
IFFLANG_FRENCH = 3,
IFFLANG_GERMAN = 4,
IFFLANG_ITALIAN = 5,
IFFLANG_SPANISH = 6,
IFFLANG_DUTCH = 7,
IFFLANG_DANISH = 8,
IFFLANG_SWEDISH = 9,
IFFLANG_NORWEGIAN = 10,
IFFLANG_FINNISH = 11,
IFFLANG_HEBREW = 12,
IFFLANG_RUSSIAN = 13,
IFFLANG_PORTUGUESE = 14,
IFFLANG_JAPANESE = 15,
IFFLANG_POLISH = 16,
IFFLANG_CHINESE_SIMPLIFIED = 17,
IFFLANG_CHINESE_TRADITIONAL = 18,
IFFLANG_THAI = 19,
IFFLANG_KOREAN = 20
};
typedef struct IFFStringPair_struct
{
uint8_t LanguageSet;
char * Key;
char * Value;
} IFFStringPair;
typedef struct IFFStringPairNode_struct
{
IFFStringPair Pair;
struct IFFStringPairNode_struct * PrevPair;
struct IFFStringPairNode_struct * NextPair;
} IFFStringPairNode;
typedef struct IFFLanguageSet_struct
{
uint16_t PairCount;
IFFStringPairNode * FirstPair;
IFFStringPairNode * LastPair;
} IFFLanguageSet;
typedef struct IFF_STR_struct
{
int16_t Format;
IFFLanguageSet LanguageSets[20];
} IFF_STR;
#ifdef __cplusplus
extern "C" {
#endif
@ -85,7 +133,7 @@ extern "C" {
*/
IFFFile * iff_create();
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize, char *FileName);
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize);
IFFChunkNode * iff_add_chunk(IFFFile * IFFFileInfo, int Position);
int iff_read_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned MaxChunkSize);
@ -99,12 +147,9 @@ void iff_delete(IFFFile * IFFFileInfo);
** IFF chunk functions
*/
IFFChunk *iff_find_first_chunk(IFFFile *IFFFileInfo, const char *type, uint16_t id);
int iff_parse_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize);
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile);
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer);
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer);
int iff_parse_bhav(IFFChunk * ChunkInfo, const uint8_t * Buffer);
int iff_parse_sprite(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile);
#ifdef __cplusplus
}

View file

@ -89,7 +89,7 @@ int main(int argc, char *argv[]){
printf("%sMemory for this file could not be allocated.", "iffexport: error: ");
return -1;
}
if(!iff_read_header(IFFFileInfo, IFFData, FileSize, InFile)){
if(!iff_read_header(IFFFileInfo, IFFData, FileSize)){
printf("%sNot a valid IFF file.", "iffexport: error: ");
return -1;
}

View file

@ -1,571 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <png.h>
#include "iff.h"
int sprite_frame_set_texel(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color);
int sprite_frame_set_texel_alpha(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color, uint8_t alpha);
int sprite_frame_export_as_targa(IFFSpriteFrame *frame, const char *filename);
int sprite_frame_export_as_png(IFFSpriteFrame *frame, const char *filename);
int iff_parse_sprite(IFFChunk * ChunkInfo, const uint8_t * pBuffer, IFFFile *SourceFile)
{
uint32_t frameCount = 0;
uint32_t paletteID = 0;
uint32_t *offsets;
IFFChunk *PaletteMap;
IFFPMap *PMap;
IFFSprite *Sprite;
IFFSpriteFrame *Frame;
uint32_t i = 0;
uint32_t l = 0;
uint32_t j = 0;
uint32_t iRow = 0;
uint32_t cPixelsSet = 0;
uint8_t bQuit = 0;
uint32_t cBytesReadInitial = 0;
uint32_t cBytesRead = 0;
uint16_t mRowHeader = 0;
uint16_t mColumnHeader = 0;
uint16_t eRowControlCode = 0;
uint16_t eColumnControlCode = 0;
uint16_t cBytesInThisRow = 0;
uint16_t cPixelCount = 0; /* Per-control-code pixel count*/
uint8_t Z;
#ifdef IFF2HTML
char *outputPath;
char *dummyName;
char *folderName;
#endif
uint32_t version = read_uint32le(pBuffer);
pBuffer += 4;
if (version == 1001)
{
paletteID = read_uint32le(pBuffer);
pBuffer += 4;
frameCount = read_uint32le(pBuffer);
pBuffer += 4;
}
else
{
frameCount = read_uint32le(pBuffer);
pBuffer += 4;
paletteID = read_uint32le(pBuffer);
pBuffer += 4;
}
/* Try to load the appropriate palette */
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", paletteID);
/* If that didn't work, try loading any palette from the IFF file */
/* Some sprites in IFFs containing only one PALT don't bother to specify a correct PALT ID */
if (PaletteMap == NULL)
{
printf("ERR");
fflush(stdout);
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", 0);
/* If there is no existing palette data, there can be no coherent image. */
if (PaletteMap == NULL)
{
return 0;
}
}
if (PaletteMap->FormattedData == NULL)
{
printf("HERE");
fflush(stdout);
iff_parse_pmap(PaletteMap, PaletteMap->Data);
}
PMap = (IFFPMap *)PaletteMap->FormattedData;
offsets = (uint32_t *)malloc(sizeof(uint32_t) * frameCount);
memset(offsets, 0, sizeof(uint32_t) * frameCount);
if (version == 1000)
{
for (i = 0; i < frameCount; i++)
{
offsets[i] = read_uint32le(pBuffer);
pBuffer += 4;
}
}
Sprite = (IFFSprite *)malloc(sizeof(IFFSprite));
Sprite->FrameCount = frameCount;
Sprite->Frames = (IFFSpriteFrame **)malloc(sizeof (IFFSpriteFrame *) * frameCount);
#ifdef IFF2HTML
Sprite->Version = version;
#endif
for (l = 0; l < frameCount; l++)
{
Frame = (IFFSpriteFrame *)malloc(sizeof(IFFSpriteFrame));
/* Version 1000 specifies offsets for each frame of image data */
if (version == 1000)
pBuffer = ChunkInfo->Data + offsets[l];
/* There are two "+=" statements here for clarity. That is optimized away by a decent compiler */
if (version == 1001)
{
pBuffer += 4; /* Version */
pBuffer += 4; /* Size */
}
if (version != 1000 && version != 1001) /* for SPR# resources */
{
Frame->YLocation = read_uint16le(pBuffer);
pBuffer += 2;
Frame->YLocation = read_uint16le(pBuffer);
pBuffer += 2;
Frame->Height = read_uint16le(pBuffer);
pBuffer += 2;
Frame->Width = read_uint16le(pBuffer);
pBuffer += 2;
}
else
{
Frame->Width = read_uint16le(pBuffer);
pBuffer += 2;
Frame->Height = read_uint16le(pBuffer);
pBuffer += 2;
}
Frame->Flag = read_uint16le(pBuffer);
pBuffer += 2;
if (version == 1000 || version == 1001)
{
pBuffer += 2;
Frame->PaletteID = read_uint16le(pBuffer); /* This is unused or the same as the master PALT ID */
pBuffer += 2;
Frame->TransparentPixel = PMap->Colors[read_uint16le(pBuffer)];
pBuffer += 2;
Frame->YLocation = read_uint16le(pBuffer);
pBuffer += 2;
Frame->XLocation = read_uint16le(pBuffer);
pBuffer += 2;
}
if (Frame->PaletteID != 0xA3A3)
{
/* Try to load the appropriate palette */
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", Frame->PaletteID);
/* If that didn't work, try loading any palette from the IFF file */
/* Some sprites in IFFs containing only one PALT don't bother to specify a correct PALT ID */
if (PaletteMap == NULL)
{
PaletteMap = iff_find_first_chunk(SourceFile, "PALT", 0);
/* If there is no existing palette data, there can be no coherent image. */
if (PaletteMap == NULL)
return 0;
}
PMap = (IFFPMap *)PaletteMap->FormattedData;
}
/* Now that we know the frame size, allocate the buffer to hold its texels */
Frame->Texels = (IFFSpriteColor *)malloc(sizeof(IFFSpriteColor) * Frame->Width * Frame->Height);
iRow = 0;
cPixelsSet = 0;
bQuit = 0;
cBytesReadInitial = 0;
cBytesRead = 0;
mRowHeader = 0;
mColumnHeader = 0;
eRowControlCode = 0;
eColumnControlCode = 0;
cBytesInThisRow = 0;
cPixelCount = 0;
if (version == 1000 || version == 1001)
{
while (!bQuit)
{
mRowHeader = read_uint16le(pBuffer);
eRowControlCode = mRowHeader>>13;
cBytesInThisRow = mRowHeader&0x1FFF;
pBuffer += 2;
cBytesRead = 2; /* We just read the row header, which is included in cBytesInThisRow */
cPixelsSet = 0;
switch (eRowControlCode)
{
case 0:
while (cBytesRead < cBytesInThisRow)
{
mColumnHeader = read_uint16le(pBuffer);
eColumnControlCode = mColumnHeader>>13;
cPixelCount = mColumnHeader&0x1FFF;
pBuffer += 2;
cBytesRead += 2;
switch (eColumnControlCode)
{
case 1: /* Add cPixelCount ZRGB pixels */
for (i = 0; i < cPixelCount; i++)
{
Z = *pBuffer++; /* TODO: Use the z-buffer */
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
cBytesRead += 2;
}
break;
case 2: /* Add cPixelCount ZRGBA pixels */
i = 0;
for (i = 0; i < cPixelCount; i++)
{
Z = *pBuffer++; /* TODO: Use the z-buffer */
sprite_frame_set_texel_alpha(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++], (uint8_t)*pBuffer++);/* Read and set the alpha channel's value */
cBytesRead += 3;
}
/* Read EA's padding byte if the current position is not a multiple of 2 */
if ((pBuffer - ChunkInfo->Data) % 2 == 1)
{
pBuffer++;
cBytesRead++;
}
break;
case 3: /* Add cPixelCount transparent pixels */
for (i = 0; i < cPixelCount; i++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
}
break;
case 6: /* Add cPixelCount RGB pixels */
i = 0;
for (i = 0; i < cPixelCount; i++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
cBytesRead++;
}
/* Read EA's padding byte if the current position is not a multiple of 2 */
if ((pBuffer - ChunkInfo->Data) % 2 == 1)
{
pBuffer++;
cBytesRead++;
}
break;
default:
/* Error reading column code */
return 0;
}
}
/* Set any extra (unread) texels in the current row to transparent */
while (cPixelsSet < Frame->Width) { sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel); }
iRow++;
break;
case 4:
for (i = 0; i < cBytesInThisRow; i++) /* cBytesInThisRow is used as the count of rows to fill with the transparent color in this case */
{
for (cPixelsSet = 0; cPixelsSet < Frame->Width; cPixelsSet++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
}
iRow++;
}
break;
case 5: /* This means to stop reading */
bQuit = 1;
break;
default:
/* Error reading row code */
return 0;
}
if ((uint32_t)(pBuffer - ChunkInfo->Data) == ChunkInfo->Size)
break;
}
}
else
{
while (bQuit == 0)
{
eRowControlCode = *pBuffer++;
cBytesInThisRow = *pBuffer++;
cBytesRead = 2;
cPixelsSet = 0;
switch (eRowControlCode)
{
case 4:
for (cBytesInThisRow = 0; cBytesInThisRow < cBytesInThisRow;)
{
eColumnControlCode = *pBuffer++;
cPixelCount = *pBuffer++;
cBytesRead += 2;
switch (eColumnControlCode)
{
case 3:
for (i = 0; i < cPixelCount; i++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
cBytesRead++;
}
if ((pBuffer - ChunkInfo->Data) % 2 == 1)
{
pBuffer++;
cBytesRead++;
}
break;
case 2:
for (i = 0; i < cPixelCount; i++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, PMap->Colors[*pBuffer++]);
pBuffer++; /* Unused value */
cBytesRead += 2;
}
break;
case 1:
for (i = 0; i < cPixelCount; i++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
}
break;
default:
/* Error reading column code */
return 0;
}
}
/* Set any extra (unread) texels in the current row to transparent */
while (cPixelsSet < Frame->Width) { sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel); }
iRow++;
break;
case 9:
for (i = 0; i < cBytesInThisRow; i++) /* cBytesInThisRow is used as the count of rows to fill with the transparent color in this case */
{
for (cPixelsSet = 0; cPixelsSet < Frame->Width; cPixelsSet++)
{
sprite_frame_set_texel(Frame, cPixelsSet++, iRow, Frame->TransparentPixel);
}
iRow++;
}
break;
case 5:
bQuit = 1;
printf("END");
fflush(stdout);
break;
default:
/* Error reading row code */
return 0;
}
/*if ((uint32_t)(pBuffer - ChunkInfo->Data) == ChunkInfo->Size)
break; */
}
}
for (i = 0; i < Frame->Height; i++) /* cBytesInThisRow is used as the count of rows to fill with the transparent color in this case */
{
for (j = 0; j < Frame->Width; j++)
{
if (sprite_are_colors_equal_rgb(Frame->Texels[i*Frame->Width+j], Frame->TransparentPixel))
Frame->Texels[i*Frame->Width+j].A = 0;
}
}
#ifdef IFF2HTML
outputPath = (char *)malloc(sizeof(char) * 255);
folderName = (char *)malloc(sizeof(char) * 255);
dummyName = (char *)malloc(sizeof(char) * 255);
strcpy(folderName, SourceFile->FileName);
*strchr(folderName, (int)'.') = '\0';
sprintf(outputPath, "./%s/%s (%d) Frame %d.png", folderName, ChunkInfo->Label, ChunkInfo->ChunkID, l);
/*printf(outputPath);
fflush(stdout);*/
sprite_frame_export_as_png (Frame, outputPath); /* The images export faster and look better as targa. This tells me I'm doing something wrong in the PNG exporter code */
Sprite->Frames[l] = Frame;
Sprite->Frames[l]->filePath = outputPath;
#endif
}
/* By adding this to the ChunkInfo at the success point, we ensure that no corrupt or partial sprite appears ingame */
ChunkInfo->FormattedData = Sprite;
return 1;
}
/* This function never returns zero because it is capable of producing logical output independent of the input's validity. */
int sprite_are_colors_equal_rgb(IFFSpriteColor clr1, IFFSpriteColor clr2)
{
return clr1.R == clr2.R && clr1.G == clr2.G && clr1.B == clr2.B;
}
/* This function never returns zero because it is capable of producing logical output independent of the input's validity. */
int iff_parse_pmap(IFFChunk * ChunkInfo, uint8_t * pBuffer)
{
uint32_t i;
uint32_t indicator;
IFFPMap *PMap = malloc(sizeof(IFFPMap));
pBuffer = ChunkInfo->Data;
PMap->Colors = (IFFSpriteColor *)malloc(sizeof(IFFSpriteColor) * 256);
indicator = read_uint32le(pBuffer);
if (indicator != 1)
pBuffer += (indicator>>24) - 8;
else
pBuffer += 12;
/* In every single one of EA's PALT resources, there have been 256 colors. */
for (i = 0; i < 256; i++)
{
if ((uint32_t)(pBuffer - ChunkInfo->Data) < ChunkInfo->Size + 3) /* Are there 3 more bytes left to read? */
{
PMap->Colors[i].R = *(pBuffer++);
PMap->Colors[i].G = *(pBuffer++);
PMap->Colors[i].B = *(pBuffer++);
PMap->Colors[i].A = 255;
}
else
{
PMap->Colors[i].R = 128;
PMap->Colors[i].G = 128;
PMap->Colors[i].B = 128;
PMap->Colors[i].A = 255;
}
}
ChunkInfo->FormattedData = PMap;
return 1;
}
int sprite_frame_set_texel(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color)
{
/*printf("Index: %d out of %d", frame->Width * row + column, frame->Width*frame->Height);*/
memcpy(&frame->Texels[frame->Width * row + column], &color, sizeof(IFFSpriteColor));
return 1;
}
int sprite_frame_set_texel_alpha(IFFSpriteFrame *frame, uint32_t column, uint32_t row, IFFSpriteColor color, uint8_t alpha)
{
/*printf("Index: %d out of %d", frame->Width * row + column, frame->Width*frame->Height);*/
memcpy(&frame->Texels[frame->Width * row + column], &color, sizeof(IFFSpriteColor));
frame->Texels[frame->Width * row + column].A = alpha;
return 1;
}
int sprite_frame_export_as_targa(IFFSpriteFrame *frame, const char *filename)
{
int i;
FILE *targaFile = fopen(filename, "w");
putc(0, targaFile);
putc(0, targaFile);
putc(2, targaFile);
putc(0, targaFile); putc(0, targaFile);
putc(0, targaFile); putc(0, targaFile);
putc(0, targaFile);
fwrite(&frame->XLocation, 2, 1, targaFile);
fwrite(&frame->YLocation, 2, 1, targaFile);
fwrite(&frame->Width, 2, 1, targaFile);
fwrite(&frame->Height, 2, 1, targaFile);
putc(32, targaFile);
putc(0, targaFile);
for (i = 0; i < frame->Width * frame->Height; i++)
{
putc(frame->Texels[i].B, targaFile);
putc(frame->Texels[i].G, targaFile);
putc(frame->Texels[i].R, targaFile);
putc(frame->Texels[i].A, targaFile);
}
fclose(targaFile);
return 1;
}
int sprite_frame_export_as_png(IFFSpriteFrame *frame, const char *filename)
{
png_structp png_ptr;
png_infop info_ptr;
png_bytepp row_pointers;
int h;
int w;
FILE *pngFile = fopen(filename, "wb");
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info_ptr = png_create_info_struct(png_ptr);
setjmp(png_jmpbuf(png_ptr));
png_init_io(png_ptr, pngFile);
setjmp(png_jmpbuf(png_ptr));
png_set_IHDR(png_ptr, info_ptr, frame->Width, frame->Height,
8, 6, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_write_info(png_ptr, info_ptr);
setjmp(png_jmpbuf(png_ptr));
row_pointers = (png_bytepp) malloc (frame->Height * sizeof (png_bytep));
for (h = 0; h < frame->Height; h++) {
row_pointers[h] = (png_bytep) malloc (frame->Width*4);
for (w = 0; w < frame->Width; w++) {
row_pointers[h][w*4] = frame->Texels[frame->Width*h + w].R;
row_pointers[h][w*4+1] = frame->Texels[frame->Width*h + w].G;
row_pointers[h][w*4+2] = frame->Texels[frame->Width*h + w].B;
row_pointers[h][w*4+3] = frame->Texels[frame->Width*h + w].A;
}
}
png_write_image(png_ptr, row_pointers);
setjmp(png_jmpbuf(png_ptr));
png_write_end(png_ptr, NULL);
for (h = 0; h < frame->Height; h++) {
free((row_pointers)[h]);
}
free(row_pointers);
fclose(pngFile);
return 1;
}

View file

@ -1,41 +0,0 @@
#define IFF2HTML
typedef struct IFFSpriteColor_struct
{
uint8_t A;
uint8_t R;
uint8_t G;
uint8_t B;
} IFFSpriteColor;
typedef struct IFFPixelMap_struct
{
IFFSpriteColor *Colors; /* This is 255 b/c sometimes SPR2 and SPR resource go out of bounds (safety first!) */
} IFFPMap;
typedef struct IFFSpriteFrame_struct
{
uint16_t XLocation;
uint16_t YLocation;
uint16_t Width;
uint16_t Height;
uint16_t Flag;
uint16_t PaletteID;
IFFSpriteColor TransparentPixel;
IFFSpriteColor *Texels;
#ifdef IFF2HTML
char *filePath;
#endif
} IFFSpriteFrame;
typedef struct IFFSprite_struct
{
IFFSpriteFrame **Frames;
uint16_t FrameCount;
#ifdef IFF2HTML
uint32_t Version;
#endif
} IFFSprite;

View file

@ -1,233 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "iff.h"
int iff_parse_str(IFFChunk * ChunkInfo, const uint8_t * Buffer){
/* No bounds checking yet */
IFF_STR * StringData;
unsigned Size = ChunkInfo->Size - 76;
if(Size < 2)
return 0;
ChunkInfo->FormattedData = malloc(sizeof(IFF_STR));
if(ChunkInfo->FormattedData == NULL)
return 0;
memset(ChunkInfo->FormattedData, 0, sizeof(IFF_STR));
StringData = (IFF_STR*) ChunkInfo->FormattedData;
StringData->Format = read_int16le(Buffer);
Buffer += 2;
if(Size-2 < 2) /* TSO allows this; as seen in the animations chunk in personglobals.iff */
return 1;
switch(StringData->Format){
case 0: {
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[0].PairCount == 0)
return 1;
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
/* Key */
length = read_uint8le(Buffer);
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
CurrentPair->Pair.Key[length] = 0x00;
}
Buffer += length+1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[0].LastPair = PrevPair;
} return 1;
case -1: {
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[0].PairCount == 0)
return 1;
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
/* Key */
length = strlen((char*)Buffer);
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
}
Buffer += length+1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[0].LastPair = PrevPair;
} return 1;
case -2: {
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[0].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[0].PairCount == 0)
return 1;
for(i=0; i<StringData->LanguageSets[0].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[0].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
/* Key */
length = strlen((char*)Buffer);
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
strcpy(CurrentPair->Pair.Key, (char*)Buffer);
}
Buffer += length+1;
/* Value */
length = strlen((char*)Buffer);
if(length != 0){
CurrentPair->Pair.Value = malloc(length+1);
strcpy(CurrentPair->Pair.Value, (char*)Buffer);
}
Buffer += length+1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[0].LastPair = PrevPair;
} return 1;
case -3: {
unsigned i, TotalPairCount;
TotalPairCount = read_uint16le(Buffer);
Buffer += 2;
if(TotalPairCount == 0)
return 1;
for(i=0; i<TotalPairCount; i++){
IFFStringPairNode * Pair;
unsigned length;
Pair = malloc(sizeof(IFFStringPairNode));
memset(Pair, 0, sizeof(IFFStringPairNode));
Pair->Pair.LanguageSet = read_uint8le(Buffer) - 1;
Buffer++;
/* Key */
length = strlen((char*)Buffer);
if(length != 0){
Pair->Pair.Key = malloc(length+1);
strcpy(Pair->Pair.Key, (char*)Buffer);
}
Buffer += length+1;
/* Value */
length = strlen((char*)Buffer);
if(length != 0){
Pair->Pair.Value = malloc(length+1);
strcpy(Pair->Pair.Value, (char*)Buffer);
}
Buffer += length+1;
/* Add the pair to the end of the associated language set */
Pair->PrevPair = StringData->LanguageSets[0].LastPair;
if(StringData->LanguageSets[0].PairCount == 0)
StringData->LanguageSets[0].FirstPair = Pair;
else
StringData->LanguageSets[0].LastPair->NextPair = Pair;
StringData->LanguageSets[0].PairCount++;
StringData->LanguageSets[0].LastPair = Pair;
}
} return 1;
case -4: {
unsigned LanguageSet;
unsigned LanguageSetCount = read_uint8le(Buffer);
Buffer++;
if(LanguageSetCount > 20) LanguageSetCount = 20;
for(LanguageSet=0; LanguageSet<LanguageSetCount; LanguageSet++){
unsigned i;
IFFStringPairNode * PrevPair = NULL;
StringData->LanguageSets[LanguageSet].PairCount = read_uint16le(Buffer);
Buffer += 2;
if(StringData->LanguageSets[LanguageSet].PairCount == 0)
continue;
for(i=0; i<StringData->LanguageSets[LanguageSet].PairCount; i++){
IFFStringPairNode * CurrentPair;
unsigned length;
CurrentPair = malloc(sizeof(IFFStringPairNode));
memset(CurrentPair, 0, sizeof(IFFStringPairNode));
if(i == 0) StringData->LanguageSets[LanguageSet].FirstPair = CurrentPair;
else PrevPair->NextPair = CurrentPair;
CurrentPair->PrevPair = PrevPair;
Buffer++; /* Skip over LanguageSet */
/* Key */
length = read_uint8le(Buffer);
if(length > 127){
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
Buffer++;
}
if(length != 0){
CurrentPair->Pair.Key = malloc(length+1);
memcpy(CurrentPair->Pair.Key, Buffer+1, length);
CurrentPair->Pair.Key[length] = 0x00;
}
Buffer += length + 1;
/* Value */
length = read_uint8le(Buffer);
if(length > 127){
length = (length & 127) | (read_uint8le(Buffer+1) << 7);
Buffer++;
}
if(length != 0){
CurrentPair->Pair.Value = malloc(length+1);
memcpy(CurrentPair->Pair.Value, Buffer+1, length);
CurrentPair->Pair.Value[length] = 0x00;
}
Buffer += length + 1;
PrevPair = CurrentPair;
}
StringData->LanguageSets[LanguageSet].LastPair = PrevPair;
}
} return 1;
}
return 0;
}

View file

@ -1,52 +0,0 @@
/* STR# chunk */
enum IFFLanguage {
IFFLANG_DEFAULT = 0,
IFFLANG_EN_US = 1,
IFFLANG_EN_INTERNATIONAL = 2,
IFFLANG_FRENCH = 3,
IFFLANG_GERMAN = 4,
IFFLANG_ITALIAN = 5,
IFFLANG_SPANISH = 6,
IFFLANG_DUTCH = 7,
IFFLANG_DANISH = 8,
IFFLANG_SWEDISH = 9,
IFFLANG_NORWEGIAN = 10,
IFFLANG_FINNISH = 11,
IFFLANG_HEBREW = 12,
IFFLANG_RUSSIAN = 13,
IFFLANG_PORTUGUESE = 14,
IFFLANG_JAPANESE = 15,
IFFLANG_POLISH = 16,
IFFLANG_CHINESE_SIMPLIFIED = 17,
IFFLANG_CHINESE_TRADITIONAL = 18,
IFFLANG_THAI = 19,
IFFLANG_KOREAN = 20
};
typedef struct IFFStringPair_struct
{
uint8_t LanguageSet;
char * Key;
char * Value;
} IFFStringPair;
typedef struct IFFStringPairNode_struct
{
IFFStringPair Pair;
struct IFFStringPairNode_struct * PrevPair;
struct IFFStringPairNode_struct * NextPair;
} IFFStringPairNode;
typedef struct IFFLanguageSet_struct
{
uint16_t PairCount;
IFFStringPairNode * FirstPair;
IFFStringPairNode * LastPair;
} IFFLanguageSet;
typedef struct IFF_STR_struct
{
int16_t Format;
IFFLanguageSet LanguageSets[20];
} IFF_STR;