cog/Plugins/Dumb/archive/umx/unrealfmt.cpp

628 lines
13 KiB
C++

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "umr.h"
namespace umr {
#include "urf.h"
/*
upkg_hdr *hdr; // read the urf.h for these 4...
upkg_exports *exports;
upkg_imports *imports;
upkg_names *names;
FILE *file; // we store the file pointer globally around here
int data_size, // a way to standardize some freaky parts of the format
pkg_opened = 0; // sanity check
int indent_level;
char header[4096], // we load the header into this buffer
buf[256]; // temp buf for get_string()
*/
// this function decodes the encoded indices in the upkg files
signed long upkg::get_fci(char *in) {
signed long a;
int size;
a = 0;
size = 1;
a = in[0] & 0x3f;
if(in[0] & 0x40) {
size++;
a |= (in[1] & 0x7f) << 6;
if(in[1] & 0x80) {
size++;
a |= (in[2] & 0x7f) << 13;
if(in[2] & 0x80) {
size++;
a |= (in[3] & 0x7f) << 20;
if(in[3] & 0x80) {
size++;
a |= (in[4] & 0x3f) << 27;
}
}
}
}
if(in[0] & 0x80)
a = -a;
data_size = size;
return a;
}
unsigned long upkg::get_u32(void *addr) {
const uint8_t *addr8 = (const uint8_t *)addr;
uint32_t rval = addr8[0] | (addr8[1] << 8) | (addr8[2] << 16) | (addr8[3] << 24);
data_size = sizeof(uint32_t);
return rval;
}
signed long upkg::get_s32(void *addr) {
const uint8_t *addr8 = (const uint8_t *)addr;
int32_t rval = addr8[0] | (addr8[1] << 8) | (addr8[2] << 16) | (addr8[3] << 24);
data_size = sizeof(int32_t);
return rval;
}
signed long upkg::get_s16(void *addr) {
const uint8_t *addr8 = (const uint8_t *)addr;
int16_t rval = addr8[0] | (addr8[1] << 8);
data_size = sizeof(int16_t);
return rval;
}
signed long upkg::get_s8(void *addr) {
data_size = sizeof(int8_t);
return *(int8_t *)addr;
}
char *upkg::get_string(char *addr, int count) {
if(count > UPKG_MAX_NAME_SIZE || count == UPKG_NAME_NOCOUNT)
count = UPKG_MAX_NAME_SIZE;
strncpy(buf, addr, count); // the string stops at count chars, or is ASCIIZ
data_size = (unsigned int)(strlen(buf) + 1);
return buf;
}
signed int export_index(signed int i) {
if(i > 0) {
return i - 1;
}
return -1;
}
signed int import_index(signed int i) {
if(i < 0) {
return -i - 1;
}
return -1;
}
// idx == exports[idx], c_idx == index to the next element from idx
int upkg::set_classname(int idx, int c_idx) {
int i, next;
i = c_idx;
do {
if(i < 0) {
i = import_index(i);
if(!strcmp(names[imports[i].class_name].name, "Class")) {
exports[idx].class_name = imports[i].object_name;
return imports[i].package_index;
}
next = imports[i].package_index;
}
if(i > 0) {
i = export_index(i);
next = exports[i].class_index;
} else {
break;
}
i = next;
} while(i >= -hdr->import_count && i < hdr->export_count);
exports[idx].class_name = hdr->name_count;
return c_idx;
}
int upkg::set_pkgname(int idx, int c_idx) {
int i, next;
i = c_idx;
do {
if(i < 0) {
i = import_index(i);
if(!strcmp(names[imports[i].class_name].name, "Package")) {
exports[idx].package_name = imports[i].object_name;
return imports[i].package_index;
}
next = imports[i].package_index;
}
if(i > 0) {
i = export_index(i);
next = exports[i].class_index;
} else {
break;
}
i = next;
} while(i >= -hdr->import_count && i < hdr->export_count);
exports[idx].package_name = hdr->name_count;
return c_idx;
}
// load in the header, AWA allocating the needed memory for the tables
int upkg::load_upkg(void) {
int index, i;
index = 0;
hdr = (upkg_hdr *)header;
if(get_u32(&hdr->tag) != UPKG_HDR_TAG)
return -1;
for(i = 0; export_desc[i].version; i++) {
if(get_u32(&hdr->file_version) == export_desc[i].version) {
break;
}
}
if(export_desc[i].version == 0)
return -1;
names =
(upkg_names *)malloc(sizeof(upkg_names) * (hdr->name_count + 1));
if(names == NULL)
return -1;
exports =
(upkg_exports *)malloc(sizeof(upkg_exports) *
hdr->export_count);
if(exports == NULL) {
free(names);
return -1;
}
imports =
(upkg_imports *)malloc(sizeof(upkg_imports) *
hdr->import_count);
if(imports == NULL) {
free(exports);
free(names);
return -1;
}
return 0;
}
// load the name table
void upkg::get_names(void) {
int i, j, index;
index = (int)get_u32(&hdr->name_offset);
for(i = 0, j = (int)get_u32(&hdr->name_count); i < j; i++) {
if(get_u32(&hdr->file_version) >= 64) {
get_string(&header[index + 1],
(int)get_s8(&header[index]));
index++;
} else {
get_string(&header[index], UPKG_NAME_NOCOUNT);
}
index += data_size;
strncpy(names[i].name, buf, UPKG_MAX_NAME_SIZE);
names[i].flags = (int32_t)get_s32(&header[index]);
index += data_size;
}
// hdr->name_count + 1 names total, this one's last
strncpy(names[i].name, "(NULL)", UPKG_MAX_NAME_SIZE);
names[i].flags = 0;
}
// load the export table (which is at the end of the file... go figure)
void upkg::get_exports_cpnames(int idx) {
int x;
if(idx < 0 || idx >= get_u32(&hdr->export_count))
return;
x = (int)get_u32(&exports[idx].class_index);
x = set_classname(idx, x);
set_pkgname(idx, x);
}
void upkg::get_exports(void) {
int i, j, index;
char readbuf[1024];
reader->seek(hdr->export_offset);
reader->read(readbuf, 1024);
index = 0;
for(i = 0, j = (int)get_u32(&hdr->export_count); i < j; i++) {
exports[i].class_index = (int32_t)get_fci(&readbuf[index]);
index += data_size;
exports[i].package_index = (int32_t)get_s32(&readbuf[index]);
index += data_size;
exports[i].super_index = (int32_t)get_fci(&readbuf[index]);
index += data_size;
exports[i].object_name = (int32_t)get_fci(&readbuf[index]);
index += data_size;
exports[i].object_flags = (int32_t)get_s32(&readbuf[index]);
index += data_size;
exports[i].serial_size = (int32_t)get_fci(&readbuf[index]);
index += data_size;
if(exports[i].serial_size > 0) {
exports[i].serial_offset =
(int32_t)get_fci(&readbuf[index]);
index += data_size;
} else {
exports[i].serial_offset = -1;
}
get_exports_cpnames(i); // go grab the class & package names
}
}
// load the import table (notice a trend?). same story as get_exports()
void upkg::get_imports(void) {
int i, j, index;
char readbuf[1024];
reader->seek(hdr->import_offset);
reader->read(readbuf, 1024);
index = 0;
for(i = 0, j = (int)get_u32(&hdr->import_count); i < j; i++) {
imports[i].class_package = (int32_t)get_fci(&readbuf[index]);
index += data_size;
imports[i].class_name = (int32_t)get_fci(&readbuf[index]);
index += data_size;
imports[i].package_index = (int32_t)get_s32(&readbuf[index]);
index += data_size;
imports[i].object_name = (int32_t)get_fci(&readbuf[index]);
index += data_size;
}
}
// load the type_names
void upkg::get_type(char *buf, int e, int d) {
int i, j, index;
signed long tmp = 0;
char *chtmp;
index = 0;
for(i = 0, j = (int)strlen(export_desc[d].order); i < j; i++) {
switch(export_desc[d].order[i]) {
case UPKG_DATA_FCI:
tmp = get_fci(&buf[index]);
index += data_size;
break;
case UPKG_DATA_32:
tmp = get_s32(&buf[index]);
index += data_size;
break;
case UPKG_DATA_16:
tmp = get_s16(&buf[index]);
index += data_size;
break;
case UPKG_DATA_8:
tmp = get_s8(&buf[index]);
index += data_size;
break;
case UPKG_DATA_ASCIC:
chtmp =
get_string(&buf[index + 1],
(int)get_s8(&buf[index]));
index += data_size + 1;
break;
case UPKG_DATA_ASCIZ:
chtmp = get_string(&buf[index], UPKG_NAME_NOCOUNT);
index += data_size;
break;
case UPKG_OBJ_JUNK: // do nothing!!!
break;
case UPKG_OBJ_NAME:
exports[e].type_name = (int32_t)tmp;
break;
case UPKG_EXP_SIZE: // maybe we'll do something later on
break;
case UPKG_OBJ_SIZE:
exports[e].object_size = (int32_t)tmp;
break;
default:
exports[e].type_name = -1;
return;
}
}
exports[e].object_offset = exports[e].serial_offset + index;
}
int upkg::get_types_isgood(int idx) {
int i;
for(i = 0; export_desc[i].version; i++) {
if(export_desc[i].version == get_u32(&hdr->file_version)) {
if(strcmp(export_desc[i].class_name,
names[exports[idx].class_name].name) == 0) {
return i;
}
}
}
return -1;
}
void upkg::check_type(int e, int d) {
int i;
char readbuf[101], s, l;
reader->seek(exports[e].object_offset);
reader->read(readbuf, 100);
for(i = 0; object_desc[i].sig_offset != -1; i++) {
s = object_desc[i].sig_offset;
l = strlen(object_desc[i].object_sig);
readbuf[100] = readbuf[s + l];
readbuf[s + l] = 0;
if(!strcmp(&readbuf[s], object_desc[i].object_sig)) {
return;
}
readbuf[s + l] = readbuf[100];
}
exports[e].type_name = -1;
}
void upkg::get_types(void) {
int i, j, k;
char readbuf[UPKG_MAX_ORDERS * 4];
for(i = 0, k = (int)get_u32(&hdr->export_count); i < k; i++) {
if((j = get_types_isgood(i)) != -1) {
reader->seek(exports[i].serial_offset);
reader->read(readbuf, 4 * UPKG_MAX_ORDERS);
get_type(readbuf, i, j);
check_type(i, j);
} else {
exports[i].type_name = -1;
}
}
}
//************** GLOBALS
// open that puppy!!! gets the file opened and the data structs read for use
bool upkg::open(file_reader *p_reader) {
if(pkg_opened) // is there a pkg opened already?
return false; // if so, don't try to open another one!
if(p_reader == NULL)
return false;
reader = p_reader;
if(reader->read(header, 4096) < 4096) {
return false;
}
if(load_upkg() != 0) {
return false;
}
pkg_opened = 1;
get_names(); // this order is important.
get_imports();
get_exports();
get_types();
return true;
}
// close everything out
void upkg::close(void) {
if(pkg_opened == 0)
return;
free(imports);
free(exports);
free(names);
hdr = (upkg_hdr *)0;
pkg_opened = 0;
}
// API stuff... should be self-explainatory (upkg_o* == unreal package object *)
signed int upkg::ocount(void) {
if(pkg_opened == 0)
return -1;
return hdr->export_count;
}
char *upkg::oname(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return NULL;
return names[exports[idx].object_name].name;
}
char *upkg::oclassname(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return NULL;
return names[exports[idx].class_name].name;
}
char *upkg::opackagename(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return NULL;
return names[exports[idx].package_name].name;
}
char *upkg::otype(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return NULL;
if(exports[idx].type_name == -1)
return NULL;
return names[exports[idx].type_name].name;
}
signed int upkg::export_size(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return 0;
return exports[idx].serial_size;
}
signed int upkg::object_size(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return 0;
return exports[idx].object_size;
}
signed int upkg::export_offset(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return 0;
return exports[idx].serial_offset;
}
signed int upkg::object_offset(signed int idx) {
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return 0;
return exports[idx].object_offset;
}
int upkg::read(void *readbuf, signed int bytes, signed int offset) {
if(pkg_opened == 0)
return -1;
reader->seek(offset);
return (int)reader->read(readbuf, bytes);
}
int upkg::export_dump(file_writer *writer, signed int idx) {
int count, diff;
void *buffer;
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return -1;
buffer = malloc(4096);
if(buffer == NULL)
return -1;
reader->seek(exports[idx].serial_offset);
count = exports[idx].serial_size;
do {
diff =
(int)reader->read(buffer, ((count > 4096) ? 4096 : count));
writer->write(buffer, diff);
count -= diff;
} while(count > 0);
free(buffer);
return 0;
}
int upkg::object_dump(file_writer *writer, signed int idx) {
int count, diff;
void *buffer;
idx = export_index(idx);
if(idx == -1 || pkg_opened == 0)
return -1;
buffer = malloc(4096);
if(buffer == NULL)
return -1;
reader->seek(exports[idx].object_offset);
count = exports[idx].object_size;
do {
diff =
(int)reader->read(buffer, ((count > 4096) ? 4096 : count));
writer->write(buffer, diff);
count -= diff;
} while(count > 0);
free(buffer);
return 0;
}
} // namespace umr