1 /*
2  * Loaders.h
3  * ---------
4  * Purpose: Common functions for module loaders
5  * Notes  : (currently none)
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 #pragma once
11 
12 #include "openmpt/all/BuildSettings.hpp"
13 
14 #include "../common/misc_util.h"
15 #include "../common/FileReader.h"
16 #include "Sndfile.h"
17 #include "SampleIO.h"
18 
19 OPENMPT_NAMESPACE_BEGIN
20 
21 // Functions to create 4-byte and 2-byte magic byte identifiers in little-endian format
22 // Use this together with uint32le/uint16le file members.
MagicLE(const char (& id)[5])23 constexpr uint32 MagicLE(const char(&id)[5])
24 {
25 	return static_cast<uint32>((static_cast<uint8>(id[3]) << 24) | (static_cast<uint8>(id[2]) << 16) | (static_cast<uint8>(id[1]) << 8) | static_cast<uint8>(id[0]));
26 }
MagicLE(const char (& id)[3])27 constexpr uint16 MagicLE(const char(&id)[3])
28 {
29 	return static_cast<uint16>((static_cast<uint8>(id[1]) << 8) | static_cast<uint8>(id[0]));
30 }
31 // Functions to create 4-byte and 2-byte magic byte identifiers in big-endian format
32 // Use this together with uint32be/uint16be file members.
33 // Note: Historically, some magic bytes in MPT-specific fields are reversed (due to the use of multi-char literals).
34 // Such fields turned up reversed in files, so MagicBE is used to keep them readable in the code.
MagicBE(const char (& id)[5])35 constexpr uint32 MagicBE(const char(&id)[5])
36 {
37 	return static_cast<uint32>((static_cast<uint8>(id[0]) << 24) | (static_cast<uint8>(id[1]) << 16) | (static_cast<uint8>(id[2]) << 8) | static_cast<uint8>(id[3]));
38 }
MagicBE(const char (& id)[3])39 constexpr uint16 MagicBE(const char(&id)[3])
40 {
41 	return static_cast<uint16>((static_cast<uint8>(id[0]) << 8) | static_cast<uint8>(id[1]));
42 }
43 
44 
45 // Read 'howMany' order items from an array.
46 // 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass uint16_max.
47 template<typename T, size_t arraySize>
48 bool ReadOrderFromArray(ModSequence &order, const T(&orders)[arraySize], size_t howMany = arraySize, uint16 stopIndex = uint16_max, uint16 ignoreIndex = uint16_max)
49 {
50 	static_assert(mpt::is_binary_safe<T>::value);
51 	LimitMax(howMany, arraySize);
52 	LimitMax(howMany, MAX_ORDERS);
53 	ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany);
54 
55 	order.resize(readEntries);
56 	for(int i = 0; i < readEntries; i++)
57 	{
58 		PATTERNINDEX pat = static_cast<PATTERNINDEX>(orders[i]);
59 		if(pat == stopIndex) pat = order.GetInvalidPatIndex();
60 		else if(pat == ignoreIndex) pat = order.GetIgnoreIndex();
61 		order.at(i) = pat;
62 	}
63 	return true;
64 }
65 
66 
67 // Read 'howMany' order items as integers with defined endianness from a file.
68 // 'stopIndex' is treated as '---', 'ignoreIndex' is treated as '+++'. If the format doesn't support such indices, just pass uint16_max.
69 template<typename T>
70 bool ReadOrderFromFile(ModSequence &order, FileReader &file, size_t howMany, uint16 stopIndex = uint16_max, uint16 ignoreIndex = uint16_max)
71 {
72 	static_assert(mpt::is_binary_safe<T>::value);
73 	if(!file.CanRead(howMany * sizeof(T)))
74 		return false;
75 	LimitMax(howMany, MAX_ORDERS);
76 	ORDERINDEX readEntries = static_cast<ORDERINDEX>(howMany);
77 
78 	order.resize(readEntries);
79 	T patF;
80 	for(auto &pat : order)
81 	{
82 		file.ReadStruct(patF);
83 		pat = static_cast<PATTERNINDEX>(patF);
84 		if(pat == stopIndex) pat = order.GetInvalidPatIndex();
85 		else if(pat == ignoreIndex) pat = order.GetIgnoreIndex();
86 	}
87 	return true;
88 }
89 
90 OPENMPT_NAMESPACE_END
91