From 66925054e9156855a7e734d92649cbb07318c32e Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Fri, 4 Oct 2013 19:25:45 -0700 Subject: [PATCH] Added J2B and UMX archive support --- Plugins/Dumb/Dumb.xcodeproj/project.pbxproj | 52 ++ Plugins/Dumb/DumbContainer.m | 9 +- Plugins/Dumb/DumbDecoder.h | 2 +- Plugins/Dumb/DumbDecoder.m | 140 +++-- Plugins/Dumb/DumbMetadataReader.m | 9 +- Plugins/Dumb/archive/j2b/j2b.c | 71 +++ Plugins/Dumb/archive/j2b/j2b.h | 15 + Plugins/Dumb/archive/umx/umr.h | 87 +++ Plugins/Dumb/archive/umx/umx.h | 15 + Plugins/Dumb/archive/umx/umx.mm | 64 ++ Plugins/Dumb/archive/umx/unrealfmt.cpp | 664 ++++++++++++++++++++ Plugins/Dumb/archive/umx/unrealfmtdata.cpp | 55 ++ Plugins/Dumb/archive/umx/urf.h | 113 ++++ 13 files changed, 1237 insertions(+), 59 deletions(-) create mode 100644 Plugins/Dumb/archive/j2b/j2b.c create mode 100644 Plugins/Dumb/archive/j2b/j2b.h create mode 100644 Plugins/Dumb/archive/umx/umr.h create mode 100644 Plugins/Dumb/archive/umx/umx.h create mode 100644 Plugins/Dumb/archive/umx/umx.mm create mode 100644 Plugins/Dumb/archive/umx/unrealfmt.cpp create mode 100644 Plugins/Dumb/archive/umx/unrealfmtdata.cpp create mode 100644 Plugins/Dumb/archive/umx/urf.h diff --git a/Plugins/Dumb/Dumb.xcodeproj/project.pbxproj b/Plugins/Dumb/Dumb.xcodeproj/project.pbxproj index d032c02ed..1b3d8f2f8 100644 --- a/Plugins/Dumb/Dumb.xcodeproj/project.pbxproj +++ b/Plugins/Dumb/Dumb.xcodeproj/project.pbxproj @@ -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 = ""; }; 8335FF6517FF6FD9002D8DD2 /* DumbContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DumbContainer.h; sourceTree = ""; }; 8335FF6617FF6FD9002D8DD2 /* DumbContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DumbContainer.m; sourceTree = ""; }; + 8337AAE617FFA0000081AFF8 /* umr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = umr.h; sourceTree = ""; }; + 8337AAE717FFA0000081AFF8 /* umx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = umx.h; sourceTree = ""; }; + 8337AAE817FFA0000081AFF8 /* umx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = umx.mm; sourceTree = ""; }; + 8337AAE917FFA0000081AFF8 /* unrealfmt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unrealfmt.cpp; sourceTree = ""; }; + 8337AAEA17FFA0000081AFF8 /* unrealfmtdata.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unrealfmtdata.cpp; sourceTree = ""; }; + 8337AAEB17FFA0000081AFF8 /* urf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = urf.h; sourceTree = ""; }; + 8337AAEF17FFA2D30081AFF8 /* j2b.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = j2b.c; sourceTree = ""; }; + 8337AAF017FFA2D30081AFF8 /* j2b.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = j2b.h; sourceTree = ""; }; + 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 = ""; }; D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; @@ -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 = ""; }; + 8337AAE317FFA0000081AFF8 /* archive */ = { + isa = PBXGroup; + children = ( + 8337AAE417FFA0000081AFF8 /* j2b */, + 8337AAE517FFA0000081AFF8 /* umx */, + ); + path = archive; + sourceTree = ""; + }; + 8337AAE417FFA0000081AFF8 /* j2b */ = { + isa = PBXGroup; + children = ( + 8337AAEF17FFA2D30081AFF8 /* j2b.c */, + 8337AAF017FFA2D30081AFF8 /* j2b.h */, + ); + path = j2b; + sourceTree = ""; + }; + 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 = ""; + }; /* 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; diff --git a/Plugins/Dumb/DumbContainer.m b/Plugins/Dumb/DumbContainer.m index a405c5de3..e98ea2104 100755 --- a/Plugins/Dumb/DumbContainer.m +++ b/Plugins/Dumb/DumbContainer.m @@ -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"); diff --git a/Plugins/Dumb/DumbDecoder.h b/Plugins/Dumb/DumbDecoder.h index 398b08ffc..00c5b66e7 100755 --- a/Plugins/Dumb/DumbDecoder.h +++ b/Plugins/Dumb/DumbDecoder.h @@ -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 { DUH *duh; diff --git a/Plugins/Dumb/DumbDecoder.m b/Plugins/Dumb/DumbDecoder.m index 557022e96..0297f90d1 100755 --- a/Plugins/Dumb/DumbDecoder.m +++ b/Plugins/Dumb/DumbDecoder.m @@ -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 diff --git a/Plugins/Dumb/DumbMetadataReader.m b/Plugins/Dumb/DumbMetadataReader.m index 73664e8cf..f4a7b04b7 100644 --- a/Plugins/Dumb/DumbMetadataReader.m +++ b/Plugins/Dumb/DumbMetadataReader.m @@ -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"); diff --git a/Plugins/Dumb/archive/j2b/j2b.c b/Plugins/Dumb/archive/j2b/j2b.c new file mode 100644 index 000000000..b90079b2e --- /dev/null +++ b/Plugins/Dumb/archive/j2b/j2b.c @@ -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 +#include +#include + +#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; +} diff --git a/Plugins/Dumb/archive/j2b/j2b.h b/Plugins/Dumb/archive/j2b/j2b.h new file mode 100644 index 000000000..6042b2a46 --- /dev/null +++ b/Plugins/Dumb/archive/j2b/j2b.h @@ -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 diff --git a/Plugins/Dumb/archive/umx/umr.h b/Plugins/Dumb/archive/umx/umr.h new file mode 100644 index 000000000..607527a79 --- /dev/null +++ b/Plugins/Dumb/archive/umx/umr.h @@ -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 diff --git a/Plugins/Dumb/archive/umx/umx.h b/Plugins/Dumb/archive/umx/umx.h new file mode 100644 index 000000000..5ba1e574f --- /dev/null +++ b/Plugins/Dumb/archive/umx/umx.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 diff --git a/Plugins/Dumb/archive/umx/umx.mm b/Plugins/Dumb/archive/umx/umx.mm new file mode 100644 index 000000000..ee525567d --- /dev/null +++ b/Plugins/Dumb/archive/umx/umx.mm @@ -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; +} diff --git a/Plugins/Dumb/archive/umx/unrealfmt.cpp b/Plugins/Dumb/archive/umx/unrealfmt.cpp new file mode 100644 index 000000000..2332f7c1f --- /dev/null +++ b/Plugins/Dumb/archive/umx/unrealfmt.cpp @@ -0,0 +1,664 @@ +#include +#include +#include +#include + +#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; +} + +} diff --git a/Plugins/Dumb/archive/umx/unrealfmtdata.cpp b/Plugins/Dumb/archive/umx/unrealfmtdata.cpp new file mode 100644 index 000000000..f439f8767 --- /dev/null +++ b/Plugins/Dumb/archive/umx/unrealfmtdata.cpp @@ -0,0 +1,55 @@ +#include +#include + +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 +}; + +} diff --git a/Plugins/Dumb/archive/umx/urf.h b/Plugins/Dumb/archive/umx/urf.h new file mode 100644 index 000000000..ea99ba6b3 --- /dev/null +++ b/Plugins/Dumb/archive/umx/urf.h @@ -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