JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
vstpresetfile.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------
2// Project : VST SDK
3//
4// Category : Helpers
5// Filename : public.sdk/source/vst/vstpresetfile.cpp
6// Created by : Steinberg, 03/2006
7// Description : VST 3 Preset File Format
8//
9//-----------------------------------------------------------------------------
10// LICENSE
11// (c) 2023, Steinberg Media Technologies GmbH, All Rights Reserved
12//-----------------------------------------------------------------------------
13// Redistribution and use in source and binary forms, with or without modification,
14// are permitted provided that the following conditions are met:
15//
16// * Redistributions of source code must retain the above copyright notice,
17// this list of conditions and the following disclaimer.
18// * Redistributions in binary form must reproduce the above copyright notice,
19// this list of conditions and the following disclaimer in the documentation
20// and/or other materials provided with the distribution.
21// * Neither the name of the Steinberg Media Technologies nor the names of its
22// contributors may be used to endorse or promote products derived from this
23// software without specific prior written permission.
24//
25// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34// OF THE POSSIBILITY OF SUCH DAMAGE.
35//-----------------------------------------------------------------------------
36
37#include "vstpresetfile.h"
38#include <algorithm>
39
40namespace Steinberg {
41namespace Vst {
42
43//------------------------------------------------------------------------
44// Preset Chunk IDs
45//------------------------------------------------------------------------
46static const ChunkID commonChunks[kNumPresetChunks] = {
47 {'V', 'S', 'T', '3'}, // kHeader
48 {'C', 'o', 'm', 'p'}, // kComponentState
49 {'C', 'o', 'n', 't'}, // kControllerState
50 {'P', 'r', 'o', 'g'}, // kProgramData
51 {'I', 'n', 'f', 'o'}, // kMetaInfo
52 {'L', 'i', 's', 't'} // kChunkList
53};
54
55//------------------------------------------------------------------------
56// Preset Header: header id + version + class id + list offset
57static const int32 kFormatVersion = 1;
58static const int32 kClassIDSize = 32; // ASCII-encoded FUID
59static const int32 kHeaderSize = sizeof (ChunkID) + sizeof (int32) + kClassIDSize + sizeof (TSize);
60static const int32 kListOffsetPos = kHeaderSize - sizeof (TSize);
61
62//------------------------------------------------------------------------
63const ChunkID& getChunkID (ChunkType type)
64{
65 return commonChunks[type];
66}
67
68#ifdef verify
69#undef verify
70#endif
71
72//------------------------------------------------------------------------
73inline bool verify (tresult result)
74{
75 return result == kResultOk || result == kNotImplemented;
76}
77
78//------------------------------------------------------------------------
79bool copyStream (IBStream* inStream, IBStream* outStream)
80{
81 if (!inStream || !outStream)
82 return false;
83
84 int8 buffer[8192];
85 int32 read = 0;
86 int32 written = 0;
87 while (inStream->read (buffer, 8192, &read) == kResultTrue && read > 0)
88 {
89 if (outStream->write (buffer, read, &written) != kResultTrue)
90 {
91 return false;
92 }
93 }
94 return true;
95}
96
97//------------------------------------------------------------------------
98// PresetFile
99//------------------------------------------------------------------------
100bool PresetFile::savePreset (IBStream* stream, const FUID& classID, IComponent* component,
101 IEditController* editController, const char* xmlBuffer, int32 xmlSize)
102{
103 PresetFile pf (stream);
104 pf.setClassID (classID);
105 if (!pf.writeHeader ())
106 return false;
107
108 if (!pf.storeComponentState (component))
109 return false;
110
111 if (editController && !pf.storeControllerState (editController))
112 return false;
113
114 if (xmlBuffer && !pf.writeMetaInfo (xmlBuffer, xmlSize))
115 return false;
116
117 return pf.writeChunkList ();
118}
119
120//------------------------------------------------------------------------
121bool PresetFile::savePreset (IBStream* stream, const FUID& classID, IBStream* componentStream,
122 IBStream* editStream, const char* xmlBuffer, int32 xmlSize)
123{
124 PresetFile pf (stream);
125 pf.setClassID (classID);
126 if (!pf.writeHeader ())
127 return false;
128
129 if (!pf.storeComponentState (componentStream))
130 return false;
131
132 if (editStream && !pf.storeControllerState (editStream))
133 return false;
134
135 if (xmlBuffer && !pf.writeMetaInfo (xmlBuffer, xmlSize))
136 return false;
137
138 return pf.writeChunkList ();
139}
140
141//------------------------------------------------------------------------
142bool PresetFile::loadPreset (IBStream* stream, const FUID& classID, IComponent* component,
143 IEditController* editController, std::vector<FUID>* otherClassIDArray)
144{
145 PresetFile pf (stream);
146 if (!pf.readChunkList ())
147 return false;
148
149 if (pf.getClassID () != classID)
150 {
151 if (otherClassIDArray)
152 {
153 // continue to load only if found in supported ID else abort load
154 if (std::find (otherClassIDArray->begin (), otherClassIDArray->end (),
155 pf.getClassID ()) == otherClassIDArray->end ())
156 return false;
157 }
158 else
159 return false;
160 }
161
162 if (!pf.restoreComponentState (component))
163 return false;
164
165 if (editController)
166 {
167 // assign component state to controller
168 if (!pf.restoreComponentState (editController))
169 return false;
170
171 // restore controller-only state (if present)
172 if (pf.contains (kControllerState) && !pf.restoreControllerState (editController))
173 return false;
174 }
175 return true;
176}
177
178//------------------------------------------------------------------------
179PresetFile::PresetFile (IBStream* stream) : stream (stream)
180{
181 memset (entries, 0, sizeof (entries));
182
183 if (stream)
184 stream->addRef ();
185}
186
187//------------------------------------------------------------------------
188PresetFile::~PresetFile ()
189{
190 if (stream)
191 stream->release ();
192}
193
194//------------------------------------------------------------------------
195const PresetFile::Entry* PresetFile::getEntry (ChunkType which) const
196{
197 const ChunkID& id = getChunkID (which);
198 for (int32 i = 0; i < entryCount; i++)
199 if (isEqualID (entries[i].id, id))
200 return &entries[i];
201 return nullptr;
202}
203
204//------------------------------------------------------------------------
206{
207 return entryCount > 0 ? &entries[entryCount - 1] : nullptr;
208}
209
210//------------------------------------------------------------------------
211bool PresetFile::readID (ChunkID id)
212{
213 int32 numBytesRead = 0;
214 stream->read (id, sizeof (ChunkID), &numBytesRead);
215 return numBytesRead == sizeof (ChunkID);
216}
217
218//------------------------------------------------------------------------
219bool PresetFile::writeID (const ChunkID id)
220{
221 int32 numBytesWritten = 0;
222 stream->write ((void*)id, sizeof (ChunkID), &numBytesWritten);
223 return numBytesWritten == sizeof (ChunkID);
224}
225
226//------------------------------------------------------------------------
227bool PresetFile::readEqualID (const ChunkID id)
228{
229 ChunkID temp = {0};
230 return readID (temp) && isEqualID (temp, id);
231}
232
233//------------------------------------------------------------------------
234bool PresetFile::readSize (TSize& size)
235{
236 int32 numBytesRead = 0;
237 stream->read (&size, sizeof (TSize), &numBytesRead);
238#if BYTEORDER == kBigEndian
239 SWAP_64 (size)
240#endif
241 return numBytesRead == sizeof (TSize);
242}
243
244//------------------------------------------------------------------------
245bool PresetFile::writeSize (TSize size)
246{
247#if BYTEORDER == kBigEndian
248 SWAP_64 (size)
249#endif
250 int32 numBytesWritten = 0;
251 stream->write (&size, sizeof (TSize), &numBytesWritten);
252 return numBytesWritten == sizeof (TSize);
253}
254
255//------------------------------------------------------------------------
256bool PresetFile::readInt32 (int32& value)
257{
258 int32 numBytesRead = 0;
259 stream->read (&value, sizeof (int32), &numBytesRead);
260#if BYTEORDER == kBigEndian
261 SWAP_32 (value)
262#endif
263 return numBytesRead == sizeof (int32);
264}
265
266//------------------------------------------------------------------------
267bool PresetFile::writeInt32 (int32 value)
268{
269#if BYTEORDER == kBigEndian
270 SWAP_32 (value)
271#endif
272 int32 numBytesWritten = 0;
273 stream->write (&value, sizeof (int32), &numBytesWritten);
274 return numBytesWritten == sizeof (int32);
275}
276
277//------------------------------------------------------------------------
278bool PresetFile::seekTo (TSize offset)
279{
280 int64 result = -1;
281 stream->seek (offset, IBStream::kIBSeekSet, &result);
282 return result == offset;
283}
284
285//------------------------------------------------------------------------
287{
288 seekTo (0);
289 entryCount = 0;
290
291 char8 classString[kClassIDSize + 1] = {0};
292
293 // Read header
294 int32 version = 0;
295 TSize listOffset = 0;
296 if (!(readEqualID (getChunkID (kHeader)) && readInt32 (version) &&
297 verify (stream->read (classString, kClassIDSize)) && readSize (listOffset) &&
298 listOffset > 0 && seekTo (listOffset)))
299 return false;
300
301 classID.fromString (classString);
302
303 // Read list
304 int32 count = 0;
305 if (!readEqualID (getChunkID (kChunkList)))
306 return false;
307 if (!readInt32 (count))
308 return false;
309
310 if (count > kMaxEntries)
311 count = kMaxEntries;
312
313 for (int32 i = 0; i < count; i++)
314 {
315 Entry& e = entries[i];
316 if (!(readID (e.id) && readSize (e.offset) && readSize (e.size)))
317 break;
318
319 entryCount++;
320 }
321
322 return entryCount > 0;
323}
324
325//------------------------------------------------------------------------
327{
328 // header id + version + class id + list offset (unknown yet)
329
330 char8 classString[kClassIDSize + 1] = {0};
331 classID.toString (classString);
332
333 return seekTo (0) && writeID (getChunkID (kHeader)) && writeInt32 (kFormatVersion) &&
334 verify (stream->write (classString, kClassIDSize)) && writeSize (0);
335}
336
337//------------------------------------------------------------------------
339{
340 // Update list offset
341 TSize pos = 0;
342 stream->tell (&pos);
343 if (!(seekTo (kListOffsetPos) && writeSize (pos) && seekTo (pos)))
344 return false;
345
346 // Write list
347 if (!writeID (getChunkID (kChunkList)))
348 return false;
349 if (!writeInt32 (entryCount))
350 return false;
351
352 for (int32 i = 0; i < entryCount; i++)
353 {
354 Entry& e = entries[i];
355 if (!(writeID (e.id) && writeSize (e.offset) && writeSize (e.size)))
356 return false;
357 }
358 return true;
359}
360
361//------------------------------------------------------------------------
362bool PresetFile::beginChunk (Entry& e, ChunkType which)
363{
364 if (entryCount >= kMaxEntries)
365 return false;
366
367 const ChunkID& id = getChunkID (which);
368 memcpy (e.id, &id, sizeof (ChunkID));
369 stream->tell (&e.offset);
370 e.size = 0;
371 return true;
372}
373
374//------------------------------------------------------------------------
375bool PresetFile::endChunk (Entry& e)
376{
377 if (entryCount >= kMaxEntries)
378 return false;
379
380 TSize pos = 0;
381 stream->tell (&pos);
382 e.size = pos - e.offset;
383 entries[entryCount++] = e;
384 return true;
385}
386
387//------------------------------------------------------------------------
388bool PresetFile::readMetaInfo (char* xmlBuffer, int32& size)
389{
390 bool result = false;
391 const Entry* e = getEntry (kMetaInfo);
392 if (e)
393 {
394 if (xmlBuffer)
395 {
396 result = seekTo (e->offset) && verify (stream->read (xmlBuffer, size, &size));
397 }
398 else
399 {
400 size = (int32)e->size;
401 result = size > 0;
402 }
403 }
404 return result;
405}
406
407//------------------------------------------------------------------------
408bool PresetFile::writeMetaInfo (const char* xmlBuffer, int32 size, bool forceWriting)
409{
410 if (contains (kMetaInfo)) // already exists!
411 {
412 if (!forceWriting)
413 return false;
414 }
415 if (!prepareMetaInfoUpdate ())
416 return false;
417
418 if (size == -1)
419 size = (int32)strlen (xmlBuffer);
420
421 Entry e = {};
422 return beginChunk (e, kMetaInfo) && verify (stream->write ((void*)xmlBuffer, size)) &&
423 endChunk (e);
424}
425
426//------------------------------------------------------------------------
428{
429 TSize writePos = 0;
430 const Entry* e = getEntry (kMetaInfo);
431 if (e)
432 {
433 // meta info must be the last entry!
434 if (e != getLastEntry ())
435 return false;
436
437 writePos = e->offset;
438 entryCount--;
439 }
440 else
441 {
442 // entries must be sorted ascending by offset!
443 e = getLastEntry ();
444 writePos = e ? e->offset + e->size : kHeaderSize;
445 }
446
447 return seekTo (writePos);
448}
449
450//------------------------------------------------------------------------
451bool PresetFile::writeChunk (const void* data, int32 size, ChunkType which)
452{
453 if (contains (which)) // already exists!
454 return false;
455
456 Entry e = {};
457 return beginChunk (e, which) && verify (stream->write ((void*)data, size)) && endChunk (e);
458}
459
460//------------------------------------------------------------------------
462{
463 const Entry* e = getEntry (kComponentState);
464 return e && seekTo (e->offset);
465}
466
467//------------------------------------------------------------------------
469{
470 if (contains (kComponentState)) // already exists!
471 return false;
472
473 Entry e = {};
474 return beginChunk (e, kComponentState) && verify (component->getState (stream)) && endChunk (e);
475}
476
477//------------------------------------------------------------------------
479{
480 if (contains (kComponentState)) // already exists!
481 return false;
482
483 Entry e = {};
484 return beginChunk (e, kComponentState) && copyStream (componentStream, stream) && endChunk (e);
485}
486
487//------------------------------------------------------------------------
489{
490 const Entry* e = getEntry (kComponentState);
491 if (!e)
492 return false;
493
494 auto readOnlyBStream = owned (new ReadOnlyBStream (stream, e->offset, e->size));
495 return verify (component->setState (readOnlyBStream));
496
497}
498
499//------------------------------------------------------------------------
501{
502 const Entry* e = getEntry (kComponentState);
503 if (e)
504 {
505 auto readOnlyBStream = owned (new ReadOnlyBStream (stream, e->offset, e->size));
506 return verify (editController->setComponentState (readOnlyBStream));
507 }
508 return false;
509}
510
511//------------------------------------------------------------------------
513{
514 const Entry* e = getEntry (kControllerState);
515 return e && seekTo (e->offset);
516}
517
518//------------------------------------------------------------------------
520{
521 if (contains (kControllerState)) // already exists!
522 return false;
523
524 Entry e = {};
525 return beginChunk (e, kControllerState) && verify (editController->getState (stream)) &&
526 endChunk (e);
527}
528
529//------------------------------------------------------------------------
531{
532 if (contains (kControllerState)) // already exists!
533 return false;
534
535 Entry e = {};
536 return beginChunk (e, kControllerState) && copyStream (editStream, stream) && endChunk (e);
537}
538
539//------------------------------------------------------------------------
541{
542 const Entry* e = getEntry (kControllerState);
543 if (e)
544 {
545 auto readOnlyBStream = owned (new ReadOnlyBStream (stream, e->offset, e->size));
546 return verify (editController->setState (readOnlyBStream));
547 }
548 return false;
549}
550
551//------------------------------------------------------------------------
553{
554 if (contains (kProgramData)) // already exists!
555 return false;
556
557 writeHeader ();
558
559 Entry e = {};
560 if (beginChunk (e, kProgramData))
561 {
562 if (writeInt32 (listID))
563 {
564 if (!copyStream (inStream, stream))
565 return false;
566
567 return endChunk (e);
568 }
569 }
570 return false;
571}
572
573//------------------------------------------------------------------------
575 int32 programIndex)
576{
577 if (contains (kProgramData)) // already exists!
578 return false;
579
580 writeHeader ();
581
582 Entry e = {};
583 return beginChunk (e, kProgramData) && writeInt32 (listID) &&
584 verify (programListData->getProgramData (listID, programIndex, stream)) && endChunk (e);
585}
586
587//------------------------------------------------------------------------
589 ProgramListID* programListID, int32 programIndex)
590{
591 const Entry* e = getEntry (kProgramData);
592 ProgramListID savedProgramListID = -1;
593 if (e && seekTo (e->offset))
594 {
595 if (readInt32 (savedProgramListID))
596 {
597 if (programListID && *programListID != savedProgramListID)
598 return false;
599
600 int32 alreadyRead = sizeof (int32);
601 auto readOnlyBStream = owned (
602 new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead));
603 return programListData && verify (programListData->setProgramData (
604 savedProgramListID, programIndex, readOnlyBStream));
605 }
606 }
607 return false;
608}
609
610//------------------------------------------------------------------------
612{
613 if (contains (kProgramData)) // already exists!
614 return false;
615
616 writeHeader ();
617
618 Entry e = {};
619 return beginChunk (e, kProgramData) && writeInt32 (unitID) &&
620 verify (unitData->getUnitData (unitID, stream)) && endChunk (e);
621}
622
623//------------------------------------------------------------------------
625{
626 const Entry* e = getEntry (kProgramData);
627 UnitID savedUnitID = -1;
628 if (e && seekTo (e->offset))
629 {
630 if (readInt32 (savedUnitID))
631 {
632 if (unitId && *unitId != savedUnitID)
633 return false;
634
635 int32 alreadyRead = sizeof (int32);
636 auto readOnlyBStream = owned (
637 new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead));
638 return (unitData && verify (unitData->setUnitData (savedUnitID, readOnlyBStream)));
639 }
640 }
641 return false;
642}
643
644//------------------------------------------------------------------------
645bool PresetFile::restoreProgramData (IUnitInfo* unitInfo, int32 unitProgramListID,
646 int32 programIndex)
647{
648 const Entry* e = getEntry (kProgramData);
649 int32 savedProgramListID = -1;
650 if (e && seekTo (e->offset))
651 {
652 if (readInt32 (savedProgramListID))
653 {
654 if (unitProgramListID != savedProgramListID)
655 return false;
656
657 int32 alreadyRead = sizeof (int32);
658 auto readOnlyBStream = owned (
659 new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead));
660 return (unitInfo && unitInfo->setUnitProgramData (unitProgramListID, programIndex,
661 readOnlyBStream));
662 }
663 }
664 return false;
665}
666
667//------------------------------------------------------------------------
668bool PresetFile::getUnitProgramListID (int32& unitProgramListID)
669{
670 const Entry* e = getEntry (kProgramData);
671 if (e && seekTo (e->offset))
672 {
673 if (readInt32 (unitProgramListID))
674 {
675 return true;
676 }
677 }
678 return false;
679}
680
681//------------------------------------------------------------------------
682// FileStream implementation
683//------------------------------------------------------------------------
684IBStream* FileStream::open (const char* filename, const char* mode)
685{
686 FILE* file = fopen (filename, mode);
687 return file ? new FileStream (file) : nullptr;
688}
689
690//------------------------------------------------------------------------
691FileStream::FileStream (FILE* file)
692: file (file) {FUNKNOWN_CTOR}
693
694//------------------------------------------------------------------------
695FileStream::~FileStream ()
696{
697 fclose (file);
698 FUNKNOWN_DTOR
699}
700
701//------------------------------------------------------------------------
702IMPLEMENT_FUNKNOWN_METHODS (FileStream, IBStream, IBStream::iid)
703
704//------------------------------------------------------------------------
705tresult PLUGIN_API FileStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
706{
707 size_t result = fread (buffer, 1, static_cast<size_t> (numBytes), file);
708 if (numBytesRead)
709 *numBytesRead = (int32)result;
710 return static_cast<int32> (result) == numBytes ? kResultOk : kResultFalse;
711}
712
713//------------------------------------------------------------------------
714tresult PLUGIN_API FileStream::write (void* buffer, int32 numBytes, int32* numBytesWritten)
715{
716 size_t result = fwrite (buffer, 1, static_cast<size_t> (numBytes), file);
717 if (numBytesWritten)
718 *numBytesWritten = (int32)result;
719 return static_cast<int32> (result) == numBytes ? kResultOk : kResultFalse;
720}
721
722//------------------------------------------------------------------------
723tresult PLUGIN_API FileStream::seek (int64 pos, int32 mode, int64* result)
724{
725 if (fseek (file, (int32)pos, mode) == 0)
726 {
727 if (result)
728 *result = ftell (file);
729 return kResultOk;
730 }
731 return kResultFalse;
732}
733
734//------------------------------------------------------------------------
735tresult PLUGIN_API FileStream::tell (int64* pos)
736{
737 if (pos)
738 *pos = ftell (file);
739 return kResultOk;
740}
741
742//------------------------------------------------------------------------
743// ReadOnlyBStream implementation
744//------------------------------------------------------------------------
745IMPLEMENT_REFCOUNT (ReadOnlyBStream)
746
747//------------------------------------------------------------------------
748ReadOnlyBStream::ReadOnlyBStream (IBStream* sourceStream, TSize sourceOffset, TSize sectionSize)
749: sourceStream (sourceStream)
750, sourceOffset (sourceOffset)
751, sectionSize (sectionSize)
752, seekPosition (0)
753{
754 FUNKNOWN_CTOR
755 if (sourceStream)
756 sourceStream->addRef ();
757}
758
759//------------------------------------------------------------------------
760ReadOnlyBStream::~ReadOnlyBStream ()
761{
762 if (sourceStream)
763 sourceStream->release ();
764
765 FUNKNOWN_DTOR
766}
767
768//------------------------------------------------------------------------
769tresult PLUGIN_API ReadOnlyBStream::queryInterface (const TUID _iid, void** obj)
770{
771 return sourceStream ? sourceStream->queryInterface (_iid, obj) : kResultFalse;
772}
773
774//------------------------------------------------------------------------
775tresult PLUGIN_API ReadOnlyBStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
776{
777 if (numBytesRead)
778 *numBytesRead = 0;
779
780 if (!sourceStream)
781 return kNotInitialized;
782
783 int32 maxBytesToRead = static_cast<int32> (sectionSize - seekPosition);
784 if (numBytes > maxBytesToRead)
785 numBytes = maxBytesToRead;
786 if (numBytes <= 0)
787 return kResultOk;
788
789 tresult result = sourceStream->seek (sourceOffset + seekPosition, kIBSeekSet);
790 if (result != kResultOk)
791 return result;
792
793 int32 numRead = 0;
794 result = sourceStream->read (buffer, numBytes, &numRead);
795
796 if (numRead > 0)
797 seekPosition += numRead;
798 if (numBytesRead)
799 *numBytesRead = numRead;
800
801 return result;
802}
803
804//------------------------------------------------------------------------
805tresult PLUGIN_API ReadOnlyBStream::write (void* /*buffer*/, int32 /*numBytes*/,
806 int32* numBytesWritten)
807{
808 if (numBytesWritten)
809 *numBytesWritten = 0;
810
811 return kNotImplemented;
812}
813
814//------------------------------------------------------------------------
815tresult PLUGIN_API ReadOnlyBStream::seek (int64 pos, int32 mode, int64* result)
816{
817 switch (mode)
818 {
819 case kIBSeekSet: seekPosition = pos; break;
820
821 case kIBSeekCur: seekPosition += pos; break;
822
823 case kIBSeekEnd: seekPosition = sectionSize + pos; break;
824 }
825
826 if (seekPosition < 0)
827 seekPosition = 0;
828 if (seekPosition > sectionSize)
829 seekPosition = sectionSize;
830
831 if (result)
832 *result = seekPosition;
833 return kResultOk;
834}
835
836//------------------------------------------------------------------------
837tresult PLUGIN_API ReadOnlyBStream::tell (int64* pos)
838{
839 if (pos)
840 *pos = seekPosition;
841 return kResultOk;
842}
843
844//------------------------------------------------------------------------
845// BufferStream implementation
846//------------------------------------------------------------------------
847IMPLEMENT_FUNKNOWN_METHODS (BufferStream, IBStream, IBStream::iid)
848
849//------------------------------------------------------------------------
850BufferStream::BufferStream () {FUNKNOWN_CTOR}
851
852//------------------------------------------------------------------------
853BufferStream::~BufferStream () {FUNKNOWN_DTOR}
854
855//------------------------------------------------------------------------
856tresult PLUGIN_API BufferStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
857{
858 uint32 size = mBuffer.get (buffer, static_cast<uint32> (numBytes));
859 if (numBytesRead)
860 *numBytesRead = static_cast<int32> (size);
861
862 return kResultTrue;
863}
864
865//------------------------------------------------------------------------
866tresult PLUGIN_API BufferStream::write (void* buffer, int32 numBytes, int32* numBytesWritten)
867{
868 bool res = mBuffer.put (buffer, static_cast<uint32> (numBytes));
869 if (numBytesWritten)
870 *numBytesWritten = res ? numBytes : 0;
871
872 return res ? kResultTrue : kResultFalse;
873}
874
875//------------------------------------------------------------------------
876tresult PLUGIN_API BufferStream::seek (int64 pos, int32 mode, int64* result)
877{
878 bool res = false;
879 switch (mode)
880 {
881 //--- -----------------
883 {
884 int64 tmp = pos;
885 if (tmp < 0)
886 tmp = 0;
887 res = mBuffer.setFillSize (static_cast<uint32> (tmp));
888 }
889 break;
890
891 //--- -----------------
893 {
894 int64 tmp = mBuffer.getFillSize () + pos;
895 if (tmp < 0)
896 tmp = 0;
897 res = mBuffer.setFillSize (static_cast<uint32> (tmp));
898 }
899 break;
900
901 //--- -----------------
903 {
904 int64 tmp = mBuffer.getSize () - pos;
905 if (tmp < 0)
906 tmp = 0;
907 res = mBuffer.setFillSize (static_cast<uint32> (tmp));
908 }
909 break;
910 }
911 if (res && result)
912 *result = mBuffer.getFillSize ();
913
914 return res ? kResultTrue : kResultFalse;
915}
916
917//------------------------------------------------------------------------
918tresult PLUGIN_API BufferStream::tell (int64* pos)
919{
920 if (pos)
921 *pos = mBuffer.getFillSize ();
922 return pos ? kResultTrue : kResultFalse;
923}
924
925//------------------------------------------------------------------------
926} // namespace Vst
927} // namespace Steinberg
T begin(T... args)
uint32 getSize() const
Definition fbuffer.h:101
bool put(uint8)
append value at end, grows Buffer if necessary
Definition fbuffer.cpp:168
bool setFillSize(uint32 c)
sets a new fill size, does not change any memory
Definition fbuffer.cpp:382
uint32 get(void *b, uint32 size)
copy to buffer from fillSize, and shift fillSize
Definition fbuffer.cpp:150
uint32 getFillSize() const
Definition fbuffer.h:117
Handling 16 Byte Globally Unique Identifiers.
Definition funknown.h:241
void toString(char8 *string) const
Converts UID to a string.
Definition funknown.cpp:296
bool fromString(const char8 *string)
Sets the UID data from a string.
Definition funknown.cpp:314
virtual uint32 PLUGIN_API addRef()=0
Adds a reference and returns the new reference count.
virtual uint32 PLUGIN_API release()=0
Releases a reference and returns the new reference count.
virtual tresult PLUGIN_API queryInterface(const TUID _iid, void **obj)=0
Query for a pointer to the specified interface.
Base class for streams.
Definition ibstream.h:30
virtual tresult PLUGIN_API tell(int64 *pos)=0
Gets current stream read-write position.
virtual tresult PLUGIN_API read(void *buffer, int32 numBytes, int32 *numBytesRead=nullptr)=0
Reads binary data from stream.
virtual tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result=nullptr)=0
Sets stream read-write position.
virtual tresult PLUGIN_API write(void *buffer, int32 numBytes, int32 *numBytesWritten=nullptr)=0
Writes binary data to stream.
@ kIBSeekCur
set seek position relative to current position
Definition ibstream.h:35
@ kIBSeekEnd
set seek position relative to stream end
Definition ibstream.h:36
@ kIBSeekSet
set absolute seek position
Definition ibstream.h:34
Stream implementation for a memory buffer.
tresult PLUGIN_API write(void *buffer, int32 numBytes, int32 *numBytesWritten=nullptr) SMTG_OVERRIDE
Writes binary data to stream.
DECLARE_FUNKNOWN_METHODS tresult PLUGIN_API read(void *buffer, int32 numBytes, int32 *numBytesRead=nullptr) SMTG_OVERRIDE
Reads binary data from stream.
tresult PLUGIN_API tell(int64 *pos) SMTG_OVERRIDE
Gets current stream read-write position.
tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result=nullptr) SMTG_OVERRIDE
Sets stream read-write position.
Stream implementation for a file using stdio.
tresult PLUGIN_API write(void *buffer, int32 numBytes, int32 *numBytesWritten=nullptr) SMTG_OVERRIDE
Writes binary data to stream.
static IBStream * open(const char *filename, const char *mode)
open a stream using stdio function
tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result=nullptr) SMTG_OVERRIDE
Sets stream read-write position.
tresult PLUGIN_API tell(int64 *pos) SMTG_OVERRIDE
Gets current stream read-write position.
Component base interface: Vst::IComponent.
virtual tresult PLUGIN_API setState(IBStream *state)=0
Sets complete state of component.
virtual tresult PLUGIN_API getState(IBStream *state)=0
Retrieves complete state of component.
Edit controller component interface: Vst::IEditController.
virtual tresult PLUGIN_API setState(IBStream *state)=0
Sets the controller state.
virtual tresult PLUGIN_API getState(IBStream *state)=0
Gets the controller state.
virtual tresult PLUGIN_API setComponentState(IBStream *state)=0
Receives the component state.
Component extension to access program list data: Vst::IProgramListData.
Definition ivstunits.h:215
virtual tresult PLUGIN_API getProgramData(ProgramListID listId, int32 programIndex, IBStream *data)=0
Gets for a given program list ID and program index the program Data.
virtual tresult PLUGIN_API setProgramData(ProgramListID listId, int32 programIndex, IBStream *data)=0
Sets for a given program list ID and program index a program Data.
Component extension to access unit data: Vst::IUnitData.
Definition ivstunits.h:247
virtual tresult PLUGIN_API getUnitData(UnitID unitId, IBStream *data)=0
Gets the preset data for the specified unit.
virtual tresult PLUGIN_API setUnitData(UnitID unitId, IBStream *data)=0
Sets the preset data for the specified unit.
Edit controller extension to describe the plug-in structure: Vst::IUnitInfo.
Definition ivstunits.h:145
virtual tresult PLUGIN_API setUnitProgramData(int32 listOrUnitId, int32 programIndex, IBStream *data)=0
Receives a preset data stream.
Handler for a VST 3 Preset File.
const Entry * getEntry(ChunkType which) const
Returns an entry for a given chunk type.
static bool loadPreset(IBStream *stream, const FUID &classID, IComponent *component, IEditController *editController=nullptr, std::vector< FUID > *otherClassIDArray=nullptr)
Shortcut helper to load preset with component/controller state.
void setClassID(const FUID &uid)
Sets the associated classID (component ID: Processor part (not the controller!)).
bool writeHeader()
Writes into the stream the main header.
bool contains(ChunkType which) const
Checks if a given chunk type exist in the stream.
PresetFile(IBStream *stream)
Constructor of Preset file based on a stream.
bool writeMetaInfo(const char *xmlBuffer, int32 size=-1, bool forceWriting=false)
Writes the meta XML info, -1 means null-terminated, forceWriting to true will force to rewrite the XM...
bool writeChunk(const void *data, int32 size, ChunkType which=kComponentState)
Writes a given data of a given size as "which" chunk type.
bool readMetaInfo(char *xmlBuffer, int32 &size)
Reads the meta XML info and its size, the size could be retrieved by passing zero as xmlBuffer.
bool storeComponentState(IComponent *component)
Stores the component state (only one time).
bool readChunkList()
Reads and build the chunk list (including the header chunk).
const Entry * getLastEntry() const
Returns the last available entry.
const FUID & getClassID() const
Returns the associated classID (component ID: Processor part (not the controller!)).
bool restoreComponentState(IComponent *component)
Restores the component state.
bool getUnitProgramListID(int32 &unitProgramListID)
Gets the unitProgramListID saved in the kProgramData chunk (if available).
bool writeChunkList()
Writes into the stream the chunk list (should be at the end).
bool seekToControllerState()
Seeks to the begin of the Controller State.
bool storeControllerState(IEditController *editController)
Stores the controller state (only one time).
bool seekToComponentState()
Seeks to the begin of the Component State.
bool prepareMetaInfoUpdate()
checks if meta info chunk is the last one and jump to correct position.
FUID classID
classID is the FUID of the component (processor) part
bool restoreControllerState(IEditController *editController)
Restores the controller state.
static bool savePreset(IBStream *stream, const FUID &classID, IComponent *component, IEditController *editController=nullptr, const char *xmlBuffer=nullptr, int32 xmlSize=-1)
Shortcut helper to create preset from component/controller state.
bool restoreProgramData(IProgramListData *programListData, ProgramListID *programListID=nullptr, int32 programIndex=0)
Restores a IProgramListData with a given identifier and index.
bool storeProgramData(IBStream *inStream, ProgramListID listID)
Store program data or unit data from stream (including the header chunk).
Internal structure used for chunk handling.
Stream representing a Read-Only subsection of its source stream.
DECLARE_FUNKNOWN_METHODS tresult PLUGIN_API read(void *buffer, int32 numBytes, int32 *numBytesRead=nullptr) SMTG_OVERRIDE
Reads binary data from stream.
tresult PLUGIN_API tell(int64 *pos) SMTG_OVERRIDE
Gets current stream read-write position.
tresult PLUGIN_API seek(int64 pos, int32 mode, int64 *result=nullptr) SMTG_OVERRIDE
Sets stream read-write position.
tresult PLUGIN_API write(void *buffer, int32 numBytes, int32 *numBytesWritten=nullptr) SMTG_OVERRIDE
Writes binary data to stream.
T end(T... args)
fclose
T find(T... args)
fopen
fread
fseek
ftell
#define SWAP_32(l)
Byte-order Conversion Macros.
Definition ftypes.h:126
fwrite
memcpy
memset
int32 ProgramListID
program list identifier
Definition vsttypes.h:82
int32 UnitID
unit identifier
Definition vsttypes.h:79
read
IPtr< I > owned(I *p)
Assigning newly created object to an IPtr.
strlen