1 /*
2  * mptStringBuffer.h
3  * -----------------
4  * Purpose: Various functions for "fixing" char array strings for writing to or
5  *          reading from module files, or for securing char arrays in general.
6  * Notes  : (currently none)
7  * Authors: OpenMPT Devs
8  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
9  */
10 
11 
12 #pragma once
13 
14 #include "openmpt/all/BuildSettings.hpp"
15 
16 #include "mpt/string/buffer.hpp"
17 
18 #include "mptString.h"
19 
20 #include <algorithm>
21 #include <string>
22 #include <vector>
23 
24 
25 
26 OPENMPT_NAMESPACE_BEGIN
27 
28 
29 
30 namespace mpt
31 {
32 
33 
34 namespace String
35 {
36 
37 
38 	enum ReadWriteMode : uint8
39 	{
40 		// Reading / Writing: Standard null-terminated string handling.
41 		nullTerminated = 1,
42 		// Reading: Source string is not guaranteed to be null-terminated (if it fills the whole char array).
43 		// Writing: Destination string is not guaranteed to be null-terminated (if it fills the whole char array).
44 		maybeNullTerminated = 2,
45 		// Reading: String may contain null characters anywhere. They should be treated as spaces.
46 		// Writing: A space-padded string is written.
47 		spacePadded = 3,
48 		// Reading: String may contain null characters anywhere. The last character is ignored (it is supposed to be 0).
49 		// Writing: A space-padded string with a trailing null is written.
50 		spacePaddedNull = 4,
51 	};
52 
53 	namespace detail
54 	{
55 
56 	std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize);
57 
58 	void WriteStringBuffer(String::ReadWriteMode mode, char *destBuffer, const std::size_t destSize, const char *srcBuffer, const std::size_t srcSize);
59 
60 	} // namespace detail
61 
62 
63 } // namespace String
64 
65 
66 
67 namespace String {
68 using mpt::ReadTypedBuf;
69 using mpt::WriteTypedBuf;
70 } // namespace String
71 
72 namespace String {
73 using mpt::ReadAutoBuf;
74 using mpt::WriteAutoBuf;
75 } // namespace String
76 
77 
78 
79 template <typename Tchar>
80 class StringModeBufRefImpl
81 {
82 private:
83 	Tchar * buf;
84 	std::size_t size;
85 	String::ReadWriteMode mode;
86 public:
87 	// cppcheck false-positive
88 	// cppcheck-suppress uninitMemberVar
StringModeBufRefImpl(Tchar * buf_,std::size_t size_,String::ReadWriteMode mode_)89 	StringModeBufRefImpl(Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_)
90 		: buf(buf_)
91 		, size(size_)
92 		, mode(mode_)
93 	{
94 		static_assert(sizeof(Tchar) == 1);
95 	}
96 	StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
97 	StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
98 	StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete;
99 	StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete;
string()100 	operator std::string () const
101 	{
102 		return String::detail::ReadStringBuffer(mode, buf, size);
103 	}
empty()104 	bool empty() const
105 	{
106 		return String::detail::ReadStringBuffer(mode, buf, size).empty();
107 	}
108 	StringModeBufRefImpl & operator = (const std::string & str)
109 	{
110 		String::detail::WriteStringBuffer(mode, buf, size, str.data(), str.size());
111 		return *this;
112 	}
113 };
114 
115 template <typename Tchar>
116 class StringModeBufRefImpl<const Tchar>
117 {
118 private:
119 	const Tchar * buf;
120 	std::size_t size;
121 	String::ReadWriteMode mode;
122 public:
123 	// cppcheck false-positive
124 	// cppcheck-suppress uninitMemberVar
StringModeBufRefImpl(const Tchar * buf_,std::size_t size_,String::ReadWriteMode mode_)125 	StringModeBufRefImpl(const Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_)
126 		: buf(buf_)
127 		, size(size_)
128 		, mode(mode_)
129 	{
130 		static_assert(sizeof(Tchar) == 1);
131 	}
132 	StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
133 	StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
134 	StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete;
135 	StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete;
string()136 	operator std::string () const
137 	{
138 		return String::detail::ReadStringBuffer(mode, buf, size);
139 	}
empty()140 	bool empty() const
141 	{
142 		return String::detail::ReadStringBuffer(mode, buf, size).empty();
143 	}
144 };
145 
146 namespace String {
147 template <typename Tchar, std::size_t size>
ReadBuf(String::ReadWriteMode mode,const std::array<Tchar,size> & buf)148 inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, const std::array<Tchar, size> &buf)
149 {
150 	return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf.data(), size, mode);
151 }
152 template <typename Tchar, std::size_t size>
ReadBuf(String::ReadWriteMode mode,const Tchar (& buf)[size])153 inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, const Tchar (&buf)[size])
154 {
155 	return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf, size, mode);
156 }
157 template <typename Tchar>
ReadBuf(String::ReadWriteMode mode,const Tchar * buf,std::size_t size)158 inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, const Tchar * buf, std::size_t size)
159 {
160 	return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf, size, mode);
161 }
162 template <typename Tchar, std::size_t size>
WriteBuf(String::ReadWriteMode mode,std::array<Tchar,size> & buf)163 inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, std::array<Tchar, size> &buf)
164 {
165 	return StringModeBufRefImpl<Tchar>(buf.data(), size, mode);
166 }
167 template <typename Tchar, std::size_t size>
WriteBuf(String::ReadWriteMode mode,Tchar (& buf)[size])168 inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, Tchar (&buf)[size])
169 {
170 	return StringModeBufRefImpl<Tchar>(buf, size, mode);
171 }
172 template <typename Tchar>
WriteBuf(String::ReadWriteMode mode,Tchar * buf,std::size_t size)173 inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size)
174 {
175 	return StringModeBufRefImpl<Tchar>(buf, size, mode);
176 }
177 } // namespace String
178 
179 template <std::size_t len, mpt::String::ReadWriteMode mode>
180 struct modecharbuf
181 {
182 public:
183 	typedef char Tchar;
184 	using char_type = Tchar;
185 	using string_type = std::basic_string<Tchar>;
186 public:
187 	Tchar buf[len];
188 public:
189 	modecharbuf() = default;
190 	modecharbuf(const modecharbuf &) = default;
191 	modecharbuf(modecharbuf &&) = default;
192 	modecharbuf & operator = (const modecharbuf &) = default;
193 	modecharbuf & operator = (modecharbuf &&) = default;
string_typemodecharbuf194 	operator string_type () const
195 	{
196 		return mpt::String::ReadBuf(mode, buf);
197 	}
emptymodecharbuf198 	bool empty() const
199 	{
200 		return mpt::String::ReadBuf(mode, buf).empty();
201 	}
202 	modecharbuf & operator = (const string_type & str)
203 	{
204 		mpt::String::WriteBuf(mode, buf) = str;
205 		return *this;
206 	}
207 };
208 
209 
210 // see MPT_BINARY_STRUCT
211 template <std::size_t len, mpt::String::ReadWriteMode mode>
declare_binary_safe(const typename mpt::modecharbuf<len,mode> &)212 constexpr bool declare_binary_safe(const typename mpt::modecharbuf<len, mode> &) { return true; }
213 //struct is_binary_safe<typename mpt::modecharbuf<len, mode>> : public std::true_type { };
214 static_assert(sizeof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 7);
215 static_assert(alignof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 1);
216 static_assert(std::is_standard_layout<mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>>::value);
217 
218 
219 #ifdef MODPLUG_TRACKER
220 
221 #if MPT_OS_WINDOWS
222 
223 namespace String {
224 using mpt::ReadWinBuf;
225 using mpt::WriteWinBuf;
226 } // namespace String
227 
228 #if defined(MPT_WITH_MFC)
229 
230 namespace String {
231 using mpt::ReadCStringBuf;
232 using mpt::WriteCStringBuf;
233 } // namespace String
234 
235 #endif // MPT_WITH_MFC
236 
237 #endif // MPT_OS_WINDOWS
238 
239 #endif // MODPLUG_TRACKER
240 
241 
242 
243 
244 
245 namespace String
246 {
247 
248 
249 #if MPT_COMPILER_MSVC
250 #pragma warning(push)
251 #pragma warning(disable:4127) // conditional expression is constant
252 #endif // MPT_COMPILER_MSVC
253 
254 
255 	// Sets last character to null in given char array.
256 	// Size of the array must be known at compile time.
257 	template <size_t size>
SetNullTerminator(char (& buffer)[size])258 	void SetNullTerminator(char (&buffer)[size])
259 	{
260 		static_assert(size > 0);
261 		buffer[size - 1] = 0;
262 	}
263 
SetNullTerminator(char * buffer,size_t size)264 	inline void SetNullTerminator(char *buffer, size_t size)
265 	{
266 		MPT_ASSERT(size > 0);
267 		buffer[size - 1] = 0;
268 	}
269 
270 #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
271 
272 	template <size_t size>
SetNullTerminator(wchar_t (& buffer)[size])273 	void SetNullTerminator(wchar_t (&buffer)[size])
274 	{
275 		static_assert(size > 0);
276 		buffer[size - 1] = 0;
277 	}
278 
SetNullTerminator(wchar_t * buffer,size_t size)279 	inline void SetNullTerminator(wchar_t *buffer, size_t size)
280 	{
281 		MPT_ASSERT(size > 0);
282 		buffer[size - 1] = 0;
283 	}
284 
285 #endif // !MPT_COMPILER_QUIRK_NO_WCHAR
286 
287 #if MPT_COMPILER_MSVC
288 #pragma warning(pop)
289 #endif // MPT_COMPILER_MSVC
290 
291 
292 } // namespace String
293 
294 
295 } // namespace mpt
296 
297 
298 
299 OPENMPT_NAMESPACE_END
300