Added J2B and UMX archive support

CQTexperiment
Chris Moeller 2013-10-04 19:25:45 -07:00
parent 718829aabe
commit 66925054e9
13 changed files with 1237 additions and 59 deletions

View File

@ -14,6 +14,11 @@
17DA363D0CC0600E0003F6B2 /* DumbMetadataReader.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17DA363B0CC0600E0003F6B2 /* DumbMetadataReader.h */; };
17DA363E0CC0600E0003F6B2 /* DumbMetadataReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 17DA363C0CC0600E0003F6B2 /* DumbMetadataReader.m */; };
8335FF6717FF6FD9002D8DD2 /* DumbContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8335FF6617FF6FD9002D8DD2 /* DumbContainer.m */; };
8337AAEC17FFA0000081AFF8 /* umx.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8337AAE817FFA0000081AFF8 /* umx.mm */; };
8337AAED17FFA0000081AFF8 /* unrealfmt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8337AAE917FFA0000081AFF8 /* unrealfmt.cpp */; };
8337AAEE17FFA0000081AFF8 /* unrealfmtdata.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8337AAEA17FFA0000081AFF8 /* unrealfmtdata.cpp */; };
8337AAF117FFA2D30081AFF8 /* j2b.c in Sources */ = {isa = PBXBuildFile; fileRef = 8337AAEF17FFA2D30081AFF8 /* j2b.c */; };
8337AAF317FFA7640081AFF8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8337AAF217FFA7640081AFF8 /* libz.dylib */; };
8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
@ -64,6 +69,15 @@
32DBCF630370AF2F00C91783 /* Dumb_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dumb_Prefix.pch; sourceTree = "<group>"; };
8335FF6517FF6FD9002D8DD2 /* DumbContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbContainer.h; sourceTree = "<group>"; };
8335FF6617FF6FD9002D8DD2 /* DumbContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DumbContainer.m; sourceTree = "<group>"; };
8337AAE617FFA0000081AFF8 /* umr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = umr.h; sourceTree = "<group>"; };
8337AAE717FFA0000081AFF8 /* umx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = umx.h; sourceTree = "<group>"; };
8337AAE817FFA0000081AFF8 /* umx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = umx.mm; sourceTree = "<group>"; };
8337AAE917FFA0000081AFF8 /* unrealfmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unrealfmt.cpp; sourceTree = "<group>"; };
8337AAEA17FFA0000081AFF8 /* unrealfmtdata.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unrealfmtdata.cpp; sourceTree = "<group>"; };
8337AAEB17FFA0000081AFF8 /* urf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = urf.h; sourceTree = "<group>"; };
8337AAEF17FFA2D30081AFF8 /* j2b.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = j2b.c; sourceTree = "<group>"; };
8337AAF017FFA2D30081AFF8 /* j2b.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = j2b.h; sourceTree = "<group>"; };
8337AAF217FFA7640081AFF8 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
8D5B49B6048680CD000E48DA /* Dumb.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Dumb.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
@ -74,6 +88,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8337AAF317FFA7640081AFF8 /* libz.dylib in Frameworks */,
17C8F7B90CBEF380008D969D /* Dumb.framework in Frameworks */,
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */,
);
@ -85,6 +100,7 @@
089C166AFE841209C02AAC07 /* Dumb */ = {
isa = PBXGroup;
children = (
8337AAF217FFA7640081AFF8 /* libz.dylib */,
08FB77AFFE84173DC02AAC07 /* Classes */,
32C88E010371C26100C91783 /* Other Sources */,
089C167CFE841241C02AAC07 /* Resources */,
@ -115,6 +131,7 @@
08FB77AFFE84173DC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
8337AAE317FFA0000081AFF8 /* archive */,
8335FF6517FF6FD9002D8DD2 /* DumbContainer.h */,
8335FF6617FF6FD9002D8DD2 /* DumbContainer.m */,
17C8F70C0CBEEC87008D969D /* Plugin.h */,
@ -169,6 +186,37 @@
name = "Other Sources";
sourceTree = "<group>";
};
8337AAE317FFA0000081AFF8 /* archive */ = {
isa = PBXGroup;
children = (
8337AAE417FFA0000081AFF8 /* j2b */,
8337AAE517FFA0000081AFF8 /* umx */,
);
path = archive;
sourceTree = "<group>";
};
8337AAE417FFA0000081AFF8 /* j2b */ = {
isa = PBXGroup;
children = (
8337AAEF17FFA2D30081AFF8 /* j2b.c */,
8337AAF017FFA2D30081AFF8 /* j2b.h */,
);
path = j2b;
sourceTree = "<group>";
};
8337AAE517FFA0000081AFF8 /* umx */ = {
isa = PBXGroup;
children = (
8337AAE617FFA0000081AFF8 /* umr.h */,
8337AAE717FFA0000081AFF8 /* umx.h */,
8337AAE817FFA0000081AFF8 /* umx.mm */,
8337AAE917FFA0000081AFF8 /* unrealfmt.cpp */,
8337AAEA17FFA0000081AFF8 /* unrealfmtdata.cpp */,
8337AAEB17FFA0000081AFF8 /* urf.h */,
);
path = umx;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -248,8 +296,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8337AAF117FFA2D30081AFF8 /* j2b.c in Sources */,
8337AAED17FFA0000081AFF8 /* unrealfmt.cpp in Sources */,
8337AAEC17FFA0000081AFF8 /* umx.mm in Sources */,
8335FF6717FF6FD9002D8DD2 /* DumbContainer.m in Sources */,
17C8F6950CBEE846008D969D /* DumbDecoder.m in Sources */,
8337AAEE17FFA0000081AFF8 /* unrealfmtdata.cpp in Sources */,
17DA363E0CC0600E0003F6B2 /* DumbMetadataReader.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -48,8 +48,15 @@ int scanCallback(void *data, int startOrder, long length)
if (![source seekable])
return 0;
[source seek:0 whence:SEEK_END];
long size = [source tell];
[source seek:0 whence:SEEK_SET];
void * data = malloc(size);
[source read:data amount:size];
DUMBFILE * df = dumbfile_open_ex(source, &dfs);
DUMBFILE * df = dumbfile_open_memory_and_free( data, size );
if (!df)
{
NSLog(@"EX Failed");

View File

@ -13,7 +13,7 @@
#import "Plugin.h"
extern DUMBFILE_SYSTEM dfs;
extern DUMBFILE *dumbfile_open_memory_and_free(char *data, long size);
@interface DumbDecoder : NSObject <CogDecoder> {
DUH *duh;

View File

@ -8,66 +8,101 @@
#import "DumbDecoder.h"
#import "umx.h"
#import "j2b.h"
@implementation DumbDecoder
int skipCallback(void *f, long n)
struct MEMANDFREEFILE
{
id source = (id)f;
if (![source seek:n whence: SEEK_CUR])
{
return 1; //Non-zero is error
}
return 0; //Zero for success
char *ptr, *ptr_begin;
long left, size;
};
static int dumb_maffile_skip(void *f, long n)
{
struct MEMANDFREEFILE *m = f;
if (n > m->left) return -1;
m->ptr += n;
m->left -= n;
return 0;
}
int getCharCallback(void *f)
static int dumb_maffile_getc(void *f)
{
id source = (id)f;
unsigned char c;
if ([source read:&c amount:1] < 1)
{
return -1;
}
return c;
struct MEMANDFREEFILE *m = f;
if (m->left <= 0) return -1;
m->left--;
return *(const unsigned char *)m->ptr++;
}
long readCallback(char *ptr, long n, void *f)
static long dumb_maffile_getnc(char *ptr, long n, void *f)
{
id source = (id)f;
return [source read:ptr amount:n];
struct MEMANDFREEFILE *m = f;
if (n > m->left) n = m->left;
memcpy(ptr, m->ptr, n);
m->ptr += n;
m->left -= n;
return n;
}
int seekCallback(void *f, long n)
static void dumb_maffile_close(void *f)
{
id source = (id)f;
if (![source seekable]) return -1;
if ([source seek:n whence:SEEK_SET]) return 0;
else return -1;
struct MEMANDFREEFILE *m = f;
free(m->ptr_begin);
free(f);
}
long getsizeCallback(void *f)
static int dumb_maffile_seek(void *f, long n)
{
id source = (id)f;
struct MEMANDFREEFILE *m = f;
if (![source seekable]) return 0;
m->ptr = m->ptr_begin + n;
m->left = m->size - n;
long current_offset = [source tell];
return 0;
}
static long dumb_maffile_get_size(void *f)
{
struct MEMANDFREEFILE *m = f;
return m->size;
}
static const DUMBFILE_SYSTEM maffile_dfs = {
NULL,
&dumb_maffile_skip,
&dumb_maffile_getc,
&dumb_maffile_getnc,
&dumb_maffile_close,
&dumb_maffile_seek,
&dumb_maffile_get_size
};
DUMBFILE *dumbfile_open_memory_and_free(char *data, long size)
{
char * try_data = unpackUmx( data, &size );
if ( try_data ) {
free( data );
data = try_data;
}
else {
try_data = unpackJ2b( data, &size );
if ( try_data ) {
free( data );
data = try_data;
}
}
[source seek:0 whence:SEEK_END];
struct MEMANDFREEFILE *m = malloc(sizeof(*m));
if (!m) return NULL;
long size = [source tell];
m->ptr_begin = data;
m->ptr = data;
m->left = size;
m->size = size;
[source seek:current_offset whence:SEEK_SET];
return size;
return dumbfile_open_ex(m, &maffile_dfs);
}
void oneTimeInit()
@ -79,16 +114,6 @@ void oneTimeInit()
}
}
DUMBFILE_SYSTEM dfs = {
.open = NULL,
.skip = skipCallback,
.getc = getCharCallback,
.getnc = readCallback,
.close = NULL,
.seek = seekCallback,
.get_size = getsizeCallback
};
int callbackLoop(void *data)
{
long * loops = (long *) data;
@ -100,11 +125,14 @@ int callbackLoop(void *data)
{
[self setSource:s];
DUMBFILE *df;
// dumb_register_stdfiles();
df = dumbfile_open_ex(s, &dfs);
[source seek:0 whence:SEEK_END];
long size = [source tell];
[source seek:0 whence:SEEK_SET];
void * data = malloc(size);
[source read:data amount:size];
DUMBFILE * df = dumbfile_open_memory_and_free( data, size );
if (!df)
{
NSLog(@"EX Failed");
@ -259,7 +287,7 @@ int callbackLoop(void *data)
+ (NSArray *)fileTypes
{
return [NSArray arrayWithObjects:@"it", @"itz", @"xm", @"xmz", @"s3m", @"s3z", @"mod", @"mdz", @"stm", @"stz", @"ptm", @"mtm", @"669", @"psm", @"am", @"dsm", @"amf", @"okt", @"okta", nil];
return [NSArray arrayWithObjects:@"it", @"itz", @"xm", @"xmz", @"s3m", @"s3z", @"mod", @"mdz", @"stm", @"stz", @"ptm", @"mtm", @"669", @"psm", @"am", @"j2b", @"dsm", @"amf", @"okt", @"okta", @"umx", nil];
}
+ (NSArray *)mimeTypes

View File

@ -34,7 +34,14 @@
if (![source seekable])
return 0;
DUMBFILE * df = dumbfile_open_ex(source, &dfs);
[source seek:0 whence:SEEK_END];
long size = [source tell];
[source seek:0 whence:SEEK_SET];
void * data = malloc(size);
[source read:data amount:size];
DUMBFILE * df = dumbfile_open_memory_and_free( data, size );
if (!df)
{
NSLog(@"EX Failed");

View File

@ -0,0 +1,71 @@
//
// j2b.c
// Dumb J2B Archive parser
//
// Created by Christopher Snowhill on 10/4/13.
// Copyright 2013 __NoWork, Inc__. All rights reserved.
//
#include <stdlib.h>
#include <stdint.h>
#include <zlib.h>
#include "j2b.h"
void * unpackJ2b( const void * in, long * size )
{
uint32_t fileLength;
uint32_t checksum;
uint32_t lenCompressed;
uint32_t lenUncompressed;
const uint8_t * in8 = ( const uint8_t * ) in;
Bytef * uncompressedData;
int zErr;
uLong dataUncompressed;
if ( *size < 8 )
return 0;
if ( in8[0] != 'M' || in8[1] != 'U' || in8[2] != 'S' || in8[3] != 'E' ||
in8[4] != 0xDE || in8[5] != 0xAD ||
( ( in8[6] != 0xBE || in8[7] != 0xAF ) && ( in8[6] != 0xBA || in8[7] != 0xBE ) ) )
{
return 0;
}
if ( *size < 12 )
return 0;
fileLength = in8[8] | (in8[9] << 8) | (in8[10] << 16) | (in8[11] << 24);
if ( fileLength < 12 || fileLength + 12 > *size )
return 0;
checksum = in8[12] | (in8[13] << 8) | (in8[14] << 16) | (in8[15] << 24);
lenCompressed = in8[16] | (in8[17] << 8) | (in8[18] << 16) | (in8[19] << 24);
lenUncompressed = in8[20] | (in8[21] << 8) | (in8[22] << 16) | (in8[23] << 24);
if ( lenCompressed + 12 > fileLength )
return 0;
if ( crc32( 0, in8 + 24, lenCompressed) != checksum )
return 0;
uncompressedData = (Bytef *) malloc( lenUncompressed );
if ( !uncompressedData )
return 0;
dataUncompressed = lenUncompressed;
zErr = uncompress( uncompressedData, &dataUncompressed, in8 + 24, lenCompressed );
if ( zErr != Z_OK )
{
free( uncompressedData );
return 0;
}
*size = dataUncompressed;
return uncompressedData;
}

View File

@ -0,0 +1,15 @@
//
// umx.h
// Dumb J2B Archive parser
//
// Created by Christopher Snowhill on 10/4/13.
// Copyright 2013 __NoWork, Inc__. All rights reserved.
//
#ifdef __cplusplus
extern "C" {
#endif
extern void * unpackJ2b( const void * in, long * size );
#ifdef __cplusplus
};
#endif

View File

@ -0,0 +1,87 @@
#ifndef _UMR_H
#define _UMR_H
namespace umr
{
class file_reader
{
public:
virtual long read(void * ptr, long howmany) =0;
virtual void seek(long where) =0;
};
class file_writer
{
public:
virtual void write(void * ptr, long howmany) =0;
};
#include "urf.h"
class upkg
{
upkg_hdr *hdr; // read the urf.h for these 4...
upkg_exports *exports;
upkg_imports *imports;
upkg_names *names;
file_reader * reader;
int data_size, // a way to standardize some freaky parts of the format
pkg_opened; // sanity check
char header[4096], // we load the header into this buffer
buf[256]; // temp buf for get_string()
public:
upkg() { pkg_opened = 0; }
~upkg() { close(); }
bool open(file_reader * reader); // open a upkg format file.
void close(void);
signed int ocount(void); // returns the number of exports
char *oname(signed int); // returns the name of the export
char *oclassname(signed int); // returns the name of the export's class
char *opackagename(signed int); // returns the name of the export's package
char *otype(signed int); // returns the name of the type of object
signed int export_size(signed int); // return the size of the export described
signed int object_size(signed int); // return the size of the object described
signed int export_offset(signed int); // return the offset to said export
signed int object_offset(signed int); // same
int read(void *, signed int, signed int); // read data from the upkg file
int export_dump(file_writer *, signed int); // dump an export
int object_dump(file_writer *, signed int); // dump an object
private:
signed long get_fci(char *in);
unsigned long get_u32(void *addr);
signed long get_s32(void *addr);
signed long get_s16(void *addr);
signed long get_s8(void *addr);
char *get_string(char *addr, int count);
int set_classname(int idx, int c_idx);
int set_pkgname(int idx, int c_idx);
int load_upkg(void);
void get_names(void);
void get_exports_cpnames(int idx);
void get_exports(void);
void get_imports(void);
void get_type(char *buf, int e, int d);
int get_types_isgood(int idx);
void check_type(int e, int d);
void get_types(void);
};
}
#endif // _UMR_H

View File

@ -0,0 +1,15 @@
//
// umx.h
// Dumb Unreal Archive parser
//
// Created by Christopher Snowhill on 10/4/13.
// Copyright 2013 __NoWork, Inc__. All rights reserved.
//
#ifdef __cplusplus
extern "C" {
#endif
extern void * unpackUmx( const void * in, long * size );
#ifdef __cplusplus
};
#endif

View File

@ -0,0 +1,64 @@
//
// umx.mm
// Dumb Unreal Archive parser
//
// Created by Christopher Snowhill on 10/4/13.
// Copyright 2013 __NoWork, Inc__. All rights reserved.
//
#include "umr.h"
#include "umx.h"
class umr_mem_reader : public umr::file_reader
{
const void * ptr;
long offset, size;
public:
umr_mem_reader(const void * buf, unsigned p_size) : ptr(buf), size(p_size), offset(0) {}
long read( void * buf, long howmany )
{
long max = size - offset;
if ( max > howmany ) max = howmany;
if ( max )
{
memcpy( buf, (const uint8_t *)ptr + offset, max );
offset += max;
}
return max;
}
void seek( long where )
{
if ( where > size ) offset = size;
else offset = where;
}
};
void * unpackUmx( const void * in, long * size )
{
umr_mem_reader memreader(in, *size);
umr::upkg pkg;
if (pkg.open(&memreader))
{
for (int i = 1, j = pkg.ocount(); i <= j; i++)
{
char * classname = pkg.oclassname(i);
if (classname && !strcmp(pkg.oclassname(i), "Music"))
{
char * type = pkg.otype(i);
if (!type) continue;
if (!strcasecmp(type, "it") || !strcasecmp(type, "s3m") || !strcasecmp(type, "xm"))
{
*size = pkg.object_size(i);
void * ret = malloc( *size );
memcpy( ret, (const uint8_t *)in + pkg.object_offset(i), *size );
return ret;
}
}
}
}
return NULL;
}

View File

@ -0,0 +1,664 @@
#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;
}
}

View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <stdlib.h>
namespace umr
{
#include "urf.h"
// version, class_name, order
const upkg_export_hdr export_desc[] = {
{61, "Music", "FjFnFd"},
{61, "Sound", "FjFnFd"},
//{61, "Palette", ""},
{62, "Music", "FjFn3sFd"},
{62, "Sound", "FjFn3sFd"},
//{62, "Palette", ""},
{63, "Music", "FjFn3sFd"},
{63, "Music", "FjFn3sFd"},
{64, "Music", "FjFn3sFd"},
{64, "Music", "FjFn3sFd"},
//{64, "Palette", ""},
{66, "Music", "FjFn3sFd"},
{66, "Sound", "FjFn3sFd"},
//{66, "Palette", ""},
{68, "Music", "FjFn3sFd"},
{68, "Sound", "FjFn3sFd"},
//{68, "Palette", ""},
{69, "Music", "FjFn3sFd"},
{69, "Sound", "FjFn3sFd"},
//{69, "Palette", ""},
{0, "", ""} // last entry must have version == 0
};
const upkg_object_hdr object_desc[] = {
{"s3m", "SCRM", 44/*, "ScreamTracker 3"*/}
,
{"it", "IMPM", 0 /*, "Impluse Tracker" */}
,
{"xm", "Fast", 38 /*, "FastTracker 2.0" */}
,
//{"WAV", "WAVE", 8, "MS PCM Sound"}
//,
{"", "", -1 /*, ""*/} // last entry must have sig_offset == -1
};
}

