1 /*
2  *  compression/DecompressorUMX.cpp
3  *
4  *  Copyright 2009 Peter Barth
5  *
6  *  This file is part of Milkytracker.
7  *
8  *  Milkytracker is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 3 of the License, or
11  *  (at your option) any later version.
12  *
13  *  Milkytracker is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 /*
24  *  DecompressorUMX.cpp
25  *  milkytracker_universal
26  *
27  *  Created by Peter Barth on 22.06.08.
28  *
29  */
30 
31 #include "DecompressorUMX.h"
32 #include "XMFile.h"
33 #include "LittleEndian.h"
34 
35 // -- UMX --------------------------------------------------------------------
DecompressorUMX(const PPSystemString & fileName)36 DecompressorUMX::DecompressorUMX(const PPSystemString& fileName) :
37 	DecompressorBase(fileName)
38 {
39 }
40 
identify(XMFile & f)41 bool DecompressorUMX::identify(XMFile& f)
42 {
43 	f.seek(0);
44 	mp_dword id = f.readDword();
45 
46 	// UMX ID
47 	return (id == 0x9E2A83C1);
48 }
49 
getDescriptors(Hints hint) const50 const PPSimpleVector<Descriptor>& DecompressorUMX::getDescriptors(Hints hint) const
51 {
52 	descriptors.clear();
53 	descriptors.add(new Descriptor("umx", "Unreal Data File"));
54 	return descriptors;
55 }
56 
57 #define TEST_SIZE 1500
58 
59 #define MAGIC4(a,b,c,d) \
60     (((pp_uint32)(a)<<24)|((pp_uint32)(b)<<16)|((pp_uint32)(c)<<8)|(d))
61 
62 #define MAGIC_IMPM	MAGIC4('I','M','P','M')
63 #define MAGIC_SCRM	MAGIC4('S','C','R','M')
64 #define MAGIC_M_K_	MAGIC4('M','.','K','.')
65 
decompress(const PPSystemString & outFileName,Hints hint)66 bool DecompressorUMX::decompress(const PPSystemString& outFileName, Hints hint)
67 {
68 	// If client requests something else than a module we can't deal we that
69 	if (hint != HintAll &&
70 		hint != HintModules)
71 		return false;
72 
73 	XMFile f(fileName);
74 
75 	int i;
76 	pp_uint8 *buf, *b;
77 	int len, offset = -1;
78 
79 	if ((b = buf = new pp_uint8[0x10000]) == NULL)
80 		return false;
81 
82 	f.read(buf, 1, TEST_SIZE);
83 	for (i = 0; i < TEST_SIZE; i++, b++) {
84 		pp_uint32 id;
85 
86 		id = BigEndian::GET_DWORD(b);
87 
88 		if (!memcmp(b, "Extended Module:", 16)) {
89 			offset = i;
90 			break;
91 		}
92 		if (id == MAGIC_IMPM) {
93 			offset = i;
94 			break;
95 		}
96 		if (i > 44 && id == MAGIC_SCRM) {
97 			offset = i - 44;
98 			break;
99 		}
100 		if (i > 1080 && id == MAGIC_M_K_) {
101 			offset = i - 1080;
102 			break;
103 		}
104 	}
105 
106 	if (offset < 0) {
107 		delete[] buf;
108 		return false;
109 	}
110 
111 	f.seek(offset);
112 
113 	XMFile fOut(outFileName, true);
114 
115 	do {
116 		len = f.read(buf, 1, 0x10000);
117 		fOut.write(buf, 1, len);
118 	} while (len == 0x10000);
119 
120 	delete[] buf;
121 
122 	return true;
123 }
124 
clone()125 DecompressorBase* DecompressorUMX::clone()
126 {
127 	return new DecompressorUMX(fileName);
128 }
129 
130 static Decompressor::RegisterDecompressor<DecompressorUMX> registerDecompressor;
131