46static const ChunkID commonChunks[kNumPresetChunks] = {
57static const int32 kFormatVersion = 1;
58static const int32 kClassIDSize = 32;
59static const int32 kHeaderSize =
sizeof (ChunkID) +
sizeof (int32) + kClassIDSize +
sizeof (TSize);
60static const int32 kListOffsetPos = kHeaderSize -
sizeof (TSize);
63const ChunkID& getChunkID (ChunkType type)
65 return commonChunks[type];
73inline bool verify (tresult result)
75 return result == kResultOk || result == kNotImplemented;
79bool copyStream (IBStream* inStream, IBStream* outStream)
81 if (!inStream || !outStream)
87 while (inStream->read (buffer, 8192, &read) == kResultTrue && read > 0)
89 if (outStream->write (buffer, read, &written) != kResultTrue)
122 IBStream* editStream,
const char* xmlBuffer, int32 xmlSize)
126 if (!pf.writeHeader ())
129 if (!pf.storeComponentState (componentStream))
132 if (editStream && !pf.storeControllerState (editStream))
135 if (xmlBuffer && !pf.writeMetaInfo (xmlBuffer, xmlSize))
138 return pf.writeChunkList ();
151 if (otherClassIDArray)
181 memset (entries, 0,
sizeof (entries));
188PresetFile::~PresetFile ()
197 const ChunkID&
id = getChunkID (which);
198 for (int32 i = 0; i < entryCount; i++)
199 if (isEqualID (entries[i].
id,
id))
207 return entryCount > 0 ? &entries[entryCount - 1] :
nullptr;
211bool PresetFile::readID (ChunkID
id)
213 int32 numBytesRead = 0;
214 stream->
read (
id,
sizeof (ChunkID), &numBytesRead);
215 return numBytesRead ==
sizeof (ChunkID);
219bool PresetFile::writeID (
const ChunkID
id)
221 int32 numBytesWritten = 0;
222 stream->
write ((
void*)
id,
sizeof (ChunkID), &numBytesWritten);
223 return numBytesWritten ==
sizeof (ChunkID);
227bool PresetFile::readEqualID (
const ChunkID
id)
230 return readID (temp) && isEqualID (temp,
id);
234bool PresetFile::readSize (TSize& size)
236 int32 numBytesRead = 0;
237 stream->
read (&size,
sizeof (TSize), &numBytesRead);
238#if BYTEORDER == kBigEndian
241 return numBytesRead ==
sizeof (TSize);
245bool PresetFile::writeSize (TSize size)
247#if BYTEORDER == kBigEndian
250 int32 numBytesWritten = 0;
251 stream->
write (&size,
sizeof (TSize), &numBytesWritten);
252 return numBytesWritten ==
sizeof (TSize);
256bool PresetFile::readInt32 (int32& value)
258 int32 numBytesRead = 0;
259 stream->
read (&value,
sizeof (int32), &numBytesRead);
260#if BYTEORDER == kBigEndian
263 return numBytesRead ==
sizeof (int32);
267bool PresetFile::writeInt32 (int32 value)
269#if BYTEORDER == kBigEndian
272 int32 numBytesWritten = 0;
273 stream->
write (&value,
sizeof (int32), &numBytesWritten);
274 return numBytesWritten ==
sizeof (int32);
278bool PresetFile::seekTo (TSize offset)
282 return result == offset;
291 char8 classString[kClassIDSize + 1] = {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)))
305 if (!readEqualID (getChunkID (kChunkList)))
307 if (!readInt32 (count))
310 if (count > kMaxEntries)
313 for (int32 i = 0; i < count; i++)
315 Entry& e = entries[i];
316 if (!(readID (e.id) && readSize (e.offset) && readSize (e.size)))
322 return entryCount > 0;
330 char8 classString[kClassIDSize + 1] = {0};
333 return seekTo (0) && writeID (getChunkID (kHeader)) && writeInt32 (kFormatVersion) &&
334 verify (stream->
write (classString, kClassIDSize)) && writeSize (0);
343 if (!(seekTo (kListOffsetPos) && writeSize (pos) && seekTo (pos)))
347 if (!writeID (getChunkID (kChunkList)))
349 if (!writeInt32 (entryCount))
352 for (int32 i = 0; i < entryCount; i++)
354 Entry& e = entries[i];
355 if (!(writeID (e.id) && writeSize (e.offset) && writeSize (e.size)))
362bool PresetFile::beginChunk (Entry& e, ChunkType which)
364 if (entryCount >= kMaxEntries)
367 const ChunkID&
id = getChunkID (which);
368 memcpy (e.id, &
id, sizeof (ChunkID));
369 stream->
tell (&e.offset);
375bool PresetFile::endChunk (Entry& e)
377 if (entryCount >= kMaxEntries)
382 e.size = pos - e.offset;
383 entries[entryCount++] = e;
396 result = seekTo (e->offset) && verify (stream->
read (xmlBuffer, size, &size));
400 size = (int32)e->size;
419 size = (int32)
strlen (xmlBuffer);
422 return beginChunk (e, kMetaInfo) && verify (stream->
write ((
void*)xmlBuffer, size)) &&
437 writePos = e->offset;
444 writePos = e ? e->offset + e->size : kHeaderSize;
447 return seekTo (writePos);
457 return beginChunk (e, which) && verify (stream->
write ((
void*)data, size)) && endChunk (e);
464 return e && seekTo (e->offset);
474 return beginChunk (e, kComponentState) && verify (component->
getState (stream)) && endChunk (e);
484 return beginChunk (e, kComponentState) && copyStream (componentStream, stream) && endChunk (e);
495 return verify (component->
setState (readOnlyBStream));
515 return e && seekTo (e->offset);
525 return beginChunk (e, kControllerState) && verify (editController->
getState (stream)) &&
536 return beginChunk (e, kControllerState) && copyStream (editStream, stream) && endChunk (e);
546 return verify (editController->
setState (readOnlyBStream));
560 if (beginChunk (e, kProgramData))
562 if (writeInt32 (listID))
564 if (!copyStream (inStream, stream))
583 return beginChunk (e, kProgramData) && writeInt32 (listID) &&
584 verify (programListData->
getProgramData (listID, programIndex, stream)) && endChunk (e);
593 if (e && seekTo (e->offset))
595 if (readInt32 (savedProgramListID))
597 if (programListID && *programListID != savedProgramListID)
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));
619 return beginChunk (e, kProgramData) && writeInt32 (unitID) &&
620 verify (unitData->
getUnitData (unitID, stream)) && endChunk (e);
628 if (e && seekTo (e->offset))
630 if (readInt32 (savedUnitID))
632 if (unitId && *unitId != savedUnitID)
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)));
649 int32 savedProgramListID = -1;
650 if (e && seekTo (e->offset))
652 if (readInt32 (savedProgramListID))
654 if (unitProgramListID != savedProgramListID)
657 int32 alreadyRead =
sizeof (int32);
658 auto readOnlyBStream =
owned (
659 new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead));
671 if (e && seekTo (e->offset))
673 if (readInt32 (unitProgramListID))
686 FILE* file =
fopen (filename, mode);
687 return file ?
new FileStream (file) :
nullptr;
691FileStream::FileStream (FILE* file)
692: file (file) {FUNKNOWN_CTOR}
695FileStream::~FileStream ()
702IMPLEMENT_FUNKNOWN_METHODS (FileStream, IBStream, IBStream::iid)
705tresult PLUGIN_API
FileStream::read (
void* buffer, int32 numBytes, int32* numBytesRead)
707 size_t result =
fread (buffer, 1,
static_cast<size_t> (numBytes), file);
709 *numBytesRead = (int32)result;
710 return static_cast<int32
> (result) == numBytes ? kResultOk : kResultFalse;
716 size_t result =
fwrite (buffer, 1,
static_cast<size_t> (numBytes), file);
718 *numBytesWritten = (int32)result;
719 return static_cast<int32
> (result) == numBytes ? kResultOk : kResultFalse;
725 if (
fseek (file, (int32)pos, mode) == 0)
728 *result =
ftell (file);
748ReadOnlyBStream::ReadOnlyBStream (
IBStream* sourceStream, TSize sourceOffset, TSize sectionSize)
749: sourceStream (sourceStream)
750, sourceOffset (sourceOffset)
751, sectionSize (sectionSize)
760ReadOnlyBStream::~ReadOnlyBStream ()
771 return sourceStream ? sourceStream->
queryInterface (_iid, obj) : kResultFalse;
781 return kNotInitialized;
783 int32 maxBytesToRead =
static_cast<int32
> (sectionSize - seekPosition);
784 if (numBytes > maxBytesToRead)
785 numBytes = maxBytesToRead;
789 tresult result = sourceStream->
seek (sourceOffset + seekPosition,
kIBSeekSet);
790 if (result != kResultOk)
794 result = sourceStream->
read (buffer, numBytes, &numRead);
797 seekPosition += numRead;
799 *numBytesRead = numRead;
806 int32* numBytesWritten)
809 *numBytesWritten = 0;
811 return kNotImplemented;
823 case kIBSeekEnd: seekPosition = sectionSize + pos;
break;
826 if (seekPosition < 0)
828 if (seekPosition > sectionSize)
829 seekPosition = sectionSize;
832 *result = seekPosition;
850BufferStream::BufferStream () {FUNKNOWN_CTOR}
853BufferStream::~BufferStream () {FUNKNOWN_DTOR}
858 uint32 size = mBuffer.
get (buffer,
static_cast<uint32
> (numBytes));
860 *numBytesRead =
static_cast<int32
> (size);
868 bool res = mBuffer.
put (buffer,
static_cast<uint32
> (numBytes));
870 *numBytesWritten = res ? numBytes : 0;
872 return res ? kResultTrue : kResultFalse;
887 res = mBuffer.
setFillSize (
static_cast<uint32
> (tmp));
897 res = mBuffer.
setFillSize (
static_cast<uint32
> (tmp));
904 int64 tmp = mBuffer.
getSize () - pos;
907 res = mBuffer.
setFillSize (
static_cast<uint32
> (tmp));
914 return res ? kResultTrue : kResultFalse;
922 return pos ? kResultTrue : kResultFalse;
bool put(uint8)
append value at end, grows Buffer if necessary
bool setFillSize(uint32 c)
sets a new fill size, does not change any memory
uint32 get(void *b, uint32 size)
copy to buffer from fillSize, and shift fillSize
uint32 getFillSize() const
Handling 16 Byte Globally Unique Identifiers.
void toString(char8 *string) const
Converts UID to a string.
bool fromString(const char8 *string)
Sets the UID data from a string.
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.
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
@ kIBSeekEnd
set seek position relative to stream end
@ kIBSeekSet
set absolute seek position
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.
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.
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.
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.
#define SWAP_32(l)
Byte-order Conversion Macros.
int32 ProgramListID
program list identifier
int32 UnitID
unit identifier
IPtr< I > owned(I *p)
Assigning newly created object to an IPtr.