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