1 /*
2  * ContainerUMX.cpp
3  * ----------------
4  * Purpose: UMX (Unreal Music) module ripper
5  * Notes  : Obviously, this code only rips modules from older Unreal Engine games, such as Unreal 1, Unreal Tournament 1 and Deus Ex.
6  * Authors: OpenMPT Devs (inspired by code from http://wiki.beyondunreal.com/Legacy:Package_File_Format)
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #include "stdafx.h"
12 #include "Loaders.h"
13 #include "UMXTools.h"
14 #include "Container.h"
15 #include "Sndfile.h"
16 
17 
18 OPENMPT_NAMESPACE_BEGIN
19 
ProbeFileHeaderUMX(MemoryFileReader file,const uint64 * pfilesize)20 CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize)
21 {
22 	return UMX::ProbeFileHeader(file, pfilesize, "music");
23 }
24 
25 
UnpackUMX(std::vector<ContainerItem> & containerItems,FileReader & file,ContainerLoadingFlags loadFlags)26 bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, ContainerLoadingFlags loadFlags)
27 {
28 	file.Rewind();
29 	containerItems.clear();
30 
31 	UMX::FileHeader fileHeader;
32 	if(!file.ReadStruct(fileHeader) || !fileHeader.IsValid())
33 		return false;
34 
35 	// Note that this can be a false positive, e.g. Unreal maps will have music and sound
36 	// in their name table because they usually import such files. However, it spares us
37 	// from wildly seeking through the file, as the name table is usually right at the
38 	// start of the file, so it is hopefully a good enough heuristic for our purposes.
39 	if(!UMX::FindNameTableEntry(file, fileHeader, "music"))
40 		return false;
41 	else if(!file.CanRead(fileHeader.GetMinimumAdditionalFileSize()))
42 		return false;
43 	else if(loadFlags == ContainerOnlyVerifyHeader)
44 		return true;
45 
46 	const std::vector<std::string> names = UMX::ReadNameTable(file, fileHeader);
47 	const std::vector<int32> classes = UMX::ReadImportTable(file, fileHeader, names);
48 
49 	// Read export table
50 	file.Seek(fileHeader.exportOffset);
51 	for(uint32 i = 0; i < fileHeader.exportCount && file.CanRead(8); i++)
52 	{
53 		auto [fileChunk, objName] = UMX::ReadExportTableEntry(file, fileHeader, classes, names, "music");
54 		if(!fileChunk.IsValid())
55 			continue;
56 
57 		ContainerItem item;
58 
59 		if(objName >= 0 && static_cast<std::size_t>(objName) < names.size())
60 		{
61 			item.name = mpt::ToUnicode(mpt::Charset::ISO8859_1, names[objName]);
62 		}
63 
64 		item.file = fileChunk;
65 
66 		containerItems.push_back(std::move(item));
67 	}
68 
69 	return !containerItems.empty();
70 }
71 
72 
73 OPENMPT_NAMESPACE_END
74