Added Propeng's tsoscan, and removed old files from libpng and zlib

This commit is contained in:
Fatbag 2012-05-28 23:51:49 -05:00
parent 1f7061d98a
commit 67fa76c747
10 changed files with 985 additions and 1 deletions

View file

@ -0,0 +1,241 @@
/*
FileHandler - General-purpose file handling library for Niotso
spr.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Fatbag <X-Fi6@phppoll.org>
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; i<SpriteList->SpriteCount; 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; s<SpriteList->SpriteCount; 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; i<PixelCount; i++){
uint8_t Index = Sprite->IndexData[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;
}

View file

@ -1,3 +1,4 @@
add_subdirectory(FARDive)
add_subdirectory(hitutils)
add_subdirectory(iff2html)
add_subdirectory(iff2html)
add_subdirectory(tsoscan)

136
Tools/iff2html/image.c Normal file
View file

@ -0,0 +1,136 @@
/*
iff2html - iff web page description generator
image.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Fatbag <X-Fi6@phppoll.org>
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 <stdio.h>
#include <iff/iff.h>
#include <bmp/read_bmp.h>
#include <setjmp.h>
#include <libpng/png.h>
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; i<Image.Height; i++)
row_pointers[i] = Image.Data + (Image.Height-i-1)*Image.Width*3;
}else{
/* SPR# or SPR2 sprite */
Image.Width = Sprite->Width;
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<Image.Height; i++)
row_pointers[i] = Image.Data + (Image.Height-i-1)*Image.Width*((ChunkData)?3:4);
/****
** PNG handling
*/
/* Initialization */
hFile = fopen(OutName, "wb");
if(hFile == NULL){
free(row_pointers);
if(ChunkData) free(Image.Data);
return 0;
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png_ptr == NULL){
fclose(hFile);
free(row_pointers);
if(ChunkData) free(Image.Data);
return 0;
}
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL){
png_destroy_write_struct(&png_ptr, NULL);
fclose(hFile);
free(row_pointers);
if(ChunkData) free(Image.Data);
return 0;
}
if(setjmp(png_jmpbuf(png_ptr))){
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(hFile);
free(row_pointers);
if(ChunkData) free(Image.Data);
return 0;
}
png_init_io(png_ptr, hFile);
png_set_filter(png_ptr, 0, PNG_ALL_FILTERS);
png_set_compression_level(png_ptr, 9);
png_set_compression_mem_level(png_ptr, 9);
png_set_compression_window_bits(png_ptr, 15);
png_set_compression_buffer_size(png_ptr, 32768);
png_set_IHDR(png_ptr, info_ptr, Image.Width, Image.Height, 8, ChunkData ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(hFile);
free(row_pointers);
if(ChunkData){
free(Image.Data);
*Width = Image.Width;
*Height = Image.Height;
}
return 1;
}

19
Tools/iff2html/image.h Normal file
View file