View File

@ -0,0 +1,113 @@
#ifndef _URF_H
#define _URF_H
#define UPKG_MAX_NAME_SIZE 64
#define UPKG_MAX_ORDERS 10
// all data types in upkg files are signed
#define UPKG_DATA_FCI 'F'
#define UPKG_DATA_32 '3'
#define UPKG_DATA_16 '1'
#define UPKG_DATA_8 '8'
#define UPKG_DATA_ASCIC 'C'
#define UPKG_DATA_ASCIZ 'Z'
#define UPKG_OBJ_JUNK 'j'
#define UPKG_OBJ_NAME 'n'
#define UPKG_EXP_SIZE 's'
#define UPKG_OBJ_SIZE 'd'
#define UPKG_NAME_NOCOUNT -1
#define UPKG_HDR_TAG 0x9e2a83c1
enum upkg_flags {
RF_Transactional = 0x00000001,
RF_SourceModified = 0x00000002,
RF_Public = 0x00000004,
RF_LoadForClient = 0x00010000,
RF_LoadForServer = 0x00020000,
RF_LoadForEdit = 0x00040000,
RF_Standalone = 0x00080000,
RF_HasStack = 0x02000000,
RF_Intrinsic = 0x04000000
};
struct unreal_pkg_hdr {
int32_t tag, // hdr tag, should == UPKG_HDR_TAG
file_version, // should be 61 for unreal. > for UT
pkg_flags, // bitflags.. we don't need them
name_count, // number of names in name table (>= 0)
name_offset, // offset to name table (>= 0)
export_count, // num. exports in export table (>= 0)
export_offset, // offset to export table (>= 0)
import_count, // -- seeing a trend yet? (>= 0)
import_offset, // (>= 0)
heritage_count, // heritage table (has GUID's) (>= 1)
heritage_offset; // (>= 0)
};
/* indices have 2 types. type 1 is harder, so I'll describe type 2 first. =)
type 2 is an index into the name table (upkg_name_table). pure and simple.
type 1 is an index into either the imports table, or the exports table, or NULL.
if index == 0, you can ignore it
if index < 0, use imports[-index - 1]
if index > 0, use exports[index - 1]
type 1 is used for dependency/inheritancy info
*/
struct unreal_pkg_export_tbl {
int32_t class_index, // index, type 1
package_index, // index, type 1
super_index, // index, type 1
object_name, // index, type 2
object_flags, // flags for the object (will be supported when I decide to code it ;-)
serial_size, // size of export described
serial_offset, // start of the export in the the package file (offset from beginning of file)
class_name, // index, type 2 (the name of the object class)
package_name, // index, type 2 (the name of the object package)
type_name, // index, type 2 (the name of the object type)
object_size, // bytes of data in object
object_offset; // offset into package file that object starts
};
struct unreal_pkg_import_tbl {
int32_t class_package, // index, type 2
class_name, // index, type 2
package_index, // index, type 1
object_name; // index, type 2
};
struct unreal_pkg_name_tbl {
char name[UPKG_MAX_NAME_SIZE]; // a name
int32_t flags; // flags for the name
};
struct unreal_pkg_export_hdr {
int32_t version; // version of pkg header this supports
const char * class_name; //[UPKG_MAX_NAME_SIZE]; // unreal class
const char * order; //[UPKG_MAX_ORDERS * 10]; // order of the header
};
struct unreal_pkg_object_hdr {
const char type_str[4]; // type string of the object type
const char object_sig[5]; // sig of the object data (if exists)
int32_t sig_offset; // offset in object that object_sig occurs
//char desc[33]; // description of the object
};
typedef struct unreal_pkg_hdr upkg_hdr;
typedef struct unreal_pkg_export_tbl upkg_exports;
typedef struct unreal_pkg_import_tbl upkg_imports;
typedef struct unreal_pkg_name_tbl upkg_names;
typedef struct unreal_pkg_export_hdr upkg_export_hdr;
typedef struct unreal_pkg_object_hdr upkg_object_hdr;
extern const upkg_export_hdr export_desc[];
extern const upkg_object_hdr object_desc[];
#endif // _URF_H