diff --git a/Libraries/FileHandler/iff/spr.c b/Libraries/FileHandler/iff/spr.c new file mode 100644 index 0000000..3ec1532 --- /dev/null +++ b/Libraries/FileHandler/iff/spr.c @@ -0,0 +1,241 @@ +/* + FileHandler - General-purpose file handling library for Niotso + spr.c - Copyright (c) 2012 Niotso Project + Author(s): Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "iff.h" + +typedef struct { + const uint8_t * StartPos; + const uint8_t * Buffer; + size_t TotalSize; + size_t Size; + uint8_t Endian; /* 0 = little, 1 = big */ +} bytestream; + +static unsigned read_uint32xe(bytestream * b){ + if(b->Size >= 4){ + unsigned value = (b->Endian == 0) ? read_uint32le(b->Buffer) : read_uint32be(b->Buffer); + b->Buffer += 4; + b->Size -= 4; + return value; + } + return 0; +} + +static unsigned read_uint16xe(bytestream * b){ + if(b->Size >= 2){ + unsigned value = (b->Endian == 0) ? read_uint16le(b->Buffer) : read_uint16be(b->Buffer); + b->Buffer += 2; + b->Size -= 2; + return value; + } + return 0; +} + +static int skipbytes(bytestream * b, uint32_t bytes){ + if(b->Size < bytes) return 0; + b->Buffer += bytes; b->Size -= bytes; + return 1; +} + +static int seekto(bytestream * b, uint32_t Position){ + if(Position > b->TotalSize) return 0; + b->Buffer = b->StartPos + Position; + b->Size = b->TotalSize - Position; + return 1; +} + +int iff_parse_spr(IFFChunk * ChunkInfo, const uint8_t * Buffer){ + IFFSpriteList *SpriteList; + unsigned ChunkSize = ChunkInfo->Size - 76; + bytestream b; + unsigned i; + + b.StartPos = Buffer; + b.Buffer = Buffer; + b.TotalSize = ChunkSize; + b.Size = ChunkSize; + b.Endian = 0; + + if(ChunkSize < 12) + return 0; + ChunkInfo->FormattedData = calloc(1, sizeof(IFFSpriteList)); + if(ChunkInfo->FormattedData == NULL) + return 0; + SpriteList = ChunkInfo->FormattedData; + + if((Buffer[0]|Buffer[1]) == 0) b.Endian++; /* Big endian */ + SpriteList->Version = read_uint32xe(&b); + SpriteList->SpriteCount = read_uint32xe(&b); + SpriteList->PaletteID = read_uint32xe(&b); + if(SpriteList->Version < 502 || (SpriteList->Version > 505 && SpriteList->Version != 1001)) + return 0; + if(SpriteList->SpriteCount == 0) + return 1; + + SpriteList->Sprites = calloc(SpriteList->SpriteCount, sizeof(IFFSprite)); + if(SpriteList->Sprites == NULL) + return 0; + + /* Skip past the offset table */ + if(SpriteList->SpriteCount > UINT_MAX/4 || !skipbytes(&b, SpriteList->SpriteCount*4)) + return 0; + + for(i=0; iSpriteCount; i++){ + IFFSprite * Sprite = &SpriteList->Sprites[i]; + unsigned SpriteSize = 0; + unsigned row = 0; + + if(SpriteList->Version != 1001){ + seekto(&b, 12 + 4*i); + if(!seekto(&b, read_uint32xe(&b))) + return 0; + SpriteSize = b.Size; + }else + seekto(&b, b.Buffer - b.StartPos); /* Update b.Size */ + + if(b.Size < ((SpriteList->Version == 1001) ? 18 : 10)) + return 0; + if(SpriteList->Version == 1001){ + if(read_uint32xe(&b) != 1001) + return 0; + SpriteSize = read_uint32xe(&b); + if(SpriteSize > b.Size || SpriteSize < 10) + return 0; + } + Sprite->Reserved = read_uint32xe(&b); + Sprite->Height = read_uint16xe(&b); + Sprite->Width = read_uint16xe(&b); + if(Sprite->Reserved != 0 || Sprite->Height == 0 || Sprite->Width == 0 || Sprite->Height > UINT_MAX/Sprite->Width/2) + return 0; + Sprite->IndexData = calloc(Sprite->Height*Sprite->Width, 2); + if(Sprite->IndexData == NULL) + return 0; + + while(1){ + /* Row command: valid commands are 0, 4, 5, and 9 */ + uint8_t Command, Count; + if(SpriteSize < 2) + return 0; + + Command = *(b.Buffer++); + Count = *(b.Buffer++); + SpriteSize -= 2; + + if(Command == 0){ + /* Do nothing */ + }else if(Command == 4){ + /* Pixel command: valid commands are 1, 2, and 3 */ + unsigned pixel = 0; + + if(row == Sprite->Height || Count < 2 || (Count -= 2) > SpriteSize || Count%2 != 0) + return 0; + SpriteSize -= Count; + while(Count){ + uint8_t PixelCommand, PixelCount; + if(Count < 2) + return 0; + + PixelCommand = *(b.Buffer++); + PixelCount = *(b.Buffer++); + Count -= 2; + + if(PixelCommand == 1){ + /* Leave pixels as transparent */ + if(PixelCount > Sprite->Width - pixel) + return 0; + pixel += PixelCount; + }else if(PixelCommand == 2){ + /* Set next n pixels to shared palette index */ + uint8_t PaletteIndex; + if(PixelCount > Sprite->Width - pixel || Count < 2) + return 0; + + PaletteIndex = *(b.Buffer++); + b.Buffer++; /* Padding byte */ + Count -= 2; + + while(PixelCount--){ + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = PaletteIndex; + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; + pixel++; + } + }else if(PixelCommand == 3){ + /* Set next n pixels to n palette indices */ + int padding = PixelCount%2; + if(PixelCount > Sprite->Width - pixel || PixelCount + padding > Count) + return 0; + Count -= PixelCount + padding; + + while(PixelCount--){ + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 0] = *(b.Buffer++); + Sprite->IndexData[(Sprite->Width*row + pixel)*2 + 1] = 0xFF; + pixel++; + } + if(padding) b.Buffer++; /* Padding byte */ + }else return 0; + } + row++; + }else if(Command == 5){ + /* End marker */ + break; + }else if(Command == 9){ + /* Leave rows as transparent */ + if(Count > Sprite->Height - row) + return 0; + row += Count; + }else return 0; + } + } + + return 1; +} + +void iff_free_spr(void * FormattedData){ + IFFSpriteList *SpriteList = FormattedData; + if(SpriteList->Sprites){ + unsigned s; + for(s=0; sSpriteCount; s++){ + IFFSprite *Sprite = &SpriteList->Sprites[s]; + free(Sprite->IndexData); + free(Sprite->BGRA32Data); + } + free(SpriteList->Sprites); + } +} + +int iff_depalette(IFFSprite * Sprite, const IFFPalette * Palette){ + unsigned PixelCount = Sprite->Width*Sprite->Height; + unsigned i; + + Sprite->BGRA32Data = malloc(PixelCount*4); + if(Sprite->BGRA32Data == NULL) return 0; + + for(i=0; iIndexData[2*i + 0]; + if(Index >= Palette->ColorCount){ + free(Sprite->BGRA32Data); + return 0; + } + Sprite->BGRA32Data[4*i + 0] = Palette->Data[3*Index + 2]; + Sprite->BGRA32Data[4*i + 1] = Palette->Data[3*Index + 1]; + Sprite->BGRA32Data[4*i + 2] = Palette->Data[3*Index + 0]; + Sprite->BGRA32Data[4*i + 3] = Sprite->IndexData[2*i + 1]; + } + + return 1; +} \ No newline at end of file diff --git a/Tools/CMakeLists.txt b/Tools/CMakeLists.txt index 2681bdf..54f7fde 100644 --- a/Tools/CMakeLists.txt +++ b/Tools/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(FARDive) add_subdirectory(hitutils) -add_subdirectory(iff2html) \ No newline at end of file +add_subdirectory(iff2html) +add_subdirectory(tsoscan) \ No newline at end of file diff --git a/Tools/iff2html/image.c b/Tools/iff2html/image.c new file mode 100644 index 0000000..c9e9bee --- /dev/null +++ b/Tools/iff2html/image.c @@ -0,0 +1,136 @@ +/* + iff2html - iff web page description generator + image.c - Copyright (c) 2012 Niotso Project + Author(s): Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite * Sprite, size_t * Width, size_t * Height){ + FILE * hFile; + png_structp png_ptr; + png_infop info_ptr; + png_bytep * row_pointers; + unsigned i; + + struct { + size_t Width; + size_t Height; + uint8_t * Data; + } Image; + + if(ChunkData){ + /* BMP_ or FBMP chunk */ + bmpheader_t BMPHeader; + + if(!bmp_read_header(&BMPHeader, ChunkData->Data, ChunkData->Size - 76)) + return 0; + + Image.Data = malloc(BMPHeader.DecompressedSize); + if(Image.Data == NULL) + return 0; + if(!bmp_read_data(&BMPHeader, ChunkData->Data, Image.Data)){ + free(Image.Data); + return 0; + } + + Image.Width = BMPHeader.biWidth; + Image.Height = BMPHeader.biHeight; + + row_pointers = malloc(Image.Height * sizeof(png_bytep)); + if(row_pointers == NULL){ + free(Image.Data); + return 0; + } + for(i=0; iWidth; + Image.Height = Sprite->Height; + Image.Data = Sprite->BGRA32Data; + } + + row_pointers = malloc(Image.Height * sizeof(png_bytep)); + if(row_pointers == NULL){ + if(ChunkData) free(Image.Data); + return 0; + } + for(i=0; i + Author(s): Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +int WritePNG(const char * OutName, const IFFChunk * ChunkData, const IFFSprite * Sprite, size_t * Width, size_t * Height); \ No newline at end of file diff --git a/Tools/tsoscan/CMakeLists.txt b/Tools/tsoscan/CMakeLists.txt new file mode 100644 index 0000000..fdb1cd5 --- /dev/null +++ b/Tools/tsoscan/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) +project(tsoscan) + +set(TSOSCAN_SOURCES + tsoscan.c + cmd.c + stats.c +) + +include_directories(${CMAKE_SOURCE_DIR}/Libraries/FileHandler) + +add_executable(tsoscan ${TSOSCAN_SOURCES}) +target_link_libraries(tsoscan iff_static) \ No newline at end of file diff --git a/Tools/tsoscan/cmd.c b/Tools/tsoscan/cmd.c new file mode 100644 index 0000000..1e5d204 --- /dev/null +++ b/Tools/tsoscan/cmd.c @@ -0,0 +1,67 @@ +/* + tsoscan - IFF statistical webpage generator + cmd.c - Copyright (c) 2012 Niotso Project + Author(s): Ahmed El-Mahdawy + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include +#include "tsoscan.h" + +CommandLineArgs* cmd_parse_args(int argc, char *argv[]){ + CommandLineArgs *CmdArgs = calloc(1, sizeof(CommandLineArgs)); + int i, InDirIndex = 0; + + if(CmdArgs == NULL) return 0; + + for(i=1; iInDirCount++; + } + if(CmdArgs->InDirCount > 0){ + CmdArgs->InDirs = calloc(CmdArgs->InDirCount, sizeof(char*)); + if(CmdArgs->InDirs == NULL) return 0; + } + + for(i=1; iForceWrite = 1; + }else if(!strcmp(argv[i], "-o")){ + if(i == argc-1 || CmdArgs->OutFile != NULL) + return NULL; + CmdArgs->OutFile = argv[++i]; + }else{ + CmdArgs->InDirs[InDirIndex] = argv[i]; + InDirIndex++; + } + } + + return CmdArgs; +} + +void cmd_delete(CommandLineArgs *args){ + unsigned i; + + if(args == NULL) return; + if(args->InDirs != NULL){ + for(i=0; iInDirCount; i++) + free(args->InDirs[i]); + free(args->InDirs); + } + free(args->OutFile); + free(args); +} \ No newline at end of file diff --git a/Tools/tsoscan/stats.c b/Tools/tsoscan/stats.c new file mode 100644 index 0000000..76792c0 --- /dev/null +++ b/Tools/tsoscan/stats.c @@ -0,0 +1,111 @@ +/* + tsoscan - IFF statistical webpage generator + stats.c - Copyright (c) 2012 Niotso Project + Author(s): Ahmed El-Mahdawy + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include +#include +#include "tsoscan.h" + +IFFStats* stats_create(){ + IFFStats *stats = calloc(1, sizeof(IFFStats)); + if (stats == NULL) return NULL; + stats->AverageChunkCount = -1; + return stats; +} + +int stats_version_increment(IFFStats *stats, char *type, unsigned version){ + ChunkStats *chunk = NULL; + VersionInfo *verinfo = NULL; + unsigned i; + + if(stats == NULL) return 0; + if(type == NULL) return 0; + + for(i=0; iChunkTypeCount; i++){ + if(!strcmp(stats->ChunkTypes[i].Type, type)){ + chunk = stats->ChunkTypes+i; + if(chunk == NULL) return 0; + } + } + if(chunk == NULL){ + stats->ChunkTypes = realloc(stats->ChunkTypes, ++(stats->ChunkTypeCount)*sizeof(ChunkStats)); + if(stats->ChunkTypes == NULL) return 0; + chunk = stats->ChunkTypes + stats->ChunkTypeCount - 1; + memset(chunk, 0, sizeof(ChunkStats)); + strcpy(chunk->Type, type); + } + chunk->ChunkCount++; + + for(i=0; iVersionCount; i++){ + if(chunk->Versions[i].Version == version){ + verinfo = chunk->Versions+i; + if(verinfo == NULL) return 0; + } + } + if(verinfo == NULL){ + chunk->Versions = realloc(chunk->Versions, ++(chunk->VersionCount)*sizeof(VersionInfo)); + if(chunk->Versions == NULL) return 0; + verinfo = chunk->Versions + chunk->VersionCount - 1; + memset(verinfo, 0, sizeof(VersionInfo)); + verinfo->Version = version; + } + verinfo->Count++; + + return 1; +} + +unsigned stats_get_version(char *type, uint8_t *data){ + /* I could've used iff_parse_chunk instead to determine chunk versions, but this + would be unnecessarily slow and would require all chunk parsers to be written, + defeating the purpose of this tool. */ + + if(!strcmp(type, "STR#") || !strcmp(type, "CTSS") || !strcmp(type, "FAMs") || + !strcmp(type, "TTAs") || !strcmp(type, "CST") || !strcmp(type, "BHAV") || + !strcmp(type, "DGRP") || !strcmp(type, "POSI")) + return read_uint16le(data); + + if(!strcmp(type, "FCNS") || !strcmp(type, "OBJf") || !strcmp(type, "Optn") || + !strcmp(type, "Rcon") || !strcmp(type, "TPRP") || !strcmp(type, "SLOT") || + !strcmp(type, "TRCN") || !strcmp(type, "rsmp")) + return read_uint32le(data+4); + + if(!strcmp(type, "OBJD") || !strcmp(type, "PALT") || !strcmp(type, "SPR2")) + return read_uint32le(data); + + if(!strcmp(type, "TTAB")) + return read_uint16le(data+2); + + if(!strcmp(type, "SPR#")){ + if(data[0] == 0) return read_uint32be(data); + else return read_uint32le(data); + } + + return -1; +} + +void stats_delete(IFFStats *stats){ + unsigned i; + + if(stats == NULL) return; + if(stats->ChunkTypes != NULL){ + for(i=0; iChunkTypeCount; i++) + free(stats->ChunkTypes[i].Versions); + free(stats->ChunkTypes); + } + free(stats); +} \ No newline at end of file diff --git a/Tools/tsoscan/tsoscan.c b/Tools/tsoscan/tsoscan.c new file mode 100644 index 0000000..26c6e1e --- /dev/null +++ b/Tools/tsoscan/tsoscan.c @@ -0,0 +1,331 @@ +/* + tsoscan - IFF statistical webpage generator + tsoscan.c - Copyright (c) 2012 Niotso Project + Author(s): Ahmed El-Mahdawy + Fatbag + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include "tsoscan.h" + +void print_usage(){ + printf("Usage: tsoscan [-f] [-o outfile] indir1 [indir2 [...]]\n" + "Generate a statistical HTML page based on a number of IFF files.\n" + "Use -f to force overwriting without confirmation.\n" + "If outfile is unspecified, the output HTML page will be written to stats.html.\n" + "\n" + "Report bugs to .\n" + "tsoscan is maintained by the Niotso project.\n" + "Home page: \n"); +} + +int main(int argc, char *argv[]){ + CommandLineArgs *CmdArgs; + unsigned i, version, FileCount = 0; + char **Files = NULL; + IFFStats *Stats = stats_create(); + FILE *OutFile; + + if(Stats == NULL){ + printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR); + return -1; + } + + if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){ + print_usage(); + return 0; + } + + CmdArgs = cmd_parse_args(argc, argv); + if(CmdArgs == NULL || CmdArgs->InDirCount == 0){ + print_usage(); + return -1; + } + if(CmdArgs->OutFile == NULL){ + CmdArgs->OutFile = "stats.html"; + } + + /**** + ** List selected input directories + */ + + for(i=0; iInDirCount; i++){ + DIR *dir = opendir(CmdArgs->InDirs[i]); + struct dirent *entry; + unsigned DirStartIndex; + + if(dir == NULL){ + printf("%sUnable to open the specified directory '%s'. Skipping.\n", TSOSCAN_WARNING, CmdArgs->InDirs[i]); + continue; + } + + DirStartIndex = FileCount; + while((entry = readdir(dir)) != NULL){ + if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) + FileCount++; + } + rewinddir(dir); + Files = realloc(Files, FileCount*sizeof(char**)); + if(Files == NULL){ + printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR); + return -1; + } + + for(; DirStartIndexd_name, ".") && strcmp(entry->d_name, "..")){ + int dirlen = strlen(CmdArgs->InDirs[i]); + int pathlen = strlen(entry->d_name); + Files[DirStartIndex] = malloc(dirlen+pathlen+2); + if(Files[DirStartIndex] == NULL){ + printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR); + return -1; + } + + memcpy(Files[DirStartIndex], CmdArgs->InDirs[i], dirlen); + Files[DirStartIndex][dirlen] = PATH_SEP; + memcpy(Files[DirStartIndex]+dirlen+1, entry->d_name, pathlen); + Files[DirStartIndex][dirlen+pathlen+1] = '\0'; + + DirStartIndex++; + } + } + + closedir(dir); + } + + /**** + ** Load and parse IFF files + */ + + Stats->AverageChunkCount = -1; + + for(i=0; iFileCount++; + if(Stats->AverageChunkCount == -1){ + Stats->AverageChunkCount = iff->ChunkCount; + }else{ + Stats->AverageChunkCount += iff->ChunkCount; + Stats->AverageChunkCount /= 2; + } + + for(ChunkIndex = 0, ChunkData = iff->Chunks; ChunkIndex < iff->ChunkCount; ChunkIndex++, ChunkData++){ + unsigned version = stats_get_version(ChunkData->Type, ChunkData->Data); + if(!stats_version_increment(Stats, ChunkData->Type, version)){ + printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR); + return -1; + } + } + iff_delete(iff); + } + + /**** + ** Write output file + */ + + if(!CmdArgs->ForceWrite){ + OutFile = fopen(CmdArgs->OutFile, "rb"); + if(OutFile != NULL){ + char c; + fclose(OutFile); + printf("File \"%s\" exists. Continue anyway? (y/n) ", CmdArgs->OutFile); + c = getchar(); + if(c != 'y' && c != 'Y') + return -1; + } + } + OutFile = fopen(CmdArgs->OutFile, "wb"); + if(OutFile == NULL){ + printf("%sThe output file '%s' could not be opened for writing.", TSOSCAN_ERROR, CmdArgs->OutFile); + return -1; + } + + fprintf(OutFile, + "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "IFF Chunk Statistics (tsostats)\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "

IFF Chunk Statistics (tsostats)

\n"); + fprintf(OutFile, "
\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n", Stats->FileCount); + fprintf(OutFile, "\n", Stats->AverageChunkCount); + fprintf(OutFile, "
Number of IFF files:%u
Average chunk count:%.1f
\n"); + fprintf(OutFile, "
\n"); + + fprintf(OutFile, "
Contents – %u chunk types
\n", Stats->ChunkTypeCount); + fprintf(OutFile, "
    \n"); + for(i=0; iChunkTypeCount; i++) + fprintf(OutFile, "
  • %u %s
  • \n", i, i+1, Stats->ChunkTypes[i].Type); + fprintf(OutFile, "
\n"); + fprintf(OutFile, "
\n"); + fprintf(OutFile, "\n"); + + for(i=0; iChunkTypeCount; i++){ + ChunkStats *chunk = Stats->ChunkTypes+i; + + fprintf(OutFile, "

%u %s (Jump)

\n", i, i+1, Stats->ChunkTypes[i].Type, i); + fprintf(OutFile, "
\n"); + + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n", chunk->ChunkCount); + if(chunk->VersionCount == 1 && chunk->Versions[0].Version == (unsigned)-1) + fprintf(OutFile, "\n"); + else + fprintf(OutFile, "\n", chunk->VersionCount); + fprintf(OutFile, "
Number of occurrences:%u
Number of versions:N/A
Number of versions:%u
\n"); + + if(chunk->VersionCount > 1 || + (chunk->VersionCount == 1 && chunk->Versions[0].Version != (unsigned)-1)){ + fprintf(OutFile, "\n"); + fprintf(OutFile, "\n"); + for(version=0; versionVersionCount; version++){ + VersionInfo *verinfo = chunk->Versions+version; + float percentage = (float)verinfo->Count / chunk->ChunkCount * 100; + + fprintf(OutFile, "\n", + version+1, verinfo->Version, verinfo->Version, verinfo->Count, percentage); + } + fprintf(OutFile, "
VersionCount
%u%u (0x%x)%u (%.1f%%)
\n"); + } + + fprintf(OutFile, "
\n\n"); + } + + fprintf(OutFile, + "
This page was generated by the use of tsostats.
\n"); + fprintf(OutFile, "\n"); + fprintf(OutFile, ""); + fclose(OutFile); + + printf("Generated statistics based on %u IFF files.\n", Stats->FileCount); + cmd_delete(CmdArgs); + stats_delete(Stats); + return 0; +} \ No newline at end of file diff --git a/Tools/tsoscan/tsoscan.h b/Tools/tsoscan/tsoscan.h new file mode 100644 index 0000000..5f63eac --- /dev/null +++ b/Tools/tsoscan/tsoscan.h @@ -0,0 +1,65 @@ +/* + tsoscan - IFF statistical webpage generator + tsoscan.h - Copyright (c) 2012 Niotso Project + Author(s): Ahmed El-Mahdawy + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include + +#define TSOSCAN_WARNING "tsoscan: warning: " +#define TSOSCAN_ERROR "tsoscan: error: " +#ifdef _WIN32 + #define PATH_SEP '\\' +#else + #define PATH_SEP '/' +#endif + +typedef struct CommandLineArgs_s +{ + int ForceWrite; + char * OutFile; + unsigned InDirCount; + char ** InDirs; +} CommandLineArgs; + +typedef struct VersionInfo_s +{ + unsigned Version; + unsigned Count; +} VersionInfo; + +typedef struct ChunkStats_s +{ + char Type[5]; + unsigned ChunkCount; + unsigned VersionCount; + VersionInfo * Versions; +} ChunkStats; + +typedef struct IFFStats_s +{ + unsigned FileCount; + float AverageChunkCount; + unsigned ChunkTypeCount; + ChunkStats * ChunkTypes; +} IFFStats; + +CommandLineArgs* cmd_parse_args(int argc, char *argv[]); +void cmd_delete(CommandLineArgs *args); + +IFFStats* stats_create(); +int stats_version_increment(IFFStats *stats, char *type, unsigned version); +unsigned stats_get_version(char *type, uint8_t *data); +void stats_delete(IFFStats *stats); \ No newline at end of file diff --git a/Tools/tsoscan/tsoscan.txt b/Tools/tsoscan/tsoscan.txt deleted file mode 100644 index e69de29..0000000