mirror of
https://github.com/simtactics/niotso.git
synced 2025-07-04 13:47:05 -04:00
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:
parent
7442579090
commit
cb751c0bb8
29 changed files with 692 additions and 1291 deletions
|
@ -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})
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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){
|
||||
|
|
|
@ -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 ¤tNode->Chunk;
|
||||
|
||||
currentNode = currentNode->NextChunk;
|
||||
}
|
||||
while (currentNode != IFFFileInfo->LastChunk && currentNode != NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
Loading…
Add table
Add a link
Reference in a new issue