Finale PDK Framework 0.77
Power Up Your Finale Music Software
Loading...
Searching...
No Matches
ff_simple_edt.h
1//
2// ff_simple_edt.h
3// RGPLua
4//
5// Created by Robert Patterson on 3/3/24.
6//
7
8#ifndef ff_simple_edt_h
9#define ff_simple_edt_h
10
11#include <optional>
12#include <finalepdk.h>
13
14#ifndef DOXYGEN_SHOULD_IGNORE_THIS
15
19const size_t kInciSize = 12;
20
22template <typename EDTTYPE, EXTAG TAG>
23class __FCSimpleEDTStruct : public EDTTYPE
24{
25protected:
26 EDataID _id;
27
28 __FCSimpleEDTStruct() // can only be constructed by subclasses
29 { memset(this, 0, sizeof(*this)); }
30
31 __FCSimpleEDTStruct(const EDTTYPE& edtStruct) : EDTTYPE(edtStruct) // can only be constructed by subclasses
32 { memset(&_id, 0, sizeof(_id)); }
33
34public:
35 void InitializeEDTStruct()
36 {
37 EDTTYPE * pEDT = dynamic_cast<EDTTYPE * >(this);
38 assert(pEDT != nullptr);
39 memset(pEDT, 0, sizeof(EDTTYPE));
40 }
41
42 bool Load(std::optional<std::reference_wrapper<EDTTYPE>> copyToStruct = std::nullopt)
43 {
44 fourbyte datasize = sizeof(EDTTYPE);
45 bool retval = FX_LoadEData(TAG, &_id, static_cast<EDTTYPE *>(this), &datasize);
46 if (retval && copyToStruct.has_value())
47 copyToStruct.value().get() = *static_cast<EDTTYPE *>(this);
48 return retval;
49 }
50
54 bool LoadFirst()
55 {
56 if (Load()) return true;
57 return LoadNext();
58 }
59
60 bool LoadNext() { return FX_NextEData(TAG, &_id, static_cast<EDTTYPE *>(this), sizeof(EDTTYPE)); }
61 bool LoadPrevious() { return FX_PreviousEData(TAG, &_id, static_cast<EDTTYPE *>(this), sizeof(EDTTYPE)); }
62 bool Save() { return FX_SaveEData(TAG, &_id, static_cast<EDTTYPE *>(this), sizeof(EDTTYPE)); }
63 bool Create() { return FX_CreateEData(TAG, &_id, static_cast<EDTTYPE *>(this), sizeof(EDTTYPE)); }
64 bool Delete() { return FX_DeleteEData(TAG, &_id); }
65};
66
67template <typename EDTTYPE, EXTAG TAG>
68class __FCSimpleOther : public __FCSimpleEDTStruct<EDTTYPE,TAG>
69{
70public:
71 __FCSimpleOther(const CMPER cmper = kNewCmper, const twobyte inci = 0)
72 {
73 __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.cmper = cmper;
74 __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.inci = inci;
75 }
76
77 __FCSimpleOther(const EDTTYPE& edtStruct, const CMPER cmper = kNewCmper, const twobyte inci = 0) : __FCSimpleEDTStruct<EDTTYPE,TAG>(edtStruct)
78 {
79 __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.cmper = cmper;
80 __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.inci = inci;
81 }
82
83 CMPER GetCmper() const
84 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.cmper; }
85
86 void SetCmper(const CMPER cmper)
87 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.cmper = cmper; }
88
89 twobyte GetInci() const
90 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.inci; }
91
92 void SetInci(const twobyte inci)
93 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.other.inci = inci; }
94};
95
96template <typename EDTTYPE, EXTAG TAG>
97class __FCSimpleDetail : public __FCSimpleEDTStruct<EDTTYPE,TAG>
98{
99public:
100 __FCSimpleDetail(const CMPER cmper1 = kNewCmper, const CMPER cmper2 = kNewCmper2, const twobyte inci = 0)
101 {
102 __FCSimpleDetail<EDTTYPE,TAG>::_id.detail.cmper1 = cmper1;
103 __FCSimpleDetail<EDTTYPE,TAG>::_id.detail.cmper2 = cmper2;
104 __FCSimpleDetail<EDTTYPE,TAG>::_id.detail.inci = inci;
105 }
106
107 __FCSimpleDetail(const EDTTYPE& edtStruct, const CMPER cmper1 = kNewCmper, const CMPER cmper2 = kNewCmper2, const twobyte inci = 0) :
108 __FCSimpleEDTStruct<EDTTYPE,TAG>(edtStruct)
109 {
110 __FCSimpleDetail<EDTTYPE,TAG>::_id.detail.cmper1 = cmper1;
111 __FCSimpleDetail<EDTTYPE,TAG>::_id.detail.cmper2 = cmper2;
112 __FCSimpleDetail<EDTTYPE,TAG>::_id.detail.inci = inci;
113 }
114
115 CMPER GetCmper1() const
116 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.detail.cmper1; }
117
118 void SetCmper1(const CMPER cmper)
119 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.detail.cmper1 = cmper; }
120
121 CMPER GetCmper2() const
122 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.detail.cmper2; }
123
124 void SetCmper2(const CMPER cmper)
125 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.detail.cmper2 = cmper; }
126
127 twobyte GetInci() const
128 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.detail.inci; }
129
130 void SetInci(const twobyte inci)
131 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.detail.inci = inci; }
132};
133
134template <typename EDTTYPE, EXTAG TAG>
135class __FCSimpleEntryDetail : public __FCSimpleEDTStruct<EDTTYPE,TAG>
136{
137public:
138 __FCSimpleEntryDetail(const ENTNUM entryNumber = kNewEntryNum, const twobyte inci = 0)
139 {
140 __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.entryDetail.entryNumber = entryNumber;
141 __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.entryDetail.inci = inci;
142 }
143
144 ENTNUM GetEntryNumber() const
145 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.entryDetail.entryNumber; }
146
147 void SetEntryNumber(const ENTNUM entryNumber)
148 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.entryDetail.entryNumber = entryNumber; }
149
150 twobyte GetInci() const
151 { return __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.entryDetail.inci; }
152
153 void SetInci(const twobyte inci)
154 { __FCSimpleEDTStruct<EDTTYPE,TAG>::_id.entryDetail.inci = inci; }
155};
156
158template <typename EDTTYPE, EXTAG TAG>
159class __FCEnigmaArray
160{
161 static_assert(HI_UTWOBYTE(TAG) == edOther || HI_UTWOBYTE(TAG) == edDetail, "EXTAG must be edDetail or edOther");
162 static constexpr bool IS_DETAIL = HI_UTWOBYTE(TAG) == edDetail;
163
164 CMPER _cmper1;
165 CMPER _cmper2;
166
167 int _maxelements; // the caller can specify a number of elements smaller than the full last inci
168 std::vector<char> _buffer;
169
170 static constexpr size_t INCISIZE = std::conditional_t<IS_DETAIL, std::integral_constant<size_t, 5>, std::integral_constant<size_t, 6>>::value;
171 class INCITYPE
172 {
173 twobyte inci[INCISIZE];
174 };
175
176 void AddToBuffer(const INCITYPE& inci)
177 {
178 size_t currsize = _buffer.size();
179 _buffer.resize(currsize + sizeof(inci));
180 memcpy(&_buffer[currsize], &inci, sizeof(inci));
181 }
182
183 auto GetInciType()
184 {
185 if constexpr(IS_DETAIL)
186 return __FCSimpleDetail<INCITYPE, TAG>(_cmper1, _cmper2, 0);
187 else
188 return __FCSimpleOther<INCITYPE, TAG>(_cmper1, 0);
189 }
190
191 bool GetInci(size_t incino, INCITYPE& inci)
192 {
193 size_t buffx = incino * sizeof(inci);
194 if (buffx < _buffer.size())
195 {
196 memset(&inci, 0, sizeof(inci));
197 memcpy(&inci, &_buffer[buffx], (std::min)(sizeof(inci), _buffer.size() - buffx));
198 return true;
199 }
200 return false;
201 }
202
203 template <class T>
204 void StoreCmpers(const T& inci)
205 {
206 if constexpr(IS_DETAIL)
207 {
208 _cmper1 = inci.GetCmper1();
209 _cmper2 = inci.GetCmper2();
210 }
211 else
212 {
213 _cmper1 = inci.GetCmper();
214 _cmper2 = 0;
215 }
216 }
217
218protected:
219 void AssignBuffer(const void* buffer, size_t numbytes)
220 {
221 _buffer.clear();
222 _buffer.resize(numbytes);
223 memcpy(_buffer.data(), buffer, _buffer.size());
224 }
225
226 bool _Load(CMPER cmper1, CMPER cmper2)
227 {
228 _cmper1 = cmper1;
229 _cmper2 = cmper2;
230 auto loader = GetInciType();
231 _buffer.clear();
232 for (EINCI inci = 0; true; inci++)
233 {
234 loader.SetInci(inci);
235 if (!loader.Load()) break;
236 AddToBuffer(loader);
237 }
238 return _buffer.size() > 0;
239 }
240
241 bool _SaveAs(CMPER cmper1, CMPER cmper2)
242 {
243 _cmper1 = cmper1;
244 _cmper2 = cmper2;
245 return Save();
246 }
247
248 bool _Delete(CMPER cmper1, CMPER cmper2)
249 {
250 _cmper1 = cmper1;
251 _cmper2 = cmper2;
252 return Delete();
253 }
254
255 CMPER _GetCmper1() const { return _cmper1; }
256 CMPER _GetCmper2() const { return _cmper2; }
257
258 void _SetCmper1(CMPER cmper) { _cmper1 = cmper; }
259 void _SetCmper2(CMPER cmper) { _cmper2 = cmper; }
260
261 const void* GetBuffer() const { return _buffer.data(); }
262
263 __FCEnigmaArray(const int maxelements) : _cmper1(kNewCmper), _cmper2(0), _maxelements(maxelements)
264 {
265 if (maxelements) AllocateFor(maxelements);
266 }
267
268public:
269
270 EDTTYPE& operator[](const size_t x)
271 {
272 const size_t requiredSize = (x + 1) * sizeof(EDTTYPE);
273 if (requiredSize > _buffer.size())
274 _buffer.resize(requiredSize);
275 return reinterpret_cast<EDTTYPE *>(_buffer.data())[x];
276 }
277
278 const EDTTYPE& operator[](const size_t x) const
279 {
280 assert(x * sizeof(EDTTYPE) <= _buffer.size() - sizeof(EDTTYPE));
281 return reinterpret_cast<const EDTTYPE *>(_buffer.data())[x];
282 }
283
284 void Reset()
285 {
286 _buffer.clear();
287 }
288
289 int NumElements() const
290 {
291 assert(_buffer.size() % sizeof(EDTTYPE) == 0);
292 int _physicalElements = static_cast<int>(_buffer.size() / sizeof(EDTTYPE));
293 if (_maxelements)
294 return (std::min)(_physicalElements, _maxelements);
295 return _physicalElements;
296 }
297
298 void AllocateFor(const int numelements)
299 {
300 assert(numelements >= 0);
301 _buffer.clear();
302 if (numelements)
303 {
304 size_t newsize = numelements * sizeof(EDTTYPE);
305 size_t remainder = newsize % INCISIZE*sizeof(twobyte);
306 if (remainder) newsize += remainder;
307 _buffer.resize(newsize);
308 }
309 _maxelements = numelements;
310 }
311
312 bool LoadNext()
313 {
314 auto inci = GetInciType();
315 inci.SetInci(TWOBYTE_MAX);
316 if (inci.LoadNext())
317 {
318 StoreCmpers(inci);
319 return _Load(_cmper1, _cmper2);
320 }
321 return false;
322 }
323
324 bool LoadFirst()
325 {
326 if (_Load(0,0)) return true;
327 return LoadNext();
328 }
329
330 bool Save()
331 {
332 Delete();
333 auto saver = GetInciType();
334 for (int inci = 0; GetInci(inci, saver); inci++)
335 {
336 saver.SetInci(inci);
337 bool success = (_cmper1 == kNewCmper) ? saver.Create() : saver.Save();
338 if (!success) return false;
339 }
340 StoreCmpers(saver);
341 return true;
342 }
343
344 bool Delete()
345 {
346 auto deleter = GetInciType();
347 bool deletedSomething = false;
348 while (deleter.Delete())
349 deletedSomething = true;
350 return deletedSomething;
351 }
352};
353
354template <typename EDTTYPE, EXTAG TAG>
355class __FCEnigmaOtherArray : public __FCEnigmaArray<EDTTYPE, TAG>
356{
357 static_assert(HI_UTWOBYTE(TAG) == edOther, "EXTAG must be edOther");
358 using __FCEnigmaOtherArrayBase = __FCEnigmaArray<EDTTYPE, TAG>;
359
360public:
367 __FCEnigmaOtherArray(const int maxelements = 0) : __FCEnigmaOtherArrayBase(maxelements) {}
368
369 CMPER GetCmper() const { return this->_GetCmper1(); }
370 void SetCmper(CMPER cmper) { this->_SetCmper1(cmper); }
371
372 bool Load(CMPER cmper) { return this->_Load(cmper, 0); }
373 bool SaveAs(CMPER cmper) { return this->_SaveAs(cmper, 0); }
374 bool Delete(CMPER cmper) { return this->_Delete(cmper, 0); }
375};
376
377template <typename EDTTYPE, EXTAG TAG>
378class __FCEnigmaDetailArray : public __FCEnigmaArray<EDTTYPE, TAG>
379{
380 static_assert(HI_UTWOBYTE(TAG) == edDetail, "EXTAG must be edDetail");
381 using __FCEnigmaDetailArrayBase = __FCEnigmaArray<EDTTYPE, TAG>;
382
383public:
390 __FCEnigmaDetailArray(const int maxelements = 0) : __FCEnigmaDetailArrayBase(maxelements) {}
391
392 using __FCEnigmaDetailArrayBase::LoadFirst;
393
394 CMPER GetCmper1() const { return this->_GetCmper1(); }
395 CMPER GetCmper2() const { return this->_GetCmper2(); }
396
397 void SetCmper1(CMPER cmper) { this->_SetCmper1(cmper); }
398 void SetCmper2(CMPER cmper) { this->_SetCmper2(cmper); }
399
400 bool Load(CMPER cmper1, CMPER cmper2) { return this->_Load(cmper1, cmper2); }
401 bool SaveAs(CMPER cmper1, CMPER cmper2) { return this->_SaveAs(cmper1, cmper2); }
402 bool Delete(CMPER cmper1, CMPER cmper2) { return this->_Delete(cmper1, cmper2); }
403
404 bool LoadNext(CMPER cmper1)
405 {
406 if (!__FCEnigmaDetailArrayBase::LoadNext()) return false;
407 return (cmper1 == GetCmper1());
408 }
409
410 bool LoadFirst(CMPER cmper1)
411 {
412 if (Load(cmper1, 0)) return true;
413 return LoadNext(cmper1);
414 }
415
416 bool LoadNextCmper1()
417 {
418 if (GetCmper1() == kNewCmper) return false; // kNewCmper is also the max cmper value
419 if (Load(GetCmper1() + 1, 0)) return true;
420 return __FCEnigmaDetailArrayBase::LoadNext();
421 }
422
423 bool Delete(CMPER cmper1)
424 {
425 if (LoadFirst(cmper1))
426 {
427 Delete(cmper1, GetCmper2());
428 while (LoadNext(cmper1))
429 Delete(cmper1, GetCmper2());
430 return true;
431 }
432 return false;
433 }
434};
435
436template <typename CHARTYPE, EXTAG TAG>
437class __FCEnigmaArrayString : public std::conditional_t<HI_UTWOBYTE(TAG) == edDetail, __FCEnigmaDetailArray<CHARTYPE, TAG>, __FCEnigmaOtherArray<CHARTYPE, TAG>>
438{
439 static_assert(std::is_integral<CHARTYPE>::value, "CHARTYPE must be an integer type");
440 using __FCEnigmaArrayStringBase = std::conditional_t<HI_UTWOBYTE(TAG) == edDetail, __FCEnigmaDetailArray<CHARTYPE, TAG>, __FCEnigmaOtherArray<CHARTYPE, TAG>>;
441
442public:
443 __FCEnigmaArrayString() : __FCEnigmaArrayStringBase() {}
444
445 template<std::size_t N>
446 __FCEnigmaArrayString(const CHARTYPE (&inpstr)[N]) : __FCEnigmaArrayStringBase()
447 { AssignString<N>(inpstr); }
448
449 template<std::size_t N>
450 void AssignString(const CHARTYPE (&inpstr)[N])
451 {
452 const std::size_t bufLen = sizeof(CHARTYPE) * (std::min)(N, std::char_traits<CHARTYPE>::length(inpstr) + 1);
453 __FCEnigmaArrayStringBase::AssignBuffer(inpstr, bufLen);
454 }
455
456 void AssignString(const CHARTYPE* inpstr)
457 {
458 const std::size_t bufLen = sizeof(CHARTYPE) * std::char_traits<CHARTYPE>::length(inpstr) + 1;
459 __FCEnigmaArrayStringBase::AssignBuffer(inpstr, bufLen);
460 }
461
462 const CHARTYPE* GetString() const { return reinterpret_cast<const CHARTYPE*>(this->GetBuffer()); }
463};
464
465template<size_t SIZE>
466struct __FCEnigmaInciStruct
467{
468 twobyte data[SIZE];
469 const twobyte& operator[](size_t index) const { return data[index]; }
470 twobyte& operator[](size_t index) { return data[index]; }
471};
472template<EXTAG TAG>
473class __FCEnigmaOtherInci : public __FCSimpleOther<__FCEnigmaInciStruct<6>, TAG>
474{
475public:
476 __FCEnigmaOtherInci(CMPER cmper, twobyte inci) : __FCSimpleOther<__FCEnigmaInciStruct<6>, TAG>(cmper, inci) {}
477};
478
479#endif // DOXYGEN_SHOULD_IGNORE_THIS
480
481
482#endif /* ff_simple_edt_h */