Support for sprites was added to libiff.

Support for SPR# and SPR2 was added to iff2html.

*NOTE: The default exporter used is the PNG one, since web browsers
don't like targa. However, since there is a bug in my PNG exporter, I would
recommend that you use the targa exporter for a precise representation of the
loaded sprite frame(s). Feel free to fix the PNG exporter, btw :)
This commit is contained in:
thnor 2012-04-04 00:24:25 -05:00
parent 02dff475c8
commit 6c85920535
16 changed files with 1150 additions and 84 deletions

View file

@ -19,14 +19,17 @@ set(FILEHANDLER_SOURCES
File.cpp
Image.cpp
cst/cst.c
iff/stbl.c
iff/bhav.c
iff/stbl.c
iff/bhav.c
iff/sprite.c
iff/chunks.c
iff/iff.c
)
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler)
include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler/libpng)
add_library(FileHandler_static STATIC ${FILEHANDLER_SOURCES})
set_target_properties(FileHandler_static PROPERTIES
OUTPUT_NAME "FileHandler${FILEHANDLER_SERIES}"
@ -41,4 +44,4 @@ set_target_properties(FileHandler_shared PROPERTIES
PREFIX ""
IMPORT_PREFIX ""
CLEAN_DIRECT_OUTPUT 1)
target_link_libraries(FileHandler_shared kernel32 jpegturbo_static)
target_link_libraries(FileHandler_shared kernel32 jpegturbo_static zlib_shared libpng_static)

View file

@ -2,10 +2,13 @@ cmake_minimum_required(VERSION 2.6)
project(iff)
set(IFF_SOURCES
bhav.c
stbl.c
chunks.c
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

@ -0,0 +1,53 @@
#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

@ -0,0 +1,29 @@
/* 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,16 +19,19 @@
#include <stdint.h>
#include "iff.h"
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer){
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile){
if( !strcmp(ChunkInfo->Type, "STR#") ||
!strcmp(ChunkInfo->Type, "CTSS") ||
!strcmp(ChunkInfo->Type, "FAMs") ||
!strcmp(ChunkInfo->Type, "TTAs") )
return iff_parse_str(ChunkInfo, Buffer);
else if (!strcmp(ChunkInfo->Type, "BHAV"))
return iff_parse_bhav(ChunkInfo, (const char *)Buffer);
else
return 0;
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_rsmp(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned IFFSize){

View file

@ -17,6 +17,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include "iff.h"
#ifndef __inline
@ -36,10 +37,11 @@ IFFFile * iff_create()
return ptr;
}
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize)
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize, char *FileName)
{
unsigned offset;
if(!FileSize) FileSize = ~0;
else if(FileSize < 64)
return 0;
@ -47,6 +49,8 @@ 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)
@ -101,7 +105,8 @@ IFFChunkNode * iff_add_chunk(IFFFile * IFFFileInfo, int Position)
node->NextChunk = ptr;
}
}
IFFFileInfo->ChunkCount++;
return ptr;
}
@ -147,4 +152,20 @@ 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);
return NULL;
}

View file

@ -15,6 +15,7 @@
*/
#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)))
@ -60,6 +61,8 @@ typedef struct IFFChunkNode_struct
typedef struct IFFFile_struct
{
uint8_t Header[64];
char *FileName;
uint32_t ChunkCount;
IFFChunkNode * FirstChunk;
@ -82,7 +85,7 @@ extern "C" {
*/
IFFFile * iff_create();
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize);
int iff_read_header(IFFFile * IFFFileInfo, const uint8_t * Buffer, unsigned FileSize, char *FileName);
IFFChunkNode * iff_add_chunk(IFFFile * IFFFileInfo, int Position);
int iff_read_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, unsigned MaxChunkSize);
@ -96,10 +99,12 @@ 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);
int iff_parse_chunk(IFFChunk * ChunkInfo, const uint8_t * Buffer, IFFFile *SourceFile);
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)){
if(!iff_read_header(IFFFileInfo, IFFData, FileSize, InFile)){
printf("%sNot a valid IFF file.", "iffexport: error: ");
return -1;
}

View file

@ -0,0 +1,518 @@
#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_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 * Buffer, 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 row = 0;
uint32_t column = 0;
uint8_t quit = 0;
uint32_t numCodesTillNewline = 0;
uint16_t encrypted = 0;
uint16_t encryptedb = 0;
uint16_t decrypted1 = 0;
uint16_t decrypted2 = 0;
uint16_t decryptedb3 = 0;
uint16_t decryptedb4 = 0;
uint32_t bytesRead = 0;
uint8_t Z;
IFFSpriteColor clr;
uint32_t rowHeader[2];
uint32_t rowHeader2[2];
uint8_t b;
uint8_t b1;
#ifdef IFF2HTML
char *outputPath;
char *dummyName;
char *folderName;
#endif
uint32_t version = read_uint32le(Buffer);
Buffer += 4;
if (version == 1001)
{
paletteID = read_uint32le(Buffer);
Buffer += 4;
frameCount = read_uint32le(Buffer);
Buffer += 4;
}
else
{
frameCount = read_uint32le(Buffer);
Buffer += 4;
paletteID = read_uint32le(Buffer);
Buffer += 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)
{
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;
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(Buffer);
Buffer += 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)
Buffer = ChunkInfo->Data + offsets[l];
/* There are two "+=" statements here for clarity. That is optimized away by a decent compiler */
if (version == 1001)
{
Buffer += 4; /* Version */
Buffer += 4; /* Size */
}
if (version != 1000 && version != 1001) /* for SPR# resources */
{
Frame->YLocation = read_uint16le(Buffer);
Buffer += 2;
Frame->YLocation = read_uint16le(Buffer);
Buffer += 2;
Frame->Height = read_uint16le(Buffer);
Buffer += 2;
Frame->Width = read_uint16le(Buffer);
Buffer += 2;
}
else
{
Frame->Width = read_uint16le(Buffer);
Buffer += 2;
Frame->Height = read_uint16le(Buffer);
Buffer += 2;
}
Frame->Flag = read_uint16le(Buffer);
Buffer += 2;
if (version == 1000 || version == 1001)
{
Buffer += 2;
Frame->PaletteID = read_uint16le(Buffer); /* This is unused or the same as the master PALT ID */
Buffer += 2;
Frame->TransparentPixel = PMap->Colors[read_uint16le(Buffer)];
Buffer += 2;
Frame->YLocation = read_uint16le(Buffer);
Buffer += 2;
Frame->XLocation = read_uint16le(Buffer);
Buffer += 2;
}
/* Now that we know the frame size, allocate the buffer to hold its texels */
Frame->Texels = (IFFSpriteColor *)malloc(sizeof(IFFSpriteColor) * Frame->Width * Frame->Height);
if (version == 1000 || version == 1001)
{
while (quit == 0)
{
encrypted = read_uint16le(Buffer);
encryptedb = 0;
decrypted1 = encrypted>>13;
decrypted2 = encrypted&0x1FFF;
decryptedb3 = 0;
decryptedb4 = 0;
Buffer += 2;
switch (decrypted1)
{
case 0:
column = 0;
numCodesTillNewline = decrypted2;
bytesRead = 0;
for (bytesRead = 0; bytesRead < numCodesTillNewline - 2; bytesRead += 2)
{
encryptedb = read_uint16le(Buffer);
Buffer += 2;
decryptedb3 = encryptedb>>13;
decryptedb4 = encryptedb&0x1FFF;
switch (decryptedb3)
{
case 1:
for (i = 0; i < decryptedb4; i++)
{
Z = *Buffer++; /* TODO: Use the z-buffer */
b = *Buffer++;
sprite_frame_set_texel(Frame, column++, row, PMap->Colors[b]);
/*c = PMap->Colors[b]; This variable is not used */
bytesRead += 2;
}
break;
case 2:
i = 0;
for (i = 0; i < decryptedb4; i++)
{
Z = *Buffer++; /* TODO: Use the z-buffer */
b = *Buffer++;
clr = PMap->Colors[b];
clr.A = *Buffer++;
sprite_frame_set_texel(Frame, column++, row, clr);
bytesRead += 3;
}
if ((Buffer - ChunkInfo->Data) % 2 == 1)
{
Buffer++;
bytesRead++;
}
break;
case 3:
column += decryptedb4;
break;
case 6:
i = 0;
for (i = 0; i < decryptedb4; i++)
{
b = *Buffer++;
sprite_frame_set_texel(Frame, column++, row, PMap->Colors[b]);
bytesRead++;
}
if ((Buffer - ChunkInfo->Data) % 2 == 1)
{
Buffer++;
bytesRead++;
}
break;
default:
break;
}
}
row++;
break;
case 4:
i = 0;
for (i = 0; i < decrypted2; i++)
{
row++;
column = 0;
}
break;
case 5:
quit = 1;
break;
default:
/* Error reading code */
return 0;
}
if ((uint32_t)(Buffer - ChunkInfo->Data) == ChunkInfo->Size)
break;
}
}
else
{
while (quit == 0)
{
b = 0;
b1 = 0;
/*b2 = 0; This variable is unused */
rowHeader[0] = *Buffer++;
rowHeader[1] = *Buffer++;
switch (rowHeader[0])
{
case 4:
column = 0;
numCodesTillNewline = rowHeader[1];
bytesRead = 0;
for (bytesRead = 0; bytesRead < numCodesTillNewline - 2; bytesRead += 2)
{
rowHeader2[0] = *Buffer++;
rowHeader2[1] = *Buffer++;
switch (rowHeader2[0])
{
case 3:
i = 0;
for (i = 0; i < rowHeader2[1]; i++)
{
b = *Buffer++;
sprite_frame_set_texel(Frame, column++, row, PMap->Colors[b]);
/*c = PMap->Colors[b]; This variable is not used */
bytesRead += 1;
}
if ((Buffer - ChunkInfo->Data) % 2 == 1)
{
Buffer++;
bytesRead++;
}
break;
case 2:
b1 = *Buffer++;
/*b2 = *Buffer++; this variable is unused */
Buffer++;
clr = PMap->Colors[b1];
i = 0;
for (i = 0; i < rowHeader2[1]; i++)
{
sprite_frame_set_texel(Frame, column++, row, clr);
}
bytesRead += 2;
break;
case 1:
column += rowHeader2[1];
break;
default:
/* Error */
return 0;
}
}
row++;
break;
case 9:
i = 0;
for (i = 0; i < rowHeader[1]; i++)
{
row++;
column = 0;
}
break;
case 5:
quit = 1;
break;
default:
/* Error */
return 0;
}
if ((uint32_t)(Buffer - ChunkInfo->Data) == ChunkInfo->Size)
break;
}
}
#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 iff_parse_pmap(IFFChunk * ChunkInfo, uint8_t * Buffer)
{
uint32_t i;
IFFPMap *PMap = malloc(sizeof(IFFPMap));
Buffer = ChunkInfo->Data;
PMap->Colors = (IFFSpriteColor *)malloc(sizeof(IFFSpriteColor) * 256);
Buffer += 16;
if (*Buffer == 0)
Buffer += 64; /* TSO-only (this took a while to figure out) Why EA does this is beyond me... */
/* In every single one of EA's PALT resources, there have been 256 colors. */
for (i = 0; i < 256; i++)
{
if ((uint32_t)(Buffer - ChunkInfo->Data) < ChunkInfo->Size + 3) /* Are there 3 more bytes left to read? */
{
PMap->Colors[i].R = *(Buffer++);
PMap->Colors[i].G = *(Buffer++);
PMap->Colors[i].B = *(Buffer++);
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_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[frame->Height-h-1] = (png_bytep) malloc (frame->Width*4);
for (w = 0; w < frame->Width; w++) {
row_pointers[frame->Height-h-1][w*4] = frame->Texels[frame->Width*h + w].R;
row_pointers[frame->Height-h-1][w*4+1] = frame->Texels[frame->Width*h + w].G;
row_pointers[frame->Height-h-1][w*4+2] = frame->Texels[frame->Width*h + w].B;
row_pointers[frame->Height-h-1][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

@ -0,0 +1,41 @@
#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

@ -0,0 +1,233 @@
#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

@ -0,0 +1,52 @@
/* 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;

View file

@ -16,7 +16,7 @@ void SetType(HWND hDlg, int type){
}
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
switch (message){
case WM_INITDIALOG: {
CenterDialog(hDlg);
@ -43,15 +43,15 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
//Create the tooltips
HWND FARInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_BALLOON | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL, hInst, NULL),
DBPFInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_BALLOON | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL, hInst, NULL);
WS_POPUP | TTS_NOPREFIX | 0x40 | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL, hInst, NULL),
DBPFInfo = CreateWindowEx(0, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | 0x40 | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL, hInst, NULL);
TOOLINFO tinfo = {
sizeof(TOOLINFO), //cbSize
@ -67,9 +67,9 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
L"FAR version 1a is found in The Sims 1.\r\n\r\n"
L"Version 1b appears to be a mistake, in which it was intended to take on the version number 2.\r\n\r\n"
L"1b and 3 are both found exclusively in The Sims Online.";
SendMessage(FARInfo, TTM_SETMAXTIPWIDTH, 2000, 200);
SendMessage(FARInfo, TTM_SETTITLE, TTI_INFO_LARGE, (LPARAM) L"FAR version");
SendMessage(FARInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
SendMessage(FARInfo, (WM_USER + 24), 2000, 200);
SendMessage(FARInfo, (WM_USER + 32), TTI_INFO_LARGE, (LPARAM) L"FAR version");
SendMessage(FARInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
SendMessage(FARInfo, TTM_SETDELAYTIME, TTDT_AUTOPOP, 12000);
tinfo.uId = (UINT_PTR) GetDlgItem(hDlg, IDC_NA_DBPFINFO);
tinfo.lpszText = (wchar_t*)
@ -78,21 +78,21 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
L"DBPF 1.0;i7.0 is found in The Sims Online and SimCity 4.\r\n\r\n"
L"1.0;i7.0 and 1.1;i7.1 are found in The Sims 2.\r\n\r\n"
L"2.0;i3.0 is found in Spore.";
SendMessage(DBPFInfo, TTM_SETMAXTIPWIDTH, 2000, 200);
SendMessage(DBPFInfo, TTM_SETTITLE, TTI_INFO_LARGE, (LPARAM) L"DBPF version");
SendMessage(DBPFInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
SendMessage(DBPFInfo, (WM_USER + 24), 2000, 200);
SendMessage(DBPFInfo, (WM_USER + 32), TTI_INFO_LARGE, (LPARAM) L"DBPF version");
SendMessage(DBPFInfo, TTM_ADDTOOL, 0, (LPARAM) &tinfo);
SendMessage(DBPFInfo, TTM_SETDELAYTIME, TTDT_AUTOPOP, 20000);
SetType(hDlg, TYPE_FAR);
} return TRUE;
case WM_CTLCOLORSTATIC:
if((HWND) lParam == GetDlgItem(hDlg, IDC_NA_TYPETEXT)){
SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)){
if((HWND) lParam == GetDlgItem(hDlg, IDC_NA_TYPETEXT)){
SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
}
break;
case WM_COMMAND:
switch(LOWORD(wParam)){
case IDC_NA_TYPE:
if(HIWORD(wParam) == CBN_SELCHANGE)
SetType(hDlg, SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0));
@ -110,7 +110,7 @@ INT_PTR CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){
EndDialog(hDlg, 0);
} break;
case WM_CLOSE:
EndDialog(hDlg, 0);
EndDialog(hDlg, 0);
}
return 0;
}

View file

@ -30,8 +30,8 @@ bool Close(){
Archive::IsOpen = false;
SetWindowText(hWnd, L"FARDive");
SendMessage(statusbar, SB_SETTEXT, 0, (LPARAM) L"");
SetWindowText(hWnd, L"FARDive");
SendMessage(statusbar, SB_SETTEXT, 0, (LPARAM) L"");
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
@ -86,7 +86,7 @@ bool PopulateEntries(){
item.mask = LVIF_TEXT;
item.iItem = 0;
item.pszText = (LPTSTR) L"Test";
SendMessage(hList, LVM_SETITEMCOUNT, EntryCount, LVSICF_NOSCROLL);
SendMessage(hList, LVM_SETITEMCOUNT, EntryCount, 0x00000002);
SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM) &item);
wchar_t buffer[17];
@ -162,7 +162,7 @@ bool SetWorkspace(){
RECT ClientRect;
GetClientRect(hWnd, &ClientRect);
hList = CreateWindowEx(WS_EX_CLIENTEDGE | LVS_EX_DOUBLEBUFFER | WS_EX_COMPOSITED, WC_LISTVIEW, NULL, LVS_LIST | LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE,
hList = CreateWindowEx(WS_EX_CLIENTEDGE | 0x00010000 | WS_EX_COMPOSITED, WC_LISTVIEW, NULL, LVS_LIST | LVS_SHOWSELALWAYS | WS_CHILD | WS_VISIBLE,
5, 5, 192, ClientRect.bottom-statusbarheight-10, hWnd, NULL, NULL, NULL);
SetWindowTheme(hList, L"Explorer", NULL);

View file

@ -13,6 +13,7 @@
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define IFF2HTML
#include <stdio.h>
#include <stdint.h>
@ -58,6 +59,9 @@ int main(int argc, char *argv[]){
unsigned chunk = 0;
IFFFile * IFFFileInfo;
IFFChunkNode * ChunkNode;
IFF_TREETABLENODE *currentNode; /* for iterating through BHAVs */
char *dummyValue;
char *resourceDir;
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
printf("Usage: iff2html [-f] infile (outfile)\n"
@ -94,7 +98,17 @@ int main(int argc, char *argv[]){
/****
** Open the file and read in entire contents to memory
*/
resourceDir = (char *)malloc(sizeof(char) * 255);
dummyValue = (char *)malloc(sizeof(char) * 255);
strcpy(resourceDir+2, InFile);
*strchr(resourceDir+2, (int)'.') = '\0';
resourceDir[0] = '.';
resourceDir[1] = '/';
CreateDirectory(resourceDir, NULL);
printf(resourceDir);
fflush(stdout);
hFile = CreateFile(InFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
hFile = fopen(InFile, "rb");
if(hFile == NULL){
@ -119,6 +133,9 @@ int main(int argc, char *argv[]){
return -1;
}
fclose(hFile);
/****
** Load header information
@ -129,7 +146,7 @@ int main(int argc, char *argv[]){
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
return -1;
}
if(!iff_read_header(IFFFileInfo, IFFData, FileSize)){
if(!iff_read_header(IFFFileInfo, IFFData, FileSize, InFile)){
printf("%sNot a valid IFF file.", "iff2html: error: ");
return -1;
}
@ -150,7 +167,7 @@ int main(int argc, char *argv[]){
free(IFFData);
for(chunk = 1, ChunkNode = IFFFileInfo->FirstChunk; ChunkNode; ChunkNode = ChunkNode->NextChunk, chunk++)
iff_parse_chunk(&ChunkNode->Chunk, ChunkNode->Chunk.Data);
iff_parse_chunk(&ChunkNode->Chunk, ChunkNode->Chunk.Data, IFFFileInfo);
/****
@ -286,8 +303,8 @@ int main(int argc, char *argv[]){
!strcmp(ChunkNode->Chunk.Type, "FAMs") ||
!strcmp(ChunkNode->Chunk.Type, "TTAs") ){
IFF_STR * StringData = (IFF_STR*) ChunkNode->Chunk.FormattedData;
IFF_STR * StringData = (IFF_STR*) ChunkNode->Chunk.FormattedData;
/****
** STR# parsing
*/
@ -352,11 +369,11 @@ int main(int argc, char *argv[]){
fprintf(hFile, "</table>\n");
}
}
else if (!strcmp(ChunkNode->Chunk.Type, "BHAV") )
{
IFF_TREETABLE * TreeTableData = (IFF_TREETABLE*) ChunkNode->Chunk.FormattedData;
fprintf(hFile, "<table>\n");
else if (!strcmp(ChunkNode->Chunk.Type, "BHAV") )
{
IFF_TREETABLE * TreeTableData = (IFF_TREETABLE*) ChunkNode->Chunk.FormattedData;
fprintf(hFile, "<table>\n");
fprintf(hFile, "<tr><td>Stream Version:</td><td>");
switch(TreeTableData->StreamVersion){
case 0x8000: fprintf(hFile, "<tt>0x8000</tt> (0)"); break;
@ -366,58 +383,100 @@ int main(int argc, char *argv[]){
default: fprintf(hFile, "Unrecognized"); break;
}
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Tree Version:</td><td>");
fprintf(hFile, "<tr><td>Tree Version:</td><td>");
fprintf(hFile, "<tt>%-#10X</tt> (%u)", TreeTableData->TreeVersion, TreeTableData->TreeVersion);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Tree Type:</td><td>");
fprintf(hFile, "<tr><td>Tree Type:</td><td>");
fprintf(hFile, "<tt>%-#4X</tt> (%u)", TreeTableData->Type, TreeTableData->Type);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Number of Parameters:</td><td>");
fprintf(hFile, "<tr><td>Number of Parameters:</td><td>");
fprintf(hFile, "<tt>%u</tt>", TreeTableData->NumParams);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Number of Local Variables:</td><td>");
fprintf(hFile, "<tr><td>Number of Local Variables:</td><td>");
fprintf(hFile, "<tt>%u</tt>", TreeTableData->NumLocals);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Number of Tree Nodes:</td><td>");
fprintf(hFile, "<tr><td>Number of Tree Nodes:</td><td>");
fprintf(hFile, "<tt>%u</tt>", (TreeTableData->NodesEnd - TreeTableData->NodesBegin));
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "</table>\n");
if(TreeTableData->StreamVersion >= 0x8000 && TreeTableData->StreamVersion <= 0x8003)
{
{
fprintf(hFile, "<br />\n");
fprintf(hFile, "<table class=\"center\">\n");
fprintf(hFile, "<tr><th>Node ID</th><th>Primitive #</th><th>Transition True</th><th>Transition False</th><th>Parameter 0</th><th>Parameter 1</th><th>Parameter 2</th><th>Parameter 3</th></tr>\n");
IFF_TREETABLENODE *currentNode;
for (currentNode = TreeTableData->NodesBegin; currentNode != TreeTableData->NodesEnd; currentNode++)
{
fprintf(hFile, "<tr><td>%d</td>\n", (currentNode-TreeTableData->NodesBegin));
{
fprintf(hFile, "<tr><td>%d</td>\n", (currentNode-TreeTableData->NodesBegin));
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->PrimitiveNumber, currentNode->PrimitiveNumber);
if (currentNode->TransitionTrue < 253)
fprintf(hFile, "<td>%d (%-#4X)</td>\n", currentNode->TransitionTrue, currentNode->TransitionTrue);
else
fprintf(hFile, "<td>%s</td>\n", currentNode->TransitionTrue == 253 ? "error" : currentNode->TransitionTrue == 254 ? "true" : "false");
if (currentNode->TransitionFalse < 253)
fprintf(hFile, "<td>%d (%-#4X)</td>\n", currentNode->TransitionFalse, currentNode->TransitionFalse);
else
fprintf(hFile, "<td>%s</td>\n", currentNode->TransitionFalse == 253 ? "error" : currentNode->TransitionFalse == 254 ? "true" : "false");
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param0, currentNode->Parameters.Param0);
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param1, currentNode->Parameters.Param1);
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param2, currentNode->Parameters.Param2);
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param3, currentNode->Parameters.Param3);
if (currentNode->TransitionTrue < 253)
fprintf(hFile, "<td>%d (%-#4X)</td>\n", currentNode->TransitionTrue, currentNode->TransitionTrue);
else
fprintf(hFile, "<td>%s</td>\n", currentNode->TransitionTrue == 253 ? "error" : currentNode->TransitionTrue == 254 ? "true" : "false");
if (currentNode->TransitionFalse < 253)
fprintf(hFile, "<td>%d (%-#4X)</td>\n", currentNode->TransitionFalse, currentNode->TransitionFalse);
else
fprintf(hFile, "<td>%s</td>\n", currentNode->TransitionFalse == 253 ? "error" : currentNode->TransitionFalse == 254 ? "true" : "false");
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param0, currentNode->Parameters.Param0);
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param1, currentNode->Parameters.Param1);
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param2, currentNode->Parameters.Param2);
fprintf(hFile, "<td>%d (%-#6X)</td>\n", currentNode->Parameters.Param3, currentNode->Parameters.Param3);
}
fprintf(hFile, "</table>\n");
}
}
}
else if (!strcmp(ChunkNode->Chunk.Type, "SPR#") || !strcmp(ChunkNode->Chunk.Type, "SPR2"))
{
IFFSprite * Sprite = (IFFSprite*) ChunkNode->Chunk.FormattedData;
fprintf(hFile, "<table>\n");
fprintf(hFile, "<tr><td>Sprite Version:</td><td>");
fprintf(hFile, "<tt>%-#6X</tt>", Sprite->Version);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Sprite Type:</td><td>");
fprintf(hFile, "<tt>%s</tt>", ChunkNode->Chunk.Type);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "<tr><td>Number of Frames:</td><td>");
fprintf(hFile, "<tt>%u</tt>", Sprite->FrameCount);
fprintf(hFile, "</td></tr>\n");
fprintf(hFile, "</table>\n");
if(Sprite->Version >= 500 && Sprite->Version <= 1001)
{
fprintf(hFile, "<br />\n");
fprintf(hFile, "<table class=\"center\">\n");
fprintf(hFile, "<tr><th>Image</th><th>X Location</th><th>Y Location</th><th>Width</th><th>Height</th><th>Flag</th><th>Palette ID</th><th>Transparent Pixel</th></tr>\n");
for (i = 0; i < Sprite->FrameCount; i++)
{
fprintf(hFile, "<tr><td><img src=\"%s\" /></td>\n", Sprite->Frames[i]->filePath);
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->XLocation);
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->YLocation);
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->Width);
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->Height);
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->Flag);
fprintf(hFile, "<td>%d</td>\n", Sprite->Frames[i]->PaletteID);
fprintf(hFile, "<td style=\"background-color:rgb(%d, %d, %d);\"></td>\n", Sprite->Frames[i]->TransparentPixel.R, Sprite->Frames[i]->TransparentPixel.G, Sprite->Frames[i]->TransparentPixel.B);
}
fprintf(hFile, "</table>\n");
}
}
else
{
fprintf(hFile, "The contents of this chunk could not be parsed.\n");
}
fprintf(hFile, "</div>\n\n");
}

View file

@ -0,0 +1,46 @@
int dummy = 0;
char *someString = &dummy;
someString += '(';
int currentParamIdx = 0;
unsigned short currentParam;
unsigned short param0;
do
{
currentParam = *(&param0 + currentParamIdx);
if (currentParamIdx > 0)
someString += ' ';
// Now, we iterate through the nibbles, starting at the high nibble and working our way down
int shiftingAmountForCurrentNibble = 12;
do
{
char nibbleType = 0;
int currentNibble = (currentParam >> shiftingAmountForCurrentNibble) & 0xF;
if (currentNibble > 9)
{
if (currentNibble > 15) //((currentNibble - 10) > 5)
nibbleType = 120;
else
nibbleType = currentNibble + 55;
}
else
nibbleType = currentNibble + 48;
char *unk = &nibbleType;
char oldVal;
do
{
oldVal = *unk;
}
while (*unk)
bool outOfBounds = shiftingAmountForCurrentNibble - 4 < 0;
shiftingAmountForCurrentNibble -= 4;
}
while (!outOfBounds);
}
while (currentParamIdx < 4);
someString += ')';