@ -0,0 +1,19 @@
/*
iff2html - iff web page description generator
image.h - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Fatbag <X-Fi6@phppoll.org>
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);

View file

@ -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)

67
Tools/tsoscan/cmd.c Normal file
View file

@ -0,0 +1,67 @@
/*
tsoscan - IFF statistical webpage generator
cmd.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
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 <stdlib.h>
#include <string.h>
#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; i<argc; i++){
if(!strcmp(argv[i], "-o"))
i++;
else if(strcmp(argv[i], "-f") != 0)
CmdArgs->InDirCount++;
}
if(CmdArgs->InDirCount > 0){
CmdArgs->InDirs = calloc(CmdArgs->InDirCount, sizeof(char*));
if(CmdArgs->InDirs == NULL) return 0;
}
for(i=1; i<argc; i++){
if(!strcmp(argv[i], "-f")){
CmdArgs->ForceWrite = 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; i<args->InDirCount; i++)
free(args->InDirs[i]);
free(args->InDirs);
}
free(args->OutFile);
free(args);
}

111
Tools/tsoscan/stats.c Normal file
View file

@ -0,0 +1,111 @@
/*
tsoscan - IFF statistical webpage generator
stats.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
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 <stdlib.h>
#include <string.h>
#include <iff/iff.h>
#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; i<stats->ChunkTypeCount; 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; i<chunk->VersionCount; 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; i<stats->ChunkTypeCount; i++)
free(stats->ChunkTypes[i].Versions);
free(stats->ChunkTypes);
}
free(stats);
}

331
Tools/tsoscan/tsoscan.c Normal file
View file

@ -0,0 +1,331 @@
/*
tsoscan - IFF statistical webpage generator
tsoscan.c - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
Fatbag <X-Fi6@phppoll.org>
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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <iff/iff.h>
#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 <X-Fi6@phppoll.org>.\n"
"tsoscan is maintained by the Niotso project.\n"
"Home page: <http://www.niotso.org/>\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; i<CmdArgs->InDirCount; 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(; DirStartIndex<FileCount;){
entry = readdir(dir);
if(strcmp(entry->d_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; i<FileCount; i++){
FILE *file;
size_t FileSize;
uint8_t *data;
IFFFile *iff;
IFFChunk *ChunkData;
unsigned ChunkIndex;
printf("(%d/%d)\r", i+1, FileCount);
file = fopen(Files[i], "rb");
if(file == NULL){
printf("%sUnable to open the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
continue;
}
fseek(file, 0, SEEK_END);
FileSize = ftell(file);
fseek(file, 0, SEEK_SET);
data = malloc(FileSize);
if(data == NULL){
printf("%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
return -1;
}
if(!fread(data, FileSize, 1, file)){
printf("%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
free(data);
fclose(file);
continue;
}
fclose(file);
iff = iff_create();
if(iff == NULL){
printf("%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
return -1;
}
if(!iff_read_header(iff, data, FileSize) || !iff_enumerate_chunks(iff, data+64, FileSize-64)){
/* Skip non-IFF files silently */
free(data);
continue;
}
free(data);
Stats->FileCount++;
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,
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n");
fprintf(OutFile, "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\">\n");
fprintf(OutFile, "<head>\n");
fprintf(OutFile, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n");
fprintf(OutFile, "<meta http-equiv=\"Content-Style-Type\" content=\"text/css; charset=utf-8\" />\n");
fprintf(OutFile, "<meta http-equiv=\"Content-Language\" content=\"en\" />\n");
fprintf(OutFile, "<meta name=\"description\" content=\"tsostats\" />\n");
fprintf(OutFile, "<meta name=\"generator\" content=\"IFF Chunk Statistics (tsostats)\" />\n");
fprintf(OutFile, "<title>IFF Chunk Statistics (tsostats)</title>\n");
fprintf(OutFile, "<style type=\"text/css\" media=\"all\">\n");
fprintf(OutFile, "html, body {\n");
fprintf(OutFile, " background: #fff;\n");
fprintf(OutFile, " color: #000;\n");
fprintf(OutFile, " font-family: sans-serif;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "\n");
fprintf(OutFile, "a:link, a:visited, a:hover, a:active { color: #00f; }\n");
fprintf(OutFile, "a:link, a:visited { text-decoration: none; }\n");
fprintf(OutFile, "a:hover, a:active { text-decoration: underline; }\n");
fprintf(OutFile, "\n");
fprintf(OutFile, "#attributes {\n");
fprintf(OutFile, " border-left: 2px solid #888; padding-left: 4px; margin-bottom: 1em;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "\n");
fprintf(OutFile, "#toc {\n");
fprintf(OutFile, " display: table-cell;\n");
fprintf(OutFile, " margin-top: 1em;\n");
fprintf(OutFile, " background: #eee; border: 1px solid #bbb;\n");
fprintf(OutFile, " padding: .25em;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "#toc div {\n");
fprintf(OutFile, " border-bottom: 1px solid #aaa;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "#toc ul {\n");
fprintf(OutFile, " list-style-type: none;\n");
fprintf(OutFile, " padding: 0;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "ul ul {\n");
fprintf(OutFile, " padding: 2em;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "\n");
fprintf(OutFile, "h2 {\n");
fprintf(OutFile, " border-bottom: 1px solid #888;\n");
fprintf(OutFile, " margin: 2em 0 0.25em 0;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "h2 a {\n");
fprintf(OutFile, " font-size: 9pt;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "\n");
fprintf(OutFile, "table {\n");
fprintf(OutFile, " border: 1px #aaa solid;\n");
fprintf(OutFile, " border-collapse: collapse;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "th, td {\n");
fprintf(OutFile, " border: 1px #aaa solid;\n");
fprintf(OutFile, " padding: 0.2em;\n");
fprintf(OutFile, " white-space: pre-wrap;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "\n");
fprintf(OutFile, ".center {\n");
fprintf(OutFile, " margin: auto auto;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "\n");
fprintf(OutFile, "#footer {\n");
fprintf(OutFile, " margin-top: 2em;\n");
fprintf(OutFile, " padding-bottom: 0.5em;\n");
fprintf(OutFile, " text-align: center;\n");
fprintf(OutFile, "}\n");
fprintf(OutFile, "</style>\n");
fprintf(OutFile, "</head>\n");
fprintf(OutFile, "<body>\n");
fprintf(OutFile, "<h1>IFF Chunk Statistics (tsostats)</h1>\n");
fprintf(OutFile, "<div id=\"attributes\">\n");
fprintf(OutFile, "<table>\n");
fprintf(OutFile, "<tr><td>Number of IFF files:</td><td>%u</td></tr>\n", Stats->FileCount);
fprintf(OutFile, "<tr><td>Average chunk count:</td><td>%.1f</td></tr>\n", Stats->AverageChunkCount);
fprintf(OutFile, "</table>\n");
fprintf(OutFile, "</div>\n");
fprintf(OutFile, "<div id=\"toc\"><div><b>Contents</b> &ndash; %u chunk types</div>\n", Stats->ChunkTypeCount);
fprintf(OutFile, "<ul>\n");
for(i=0; i<Stats->ChunkTypeCount; i++)
fprintf(OutFile, "<li><a href=\"#type%u\">%u %s</a></li>\n", i, i+1, Stats->ChunkTypes[i].Type);
fprintf(OutFile, "</ul>\n");
fprintf(OutFile, "</div>\n");
fprintf(OutFile, "\n");
for(i=0; i<Stats->ChunkTypeCount; i++){
ChunkStats *chunk = Stats->ChunkTypes+i;
fprintf(OutFile, "<h2 id=\"type%u\">%u %s <a href=\"#type%u\">(Jump)</a></h2>\n", i, i+1, Stats->ChunkTypes[i].Type, i);
fprintf(OutFile, "<div>\n");
fprintf(OutFile, "<table>\n");
fprintf(OutFile, "<tr><td>Number of occurrences:</td><td>%u</td></tr>\n", chunk->ChunkCount);
if(chunk->VersionCount == 1 && chunk->Versions[0].Version == (unsigned)-1)
fprintf(OutFile, "<tr><td>Number of versions:</td><td>N/A</td></tr>\n");
else
fprintf(OutFile, "<tr><td>Number of versions:</td><td>%u</td></tr>\n", chunk->VersionCount);
fprintf(OutFile, "</table>\n");
if(chunk->VersionCount > 1 ||
(chunk->VersionCount == 1 && chunk->Versions[0].Version != (unsigned)-1)){
fprintf(OutFile, "<table class=\"center\">\n");
fprintf(OutFile, "<tr><th></th><th>Version</th><th>Count</th></tr>\n");
for(version=0; version<chunk->VersionCount; version++){
VersionInfo *verinfo = chunk->Versions+version;
float percentage = (float)verinfo->Count / chunk->ChunkCount * 100;
fprintf(OutFile, "<tr><td>%u</td><td>%u (<tt>0x%x</tt>)</td><td>%u (%.1f%%)</td></tr>\n",
version+1, verinfo->Version, verinfo->Version, verinfo->Count, percentage);
}
fprintf(OutFile, "</table>\n");
}
fprintf(OutFile, "</div>\n\n");
}
fprintf(OutFile,
"<div id=\"footer\">This page was generated by the use of <a href=\"http://www.niotso.org/\">tsostats</a>.</div>\n");
fprintf(OutFile, "</body>\n");
fprintf(OutFile, "</html>");
fclose(OutFile);
printf("Generated statistics based on %u IFF files.\n", Stats->FileCount);
cmd_delete(CmdArgs);
stats_delete(Stats);
return 0;
}

65
Tools/tsoscan/tsoscan.h Normal file
View file

@ -0,0 +1,65 @@
/*
tsoscan - IFF statistical webpage generator
tsoscan.h - Copyright (c) 2012 Niotso Project <http://niotso.org/>
Author(s): Ahmed El-Mahdawy <aa.mahdawy.10@gmail.com>
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 <stdint.h>
#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);