Added J2B and UMX archive support
parent
718829aabe
commit
66925054e9
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue