mirror of
https://github.com/simtactics/niotso.git
synced 2025-03-15 08:11:22 +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);
|
||||
fclose(hFile);
|
||||
if(bytestransferred != FileSize){
|
||||
free(InData);
|
||||
fclose(hFile);
|
||||
File::Error = FERR_READ;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -68,9 +68,9 @@ struct Sound_t {
|
|||
|
||||
namespace File {
|
||||
|
||||
inline unsigned GetFileSize(FILE * hFile){
|
||||
inline size_t GetFileSize(FILE * hFile){
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
unsigned FileSize = ftell(hFile);
|
||||
size_t FileSize = ftell(hFile);
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
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)
|
||||
{
|
||||
struct jpeg_source_mgr * src = cinfo->src;
|
||||
jpeg_source_mgr * src = cinfo->src;
|
||||
|
||||
if(bytes > (long) src->bytes_in_buffer){
|
||||
ERREXIT(cinfo, JERR_FILE_READ);
|
||||
|
|
|
@ -34,7 +34,7 @@ enum {
|
|||
|
||||
int main(int argc, char *argv[]){
|
||||
int profile = 0, overwrite = 0;
|
||||
char infile[256] = "", outdirectory[256] = "";
|
||||
const char * InFile = "", * OutDirectory;
|
||||
FILE * hFile;
|
||||
size_t ArchiveSize;
|
||||
uint8_t * ArchiveData;
|
||||
|
@ -66,7 +66,7 @@ int main(int argc, char *argv[]){
|
|||
return 0;
|
||||
}
|
||||
|
||||
for(i=1; !infile[0] && i != argc-1; i++){
|
||||
for(i=1; !InFile[0] && i != argc-1; i++){
|
||||
/* Match for options */
|
||||
if(!profile){
|
||||
if(!strcmp(argv[i], "-ts1")){ profile = profile_ts1; continue; }
|
||||
|
@ -82,18 +82,18 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
/* Not an option */
|
||||
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;
|
||||
}
|
||||
strcpy(infile, argv[i]);
|
||||
InFile = argv[i];
|
||||
continue;
|
||||
}
|
||||
/* We're left with the out directory */
|
||||
if(!infile[0]){
|
||||
printf("%sReading from standard input is not yet implemented.", "farextract: error: ");
|
||||
if(!InFile[0]){
|
||||
fprintf(stderr, "%sReading from standard input is not yet implemented.", "farextract: error: ");
|
||||
return -1;
|
||||
}
|
||||
strcpy(outdirectory, argv[i]);
|
||||
OutDirectory = argv[i];
|
||||
|
||||
/****
|
||||
** Handle profile settings
|
||||
|
@ -107,26 +107,26 @@ int main(int argc, char *argv[]){
|
|||
** Open the file and read in the entire contents to memory
|
||||
*/
|
||||
|
||||
hFile = fopen(infile, "rb");
|
||||
hFile = fopen(InFile, "rb");
|
||||
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;
|
||||
}
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
ArchiveSize = ftell(hFile);
|
||||
if(ArchiveSize < 24){
|
||||
printf("%sNot a valid archive.", "farextract: error: ");
|
||||
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||
return -1;
|
||||
}
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
ArchiveData = malloc(ArchiveSize);
|
||||
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;
|
||||
}
|
||||
if(!fread(ArchiveData, ArchiveSize, 1, hFile)){
|
||||
printf("%sThe input file could not be read.", "farextract: error: ");
|
||||
if(fread(ArchiveData, 1, ArchiveSize, hFile) != ArchiveSize){
|
||||
fprintf(stderr, "%sThe input file could not be read.", "farextract: error: ");
|
||||
return -1;
|
||||
}
|
||||
fclose(hFile);
|
||||
|
@ -137,7 +137,7 @@ int main(int argc, char *argv[]){
|
|||
|
||||
ArchiveType = far_identify(ArchiveData, ArchiveSize);
|
||||
if(ArchiveType == FAR_TYPE_INVALID){
|
||||
printf("%sNot a valid archive.", "farextract: error: ");
|
||||
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -151,11 +151,11 @@ int main(int argc, char *argv[]){
|
|||
|
||||
FARFile * FARFileInfo = far_create_archive(ArchiveType);
|
||||
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;
|
||||
}
|
||||
if(!far_read_header(FARFileInfo, ArchiveData, ArchiveSize)){
|
||||
printf("%sNot a valid archive.", "farextract: error: ");
|
||||
fprintf(stderr, "%sNot a valid archive.", "farextract: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ int main(int argc, char *argv[]){
|
|||
|
||||
if(!far_enumerate_entries(FARFileInfo, ArchiveData+FARFileInfo->IndexOffset,
|
||||
ArchiveSize-FARFileInfo->IndexOffset, ArchiveSize)){
|
||||
printf("%sEntry data is corrupt.", "farextract: error: ");
|
||||
fprintf(stderr, "%sEntry data is corrupt.", "farextract: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -181,9 +181,9 @@ int main(int argc, char *argv[]){
|
|||
|
||||
file++;
|
||||
if(EntryNode->Entry.Filename)
|
||||
sprintf(destination, "%s/%s", outdirectory, EntryNode->Entry.Filename);
|
||||
sprintf(destination, "%s/%s", OutDirectory, EntryNode->Entry.Filename);
|
||||
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);
|
||||
|
||||
if(!far_read_entry_data(FARFileInfo, &(EntryNode->Entry), ArchiveData)){
|
||||
|
@ -233,7 +233,7 @@ int main(int argc, char *argv[]){
|
|||
/* Persist file */
|
||||
PersistFile * PersistInfo;
|
||||
char destination[256];
|
||||
sprintf(destination, "%s/%s.out", outdirectory, infile);
|
||||
sprintf(destination, "%s/%s.out", OutDirectory, InFile);
|
||||
|
||||
/****
|
||||
** Load header information
|
||||
|
@ -241,11 +241,11 @@ int main(int argc, char *argv[]){
|
|||
|
||||
PersistInfo = far_create_persist();
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -255,7 +255,7 @@ int main(int argc, char *argv[]){
|
|||
printf("Extracting\n");
|
||||
BeginningTime = clock();
|
||||
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;
|
||||
}
|
||||
EndingTime = clock();
|
||||
|
@ -265,14 +265,14 @@ int main(int argc, char *argv[]){
|
|||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
fclose(hFile);
|
||||
printf("%sFile exists.", "farextract: error: ");
|
||||
fprintf(stderr, "%sFile exists.", "farextract: error: ");
|
||||
libfar_free(PersistInfo->DecompressedData);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
hFile = fopen(destination, "wb");
|
||||
if(hFile == NULL){
|
||||
printf("%sCould not open.", "farextract: error: ");
|
||||
fprintf(stderr, "%sCould not open.", "farextract: error: ");
|
||||
libfar_free(PersistInfo->DecompressedData);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,21 @@
|
|||
#include <time.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){
|
||||
if(c == *filter) return 1;
|
||||
filter++;
|
||||
|
@ -32,18 +46,15 @@ int charmatches(char c, const char * filter){
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
FILE * hFile;
|
||||
int overwrite = 0;
|
||||
char *InFile, *OutDirectory;
|
||||
const char *InFile, *OutDirectory;
|
||||
size_t FileSize;
|
||||
uint8_t * IFFData;
|
||||
clock_t BeginningTime;
|
||||
unsigned chunkcount, chunk;
|
||||
unsigned exported = 0;
|
||||
IFFFile IFFFileInfo;
|
||||
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"
|
||||
"Export the resources of an EA IFF file.\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
|
@ -68,50 +79,39 @@ int main(int argc, char *argv[]){
|
|||
*/
|
||||
|
||||
hFile = fopen(InFile, "rb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
FileSize = ftell(hFile);
|
||||
if(FileSize < 24){
|
||||
printf("%sNot a valid IFF file.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(FileSize < 24)
|
||||
Shutdown_M("Not a valid IFF file");
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
IFFData = malloc(FileSize);
|
||||
if(IFFData == NULL){
|
||||
printf("%sMemory for this file could not be allocated.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!fread(IFFData, FileSize, 1, hFile)){
|
||||
printf("%sThe input file could not be read.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
fclose(hFile);
|
||||
if(IFFData == NULL)
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
if(fread(IFFData, 1, FileSize, hFile) != FileSize)
|
||||
Shutdown_M("The input file could not be read");
|
||||
fclose(hFile); hFile = NULL;
|
||||
|
||||
/****
|
||||
** Load header information
|
||||
*/
|
||||
|
||||
if(!iff_create(&IFFFileInfo)){
|
||||
printf("%sMemory for this file could not be allocated.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!iff_read_header(&IFFFileInfo, IFFData, FileSize)){
|
||||
printf("%sNot a valid IFF file.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!iff_create(&IFFFileInfo))
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
iffcreated++;
|
||||
if(!iff_read_header(&IFFFileInfo, IFFData, FileSize))
|
||||
Shutdown_M("Not a valid IFF file");
|
||||
|
||||
/****
|
||||
** Load entry information
|
||||
*/
|
||||
|
||||
if(!iff_enumerate_chunks(&IFFFileInfo, IFFData+64, FileSize-64)){
|
||||
printf("%sChunk data is corrupt.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!iff_enumerate_chunks(&IFFFileInfo, IFFData+64, FileSize-64))
|
||||
Shutdown_M("Chunk data is corrupt");
|
||||
|
||||
free(IFFData); IFFData = NULL;
|
||||
|
||||
chunkcount = IFFFileInfo.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){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile);
|
||||
fclose(hFile); hFile = NULL;
|
||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", destination);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y'){
|
||||
printf("\nAborted.");
|
||||
return -1;
|
||||
printf("\n");
|
||||
Shutdown_M("Aborted");
|
||||
}
|
||||
}
|
||||
overwrite++;
|
||||
}
|
||||
hFile = fopen(destination, "wb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe output file could not be opened for writing.", "iffexport: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("The output file could not be opened for writing");
|
||||
fwrite(ChunkData->Data, 1, ChunkData->Size, hFile);
|
||||
fclose(hFile);
|
||||
|
||||
|
@ -168,5 +166,7 @@ int main(int argc, char *argv[]){
|
|||
printf("\nExported %u of %u chunks in %.2f seconds.", exported, chunkcount,
|
||||
((float) (clock() - BeginningTime))/CLOCKS_PER_SEC);
|
||||
|
||||
iff_delete(&IFFFileInfo);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -26,9 +26,10 @@
|
|||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||
#endif
|
||||
#ifndef write_int32
|
||||
#define write_uint16(dest, src) \
|
||||
#define write_uint16(dest, src) do {\
|
||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1)
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#ifndef round
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
FileHandler - General-purpose file handling library for Niotso
|
||||
utkdecode.c - Copyright (c) 2011-2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
utkdecode.c - Copyright (c) 2011-2012 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
|
||||
|
@ -24,22 +22,34 @@
|
|||
#include "read_utk.h"
|
||||
|
||||
#ifndef write_int32
|
||||
#define write_uint32(dest, src) \
|
||||
#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)
|
||||
#define write_uint16(dest, src) \
|
||||
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||
} while(0)
|
||||
#define write_uint16(dest, src) do {\
|
||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1)
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||
} while(0)
|
||||
#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 overwrite = 0;
|
||||
char *InFile, *OutFile;
|
||||
FILE * hFile;
|
||||
const char *InFile, *OutFile;
|
||||
size_t FileSize;
|
||||
uint8_t * UTKData;
|
||||
utkheader_t UTKHeader;
|
||||
clock_t BeginningTime, EndingTime;
|
||||
|
||||
|
@ -69,55 +79,41 @@ int main(int argc, char *argv[]){
|
|||
*/
|
||||
|
||||
hFile = fopen(InFile, "rb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
FileSize = ftell(hFile);
|
||||
if(FileSize < 24){
|
||||
printf("%sNot a valid UTK file.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(FileSize < 32)
|
||||
Shutdown_M("Not a valid UTK file");
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
UTKData = malloc(FileSize);
|
||||
if(UTKData == NULL){
|
||||
printf("%sMemory for this file could not be allocated.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!fread(UTKData, FileSize, 1, hFile)){
|
||||
printf("%sThe input file could not be read.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
fclose(hFile);
|
||||
if(UTKData == NULL)
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
if(fread(UTKData, 1, FileSize, hFile) != FileSize)
|
||||
Shutdown_M("The input file could not be read");
|
||||
fclose(hFile); hFile = NULL;
|
||||
|
||||
/****
|
||||
** Transcode the data from UTK to LPCM
|
||||
*/
|
||||
|
||||
if(!utk_read_header(&UTKHeader, UTKData, FileSize)){
|
||||
printf("%sNot a valid UTK file.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!utk_read_header(&UTKHeader, UTKData, FileSize))
|
||||
Shutdown_M("Not a valid UTK file");
|
||||
|
||||
if(argc >= 3){ /* Transcode */
|
||||
uint8_t * WaveData = malloc(44+UTKHeader.dwOutSize);
|
||||
if(WaveData == NULL){
|
||||
printf("%sMemory for this file could not be allocated.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
WaveData = malloc(44+UTKHeader.dwOutSize);
|
||||
if(WaveData == NULL)
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
|
||||
UTKGenerateTables();
|
||||
|
||||
BeginningTime = clock();
|
||||
if(!utk_decode(UTKData+32, WaveData+44, UTKHeader.Frames)){
|
||||
printf("%sMemory for this file could not be allocated.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!utk_decode(UTKData+32, WaveData+44, UTKHeader.Frames))
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
EndingTime = clock();
|
||||
|
||||
free(UTKData);
|
||||
free(UTKData); UTKData = NULL;
|
||||
|
||||
/****
|
||||
** Write the Microsoft WAV header
|
||||
|
@ -146,23 +142,22 @@ int main(int argc, char *argv[]){
|
|||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile);
|
||||
fclose(hFile); hFile = NULL;
|
||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y'){
|
||||
printf("\nAborted.\n");
|
||||
return -1;
|
||||
printf("\n");
|
||||
Shutdown_M("Aborted");
|
||||
}
|
||||
}
|
||||
}
|
||||
hFile = fopen(OutFile, "wb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe output file could not be opened for writing.", "utkdecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("The output file could not be opened for writing");
|
||||
printf("Extracted %u bytes in %.2f seconds.\n", (unsigned) UTKHeader.dwOutSize,
|
||||
((float)(EndingTime - BeginningTime))/CLOCKS_PER_SEC);
|
||||
fwrite(WaveData, 1, 44+UTKHeader.dwOutSize, hFile);
|
||||
free(WaveData);
|
||||
fclose(hFile);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,22 +22,34 @@
|
|||
#include "read_xa.h"
|
||||
|
||||
#ifndef write_int32
|
||||
#define write_uint32(dest, src) \
|
||||
#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)
|
||||
#define write_uint16(dest, src) \
|
||||
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||
} while(0)
|
||||
#define write_uint16(dest, src) do {\
|
||||
(dest)[0] = ((src)&0x00FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1)
|
||||
(dest)[1] = ((src)&0xFF00)>>(8*1); \
|
||||
} while(0)
|
||||
#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 overwrite = 0;
|
||||
char *InFile, *OutFile;
|
||||
FILE * hFile;
|
||||
const char *InFile, *OutFile;
|
||||
size_t FileSize;
|
||||
uint8_t * XAData;
|
||||
xaheader_t XAHeader;
|
||||
clock_t BeginningTime, EndingTime;
|
||||
|
||||
|
@ -67,53 +79,39 @@ int main(int argc, char *argv[]){
|
|||
*/
|
||||
|
||||
hFile = fopen(InFile, "rb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe specified input file does not exist or could not be opened for reading.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
FileSize = ftell(hFile);
|
||||
if(FileSize < 24){
|
||||
printf("%sNot a valid XA file.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(FileSize < 24)
|
||||
Shutdown_M("Not a valid XA file");
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
XAData = malloc(FileSize);
|
||||
if(XAData == NULL){
|
||||
printf("%sMemory for this file could not be allocated.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!fread(XAData, FileSize, 1, hFile)){
|
||||
printf("%sThe input file could not be read.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
fclose(hFile);
|
||||
if(XAData == NULL)
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
if(fread(XAData, 1, FileSize, hFile) != FileSize)
|
||||
Shutdown_M("The input file could not be read");
|
||||
fclose(hFile); hFile = NULL;
|
||||
|
||||
/****
|
||||
** Transcode the data from XA to LPCM
|
||||
*/
|
||||
|
||||
if(!xa_read_header(&XAHeader, XAData, FileSize)){
|
||||
printf("%sNot a valid XA file.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!xa_read_header(&XAHeader, XAData, FileSize))
|
||||
Shutdown_M("Not a valid XA file");
|
||||
|
||||
if(argc >= 3){ /* Transcode */
|
||||
uint8_t * WaveData = malloc(44+XAHeader.dwOutSize);
|
||||
if(WaveData == NULL){
|
||||
printf("%sMemory for this file could not be allocated.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
WaveData = malloc(44+XAHeader.dwOutSize);
|
||||
if(WaveData == NULL)
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
|
||||
BeginningTime = clock();
|
||||
if(!xa_decode(XAData+24, WaveData+44, XAHeader.Frames, XAHeader.nChannels)){
|
||||
printf("%sMemory for this file could not be allocated.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!xa_decode(XAData+24, WaveData+44, XAHeader.Frames, XAHeader.nChannels))
|
||||
Shutdown_M("Memory for this file could not be allocated");
|
||||
EndingTime = clock();
|
||||
|
||||
free(XAData);
|
||||
free(XAData); XAData = NULL;
|
||||
|
||||
/****
|
||||
** Write the Microsoft WAV header
|
||||
|
@ -142,23 +140,22 @@ int main(int argc, char *argv[]){
|
|||
if(hFile != NULL){
|
||||
/* File exists */
|
||||
char c;
|
||||
fclose(hFile);
|
||||
fclose(hFile); hFile = NULL;
|
||||
printf("File \"%s\" exists.\nContinue anyway? (y/n) ", OutFile);
|
||||
c = getchar();
|
||||
if(c != 'y' && c != 'Y'){
|
||||
printf("\nAborted.\n");
|
||||
return -1;
|
||||
printf("\n");
|
||||
Shutdown_M("Aborted");
|
||||
}
|
||||
}
|
||||
}
|
||||
hFile = fopen(OutFile, "wb");
|
||||
if(hFile == NULL){
|
||||
printf("%sThe output file could not be opened for writing.", "xadecode: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(hFile == NULL)
|
||||
Shutdown_M("The output file could not be opened for writing");
|
||||
printf("Extracted %u bytes in %.2f seconds.\n", (unsigned) XAHeader.dwOutSize,
|
||||
((float)(EndingTime - BeginningTime))/CLOCKS_PER_SEC);
|
||||
fwrite(WaveData, 1, 44+XAHeader.dwOutSize, hFile);
|
||||
free(WaveData);
|
||||
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
|
||||
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);
|
||||
ssize_t packetsize = recvfrom(epev[0].data.fd, packetdata, 1500, 0, (sockaddr*) &client_addr, &addrlen);
|
||||
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;
|
||||
|
||||
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(hitutils)
|
||||
add_subdirectory(iff2html)
|
||||
add_subdirectory(rtti-reader)
|
||||
add_subdirectory(tsoscan)
|
|
@ -27,23 +27,23 @@ int main(){
|
|||
return -1;
|
||||
}
|
||||
|
||||
cEdithEditorCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||
(cEdithEditorCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||
cTSOEdithEditorDCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||
(cTSOEdithEditorDCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||
if(GZDllGetGZCOMDirector == NULL){
|
||||
printf("TSOEdithEditor: Error: Failed to find GZDllGetGZCOMDirector() in TSOEdithEditorD.dll.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("TSOEdithEditor: Calling GZDllGetGZCOMDirector() ...\n");
|
||||
cEdithEditorCOMDirector * Edith = GZDllGetGZCOMDirector();
|
||||
cTSOEdithEditorDCOMDirector * Edith = GZDllGetGZCOMDirector();
|
||||
printf("TSOEdithEditor: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Edith);
|
||||
|
||||
while(true){
|
||||
char buffer[8];
|
||||
printf("\nCall a function (0, 1, 2, ...) or q to exit. ");
|
||||
fgets(buffer, 8, stdin);
|
||||
if(buffer[0] == 'q') break;
|
||||
Edith->Object1.vtable5[atoi(buffer)]();
|
||||
//fgets(buffer, 8, stdin);
|
||||
//if(buffer[0] == 'q') break;
|
||||
//Edith->Object1.vtable5[atoi(buffer)]();
|
||||
}
|
||||
|
||||
printf("TSOEdithEditor: Exiting.\n");
|
||||
|
|
|
@ -41,7 +41,7 @@ DECLARE_INTERFACE(cUnknownObject1)
|
|||
DWORD Unknown12;
|
||||
};
|
||||
|
||||
DECLARE_INTERFACE(cEdithEditorCOMDirector)
|
||||
DECLARE_INTERFACE(cTSOEdithEditorDCOMDirector)
|
||||
{
|
||||
void * vtable2;
|
||||
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();
|
||||
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");
|
||||
FreeLibrary(dllmodule);
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
#include <basetyps.h>
|
||||
#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 Zero2;
|
||||
void * vtable5;
|
||||
|
@ -43,13 +44,14 @@ DECLARE_INTERFACE(cUnknownObject1)
|
|||
|
||||
DECLARE_INTERFACE(cTSOSimulatorClientDCOMDirector)
|
||||
{
|
||||
//Base classes: cTSOSimulatorClientDCOMDirector, cRZCOMDllDirector, cIGZCOMDirector, cIGZUnknown, cIGZFrameWorkHooks, cIGZUnknown
|
||||
void * vtable2;
|
||||
void * vtable1;
|
||||
cUnknownObject1 Object1;
|
||||
cRZString String1;
|
||||
void * vtable4;
|
||||
void * vtable3;
|
||||
cUnknownObject1 Object2;
|
||||
cUnknownObject1 Object3;
|
||||
cRZString String2;
|
||||
cRZString String3;
|
||||
|
||||
DWORD Zero1;
|
||||
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);
|
||||
FileSize = ftell(hFile);
|
||||
if(FileSize < 64){
|
||||
fclose(hFile);
|
||||
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
@ -126,10 +127,12 @@ int main(int argc, char *argv[]){
|
|||
|
||||
IFFData = malloc(FileSize);
|
||||
if(IFFData == NULL){
|
||||
fclose(hFile);
|
||||
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
||||
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: ");
|
||||
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 "tsoscan.h"
|
||||
|
||||
void print_usage(){
|
||||
static 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"
|
||||
|
@ -43,7 +43,7 @@ int main(int argc, char *argv[]){
|
|||
FILE *OutFile;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ int main(int argc, char *argv[]){
|
|||
unsigned DirStartIndex;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ int main(int argc, char *argv[]){
|
|||
rewinddir(dir);
|
||||
Files = realloc(Files, FileCount*sizeof(char**));
|
||||
if(Files == NULL){
|
||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ int main(int argc, char *argv[]){
|
|||
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);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ int main(int argc, char *argv[]){
|
|||
|
||||
file = fopen(Files[i], "rb");
|
||||
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;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
|
@ -135,11 +135,11 @@ int main(int argc, char *argv[]){
|
|||
|
||||
data = malloc(FileSize);
|
||||
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;
|
||||
}
|
||||
if(!fread(data, FileSize, 1, file)){
|
||||
printf("%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
if(fread(data, 1, FileSize, file) != FileSize){
|
||||
fprintf(stderr, "%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
free(data);
|
||||
fclose(file);
|
||||
continue;
|
||||
|
@ -147,7 +147,7 @@ int main(int argc, char *argv[]){
|
|||
fclose(file);
|
||||
|
||||
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;
|
||||
}
|
||||
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++){
|
||||
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);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
OutFile = fopen(CmdArgs->OutFile, "wb");
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue