mirror of
https://github.com/simtactics/niotso.git
synced 2025-03-22 10:52:20 +00:00
Added rtti-reader and made various cleanups, switching to Shutdown_M for error handling
This commit is contained in:
parent
5444c9aea6
commit
6dddbd2efa
25 changed files with 771 additions and 194 deletions
|
@ -45,9 +45,9 @@ uint8_t * ReadFile(const char * Filename){
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytestransferred = fread(InData, 1, FileSize, hFile);
|
size_t bytestransferred = fread(InData, 1, FileSize, hFile);
|
||||||
|
fclose(hFile);
|
||||||
if(bytestransferred != FileSize){
|
if(bytestransferred != FileSize){
|
||||||
free(InData);
|
free(InData);
|
||||||
fclose(hFile);
|
|
||||||
File::Error = FERR_READ;
|
File::Error = FERR_READ;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,9 +68,9 @@ struct Sound_t {
|
||||||
|
|
||||||
namespace File {
|
namespace File {
|
||||||
|
|
||||||
inline unsigned GetFileSize(FILE * hFile){
|
inline size_t GetFileSize(FILE * hFile){
|
||||||
fseek(hFile, 0, SEEK_END);
|
fseek(hFile, 0, SEEK_END);
|
||||||
unsigned FileSize = ftell(hFile);
|
size_t FileSize = ftell(hFile);
|
||||||
fseek(hFile, 0, SEEK_SET);
|
fseek(hFile, 0, SEEK_SET);
|
||||||
return FileSize;
|
return FileSize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ static int fill_mem_input_buffer(j_decompress_ptr cinfo){
|
||||||
}
|
}
|
||||||
static void skip_input_data(j_decompress_ptr cinfo, long bytes)
|
static void skip_input_data(j_decompress_ptr cinfo, long bytes)
|
||||||
{
|
{
|
||||||
struct jpeg_source_mgr * src = cinfo->src;
|
jpeg_source_mgr * src = cinfo->src;
|
||||||
|
|
||||||
if(bytes > (long) src->bytes_in_buffer){
|
if(bytes > (long) src->bytes_in_buffer){
|
||||||
ERREXIT(cinfo, JERR_FILE_READ);
|
ERREXIT(cinfo, JERR_FILE_READ);
|
||||||
|
|
|
@ -34,7 +34,7 @@ enum {
|
||||||
|
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
int profile = 0, overwrite = 0;
|
int profile = 0, overwrite = 0;
|
||||||
char infile[256] = "", outdirectory[256] = "";
|
const char * InFile = "", * OutDirectory;
|
||||||
FILE * hFile;
|
FILE * hFile;
|
||||||
size_t ArchiveSize;
|
size_t ArchiveSize;
|
||||||
uint8_t * ArchiveData;
|
uint8_t * ArchiveData;
|
||||||
|
@ -66,7 +66,7 @@ int main(int argc, char *argv[]){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=1; !infile[0] && i != argc-1; i++){
|
for(i=1; !InFile[0] && i != argc-1; i++){
|
||||||
/* Match for options */
|
/* Match for options */
|
||||||
if(!profile){
|
if(!profile){
|
||||||
if(!strcmp(argv[i], "-ts1")){ profile = profile_ts1; continue; }
|
if(!strcmp(argv[i], "-ts1")){ profile = profile_ts1; continue; }
|
||||||
|
@ -82,18 +82,18 @@ int main(int argc, char *argv[]){
|
||||||
}
|
}
|
||||||
/* Not an option */
|
/* Not an option */
|
||||||
if(!strcmp(argv[i], "-")){
|
if(!strcmp(argv[i], "-")){
|
||||||
printf("%sReading from standard input is not yet implemented.", "farextract: error: ");
|
fprintf(stderr, "%sReading from standard input is not yet implemented.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strcpy(infile, argv[i]);
|
InFile = argv[i];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* We're left with the out directory */
|
/* We're left with the out directory */
|
||||||
if(!infile[0]){
|
if(!InFile[0]){
|
||||||
printf("%sReading from standard input is not yet implemented.", "farextract: error: ");
|
fprintf(stderr, "%sReading from standard input is not yet implemented.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
strcpy(outdirectory, argv[i]);
|
OutDirectory = argv[i];
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Handle profile settings
|
** Handle profile settings
|
||||||
|
@ -107,26 +107,26 @@ int main(int argc, char *argv[]){
|
||||||
** Open the file and read in the entire contents to memory
|
** Open the file and read in the entire contents to memory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hFile = fopen(infile, "rb");
|
hFile = fopen(InFile, "rb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL){
|
||||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "farextract: error: ");
|
fprintf(stderr, "%sThe specified input file does not exist or could not be opened for reading.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fseek(hFile, 0, SEEK_END);
|
fseek(hFile, 0, SEEK_END);
|
||||||
ArchiveSize = ftell(hFile);
|
ArchiveSize = ftell(hFile);
|
||||||
if(ArchiveSize < 24){
|
if(ArchiveSize < 24){
|
||||||
printf("%sNot a valid archive.", "farextract: error: ");
|
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fseek(hFile, 0, SEEK_SET);
|
fseek(hFile, 0, SEEK_SET);
|
||||||
|
|
||||||
ArchiveData = malloc(ArchiveSize);
|
ArchiveData = malloc(ArchiveSize);
|
||||||
if(ArchiveData == NULL){
|
if(ArchiveData == NULL){
|
||||||
printf("%sMemory for this archive could not be allocated.", "farextract: error: ");
|
fprintf(stderr, "%sMemory for this archive could not be allocated.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!fread(ArchiveData, ArchiveSize, 1, hFile)){
|
if(fread(ArchiveData, 1, ArchiveSize, hFile) != ArchiveSize){
|
||||||
printf("%sThe input file could not be read.", "farextract: error: ");
|
fprintf(stderr, "%sThe input file could not be read.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fclose(hFile);
|
fclose(hFile);
|
||||||
|
@ -137,7 +137,7 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
ArchiveType = far_identify(ArchiveData, ArchiveSize);
|
ArchiveType = far_identify(ArchiveData, ArchiveSize);
|
||||||
if(ArchiveType == FAR_TYPE_INVALID){
|
if(ArchiveType == FAR_TYPE_INVALID){
|
||||||
printf("%sNot a valid archive.", "farextract: error: ");
|
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,11 +151,11 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
FARFile * FARFileInfo = far_create_archive(ArchiveType);
|
FARFile * FARFileInfo = far_create_archive(ArchiveType);
|
||||||
if(FARFileInfo == NULL){
|
if(FARFileInfo == NULL){
|
||||||
printf("%sMemory for this archive could not be allocated.", "farextract: error: ");
|
fprintf(stderr, "%sMemory for this archive could not be allocated.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!far_read_header(FARFileInfo, ArchiveData, ArchiveSize)){
|
if(!far_read_header(FARFileInfo, ArchiveData, ArchiveSize)){
|
||||||
printf("%sNot a valid archive.", "farextract: error: ");
|
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
if(!far_enumerate_entries(FARFileInfo, ArchiveData+FARFileInfo->IndexOffset,
|
if(!far_enumerate_entries(FARFileInfo, ArchiveData+FARFileInfo->IndexOffset,
|
||||||
ArchiveSize-FARFileInfo->IndexOffset, ArchiveSize)){
|
ArchiveSize-FARFileInfo->IndexOffset, ArchiveSize)){
|
||||||
printf("%sEntry data is corrupt.", "farextract: error: ");
|
fprintf(stderr, "%sEntry data is corrupt.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,9 +181,9 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
file++;
|
file++;
|
||||||
if(EntryNode->Entry.Filename)
|
if(EntryNode->Entry.Filename)
|
||||||
sprintf(destination, "%s/%s", outdirectory, EntryNode->Entry.Filename);
|
sprintf(destination, "%s/%s", OutDirectory, EntryNode->Entry.Filename);
|
||||||
else
|
else
|
||||||
sprintf(destination, "%s/%08x-%08x-%08x.dat", outdirectory,
|
sprintf(destination, "%s/%08x-%08x-%08x.dat", OutDirectory,
|
||||||
EntryNode->Entry.TypeID, EntryNode->Entry.GroupID, EntryNode->Entry.FileID);
|
EntryNode->Entry.TypeID, EntryNode->Entry.GroupID, EntryNode->Entry.FileID);
|
||||||
|
|
||||||
if(!far_read_entry_data(FARFileInfo, &(EntryNode->Entry), ArchiveData)){
|
if(!far_read_entry_data(FARFileInfo, &(EntryNode->Entry), ArchiveData)){
|
||||||
|
@ -233,7 +233,7 @@ int main(int argc, char *argv[]){
|
||||||
/* Persist file */
|
/* Persist file */
|
||||||
PersistFile * PersistInfo;
|
PersistFile * PersistInfo;
|
||||||
char destination[256];
|
char destination[256];
|
||||||
sprintf(destination, "%s/%s.out", outdirectory, infile);
|
sprintf(destination, "%s/%s.out", OutDirectory, InFile);
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Load header information
|
** Load header information
|
||||||
|
@ -241,11 +241,11 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
PersistInfo = far_create_persist();
|
PersistInfo = far_create_persist();
|
||||||
if(PersistInfo == NULL){
|
if(PersistInfo == NULL){
|
||||||
printf("%sMemory for this archive could not be allocated.", "farextract: error: ");
|
fprintf(stderr, "%sMemory for this archive could not be allocated.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!far_read_persist_header(PersistInfo, ArchiveData, ArchiveSize)){
|
if(!far_read_persist_header(PersistInfo, ArchiveData, ArchiveSize)){
|
||||||
printf("%sNot a valid archive.", "farextract: error: ");
|
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +255,7 @@ int main(int argc, char *argv[]){
|
||||||
printf("Extracting\n");
|
printf("Extracting\n");
|
||||||
BeginningTime = clock();
|
BeginningTime = clock();
|
||||||
if(!far_read_persist_data(PersistInfo, ArchiveData+18)){
|
if(!far_read_persist_data(PersistInfo, ArchiveData+18)){
|
||||||
printf("%sNot a valid archive.", "farextract: error: ");
|
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
EndingTime = clock();
|
EndingTime = clock();
|
||||||
|
@ -265,14 +265,14 @@ int main(int argc, char *argv[]){
|
||||||
if(hFile != NULL){
|
if(hFile != NULL){
|
||||||
/* File exists */
|
/* File exists */
|
||||||
fclose(hFile);
|
fclose(hFile);
|
||||||
printf("%sFile exists.", "farextract: error: ");
|
fprintf(stderr, "%sFile exists.", "farextract: error: ");
|
||||||
libfar_free(PersistInfo->DecompressedData);
|
libfar_free(PersistInfo->DecompressedData);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hFile = fopen(destination, "wb");
|
hFile = fopen(destination, "wb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL){
|
||||||
printf("%sCould not open.", "farextract: error: ");
|
fprintf(stderr, "%sCould not open.", "farextract: error: ");
|
||||||
libfar_free(PersistInfo->DecompressedData);
|
libfar_free(PersistInfo->DecompressedData);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,21 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "iff.h"
|
#include "iff.h"
|
||||||
|
|
||||||
int charmatches(char c, const char * filter){
|
static FILE * hFile = NULL;
|
||||||
|
static uint8_t * IFFData = NULL;
|
||||||
|
static IFFFile IFFFileInfo;
|
||||||
|
static int iffcreated = 0;
|
||||||
|
|
||||||
|
static void Shutdown_M(const char * Message){
|
||||||
|
fprintf(stderr, "iffexport: error: %s.", Message);
|
||||||
|
if(iffcreated)
|
||||||
|
iff_delete(&IFFFileInfo);
|
||||||
|
free(IFFData);
|
||||||
|
fclose(hFile);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int charmatches(char c, const char * filter){
|
||||||
while(*filter){
|
while(*filter){
|
||||||
if(c == *filter) return 1;
|
if(c == *filter) return 1;
|
||||||
filter++;
|
filter++;
|
||||||
|
@ -32,18 +46,15 @@ int charmatches(char c, const char * filter){
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
FILE * hFile;
|
|
||||||
int overwrite = 0;
|
int overwrite = 0;
|
||||||
char *InFile, *OutDirectory;
|
const char *InFile, *OutDirectory;
|
||||||
size_t FileSize;
|
size_t FileSize;
|
||||||
uint8_t * IFFData;
|
|
||||||
clock_t BeginningTime;
|
clock_t BeginningTime;
|
||||||
unsigned chunkcount, chunk;
|
unsigned chunkcount, chunk;
|
||||||
unsigned exported = 0;
|
unsigned exported = 0;
|
||||||
IFFFile IFFFileInfo;
|
|
||||||
IFFChunk * ChunkData;
|
IFFChunk * ChunkData;
|
||||||
|
|
||||||
if(argc == 1 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
if(argc < 3 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||||
printf("Usage: iffexport [-f] infile outdirectory\n"
|
printf("Usage: iffexport [-f] infile outdirectory\n"
|
||||||
"Export the resources of an EA IFF file.\n"
|
"Export the resources of an EA IFF file.\n"
|
||||||
"Use -f to force overwriting without confirmation.\n"
|
"Use -f to force overwriting without confirmation.\n"
|
||||||
|
@ -68,50 +79,39 @@ int main(int argc, char *argv[]){
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hFile = fopen(InFile, "rb");
|
hFile = fopen(InFile, "rb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL)
|
||||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "iffexport: error: ");
|
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fseek(hFile, 0, SEEK_END);
|
fseek(hFile, 0, SEEK_END);
|
||||||
FileSize = ftell(hFile);
|
FileSize = ftell(hFile);
|
||||||
if(FileSize < 24){
|
if(FileSize < 24)
|
||||||
printf("%sNot a valid IFF file.", "iffexport: error: ");
|
Shutdown_M("Not a valid IFF file");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fseek(hFile, 0, SEEK_SET);
|
fseek(hFile, 0, SEEK_SET);
|
||||||
|
|
||||||
IFFData = malloc(FileSize);
|
IFFData = malloc(FileSize);
|
||||||
if(IFFData == NULL){
|
if(IFFData == NULL)
|
||||||
printf("%sMemory for this file could not be allocated.", "iffexport: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
if(fread(IFFData, 1, FileSize, hFile) != FileSize)
|
||||||
}
|
Shutdown_M("The input file could not be read");
|
||||||
if(!fread(IFFData, FileSize, 1, hFile)){
|
fclose(hFile); hFile = NULL;
|
||||||
printf("%sThe input file could not be read.", "iffexport: error: ");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fclose(hFile);
|
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Load header information
|
** Load header information
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(!iff_create(&IFFFileInfo)){
|
if(!iff_create(&IFFFileInfo))
|
||||||
printf("%sMemory for this file could not be allocated.", "iffexport: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
iffcreated++;
|
||||||
}
|
if(!iff_read_header(&IFFFileInfo, IFFData, FileSize))
|
||||||
if(!iff_read_header(&IFFFileInfo, IFFData, FileSize)){
|
Shutdown_M("Not a valid IFF file");
|
||||||
printf("%sNot a valid IFF file.", "iffexport: error: ");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Load entry information
|
** Load entry information
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(!iff_enumerate_chunks(&IFFFileInfo, IFFData+64, FileSize-64)){
|
if(!iff_enumerate_chunks(&IFFFileInfo, IFFData+64, FileSize-64))
|
||||||
printf("%sChunk data is corrupt.", "iffexport: error: ");
|
Shutdown_M("Chunk data is corrupt");
|
||||||
return -1;
|
|
||||||
}
|
free(IFFData); IFFData = NULL;
|
||||||
|
|
||||||
chunkcount = IFFFileInfo.ChunkCount;
|
chunkcount = IFFFileInfo.ChunkCount;
|
||||||
printf("This IFF file contains %u chunks.\n\nExporting\n", chunkcount);
|
printf("This IFF file contains %u chunks.\n\nExporting\n", chunkcount);
|
||||||
|
@ -144,21 +144,19 @@ int main(int argc, char *argv[]){
|
||||||
if(hFile != NULL){
|
if(hFile != NULL){
|
||||||
/* File exists */
|
/* File exists */
|
||||||
char c;
|
char c;
|
||||||
fclose(hFile);
|
fclose(hFile); hFile = NULL;
|
||||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", destination);
|
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", destination);
|
||||||
c = getchar();
|
c = getchar();
|
||||||
if(c != 'y' && c != 'Y'){
|
if(c != 'y' && c != 'Y'){
|
||||||
printf("\nAborted.");
|
printf("\n");
|
||||||
return -1;
|
Shutdown_M("Aborted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
overwrite++;
|
overwrite++;
|
||||||
}
|
}
|
||||||
hFile = fopen(destination, "wb");
|
hFile = fopen(destination, "wb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL)
|
||||||
printf("%sThe output file could not be opened for writing.", "iffexport: error: ");
|
Shutdown_M("The output file could not be opened for writing");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fwrite(ChunkData->Data, 1, ChunkData->Size, hFile);
|
fwrite(ChunkData->Data, 1, ChunkData->Size, hFile);
|
||||||
fclose(hFile);
|
fclose(hFile);
|
||||||
|
|
||||||
|
@ -168,5 +166,7 @@ int main(int argc, char *argv[]){
|
||||||
printf("\nExported %u of %u chunks in %.2f seconds.", exported, chunkcount,
|
printf("\nExported %u of %u chunks in %.2f seconds.", exported, chunkcount,
|
||||||
((float) (clock() - BeginningTime))/CLOCKS_PER_SEC);
|
((float) (clock() - BeginningTime))/CLOCKS_PER_SEC);
|
||||||
|
|
||||||
|
iff_delete(&IFFFileInfo);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -26,9 +26,10 @@
|
||||||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||||
#endif
|
#endif
|
||||||
#ifndef write_int32
|
#ifndef write_int32
|
||||||
#define write_uint16(dest, src) \
|
#define write_uint16(dest, src) do {\
|
||||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||||
(dest)[1] = ((src)&0xFF00)>>(8*1)
|
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||||
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef round
|
#ifndef round
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FileHandler - General-purpose file handling library for Niotso
|
utkdecode.c - Copyright (c) 2011-2012 Fatbag <X-Fi6@phppoll.org>
|
||||||
utkdecode.c - Copyright (c) 2011-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
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
purpose with or without fee is hereby granted, provided that the above
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -24,22 +22,34 @@
|
||||||
#include "read_utk.h"
|
#include "read_utk.h"
|
||||||
|
|
||||||
#ifndef write_int32
|
#ifndef write_int32
|
||||||
#define write_uint32(dest, src) \
|
#define write_uint32(dest, src) do {\
|
||||||
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
||||||
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
||||||
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
||||||
(dest)[3] = ((src)&0xFF000000)>>(8*3)
|
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||||
#define write_uint16(dest, src) \
|
} while(0)
|
||||||
|
#define write_uint16(dest, src) do {\
|
||||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||||
(dest)[1] = ((src)&0xFF00)>>(8*1)
|
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||||
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static FILE * hFile = NULL;
|
||||||
|
static uint8_t * UTKData = NULL;
|
||||||
|
static uint8_t * WaveData = NULL;
|
||||||
|
|
||||||
|
static void Shutdown_M(const char * Message){
|
||||||
|
fprintf(stderr, "utkdecode: error: %s.", Message);
|
||||||
|
free(WaveData);
|
||||||
|
free(UTKData);
|
||||||
|
fclose(hFile);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
int overwrite = 0;
|
int overwrite = 0;
|
||||||
char *InFile, *OutFile;
|
const char *InFile, *OutFile;
|
||||||
FILE * hFile;
|
|
||||||
size_t FileSize;
|
size_t FileSize;
|
||||||
uint8_t * UTKData;
|
|
||||||
utkheader_t UTKHeader;
|
utkheader_t UTKHeader;
|
||||||
clock_t BeginningTime, EndingTime;
|
clock_t BeginningTime, EndingTime;
|
||||||
|
|
||||||
|
@ -69,55 +79,41 @@ int main(int argc, char *argv[]){
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hFile = fopen(InFile, "rb");
|
hFile = fopen(InFile, "rb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL)
|
||||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "utkdecode: error: ");
|
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fseek(hFile, 0, SEEK_END);
|
fseek(hFile, 0, SEEK_END);
|
||||||
FileSize = ftell(hFile);
|
FileSize = ftell(hFile);
|
||||||
if(FileSize < 24){
|
if(FileSize < 32)
|
||||||
printf("%sNot a valid UTK file.", "utkdecode: error: ");
|
Shutdown_M("Not a valid UTK file");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fseek(hFile, 0, SEEK_SET);
|
fseek(hFile, 0, SEEK_SET);
|
||||||
|
|
||||||
UTKData = malloc(FileSize);
|
UTKData = malloc(FileSize);
|
||||||
if(UTKData == NULL){
|
if(UTKData == NULL)
|
||||||
printf("%sMemory for this file could not be allocated.", "utkdecode: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
if(fread(UTKData, 1, FileSize, hFile) != FileSize)
|
||||||
}
|
Shutdown_M("The input file could not be read");
|
||||||
if(!fread(UTKData, FileSize, 1, hFile)){
|
fclose(hFile); hFile = NULL;
|
||||||
printf("%sThe input file could not be read.", "utkdecode: error: ");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fclose(hFile);
|
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Transcode the data from UTK to LPCM
|
** Transcode the data from UTK to LPCM
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(!utk_read_header(&UTKHeader, UTKData, FileSize)){
|
if(!utk_read_header(&UTKHeader, UTKData, FileSize))
|
||||||
printf("%sNot a valid UTK file.", "utkdecode: error: ");
|
Shutdown_M("Not a valid UTK file");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc >= 3){ /* Transcode */
|
if(argc >= 3){ /* Transcode */
|
||||||
uint8_t * WaveData = malloc(44+UTKHeader.dwOutSize);
|
WaveData = malloc(44+UTKHeader.dwOutSize);
|
||||||
if(WaveData == NULL){
|
if(WaveData == NULL)
|
||||||
printf("%sMemory for this file could not be allocated.", "utkdecode: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
UTKGenerateTables();
|
UTKGenerateTables();
|
||||||
|
|
||||||
BeginningTime = clock();
|
BeginningTime = clock();
|
||||||
if(!utk_decode(UTKData+32, WaveData+44, UTKHeader.Frames)){
|
if(!utk_decode(UTKData+32, WaveData+44, UTKHeader.Frames))
|
||||||
printf("%sMemory for this file could not be allocated.", "utkdecode: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
EndingTime = clock();
|
EndingTime = clock();
|
||||||
|
|
||||||
free(UTKData);
|
free(UTKData); UTKData = NULL;
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Write the Microsoft WAV header
|
** Write the Microsoft WAV header
|
||||||
|
@ -146,23 +142,22 @@ int main(int argc, char *argv[]){
|
||||||
if(hFile != NULL){
|
if(hFile != NULL){
|
||||||
/* File exists */
|
/* File exists */
|
||||||
char c;
|
char c;
|
||||||
fclose(hFile);
|
fclose(hFile); hFile = NULL;
|
||||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
||||||
c = getchar();
|
c = getchar();
|
||||||
if(c != 'y' && c != 'Y'){
|
if(c != 'y' && c != 'Y'){
|
||||||
printf("\nAborted.\n");
|
printf("\n");
|
||||||
return -1;
|
Shutdown_M("Aborted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hFile = fopen(OutFile, "wb");
|
hFile = fopen(OutFile, "wb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL)
|
||||||
printf("%sThe output file could not be opened for writing.", "utkdecode: error: ");
|
Shutdown_M("The output file could not be opened for writing");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Extracted %u bytes in %.2f seconds.\n", (unsigned) UTKHeader.dwOutSize,
|
printf("Extracted %u bytes in %.2f seconds.\n", (unsigned) UTKHeader.dwOutSize,
|
||||||
((float)(EndingTime - BeginningTime))/CLOCKS_PER_SEC);
|
((float)(EndingTime - BeginningTime))/CLOCKS_PER_SEC);
|
||||||
fwrite(WaveData, 1, 44+UTKHeader.dwOutSize, hFile);
|
fwrite(WaveData, 1, 44+UTKHeader.dwOutSize, hFile);
|
||||||
|
free(WaveData);
|
||||||
fclose(hFile);
|
fclose(hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,22 +22,34 @@
|
||||||
#include "read_xa.h"
|
#include "read_xa.h"
|
||||||
|
|
||||||
#ifndef write_int32
|
#ifndef write_int32
|
||||||
#define write_uint32(dest, src) \
|
#define write_uint32(dest, src) do {\
|
||||||
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
||||||
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
||||||
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
||||||
(dest)[3] = ((src)&0xFF000000)>>(8*3)
|
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||||
#define write_uint16(dest, src) \
|
} while(0)
|
||||||
|
#define write_uint16(dest, src) do {\
|
||||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||||
(dest)[1] = ((src)&0xFF00)>>(8*1)
|
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||||
|
} while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static FILE * hFile = NULL;
|
||||||
|
static uint8_t * XAData = NULL;
|
||||||
|
static uint8_t * WaveData = NULL;
|
||||||
|
|
||||||
|
static void Shutdown_M(const char * Message){
|
||||||
|
fprintf(stderr, "xadecode: error: %s.", Message);
|
||||||
|
free(WaveData);
|
||||||
|
free(XAData);
|
||||||
|
fclose(hFile);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]){
|
int main(int argc, char *argv[]){
|
||||||
int overwrite = 0;
|
int overwrite = 0;
|
||||||
char *InFile, *OutFile;
|
const char *InFile, *OutFile;
|
||||||
FILE * hFile;
|
|
||||||
size_t FileSize;
|
size_t FileSize;
|
||||||
uint8_t * XAData;
|
|
||||||
xaheader_t XAHeader;
|
xaheader_t XAHeader;
|
||||||
clock_t BeginningTime, EndingTime;
|
clock_t BeginningTime, EndingTime;
|
||||||
|
|
||||||
|
@ -67,53 +79,39 @@ int main(int argc, char *argv[]){
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hFile = fopen(InFile, "rb");
|
hFile = fopen(InFile, "rb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL)
|
||||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "xadecode: error: ");
|
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fseek(hFile, 0, SEEK_END);
|
fseek(hFile, 0, SEEK_END);
|
||||||
FileSize = ftell(hFile);
|
FileSize = ftell(hFile);
|
||||||
if(FileSize < 24){
|
if(FileSize < 24)
|
||||||
printf("%sNot a valid XA file.", "xadecode: error: ");
|
Shutdown_M("Not a valid XA file");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fseek(hFile, 0, SEEK_SET);
|
fseek(hFile, 0, SEEK_SET);
|
||||||
|
|
||||||
XAData = malloc(FileSize);
|
XAData = malloc(FileSize);
|
||||||
if(XAData == NULL){
|
if(XAData == NULL)
|
||||||
printf("%sMemory for this file could not be allocated.", "xadecode: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
if(fread(XAData, 1, FileSize, hFile) != FileSize)
|
||||||
}
|
Shutdown_M("The input file could not be read");
|
||||||
if(!fread(XAData, FileSize, 1, hFile)){
|
fclose(hFile); hFile = NULL;
|
||||||
printf("%sThe input file could not be read.", "xadecode: error: ");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
fclose(hFile);
|
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Transcode the data from XA to LPCM
|
** Transcode the data from XA to LPCM
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(!xa_read_header(&XAHeader, XAData, FileSize)){
|
if(!xa_read_header(&XAHeader, XAData, FileSize))
|
||||||
printf("%sNot a valid XA file.", "xadecode: error: ");
|
Shutdown_M("Not a valid XA file");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(argc >= 3){ /* Transcode */
|
if(argc >= 3){ /* Transcode */
|
||||||
uint8_t * WaveData = malloc(44+XAHeader.dwOutSize);
|
WaveData = malloc(44+XAHeader.dwOutSize);
|
||||||
if(WaveData == NULL){
|
if(WaveData == NULL)
|
||||||
printf("%sMemory for this file could not be allocated.", "xadecode: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
BeginningTime = clock();
|
BeginningTime = clock();
|
||||||
if(!xa_decode(XAData+24, WaveData+44, XAHeader.Frames, XAHeader.nChannels)){
|
if(!xa_decode(XAData+24, WaveData+44, XAHeader.Frames, XAHeader.nChannels))
|
||||||
printf("%sMemory for this file could not be allocated.", "xadecode: error: ");
|
Shutdown_M("Memory for this file could not be allocated");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
EndingTime = clock();
|
EndingTime = clock();
|
||||||
|
|
||||||
free(XAData);
|
free(XAData); XAData = NULL;
|
||||||
|
|
||||||
/****
|
/****
|
||||||
** Write the Microsoft WAV header
|
** Write the Microsoft WAV header
|
||||||
|
@ -142,23 +140,22 @@ int main(int argc, char *argv[]){
|
||||||
if(hFile != NULL){
|
if(hFile != NULL){
|
||||||
/* File exists */
|
/* File exists */
|
||||||
char c;
|
char c;
|
||||||
fclose(hFile);
|
fclose(hFile); hFile = NULL;
|
||||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
||||||
c = getchar();
|
c = getchar();
|
||||||
if(c != 'y' && c != 'Y'){
|
if(c != 'y' && c != 'Y'){
|
||||||
printf("\nAborted.\n");
|
printf("\n");
|
||||||
return -1;
|
Shutdown_M("Aborted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hFile = fopen(OutFile, "wb");
|
hFile = fopen(OutFile, "wb");
|
||||||
if(hFile == NULL){
|
if(hFile == NULL)
|
||||||
printf("%sThe output file could not be opened for writing.", "xadecode: error: ");
|
Shutdown_M("The output file could not be opened for writing");
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
printf("Extracted %u bytes in %.2f seconds.\n", (unsigned) XAHeader.dwOutSize,
|
printf("Extracted %u bytes in %.2f seconds.\n", (unsigned) XAHeader.dwOutSize,
|
||||||
((float)(EndingTime - BeginningTime))/CLOCKS_PER_SEC);
|
((float)(EndingTime - BeginningTime))/CLOCKS_PER_SEC);
|
||||||
fwrite(WaveData, 1, 44+XAHeader.dwOutSize, hFile);
|
fwrite(WaveData, 1, 44+XAHeader.dwOutSize, hFile);
|
||||||
|
free(WaveData);
|
||||||
fclose(hFile);
|
fclose(hFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
Server/AUTHORS
Normal file
1
Server/AUTHORS
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fatbag <X-Fi6@phppoll.org>
|
2
Server/CHANGES
Normal file
2
Server/CHANGES
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
Technical Preview 1
|
||||||
|
* Initial release
|
|
@ -1,3 +1,24 @@
|
||||||
|
IMPORTANT:
|
||||||
|
Niotso is distributed under the terms of the GNU GPLv3.
|
||||||
|
|
||||||
|
While this license does permit others to compile, distribute, change,
|
||||||
|
and distribute changes to Niotso, in reality, many of these freedoms
|
||||||
|
cannot legally be enacted by anybody.
|
||||||
|
|
||||||
|
Specifically, if you make changes to Niotso such that it significantly
|
||||||
|
changes the "game experience as presented to the player", it cannot
|
||||||
|
be distributed to others. You also may not distribute a version of
|
||||||
|
Niotso that has stripped the EA or Maxis trademarked names or logos
|
||||||
|
anywhere from the game. Personal use of these modifications is okay.
|
||||||
|
|
||||||
|
These restrictions are not enforced by us, but may potentially be used
|
||||||
|
by EA in attempt to take down your game.
|
||||||
|
|
||||||
|
If you have any questions, you may visit
|
||||||
|
<http://wiki.niotso.org/Niotso/Legal_Summary>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
|
0
Server/README
Normal file
0
Server/README
Normal file
|
@ -152,7 +152,8 @@ int main(int, char **)
|
||||||
socklen_t addrlen = sizeof(sockaddr_in6);
|
socklen_t addrlen = sizeof(sockaddr_in6);
|
||||||
ssize_t packetsize = recvfrom(epev[0].data.fd, packetdata, 1500, 0, (sockaddr*) &client_addr, &addrlen);
|
ssize_t packetsize = recvfrom(epev[0].data.fd, packetdata, 1500, 0, (sockaddr*) &client_addr, &addrlen);
|
||||||
if(packetsize < 0){
|
if(packetsize < 0){
|
||||||
if(errno == EINTR || errno == ECONNRESET || errno == ENOTCONN || errno == ETIMEDOUT)
|
if(errno == EINTR || errno == ECONNRESET || errno == ENOTCONN || errno == ETIMEDOUT ||
|
||||||
|
errno == EAGAIN || errno == EWOULDBLOCK)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SHUTDOWN_M("Socket closed unexpectedly on call to recvfrom", close_epoll);
|
SHUTDOWN_M("Socket closed unexpectedly on call to recvfrom", close_epoll);
|
||||||
|
|
21
Server/TODO
Normal file
21
Server/TODO
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
Because there are too many long-term things to list that we still have "to do" to reach the next development phase (e.g.
|
||||||
|
alpha to beta), this file contains only the things that are worked on currently or that will be in the very near future.
|
||||||
|
|
||||||
|
While anybody is free to work on _anything_ at any point during Niotso's time, this list shall ONLY contain those relevant
|
||||||
|
to complete the criteria for the next development phase, which can be found here:
|
||||||
|
<http://wiki.niotso.org/Niotso_Release_Schedule>
|
||||||
|
|
||||||
|
//----------//
|
||||||
|
|
||||||
|
Development Phase: Planning
|
||||||
|
|
||||||
|
Technical Preview 1
|
||||||
|
Schedule: (Not very subject to change)
|
||||||
|
1. Implement cst, uis, ini, and xml parsers with support for UTF-8 [20%]
|
||||||
|
2. Replicate functionality up until the login dialog [90%]
|
||||||
|
3. Implement the audio engine
|
||||||
|
4. Implement the OpenGL-based windowing system
|
||||||
|
5. Replicate character selection and creation features and the city selection dialog
|
||||||
|
6. Implement debug logging and support for configuration files
|
||||||
|
7. Implement the code needed to allow the game to read all necessary files from the TSOClient folder
|
||||||
|
8. Port the client to Linux
|
|
@ -1,4 +1,5 @@
|
||||||
add_subdirectory(FARDive)
|
add_subdirectory(FARDive)
|
||||||
add_subdirectory(hitutils)
|
add_subdirectory(hitutils)
|
||||||
add_subdirectory(iff2html)
|
add_subdirectory(iff2html)
|
||||||
|
add_subdirectory(rtti-reader)
|
||||||
add_subdirectory(tsoscan)
|
add_subdirectory(tsoscan)
|
|
@ -27,23 +27,23 @@ int main(){
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cEdithEditorCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
cTSOEdithEditorDCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||||
(cEdithEditorCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
(cTSOEdithEditorDCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||||
if(GZDllGetGZCOMDirector == NULL){
|
if(GZDllGetGZCOMDirector == NULL){
|
||||||
printf("TSOEdithEditor: Error: Failed to find GZDllGetGZCOMDirector() in TSOEdithEditorD.dll.");
|
printf("TSOEdithEditor: Error: Failed to find GZDllGetGZCOMDirector() in TSOEdithEditorD.dll.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("TSOEdithEditor: Calling GZDllGetGZCOMDirector() ...\n");
|
printf("TSOEdithEditor: Calling GZDllGetGZCOMDirector() ...\n");
|
||||||
cEdithEditorCOMDirector * Edith = GZDllGetGZCOMDirector();
|
cTSOEdithEditorDCOMDirector * Edith = GZDllGetGZCOMDirector();
|
||||||
printf("TSOEdithEditor: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Edith);
|
printf("TSOEdithEditor: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Edith);
|
||||||
|
|
||||||
while(true){
|
while(true){
|
||||||
char buffer[8];
|
char buffer[8];
|
||||||
printf("\nCall a function (0, 1, 2, ...) or q to exit. ");
|
printf("\nCall a function (0, 1, 2, ...) or q to exit. ");
|
||||||
fgets(buffer, 8, stdin);
|
//fgets(buffer, 8, stdin);
|
||||||
if(buffer[0] == 'q') break;
|
//if(buffer[0] == 'q') break;
|
||||||
Edith->Object1.vtable5[atoi(buffer)]();
|
//Edith->Object1.vtable5[atoi(buffer)]();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("TSOEdithEditor: Exiting.\n");
|
printf("TSOEdithEditor: Exiting.\n");
|
||||||
|
|
|
@ -41,7 +41,7 @@ DECLARE_INTERFACE(cUnknownObject1)
|
||||||
DWORD Unknown12;
|
DWORD Unknown12;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_INTERFACE(cEdithEditorCOMDirector)
|
DECLARE_INTERFACE(cTSOEdithEditorDCOMDirector)
|
||||||
{
|
{
|
||||||
void * vtable2;
|
void * vtable2;
|
||||||
void * vtable1;
|
void * vtable1;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
gcc -Wall -Wextra -Wabi -pedantic -m32 -o TSOEdithEditor.exe TSOEdithEditor.cpp -mconsole
|
gcc -Wall -Wextra -Wabi -pedantic -fno-exceptions -m32 -o TSOEdithEditor.exe TSOEdithEditor.cpp -mconsole
|
|
@ -38,7 +38,7 @@ int main(){
|
||||||
cTSOSimulatorClientDCOMDirector * Simulator = GZDllGetGZCOMDirector();
|
cTSOSimulatorClientDCOMDirector * Simulator = GZDllGetGZCOMDirector();
|
||||||
printf("TSOSimulatorClient: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Simulator);
|
printf("TSOSimulatorClient: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Simulator);
|
||||||
|
|
||||||
printf("%s\n%s\n%s\n", Simulator->Object1.Strings1[0], Simulator->Object1.Strings2[0], Simulator->Object1.Strings3[0]);
|
printf("%s\n%s\n%s\n", Simulator->String1.Strings1[0], Simulator->String1.Strings2[0], Simulator->String1.Strings3[0]);
|
||||||
|
|
||||||
printf("TSOSimulatorClient: Exiting.\n");
|
printf("TSOSimulatorClient: Exiting.\n");
|
||||||
FreeLibrary(dllmodule);
|
FreeLibrary(dllmodule);
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
#include <basetyps.h>
|
#include <basetyps.h>
|
||||||
#pragma pack(0)
|
#pragma pack(0)
|
||||||
|
|
||||||
DECLARE_INTERFACE(cUnknownObject1)
|
DECLARE_INTERFACE(cRZString)
|
||||||
{
|
{
|
||||||
|
//Base classes: cRZString, std::char_traits, ?$_String_base@DV?$__default_alloc_template@$00$0A@@std@@@std, cIGZString, cIGZUnknown
|
||||||
DWORD Zero1;
|
DWORD Zero1;
|
||||||
DWORD Zero2;
|
DWORD Zero2;
|
||||||
void * vtable5;
|
void * vtable5;
|
||||||
|
@ -43,13 +44,14 @@ DECLARE_INTERFACE(cUnknownObject1)
|
||||||
|
|
||||||
DECLARE_INTERFACE(cTSOSimulatorClientDCOMDirector)
|
DECLARE_INTERFACE(cTSOSimulatorClientDCOMDirector)
|
||||||
{
|
{
|
||||||
|
//Base classes: cTSOSimulatorClientDCOMDirector, cRZCOMDllDirector, cIGZCOMDirector, cIGZUnknown, cIGZFrameWorkHooks, cIGZUnknown
|
||||||
void * vtable2;
|
void * vtable2;
|
||||||
void * vtable1;
|
void * vtable1;
|
||||||
cUnknownObject1 Object1;
|
cRZString String1;
|
||||||
void * vtable4;
|
void * vtable4;
|
||||||
void * vtable3;
|
void * vtable3;
|
||||||
cUnknownObject1 Object2;
|
cRZString String2;
|
||||||
cUnknownObject1 Object3;
|
cRZString String3;
|
||||||
|
|
||||||
DWORD Zero1;
|
DWORD Zero1;
|
||||||
DWORD Zero2;
|
DWORD Zero2;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
gcc -Wall -Wextra -Wabi -pedantic -m32 -o TSOSimulatorClient.exe TSOSimulatorClient.cpp -mconsole
|
gcc -Wall -Wextra -Wabi -pedantic -fno-exceptions -m32 -o TSOSimulatorClient.exe TSOSimulatorClient.cpp -mconsole
|
|
@ -119,6 +119,7 @@ int main(int argc, char *argv[]){
|
||||||
fseek(hFile, 0, SEEK_END);
|
fseek(hFile, 0, SEEK_END);
|
||||||
FileSize = ftell(hFile);
|
FileSize = ftell(hFile);
|
||||||
if(FileSize < 64){
|
if(FileSize < 64){
|
||||||
|
fclose(hFile);
|
||||||
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -126,10 +127,12 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
IFFData = malloc(FileSize);
|
IFFData = malloc(FileSize);
|
||||||
if(IFFData == NULL){
|
if(IFFData == NULL){
|
||||||
|
fclose(hFile);
|
||||||
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!fread(IFFData, FileSize, 1, hFile)){
|
if(fread(IFFData, 1, FileSize, hFile) != FileSize){
|
||||||
|
fclose(hFile);
|
||||||
printf("%sThe input file could not be read.", "iff2html: error: ");
|
printf("%sThe input file could not be read.", "iff2html: error: ");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
8
Tools/rtti-reader/CMakeLists.txt
Normal file
8
Tools/rtti-reader/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
project(rtti-reader)
|
||||||
|
|
||||||
|
set(RTTIREADER_SOURCES
|
||||||
|
rtti-reader.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(rtti-reader ${RTTIREADER_SOURCES})
|
524
Tools/rtti-reader/rtti-reader.cpp
Normal file
524
Tools/rtti-reader/rtti-reader.cpp
Normal file
|
@ -0,0 +1,524 @@
|
||||||
|
/*
|
||||||
|
rtti-reader - The Sims Online MSVC RTTI Class Hierarchy Extractor
|
||||||
|
rtti-reader.cpp - 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//For information about MSVC RTTI, read:
|
||||||
|
//<http://www.openrce.org/articles/full_view/23>
|
||||||
|
//<https://www.blackhat.com/presentations/bh-dc-07/Sabanal_Yason/Paper/bh-dc-07-Sabanal_Yason-WP.pdf>
|
||||||
|
|
||||||
|
//For information about the Windows PE header, read:
|
||||||
|
//<https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#File_Format>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef read_int32
|
||||||
|
#define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3)))
|
||||||
|
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||||
|
#endif
|
||||||
|
#ifndef write_int32
|
||||||
|
#define write_uint32(dest, src) do { \
|
||||||
|
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
||||||
|
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
||||||
|
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
||||||
|
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void Shutdown_M(const char * Message);
|
||||||
|
|
||||||
|
struct Segment {
|
||||||
|
size_t size, offset;
|
||||||
|
Segment() : size(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ByteReaderContext {
|
||||||
|
size_t start, position, end;
|
||||||
|
bool seek(size_t pos){
|
||||||
|
if(pos > end)
|
||||||
|
return false;
|
||||||
|
position = pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool skip(int pos = 1){
|
||||||
|
if(position + pos > end)
|
||||||
|
return false;
|
||||||
|
position += pos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PaddingTest {
|
||||||
|
uint32_t A;
|
||||||
|
uint32_t B;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct RTTIVector {
|
||||||
|
size_t Count, SizeAllocated;
|
||||||
|
T * Buffer;
|
||||||
|
|
||||||
|
void init(){
|
||||||
|
Count = 0, SizeAllocated = sizeof(T);
|
||||||
|
if(!(Buffer = (T*) malloc(sizeof(T))))
|
||||||
|
Shutdown_M("Failed to allocate memory");
|
||||||
|
}
|
||||||
|
T& add(){
|
||||||
|
if((Count+1)*sizeof(T) > SizeAllocated)
|
||||||
|
if(SizeAllocated > SIZE_MAX/2 || !(Buffer = (T*) realloc(Buffer, SizeAllocated<<=1)))
|
||||||
|
Shutdown_M("Failed to allocate memory");
|
||||||
|
|
||||||
|
return Buffer[Count++];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTTITypeDescriptor {
|
||||||
|
struct {
|
||||||
|
uint32_t Address;
|
||||||
|
uint32_t VTableAddress;
|
||||||
|
uint32_t Reserved;
|
||||||
|
} Fields;
|
||||||
|
char * Name;
|
||||||
|
char * UnmangledName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTTIBaseClassDescriptor {
|
||||||
|
struct {
|
||||||
|
uint32_t Address;
|
||||||
|
uint32_t TypeDescriptorAddress;
|
||||||
|
uint32_t BaseClassCount;
|
||||||
|
uint32_t MemberOffset;
|
||||||
|
uint32_t COLAddressOffset;
|
||||||
|
uint32_t VTableOffset;
|
||||||
|
uint32_t Attributes;
|
||||||
|
} Fields;
|
||||||
|
RTTITypeDescriptor TD;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTTIClassHierarchyDescriptor {
|
||||||
|
struct {
|
||||||
|
uint32_t Address;
|
||||||
|
uint32_t Reserved;
|
||||||
|
uint32_t Attributes;
|
||||||
|
uint32_t BaseClassCount;
|
||||||
|
uint32_t BaseClassListAddress;
|
||||||
|
} Fields;
|
||||||
|
RTTIVector<RTTIBaseClassDescriptor> BCDL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTTICompleteObjectLocator {
|
||||||
|
struct {
|
||||||
|
uint32_t Address;
|
||||||
|
uint32_t Reserved;
|
||||||
|
uint32_t Offset;
|
||||||
|
uint32_t CDOffset;
|
||||||
|
uint32_t TypeDescriptorAddress;
|
||||||
|
uint32_t ClassDescriptorAddress;
|
||||||
|
} Fields;
|
||||||
|
uint32_t VTableAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RTTIClass {
|
||||||
|
RTTIVector<RTTICompleteObjectLocator> COLL;
|
||||||
|
RTTITypeDescriptor TD;
|
||||||
|
RTTIClassHierarchyDescriptor CHD;
|
||||||
|
void init(){
|
||||||
|
COLL.init();
|
||||||
|
CHD.BCDL.init();
|
||||||
|
}
|
||||||
|
bool DependsOn(const RTTIClass& X) const {
|
||||||
|
for(uint32_t i=1; i<CHD.BCDL.Count; i++)
|
||||||
|
if(CHD.BCDL.Buffer[i].TD.Fields.Address == X.TD.Fields.Address)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
static int Compare(const void * Aptr, const void * Bptr){
|
||||||
|
const RTTIClass& A = *reinterpret_cast<const RTTIClass*>(Aptr);
|
||||||
|
const RTTIClass& B = *reinterpret_cast<const RTTIClass*>(Bptr);
|
||||||
|
|
||||||
|
if(A.DependsOn(B)) return 1; //If A depends on B, A > B
|
||||||
|
if(B.DependsOn(A)) return -1; //If B depends on A, B > A
|
||||||
|
return strcmp(A.TD.UnmangledName, B.TD.UnmangledName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PEFile {
|
||||||
|
static PEFile * ptr;
|
||||||
|
FILE * hFile;
|
||||||
|
uint8_t * Data;
|
||||||
|
Segment rdata, data;
|
||||||
|
ByteReaderContext brc;
|
||||||
|
|
||||||
|
PEFile(const char * filename) : Data(NULL) {
|
||||||
|
PEFile::ptr = this;
|
||||||
|
|
||||||
|
hFile = fopen(filename, "rb");
|
||||||
|
if(!hFile)
|
||||||
|
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||||
|
|
||||||
|
fseek(hFile, 0, SEEK_END);
|
||||||
|
size_t FileSize = ftell(hFile);
|
||||||
|
if(FileSize < 64)
|
||||||
|
Shutdown_M("Not a valid Windows PE file");
|
||||||
|
fseek(hFile, 0, SEEK_SET);
|
||||||
|
|
||||||
|
Data = (uint8_t*) malloc(FileSize);
|
||||||
|
if(!Data)
|
||||||
|
Shutdown_M("Failed to allocate memory");
|
||||||
|
if(fread(Data, 1, FileSize, hFile) != FileSize)
|
||||||
|
Shutdown_M("Failed to read input file");
|
||||||
|
|
||||||
|
fclose(hFile);
|
||||||
|
|
||||||
|
brc.start = brc.position = 0;
|
||||||
|
brc.end = FileSize;
|
||||||
|
}
|
||||||
|
~PEFile(){
|
||||||
|
if(hFile)
|
||||||
|
fclose(hFile);
|
||||||
|
if(Data)
|
||||||
|
free(Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool seek(size_t pos, int offset = 0){
|
||||||
|
return brc.seek(pos + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool skip(size_t pos = 1, int offset = 0){
|
||||||
|
return brc.skip(pos + offset);
|
||||||
|
}
|
||||||
|
int nextchar(){
|
||||||
|
if(!brc.skip())
|
||||||
|
return EOF;
|
||||||
|
return Data[brc.position-1];
|
||||||
|
}
|
||||||
|
void lookat(Segment& segment){
|
||||||
|
brc.start = brc.position = segment.offset;
|
||||||
|
brc.end = segment.offset + segment.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t read32(){
|
||||||
|
return brc.skip(4) ? read_uint32(Data+brc.position-4) : -1;
|
||||||
|
}
|
||||||
|
uint16_t read16(){
|
||||||
|
return brc.skip(2) ? read_uint16(Data+brc.position-2) : -1;
|
||||||
|
}
|
||||||
|
size_t strlen(){
|
||||||
|
size_t i = (size_t)-1;
|
||||||
|
int byte;
|
||||||
|
do {
|
||||||
|
byte = nextchar();
|
||||||
|
if(byte == EOF)
|
||||||
|
return -1;
|
||||||
|
i++;
|
||||||
|
} while(byte);
|
||||||
|
skip(-(int)i-1); //Seek back
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
bool strcpy(char * dest){
|
||||||
|
int i = 0;
|
||||||
|
do {
|
||||||
|
int byte = nextchar();
|
||||||
|
if(byte == EOF)
|
||||||
|
return false;
|
||||||
|
*dest = (char) byte;
|
||||||
|
i--;
|
||||||
|
} while(*dest++);
|
||||||
|
skip(i); //Seek back
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int strcmp(const char * data){
|
||||||
|
int i = 0;
|
||||||
|
int byte;
|
||||||
|
do {
|
||||||
|
byte = nextchar();
|
||||||
|
if(byte == EOF)
|
||||||
|
return -1;
|
||||||
|
i--;
|
||||||
|
} while(*data++ && (char)byte == *(data-1));
|
||||||
|
skip(i); //Seek back
|
||||||
|
return byte - *(data-1);
|
||||||
|
}
|
||||||
|
enum { Parse_QuestionMark = 1};
|
||||||
|
bool memfind(const char * data, size_t size, int MemParse = 0){
|
||||||
|
size_t i = 0;
|
||||||
|
do {
|
||||||
|
int byte = nextchar();
|
||||||
|
if(byte == EOF)
|
||||||
|
return false;
|
||||||
|
else if((char)byte != data[i] && (!MemParse || data[i] != '?')){
|
||||||
|
skip(-(int)i);
|
||||||
|
i = 0;
|
||||||
|
} else i++;
|
||||||
|
} while(i<size);
|
||||||
|
skip(-(int)i); //Seek back
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool find32(uint32_t address){
|
||||||
|
char buffer[4];
|
||||||
|
write_uint32(buffer, address);
|
||||||
|
return memfind(buffer, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GenericFill(uint8_t *ptr, size_t count){
|
||||||
|
const size_t padding = offsetof(PaddingTest,B)-offsetof(PaddingTest,A);
|
||||||
|
count -= padding;
|
||||||
|
if(count > brc.end - brc.position)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t *field = reinterpret_cast<uint32_t*>(ptr);
|
||||||
|
*field = brc.position; //The Address field always comes first
|
||||||
|
|
||||||
|
do {
|
||||||
|
ptr += padding; count -= padding;
|
||||||
|
field = reinterpret_cast<uint32_t*>(ptr);
|
||||||
|
*field = read32();
|
||||||
|
} while(count);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline bool Fill(T& context) {
|
||||||
|
return GenericFill(reinterpret_cast<uint8_t*>(&context.Fields), sizeof(context.Fields));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PEFile * PEFile::ptr;
|
||||||
|
|
||||||
|
static void Shutdown_M(const char * Message){
|
||||||
|
fprintf(stderr, "rtti-reader: error: %s.", Message);
|
||||||
|
if(PEFile::ptr)
|
||||||
|
PEFile::ptr->~PEFile();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]){
|
||||||
|
unsigned i;
|
||||||
|
const char * InFile, * BaseName;
|
||||||
|
|
||||||
|
if(argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||||
|
printf("Usage: rtti-reader infile\n"
|
||||||
|
"Extract class information from an EXE or DLL using MSVC RTTI.\n"
|
||||||
|
"\n"
|
||||||
|
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||||
|
"rtti-reader is maintained by the Niotso project.\n"
|
||||||
|
"Home page: <http://www.niotso.org/>\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InFile = argv[1];
|
||||||
|
|
||||||
|
int slash;
|
||||||
|
for(i=0, slash=-1; InFile[i]; i++)
|
||||||
|
if(InFile[i] == '/' || InFile[i] == '\\') slash = i;
|
||||||
|
BaseName = InFile + slash + 1;
|
||||||
|
|
||||||
|
PEFile DLL(InFile);
|
||||||
|
if(DLL.read16() != 0x5A4D) //"MZ"
|
||||||
|
Shutdown_M("Not a valid Windows PE file");
|
||||||
|
|
||||||
|
DLL.seek(60);
|
||||||
|
DLL.seek(DLL.read32(), 6); unsigned SegmentCount = DLL.read16();
|
||||||
|
DLL.skip(12); unsigned OptionalHeaderSize = DLL.read16();
|
||||||
|
DLL.skip(30); unsigned ImageBase = DLL.read32();
|
||||||
|
DLL.skip(OptionalHeaderSize, -32);
|
||||||
|
|
||||||
|
for(i=0; i<SegmentCount; i++){
|
||||||
|
if(!DLL.strcmp(".rdata")){
|
||||||
|
DLL.skip(8); DLL.rdata.size = DLL.read32();
|
||||||
|
DLL.rdata.offset = DLL.read32();
|
||||||
|
DLL.skip(24);
|
||||||
|
} else if(!DLL.strcmp(".data")){
|
||||||
|
DLL.skip(8); DLL.data.size = DLL.read32();
|
||||||
|
DLL.data.offset = DLL.read32();
|
||||||
|
DLL.skip(24);
|
||||||
|
} else DLL.skip(40);
|
||||||
|
}
|
||||||
|
if(DLL.rdata.size == 0)
|
||||||
|
Shutdown_M("Missing .rdata segment");
|
||||||
|
else if(DLL.data.size == 0)
|
||||||
|
Shutdown_M("Missing .data segment");
|
||||||
|
else if(DLL.rdata.size > UINT_MAX-DLL.rdata.offset || DLL.rdata.size+DLL.rdata.offset > DLL.brc.end)
|
||||||
|
Shutdown_M(".rdata segment is invalid");
|
||||||
|
else if(DLL.data.size > UINT_MAX-DLL.data.offset || DLL.data.size+DLL.data.offset > DLL.brc.end)
|
||||||
|
Shutdown_M(".data segment is invalid");
|
||||||
|
|
||||||
|
printf("\n****\n** [ 1 of 2] RTTI Report for %s\n****\n", BaseName);
|
||||||
|
|
||||||
|
RTTIVector<RTTIClass> RCL;
|
||||||
|
RCL.init();
|
||||||
|
|
||||||
|
DLL.lookat(DLL.data);
|
||||||
|
unsigned TotalClassCount = 0;
|
||||||
|
while(DLL.skip(8) && DLL.memfind(".?AV", 4, PEFile::Parse_QuestionMark)){
|
||||||
|
TotalClassCount++;
|
||||||
|
size_t length = DLL.strlen();
|
||||||
|
if(length == (unsigned)-1)
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
|
||||||
|
size_t TDAddress = DLL.brc.position + ImageBase - 8, datapos = DLL.brc.position + length + 1;
|
||||||
|
DLL.lookat(DLL.rdata);
|
||||||
|
|
||||||
|
RTTIClass * RCPointer = NULL;
|
||||||
|
|
||||||
|
for(size_t rdatapos = DLL.brc.position + 12;
|
||||||
|
DLL.seek(rdatapos) && DLL.find32(TDAddress); rdatapos += 4, DLL.lookat(DLL.rdata)){
|
||||||
|
//Find all complete object locators that belong to this class
|
||||||
|
rdatapos = DLL.brc.position;
|
||||||
|
if(!DLL.skip(4))
|
||||||
|
continue;
|
||||||
|
size_t CDAddress = DLL.read32() - ImageBase;
|
||||||
|
if(CDAddress < DLL.brc.start || CDAddress > DLL.brc.end-4)
|
||||||
|
continue; //This was a base class descriptor
|
||||||
|
|
||||||
|
//Add this COL to our respective RTTIClass
|
||||||
|
bool newclass = false;
|
||||||
|
if(RCPointer == NULL){
|
||||||
|
//This is a new class; add it to the RCL
|
||||||
|
newclass = true;
|
||||||
|
RTTIClass& RC = RCL.add();
|
||||||
|
RCPointer = &RC;
|
||||||
|
RC.init();
|
||||||
|
}
|
||||||
|
RTTIClass& RC = *RCPointer;
|
||||||
|
|
||||||
|
RTTICompleteObjectLocator& COL = RC.COLL.add();
|
||||||
|
|
||||||
|
DLL.seek(rdatapos,-12);
|
||||||
|
size_t COLAddress = DLL.brc.position + ImageBase;
|
||||||
|
if(!DLL.Fill(COL))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
|
||||||
|
DLL.lookat(DLL.rdata);
|
||||||
|
COL.VTableAddress = (DLL.find32(COLAddress)) ? DLL.brc.position + ImageBase : (uint32_t)-1;
|
||||||
|
|
||||||
|
if(newclass){
|
||||||
|
if(!DLL.seek(COL.Fields.ClassDescriptorAddress - ImageBase))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
RTTIClassHierarchyDescriptor& CHD = RC.CHD;
|
||||||
|
if(!DLL.Fill(CHD))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
|
||||||
|
if(!DLL.seek(CHD.Fields.BaseClassListAddress - ImageBase))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
size_t bcdlpos;
|
||||||
|
for(i=0, bcdlpos = DLL.brc.position; i<CHD.Fields.BaseClassCount; i++, bcdlpos+=4){
|
||||||
|
DLL.lookat(DLL.rdata);
|
||||||
|
if(!DLL.seek(bcdlpos))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
uint32_t BCDAddress = DLL.read32();
|
||||||
|
if(!DLL.seek(BCDAddress - ImageBase))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
|
||||||
|
RTTIBaseClassDescriptor& BCD = CHD.BCDL.add();
|
||||||
|
if(!DLL.Fill(BCD))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
|
||||||
|
DLL.lookat(DLL.data);
|
||||||
|
if(!DLL.seek(BCD.Fields.TypeDescriptorAddress - ImageBase))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
if(!DLL.Fill(BCD.TD))
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
|
||||||
|
length = DLL.strlen();
|
||||||
|
if(length == (unsigned)-1)
|
||||||
|
Shutdown_M("Unexpectedly reached end of binary");
|
||||||
|
BCD.TD.Name = (char*) malloc(length+1);
|
||||||
|
BCD.TD.UnmangledName = (char*) malloc(length+1-6);
|
||||||
|
if(!BCD.TD.Name || !BCD.TD.UnmangledName)
|
||||||
|
Shutdown_M("Failed to allocate memory");
|
||||||
|
DLL.strcpy(BCD.TD.Name);
|
||||||
|
for(size_t j=0; j<length-6; j++){
|
||||||
|
char c = BCD.TD.Name[j+4];
|
||||||
|
BCD.TD.UnmangledName[j] = (
|
||||||
|
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= '0' && c <= '9') || c == '_')
|
||||||
|
? c : ' ';
|
||||||
|
}
|
||||||
|
BCD.TD.UnmangledName[length-6] = '\0';
|
||||||
|
|
||||||
|
if(newclass){
|
||||||
|
newclass = false;
|
||||||
|
memcpy(&RC.TD, &BCD.TD, sizeof(RTTITypeDescriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL.lookat(DLL.data);
|
||||||
|
DLL.seek(datapos);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<RCL.Count; i++){
|
||||||
|
RTTIClass& RC = RCL.Buffer[i];
|
||||||
|
RTTIClassHierarchyDescriptor& CHD = RC.CHD;
|
||||||
|
printf("\nClass %s (mangled: %s)\n", RC.TD.UnmangledName, RC.TD.Name);
|
||||||
|
printf(" * Class Hierarchy Descriptor: (Address %08X)\n", CHD.Fields.Address + ImageBase);
|
||||||
|
printf(" * Reserved: %u\n", CHD.Fields.Reserved);
|
||||||
|
printf(" * Attributes: %u\n", CHD.Fields.Attributes);
|
||||||
|
printf(" * Base class count: %u\n", CHD.Fields.BaseClassCount);
|
||||||
|
printf(" * Base class list address: %08X\n", CHD.Fields.BaseClassListAddress);
|
||||||
|
for(uint32_t j=0; j<CHD.Fields.BaseClassCount; j++){
|
||||||
|
RTTIBaseClassDescriptor& BCD = CHD.BCDL.Buffer[j];
|
||||||
|
printf(" * Base class descriptor #%u: (Address %08X)\n", j, BCD.Fields.Address + ImageBase);
|
||||||
|
printf(" * Base class count: %u\n", BCD.Fields.BaseClassCount);
|
||||||
|
printf(" * Member offset: %d\n", BCD.Fields.MemberOffset);
|
||||||
|
printf(" * COL address offset: %d\n", BCD.Fields.COLAddressOffset);
|
||||||
|
printf(" * v-table offset: %d\n", BCD.Fields.VTableOffset);
|
||||||
|
printf(" * Attributes: %u\n", BCD.Fields.Attributes);
|
||||||
|
printf(" * Type descriptor: (Address %08X)\n", BCD.Fields.TypeDescriptorAddress);
|
||||||
|
printf(" * v-table address: %08X\n", BCD.TD.Fields.VTableAddress);
|
||||||
|
printf(" * Reserved: %u\n", BCD.TD.Fields.Reserved);
|
||||||
|
printf(" * Name: %s (mangled: %s)\n", BCD.TD.UnmangledName, BCD.TD.Name);
|
||||||
|
}
|
||||||
|
for(uint32_t j=0; j<RC.COLL.Count; j++){
|
||||||
|
RTTICompleteObjectLocator& COL = RC.COLL.Buffer[j];
|
||||||
|
printf(" * Complete object locator #%u: (Address %08X)\n", j, COL.Fields.Address + ImageBase);
|
||||||
|
printf(" * Reserved: %u\n", COL.Fields.Reserved);
|
||||||
|
printf(" * Offset: %d\n", COL.Fields.Offset);
|
||||||
|
printf(" * CD Offset: %d\n", COL.Fields.CDOffset);
|
||||||
|
printf(" * Type descriptor address: %08X\n", COL.Fields.TypeDescriptorAddress);
|
||||||
|
printf(" * Class descriptor address: %08X\n", COL.Fields.ClassDescriptorAddress);
|
||||||
|
printf(" * v-table address: %08X\n", COL.VTableAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n****\n** [ 2 of 2 ] Class Hierarchy for %s\n****\n", BaseName);
|
||||||
|
|
||||||
|
qsort(RCL.Buffer, RCL.Count, sizeof(RTTIClass), RTTIClass::Compare);
|
||||||
|
|
||||||
|
for(i=0; i<RCL.Count; i++){
|
||||||
|
RTTIClass& RC = RCL.Buffer[i];
|
||||||
|
printf("\nclass %s", RC.TD.UnmangledName);
|
||||||
|
if(RC.CHD.BCDL.Count > 1){
|
||||||
|
//The first BCD always refers to the class itself, e.g. class A "depends on class A".
|
||||||
|
printf(" : %s", RC.CHD.BCDL.Buffer[1].TD.UnmangledName);
|
||||||
|
for(uint32_t j=2; j<RC.CHD.BCDL.Count; j++)
|
||||||
|
printf(", %s", RC.CHD.BCDL.Buffer[j].TD.UnmangledName);
|
||||||
|
}
|
||||||
|
printf(";");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n\nCompleted RTTI report.\nDependencies provided for %u of %u classes.\n", RCL.Count, TotalClassCount);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -24,7 +24,7 @@
|
||||||
#include <iff/iff.h>
|
#include <iff/iff.h>
|
||||||
#include "tsoscan.h"
|
#include "tsoscan.h"
|
||||||
|
|
||||||
void print_usage(){
|
static void print_usage(){
|
||||||
printf("Usage: tsoscan [-f] [-o outfile] indir1 [indir2 [...]]\n"
|
printf("Usage: tsoscan [-f] [-o outfile] indir1 [indir2 [...]]\n"
|
||||||
"Generate a statistical HTML page based on a number of IFF files.\n"
|
"Generate a statistical HTML page based on a number of IFF files.\n"
|
||||||
"Use -f to force overwriting without confirmation.\n"
|
"Use -f to force overwriting without confirmation.\n"
|
||||||
|
@ -43,7 +43,7 @@ int main(int argc, char *argv[]){
|
||||||
FILE *OutFile;
|
FILE *OutFile;
|
||||||
|
|
||||||
if(!stats_create(&Stats)){
|
if(!stats_create(&Stats)){
|
||||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ int main(int argc, char *argv[]){
|
||||||
unsigned DirStartIndex;
|
unsigned DirStartIndex;
|
||||||
|
|
||||||
if(dir == NULL){
|
if(dir == NULL){
|
||||||
printf("%sUnable to open the specified directory '%s'. Skipping.\n", TSOSCAN_WARNING, CmdArgs->InDirs[i]);
|
fprintf(stderr, "%sUnable to open the specified directory '%s'. Skipping.\n", TSOSCAN_WARNING, CmdArgs->InDirs[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ int main(int argc, char *argv[]){
|
||||||
rewinddir(dir);
|
rewinddir(dir);
|
||||||
Files = realloc(Files, FileCount*sizeof(char**));
|
Files = realloc(Files, FileCount*sizeof(char**));
|
||||||
if(Files == NULL){
|
if(Files == NULL){
|
||||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ int main(int argc, char *argv[]){
|
||||||
int pathlen = strlen(entry->d_name);
|
int pathlen = strlen(entry->d_name);
|
||||||
Files[DirStartIndex] = malloc(dirlen+pathlen+2);
|
Files[DirStartIndex] = malloc(dirlen+pathlen+2);
|
||||||
if(Files[DirStartIndex] == NULL){
|
if(Files[DirStartIndex] == NULL){
|
||||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
file = fopen(Files[i], "rb");
|
file = fopen(Files[i], "rb");
|
||||||
if(file == NULL){
|
if(file == NULL){
|
||||||
printf("%sUnable to open the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
fprintf(stderr, "%sUnable to open the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
|
@ -135,11 +135,11 @@ int main(int argc, char *argv[]){
|
||||||
|
|
||||||
data = malloc(FileSize);
|
data = malloc(FileSize);
|
||||||
if(data == NULL){
|
if(data == NULL){
|
||||||
printf("%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
fprintf(stderr, "%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!fread(data, FileSize, 1, file)){
|
if(fread(data, 1, FileSize, file) != FileSize){
|
||||||
printf("%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
fprintf(stderr, "%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||||
free(data);
|
free(data);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
continue;
|
continue;
|
||||||
|
@ -147,7 +147,7 @@ int main(int argc, char *argv[]){
|
||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
if(!iff_create(&iff)){
|
if(!iff_create(&iff)){
|
||||||
printf("%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
fprintf(stderr, "%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(!iff_read_header(&iff, data, FileSize) || !iff_enumerate_chunks(&iff, data+64, FileSize-64)){
|
if(!iff_read_header(&iff, data, FileSize) || !iff_enumerate_chunks(&iff, data+64, FileSize-64)){
|
||||||
|
@ -168,7 +168,7 @@ int main(int argc, char *argv[]){
|
||||||
for(ChunkIndex = 0, ChunkData = iff.Chunks; ChunkIndex < iff.ChunkCount; ChunkIndex++, ChunkData++){
|
for(ChunkIndex = 0, ChunkData = iff.Chunks; ChunkIndex < iff.ChunkCount; ChunkIndex++, ChunkData++){
|
||||||
unsigned version = stats_get_version(ChunkData->Type, ChunkData->Data);
|
unsigned version = stats_get_version(ChunkData->Type, ChunkData->Data);
|
||||||
if(!stats_version_increment(&Stats, ChunkData->Type, version)){
|
if(!stats_version_increment(&Stats, ChunkData->Type, version)){
|
||||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ int main(int argc, char *argv[]){
|
||||||
}
|
}
|
||||||
OutFile = fopen(CmdArgs->OutFile, "wb");
|
OutFile = fopen(CmdArgs->OutFile, "wb");
|
||||||
if(OutFile == NULL){
|
if(OutFile == NULL){
|
||||||
printf("%sThe output file '%s' could not be opened for writing.", TSOSCAN_ERROR, CmdArgs->OutFile);
|
fprintf(stderr, "%sThe output file '%s' could not be opened for writing.", TSOSCAN_ERROR, CmdArgs->OutFile);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue