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

665 lines
13 KiB
C++

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.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 = 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 = get_u32(&hdr->name_offset);
for (i = 0, j = get_u32(&hdr->name_count); i < j; i++) {
if (get_u32(&hdr->file_version) >= 64) {
get_string(&header[index + 1],
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 = 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 = 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 = get_u32(&hdr->export_count); i < j; i++) {
exports[i].class_index = get_fci(&readbuf[index]);
index += data_size;
exports[i].package_index = get_s32(&readbuf[index]);
index += data_size;
exports[i].super_index = get_fci(&readbuf[index]);
index += data_size;
exports[i].object_name = get_fci(&readbuf[index]);
index += data_size;
exports[i].object_flags = get_s32(&readbuf[index]);
index += data_size;
exports[i].serial_size = get_fci(&readbuf[index]);
index += data_size;
if (exports[i].serial_size > 0) {
exports[i].serial_offset =
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 = get_u32(&hdr->import_count); i < j; i++) {
imports[i].class_package = get_fci(&readbuf[index]);
index += data_size;
imports[i].class_name = get_fci(&readbuf[index]);
index += data_size;
imports[i].package_index = get_s32(&readbuf[index]);
index += data_size;
imports[i].object_name = 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;
char *chtmp;
index = 0;
for (i = 0, j = 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],
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 = tmp;
break;
case UPKG_EXP_SIZE: // maybe we'll do something later on
break;
case UPKG_OBJ_SIZE:
exports[e].object_size = 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 = 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 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 =
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 =
reader->read(buffer, ((count > 4096) ? 4096 : count));
writer->write(buffer, diff);
count -= diff;
} while (count > 0);
free(buffer);
return 0;
}
}