text:
//------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vsteditcontroller.h
// Created by  : Steinberg, 04/2005
// Description : VST Edit Controller Implementation
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#include "public.sdk/source/vst/vstcomponentbase.h"
#include "public.sdk/source/vst/vstparameters.h"
#include "public.sdk/source/common/pluginview.h"
#include "base/source/fstring.h"

#include "pluginterfaces/vst/ivsteditcontroller.h"
#include "pluginterfaces/vst/ivstunits.h"

#include <vector>
#include <map>

//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {

class EditorView;

//------------------------------------------------------------------------
/** Default implementation for a VST 3 edit controller.
\ingroup vstClasses
Can be used as base class for a specific controller implementation */
//------------------------------------------------------------------------
class EditController: public ComponentBase,
					  public IEditController,
					  public IEditController2
{
public:
//------------------------------------------------------------------------
	EditController ();

	//---from IEditController-------
	virtual tresult PLUGIN_API setComponentState (IBStream* state) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API setState (IBStream* state) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getState (IBStream* state) SMTG_OVERRIDE;
	virtual int32 PLUGIN_API getParameterCount () SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getParameterInfo (int32 paramIndex, ParameterInfo& info) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getParamStringByValue (ParamID tag, ParamValue valueNormalized, String128 string) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getParamValueByString (ParamID tag, TChar* string, ParamValue& valueNormalized) SMTG_OVERRIDE;
	virtual ParamValue PLUGIN_API normalizedParamToPlain (ParamID tag, ParamValue valueNormalized) SMTG_OVERRIDE;
	virtual ParamValue PLUGIN_API plainParamToNormalized (ParamID tag, ParamValue plainValue) SMTG_OVERRIDE;
	virtual ParamValue PLUGIN_API getParamNormalized (ParamID tag) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API setParamNormalized (ParamID tag, ParamValue value) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API setComponentHandler (IComponentHandler* handler) SMTG_OVERRIDE;
	virtual IPlugView* PLUGIN_API createView (FIDString /*name*/) SMTG_OVERRIDE {return 0;}

	//---from IEditController2-------
	virtual tresult PLUGIN_API setKnobMode (KnobMode mode) SMTG_OVERRIDE { hostKnobMode = mode; return kResultTrue; }
	virtual tresult PLUGIN_API openHelp (TBool /*onlyCheck*/) SMTG_OVERRIDE {return kResultFalse;}
	virtual tresult PLUGIN_API openAboutBox (TBool /*onlyCheck*/) SMTG_OVERRIDE {return kResultFalse;}

	//---from ComponentBase---------
	virtual tresult PLUGIN_API initialize (FUnknown* context) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API terminate  () SMTG_OVERRIDE;

	//---Internal Methods-------
	virtual tresult beginEdit (ParamID tag);	///< to be called before a serie of performEdit
	virtual tresult performEdit (ParamID tag, ParamValue valueNormalized); ///< will inform the host about the value change
	virtual tresult endEdit (ParamID tag);		///< to be called after a serie of performEdit
	virtual tresult startGroupEdit ();			///< calls IComponentHandler2::startGroupEdit() if host supports it
	virtual tresult finishGroupEdit ();			///< calls IComponentHandler2::finishGroupEdit() if host supports it

	virtual void editorDestroyed (EditorView* /*editor*/) {}	///< called from EditorView if it was destroyed
	virtual void editorAttached (EditorView* /*editor*/) {}		///< called from EditorView if it was attached to a parent
	virtual void editorRemoved (EditorView* /*editor*/) {}		///< called from EditorView if it was removed from a parent

	static KnobMode getHostKnobMode () { return hostKnobMode; }	///< return host knob mode

	/** Gets for a given tag the parameter object. */
	virtual Parameter* getParameterObject (ParamID tag) { return parameters.getParameter (tag); }

	/** Gets for a given tag the parameter information. */
	virtual tresult getParameterInfoByTag (ParamID tag, ParameterInfo& info);

	/** Calls IComponentHandler2::setDirty (state) if host supports it. */
	virtual tresult setDirty (TBool state);

	/** Calls IComponentHandler2::requestOpenEditor (name) if host supports it. */
	virtual tresult requestOpenEditor (FIDString name = ViewType::kEditor);

	//---Accessor Methods-------
	IComponentHandler* getComponentHandler () const { return componentHandler; }

	//---Interface---------
	OBJ_METHODS (EditController, ComponentBase)
	DEFINE_INTERFACES
		DEF_INTERFACE (IEditController)
		DEF_INTERFACE (IEditController2)
	END_DEFINE_INTERFACES (ComponentBase)
	REFCOUNT_METHODS(ComponentBase)
//------------------------------------------------------------------------
protected:
	IComponentHandler* componentHandler;
	IComponentHandler2* componentHandler2;

	ParameterContainer parameters;

	static KnobMode hostKnobMode;
};

//------------------------------------------------------------------------
/** View related to an edit controller.
\ingroup vstClasses  */
//------------------------------------------------------------------------
class EditorView: public CPluginView
{
public:
//------------------------------------------------------------------------
	EditorView (EditController* controller, ViewRect* size = 0);
	virtual ~EditorView ();

	/** Gets its controller part. */
	EditController* getController () { return controller; }

	//---from CPluginView-------------
	virtual void attachedToParent () SMTG_OVERRIDE;
	virtual void removedFromParent () SMTG_OVERRIDE;

//------------------------------------------------------------------------
protected:
	EditController* controller;
};

//------------------------------------------------------------------------
/** Unit element.
\ingroup vstClasses  */
//------------------------------------------------------------------------
class Unit: public FObject
{
public:
//------------------------------------------------------------------------
	Unit (const String128 name, UnitID unitId, UnitID parentUnitId = kRootUnitId, ProgramListID programListId = kNoProgramListId);
	Unit (const UnitInfo& unit);

	/** Returns its info. */
	const UnitInfo& getInfo () const {return info;}

	/** Returns its Unit ID. */
	UnitID getID () const {return info.id;}

	/** Sets a new Unit ID. */
	void setID (UnitID newID) {info.id = newID;}

	/** Returns its Unit Name. */
	const TChar* getName () const {return info.name;}

	/** Sets a new Unit Name. */
	void setName (const String128 newName);

	/** Returns its ProgramList ID. */
	ProgramListID getProgramListID () const {return info.programListId;}

	/** Sets a new ProgramList ID. */
	void setProgramListID (ProgramListID newID) {info.programListId = newID;}

	OBJ_METHODS (Unit, FObject)
//------------------------------------------------------------------------
protected:
	Unit ();
	UnitInfo info;
};

//------------------------------------------------------------------------
/** ProgramList element.
\ingroup vstClasses  */
//------------------------------------------------------------------------
class ProgramList: public FObject
{
public:
//------------------------------------------------------------------------
	ProgramList (const String128 name, ProgramListID listId, UnitID unitId);
	ProgramList (const ProgramList& programList);

	const ProgramListInfo& getInfo () const { return info; }
	ProgramListID getID () const { return info.id; }
	const TChar* getName () const { return info.name; }
	int32 getCount () const { return info.programCount; }

	virtual tresult getProgramName (int32 programIndex, String128 name /*out*/);
	virtual tresult setProgramName (int32 programIndex, const String128 name /*in*/);
	virtual tresult getProgramInfo (int32 programIndex, CString attributeId, String128 value /*out*/);
	virtual tresult hasPitchNames (int32 programIndex) { return kResultFalse; }
	virtual tresult getPitchName (int32 programIndex, int16 midiPitch, String128 name /*out*/) { return kResultFalse; }

	/** Adds a program to the end of the list. returns the index of the program. */
	virtual int32 addProgram (const String128 name);

	/** Sets a program attribute value. */
	virtual bool setProgramInfo (int32 programIndex, CString attributeId, const String128 value);

	/** Creates and returns the program parameter. */
	virtual Parameter* getParameter ();

	OBJ_METHODS (ProgramList, FObject)
//------------------------------------------------------------------------
protected:
	typedef std::map<String, String> StringMap;
	typedef std::vector<String> StringVector;
	typedef std::vector<StringMap> ProgramInfoVector;
	ProgramListInfo info;
	UnitID unitId;
	StringVector programNames;
	ProgramInfoVector programInfos;
	Parameter* parameter;
};

//------------------------------------------------------------------------
/** ProgramListWithPitchNames element.
\ingroup vstClasses  */
//-----------------------------------------------------------------------------
class ProgramListWithPitchNames: public ProgramList
{
public:
	ProgramListWithPitchNames (const String128 name, ProgramListID listId, UnitID unitId);

	/** Sets a name for the given program index and a given pitch. */
	bool setPitchName (int32 programIndex, int16 pitch, const String128 pitchName);

	/** Removes the PitchName entry for the given program index and a given pitch. Returns true if it was found and removed. */
	bool removePitchName (int32 programIndex, int16 pitch);

	//---from ProgramList---------
	int32 addProgram (const String128 name) SMTG_OVERRIDE;
	tresult hasPitchNames (int32 programIndex) SMTG_OVERRIDE;
	tresult getPitchName (int32 programIndex, int16 midiPitch, String128 name /*out*/) SMTG_OVERRIDE;

	OBJ_METHODS (ProgramListWithPitchNames, ProgramList)
protected:
	typedef std::map<int16, String> PitchNameMap;
	typedef std::vector<PitchNameMap> PitchNamesVector;
	PitchNamesVector pitchNames;
};

//------------------------------------------------------------------------
/** Advanced implementation (support IUnitInfo) for a VST 3 edit controller.
\ingroup vstClasses
- [extends EditController]
*/
//------------------------------------------------------------------------
class EditControllerEx1: public EditController, public IUnitInfo
{
public:
	EditControllerEx1 ();
	virtual ~EditControllerEx1 ();

	/** Adds a given unit. */
	bool addUnit (Unit* unit);

	/** Adds a given program list. */
	bool addProgramList (ProgramList* list);

	/** Returns the ProgramList associated to a given listId. */
	ProgramList* getProgramList (ProgramListID listId) const;

	/** Notifies the host about program list changes. */
	tresult notifyProgramListChange (ProgramListID listId, int32 programIndex = kAllProgramInvalid);

	//---from IUnitInfo------------------
	virtual int32 PLUGIN_API getUnitCount () SMTG_OVERRIDE { return static_cast<int32> (units.size ()); }
	virtual tresult PLUGIN_API getUnitInfo (int32 unitIndex, UnitInfo& info /*out*/) SMTG_OVERRIDE;

	virtual int32 PLUGIN_API getProgramListCount () SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getProgramListInfo (int32 listIndex, ProgramListInfo& info /*out*/) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getProgramName (ProgramListID listId, int32 programIndex, String128 name /*out*/) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getProgramInfo (ProgramListID listId, int32 programIndex, CString attributeId /*in*/, String128 attributeValue /*out*/) SMTG_OVERRIDE;

	virtual tresult PLUGIN_API hasProgramPitchNames (ProgramListID listId, int32 programIndex) SMTG_OVERRIDE;
	virtual tresult PLUGIN_API getProgramPitchName (ProgramListID listId, int32 programIndex, int16 midiPitch, String128 name /*out*/) SMTG_OVERRIDE;

	virtual tresult setProgramName (ProgramListID listId, int32 programIndex, const String128 name /*in*/);

	// units selection --------------------
	virtual UnitID PLUGIN_API getSelectedUnit () SMTG_OVERRIDE {return selectedUnit;}
	virtual tresult PLUGIN_API selectUnit (UnitID unitId) SMTG_OVERRIDE {selectedUnit = unitId; return kResultTrue;}

	virtual tresult PLUGIN_API getUnitByBus (MediaType /*type*/, BusDirection /*dir*/, int32 /*busIndex*/,
		int32 /*channel*/, UnitID& /*unitId*/ /*out*/) SMTG_OVERRIDE {return kResultFalse;}
	virtual tresult PLUGIN_API setUnitProgramData (int32 /*listOrUnitId*/, int32 /*programIndex*/, IBStream* /*data*/) SMTG_OVERRIDE {return kResultFalse;}

	/** Notifies the host about the selected Unit. */
	virtual tresult notifyUnitSelection ();

	//---from IDependent------------------
	virtual void PLUGIN_API update (FUnknown* changedUnknown, int32 message) SMTG_OVERRIDE;

	//---Interface---------
	OBJ_METHODS (EditControllerEx1, EditController)
	DEFINE_INTERFACES
		DEF_INTERFACE (IUnitInfo)
	END_DEFINE_INTERFACES (EditController)
	REFCOUNT_METHODS(EditController)

protected:
	typedef std::vector<IPtr<ProgramList> > ProgramListVector;
	typedef std::map<ProgramListID, ProgramListVector::size_type> ProgramIndexMap;
	typedef std::vector<IPtr<Unit> > UnitVector;
	UnitVector units;
	ProgramListVector programLists;
	ProgramIndexMap programIndexMap;
	UnitID selectedUnit;
};

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstspeakerarray,.h
// Created by  : Steinberg, 04/2015
// Description : Helper class representing speaker arrangement as array of speaker types.
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#include "pluginterfaces/vst/vsttypes.h"

//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {

//------------------------------------------------------------------------
// SpeakerArray
/** Helper class representing speaker arrangement as array of speaker types. */
//------------------------------------------------------------------------
class SpeakerArray
{
public:
//------------------------------------------------------------------------
	SpeakerArray (SpeakerArrangement arr = 0)
	{
		setArrangement (arr);
	}

	enum { kMaxSpeakers = 64 };

	typedef uint64 SpeakerType;

	int32 total () const { return count; }
	SpeakerType at (int32 index) const { return speaker[index]; }

	void setArrangement (SpeakerArrangement arr)
	{
		count = 0;
		memset (speaker, 0, sizeof (speaker));

		for (int32 i = 0; i < kMaxSpeakers; i++)
		{
			SpeakerType mask = 1ll << i;
			if (arr & mask)
				speaker[count++] = mask;
		}
	}

	SpeakerArrangement getArrangement () const
	{
		SpeakerArrangement arr = 0;
		for (int32 i = 0; i < count; i++)
			arr |= speaker[i];
		return arr;
	}

	int32 getSpeakerIndex (SpeakerType which) const
	{
		for (int32 i = 0; i < count; i++)
			if (speaker[i] == which)
				return i;
		return -1;
	}
//------------------------------------------------------------------------
protected:
	int32 count;
	SpeakerType speaker[kMaxSpeakers];
};

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstaudioprocessoralgo.h
// Created by  : Steinberg, 04/2015
// Description : Helper algo for AudioBusBuffers
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#include "pluginterfaces/vst/ivstaudioprocessor.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include <algorithm>
#include <cmath>

namespace Steinberg {
namespace Vst {
namespace Algo {

//------------------------------------------------------------------------
template <typename T>
inline void foreach (AudioBusBuffers* audioBusBuffers, int32 busCount, const T& func)
{
	if (!audioBusBuffers)
		return;

	for (int32 busIndex = 0; busIndex < busCount; ++busIndex)
	{
		func (audioBusBuffers[busIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
inline void foreach32 (AudioBusBuffers& audioBuffer, const T& func)
{
	for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
	{
		if (!audioBuffer.channelBuffers32[channelIndex])
			return;

		func (audioBuffer.channelBuffers32[channelIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
inline void foreach64 (AudioBusBuffers& audioBuffer, const T& func)
{
	for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
	{
		if (!audioBuffer.channelBuffers64[channelIndex])
			return;

		func (audioBuffer.channelBuffers64[channelIndex]);
	}
}

//------------------------------------------------------------------------
template <typename T>
inline void foreach32 (AudioBusBuffers& buffer1, AudioBusBuffers& buffer2, const T& func)
{
	int32 numChannels = std::min<int32> (buffer1.numChannels, buffer2.numChannels);

	for (int32 channelIndex = 0; channelIndex < numChannels; ++channelIndex)
	{
		func (buffer1.channelBuffers32[channelIndex], buffer2.channelBuffers32[channelIndex],
		      channelIndex);
	}
}

//------------------------------------------------------------------------
template <typename T>
inline void foreach64 (AudioBusBuffers& buffer1, AudioBusBuffers& buffer2, const T& func)
{
	int32 numChannels = std::min<int32> (buffer1.numChannels, buffer2.numChannels);

	for (int32 channelIndex = 0; channelIndex < numChannels; ++channelIndex)
	{
		func (buffer1.channelBuffers64[channelIndex], buffer2.channelBuffers64[channelIndex],
		      channelIndex);
	}
}

//------------------------------------------------------------------------
inline void copy32 (AudioBusBuffers* src, AudioBusBuffers* dest, int32 sliceSize, int32 startIndex)
{
	if (!src || !dest)
		return;

	int32 numChannels = std::min<int32> (src->numChannels, dest->numChannels);
	size_t numBytes = sliceSize * sizeof (Sample32);
	for (int32 chIdx = 0; chIdx < numChannels; ++chIdx)
	{
		memcpy (&dest->channelBuffers32[chIdx][startIndex], src->channelBuffers32[chIdx], numBytes);
	}
}

//------------------------------------------------------------------------
inline void copy64 (AudioBusBuffers* src, AudioBusBuffers* dest, int32 sliceSize, int32 startIndex)
{
	if (!src || !dest)
		return;

	int32 numChannels = std::min<int32> (src->numChannels, dest->numChannels);
	size_t numBytes = sliceSize * sizeof (Sample64);
	for (int32 chIdx = 0; chIdx < numChannels; ++chIdx)
	{
		memcpy (&dest->channelBuffers64[chIdx][startIndex], src->channelBuffers64[chIdx], numBytes);
	}
}

//------------------------------------------------------------------------
inline void clear32 (AudioBusBuffers* audioBusBuffers, int32 sampleCount, int32 busCount = 1)
{
	if (!audioBusBuffers)
		return;

	const int32 numBytes = sampleCount * sizeof (Sample32);
	foreach (audioBusBuffers, busCount, [&] (AudioBusBuffers& audioBuffer) {
		foreach32 (audioBuffer, [&] (Sample32* channelBuffer) {
			memset (channelBuffer, 0, numBytes);
		});
	});
}

//------------------------------------------------------------------------
inline void clear64 (AudioBusBuffers* audioBusBuffers, int32 sampleCount, int32 busCount = 1)
{
	if (!audioBusBuffers)
		return;

	const int32 numBytes = sampleCount * sizeof (Sample64);
	foreach (audioBusBuffers, busCount, [&](AudioBusBuffers& audioBuffer) {
		foreach64 (audioBuffer, [&](Sample64* channelBuffer) {
			memset (channelBuffer, 0, numBytes);
		});
	});
}

//------------------------------------------------------------------------
inline void mix32 (AudioBusBuffers& src, AudioBusBuffers& dest, int32 sampleCount)
{
	foreach32 (src, dest, [&] (Sample32* srcBuffer, Sample32* destBuffer, int32 /*channelIndex*/) {
		for (int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
			destBuffer[sampleIndex] += srcBuffer[sampleIndex];
	});
}

//------------------------------------------------------------------------
inline void mix64 (AudioBusBuffers& src, AudioBusBuffers& dest, int32 sampleCount)
{
	foreach64 (src, dest, [&] (Sample64* srcBuffer, Sample64* destBuffer, int32 /*channelIndex*/) {
		for (int32 sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex)
			destBuffer[sampleIndex] += srcBuffer[sampleIndex];
	});
}

//------------------------------------------------------------------------
inline bool isSilent32 (AudioBusBuffers& audioBuffer, int32 sampleCount, int32 startIndex = 0)
{
	const float epsilon = 1e-10f; // under -200dB...

	sampleCount += startIndex;
	for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
	{
		if (!audioBuffer.channelBuffers32[channelIndex])
			return true;

		for (int32 sampleIndex = startIndex; sampleIndex < sampleCount; ++sampleIndex)
		{
			float val = audioBuffer.channelBuffers32[channelIndex][sampleIndex];
			if (std::abs (val) > epsilon)
				return false;
		}
	}

	return true;
}

//------------------------------------------------------------------------
inline bool isSilent64 (AudioBusBuffers& audioBuffer, int32 sampleCount, int32 startIndex = 0)
{
	const double epsilon = 1e-10f; // under -200dB...

	sampleCount += startIndex;
	for (int32 channelIndex = 0; channelIndex < audioBuffer.numChannels; ++channelIndex)
	{
		if (!audioBuffer.channelBuffers64[channelIndex])
			return true;

		for (int32 sampleIndex = startIndex; sampleIndex < sampleCount; ++sampleIndex)
		{
			double val = audioBuffer.channelBuffers64[channelIndex][sampleIndex];
			if (std::abs (val) > epsilon)
				return false;
		}
	}

	return true;
}

//------------------------------------------------------------------------
//------------------------------------------------------------------------
template <typename T>
inline void foreach (IEventList* eventList, const T& func)
{
	if (!eventList)
		return;

	auto eventCount = eventList->getEventCount ();
	for (int32 eventIndex = 0; eventIndex < eventCount; ++eventIndex)
	{
		Event event = {0};
		if (eventList->getEvent (eventIndex, event) != kResultOk)
			continue;

		func (event);
	}
}

//------------------------------------------------------------------------
template <typename T>
inline void foreach (IParamValueQueue& paramQueue, const T& func)
{
	auto paramId = paramQueue.getParameterId ();
	auto numPoints = paramQueue.getPointCount ();
	for (int32 pointIndex = 0; pointIndex < numPoints; ++pointIndex)
	{
		int32 sampleOffset = 0;
		ParamValue value = 0;
		if (paramQueue.getPoint (pointIndex, sampleOffset, value) != kResultOk)
			continue;

		func (paramId, sampleOffset, value);
	}
}

//------------------------------------------------------------------------
template <typename T>
inline void foreachLast (IParamValueQueue& paramQueue, const T& func)
{
	auto paramId = paramQueue.getParameterId ();
	auto numPoints = paramQueue.getPointCount ();
	int32 sampleOffset = 0;
	ParamValue value = 0;
	if (paramQueue.getPoint (numPoints - 1, sampleOffset, value) == kResultOk)
		func (paramId, sampleOffset, value);
}

//------------------------------------------------------------------------
template <typename T>
inline void foreach (IParameterChanges* changes, const T& func)
{
	if (!changes)
		return;

	auto paramCount = changes->getParameterCount ();
	for (int32 paramIndex = 0; paramIndex < paramCount; ++paramIndex)
	{
		auto paramValueQueue = changes->getParameterData (paramIndex);
		if (!paramValueQueue)
			continue;

		func (*paramValueQueue);
	}
}

//------------------------------------------------------------------------
} // namespace Algo
} // namespace Vst
} // namespace Steinberg


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstaudioeffect.cpp
// Created by  : Steinberg, 04/2005
// Description : Basic Audio Effect Implementation
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#include "vstaudioeffect.h"

namespace Steinberg {
namespace Vst {

//------------------------------------------------------------------------
// AudioEffect
//------------------------------------------------------------------------
AudioEffect::AudioEffect ()
{
	processSetup.maxSamplesPerBlock = 1024;
	processSetup.processMode = Vst::kRealtime;
	processSetup.sampleRate = 44100.0;
	processSetup.symbolicSampleSize = Vst::kSample32;
}

//------------------------------------------------------------------------
AudioBus* AudioEffect::addAudioInput (const TChar* name, SpeakerArrangement arr,
									  BusType busType, int32 flags)
{
	AudioBus* newBus = new AudioBus (name, busType, flags, arr);
	audioInputs.push_back (IPtr<Vst::Bus> (newBus, false));
	return newBus;
}

//------------------------------------------------------------------------
AudioBus* AudioEffect::addAudioOutput (const TChar* name, SpeakerArrangement arr,
									   BusType busType, int32 flags)
{
	AudioBus* newBus = new AudioBus (name, busType, flags, arr);
	audioOutputs.push_back (IPtr<Vst::Bus> (newBus, false));
	return newBus;
}

//------------------------------------------------------------------------
AudioBus* AudioEffect::getAudioInput (int32 index)
{
	AudioBus* bus = FCast<Vst::AudioBus> (audioInputs.at (index));
	return bus;
}

//------------------------------------------------------------------------
AudioBus* AudioEffect::getAudioOutput (int32 index)
{
	AudioBus* bus = FCast<Vst::AudioBus> (audioOutputs.at (index));
	return bus;
}

//------------------------------------------------------------------------
EventBus* AudioEffect::addEventInput (const TChar* name, int32 channels,
									  BusType busType, int32 flags)
{
	EventBus* newBus = new EventBus (name, busType, flags, channels);
	eventInputs.push_back (IPtr<Vst::Bus> (newBus, false));
	return newBus;
}

//------------------------------------------------------------------------
EventBus* AudioEffect::addEventOutput (const TChar* name, int32 channels,
									   BusType busType, int32 flags)
{
	EventBus* newBus = new EventBus (name, busType, flags, channels);
	eventOutputs.push_back (IPtr<Vst::Bus> (newBus, false));
	return newBus;
}

//------------------------------------------------------------------------
EventBus* AudioEffect::getEventInput (int32 index)
{
	EventBus* bus = FCast<Vst::EventBus> (eventInputs.at (index));
	return bus;
}

//------------------------------------------------------------------------
EventBus* AudioEffect::getEventOutput (int32 index)
{
	EventBus* bus = FCast<Vst::EventBus> (eventOutputs.at (index));
	return bus;
}

//------------------------------------------------------------------------
tresult PLUGIN_API AudioEffect::setBusArrangements (SpeakerArrangement* inputs, int32 numIns,
													SpeakerArrangement* outputs, int32 numOuts)
{
	if (numIns < 0 || numOuts < 0)
		return kInvalidArgument;

	if (numIns > static_cast<int32> (audioInputs.size ()) ||
	    numOuts > static_cast<int32> (audioOutputs.size ()))
		return kResultFalse;

	for (int32 index = 0; index < audioInputs.size (); ++index)
	{
		if (index >= numIns)
			break;
		FCast<Vst::AudioBus> (audioInputs[index].get ())->setArrangement (inputs[index]);
	}

	for (int32 index = 0; index < audioOutputs.size (); ++index)
	{
		if (index >= numOuts)
			break;
		FCast<Vst::AudioBus> (audioOutputs[index].get ())->setArrangement (outputs[index]);
	}

	return kResultTrue;
}

//------------------------------------------------------------------------
tresult PLUGIN_API AudioEffect::getBusArrangement (BusDirection dir, int32 busIndex, SpeakerArrangement& arr)
{
	BusList* busList = getBusList (kAudio, dir);
	if (!busList || busIndex < 0 || busList->size () <= busIndex)
		return kInvalidArgument;
	AudioBus* audioBus = FCast<Vst::AudioBus> (busList->at (busIndex));
	if (audioBus)
	{
		arr = audioBus->getArrangement ();
		return kResultTrue;
	}
	return kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API AudioEffect::setupProcessing (ProcessSetup& newSetup)
{
	processSetup.maxSamplesPerBlock = newSetup.maxSamplesPerBlock;
	processSetup.processMode = newSetup.processMode;
	processSetup.sampleRate = newSetup.sampleRate;

	if (canProcessSampleSize (newSetup.symbolicSampleSize) != kResultTrue)
		return kResultFalse;

	processSetup.symbolicSampleSize = newSetup.symbolicSampleSize;

	return kResultOk;
}

//------------------------------------------------------------------------
tresult PLUGIN_API AudioEffect::setProcessing (TBool /*state*/)
{
	return kNotImplemented;
}

//------------------------------------------------------------------------
tresult PLUGIN_API AudioEffect::canProcessSampleSize (int32 symbolicSampleSize)
{
	return symbolicSampleSize == kSample32 ? kResultTrue : kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API AudioEffect::process (ProcessData& /*data*/)
{
	return kNotImplemented;
}

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstrepresentation.cpp
// Created by  : Steinberg, 08/2010
// Description : VST Representation Helper
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#include "vstrepresentation.h"

#include "base/source/fstring.h"
#include "pluginterfaces/base/ibstream.h"

namespace Steinberg {
namespace Vst {

#define START_TAG_STRING(string) "<" string">"
#define END_TAG_STRING(string)	 "</" string">"
#define MEDIUM_TITLE_LIMIT			8
#define SHORT_TITLE_LIMIT			4

//------------------------------------------------------------------------
struct StringWriter
{
	StringWriter (IBStream* stream) : stream (stream) {}

	void write (const ConstString& str)
	{
		stream->write (const_cast<char8*> (str.text8 ()), str.length (), 0);
	}

	IBStream* stream;
};

//------------------------------------------------------------------------
// XmlRepresentationHelper Implementation
//------------------------------------------------------------------------
XmlRepresentationHelper::XmlRepresentationHelper (const Vst::RepresentationInfo& info,
                                                  const FIDString companyName,
                                                  const FIDString pluginName, const TUID& pluginUID,
                                                  IBStream* stream)
: stream (stream)
{
	StringWriter writer (stream);
	String string;
	writer.write ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
	writer.write (ENDLINE_A);
	string.printf ("<!DOCTYPE %s PUBLIC \"-//Steinberg//DTD VST Remote 1.1//EN\" \"http://dtd.steinberg.net/VST-Remote-1.1.dtd\">", ROOTXML_TAG);
	writer.write (string.text8 ());
	writer.write (ENDLINE_A);

	string.printf ("<%s %s=\"1.0\">", ROOTXML_TAG, ATTR_VERSION);
	writer.write (string.text8 ());
	writer.write (ENDLINE_A);

	//---Plug-in Tag----------------
	FUID uid (pluginUID);
	char uidText[33];
	uid.toString (uidText);

	string.printf ("<%s %s=\"%s\" %s=\"%s\" %s=\"%s\"/>", PLUGIN_TAG, ATTR_CLASSID, uidText, ATTR_NAME, pluginName, ATTR_VENDOR, companyName);
	writer.write (string);
	writer.write (ENDLINE_A);

	//---Representation Tag----------------
	string.printf ("\t<%s", REPRESENTATION_TAG);
	writer.write (string);
	string.printf (" %s=\"%s\"", ATTR_NAME, info.name);
	writer.write (string);
	string.printf (" %s=\"%s\"", ATTR_VENDOR, info.vendor);
	writer.write (string);
	string.printf (" %s=\"%s\"", ATTR_VERSION, info.version);
	writer.write (string);
	if (strcmp ((char*)info.host, ""))
	{
		string.printf (" %s=\"%s\"", ATTR_HOST, info.host);
		writer.write (string);
	}
	writer.write (">");
	writer.write (ENDLINE_A);

	state = kInRepresentation;
}

//------------------------------------------------------------------------
XmlRepresentationHelper::~XmlRepresentationHelper ()
{
	if (state == kInLayer)
		endLayer ();
	if (state == kInCell)
		endCell ();
	if (state == kInPage)
		endPage ();

	StringWriter writer (stream);
	String string;

	// end representation
	string.printf ("\t%s", END_TAG_STRING(REPRESENTATION_TAG));
	writer.write (string);
	writer.write (ENDLINE_A);

	// end piper
	writer.write (END_TAG_STRING(ROOTXML_TAG));
	writer.write (ENDLINE_A);
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::checkState (int32 newState)
{
	if (newState - state == 1 || state - newState == 1) // we go down or up
	{
		state = newState;
		return true;
	}
	return false;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startPage (FIDString name, int32 unitID)
{
	if (!checkState (kInPage))
		return false;

	StringWriter writer (stream);
	String string;
	if (unitID != -1)
		string.printf ("<%s %s=\"%s\" %s=\"%d\">", PAGE_TAG, ATTR_NAME, name, ATTR_UNITID, unitID);
	else
		string.printf ("<%s %s=\"%s\">", PAGE_TAG, ATTR_NAME, name);
	writer.write (string);
	writer.write (ENDLINE_A);

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::endPage ()
{
	if (!checkState (kInRepresentation))
		return false;

	StringWriter writer (stream);
	String string;
	string.printf ("%s", END_TAG_STRING(PAGE_TAG));
	writer.write (string);
	writer.write (ENDLINE_A);

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startCell ()
{
	if (!checkState (kInCell))
		return false;

	StringWriter writer (stream);
	String string;
	string.printf ("%s", START_TAG_STRING(CELL_TAG));
	writer.write (string);
	writer.write (ENDLINE_A);

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::endCell ()
{
	if (!checkState (kInPage))
		return false;

	StringWriter writer (stream);
	String string;
	string.printf ("%s", END_TAG_STRING(CELL_TAG));
	writer.write (string);
	writer.write (ENDLINE_A);

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndCell ()
{
	if (!checkState (kInCell))
		return false;

	StringWriter writer (stream);
	String string;
	string.printf ("<%s/>", CELL_TAG);
	writer.write (string);
	writer.write (ENDLINE_A);

	if (!checkState (kInPage))
		return false;
	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startLayer (int32 type, int32 id, FIDString _function, FIDString style)
{
	return startLayer (type, id, _function, style, false);
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::endLayer ()
{
	if (!checkState (kInCell))
		return false;

	StringWriter writer (stream);
	String string;
	string.printf ("%s", END_TAG_STRING(LAYER_TAG));
	writer.write (string);
	writer.write (ENDLINE_A);

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndLayer (int32 type, int32 id, FIDString _function, FIDString style)
{
	return startLayer (type, id, _function, style, true);
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startLayer (int32 type, int32 id, FIDString _function, FIDString style, bool ended)
{
	if (!checkState (kInLayer))
		return false;

	StringWriter writer (stream);
	String string;

	string.printf ("<%s %s=\"%s\" %s=\"%d\"", LAYER_TAG, ATTR_TYPE, Vst::LayerType::layerTypeFIDString[type], ATTR_PARAMID, id);
	writer.write (string);

	if (_function)
	{
		string.printf (" %s=\"%s\"", Vst::Attributes::kFunction, _function);
		writer.write (string);
	}
	if (style)
	{
		string = Vst::LayerType::layerTypeFIDString[type];
		if (type == Vst::LayerType::kSwitch)
			string.printf (" %s=\"%s\"", Vst::Attributes::kSwitchStyle, style);
		else if (type == Vst::LayerType::kLED)
			string.printf (" %s=\"%s\"", Vst::Attributes::kLEDStyle, style);
		else
			string.printf (" %s=\"%s\"",  Vst::Attributes::kStyle, style);
		writer.write (string);
	}

	if (ended)
	{
		writer.write ("/>");
		if (!checkState (kInCell))
			return false;
	}
	else
		writer.write (">");
	writer.write (ENDLINE_A);

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndCellOneLayer (int32 type, int32 id, FIDString _function, FIDString style)
{
	if (!startCell ())
		return false;
	startEndLayer (type, id, _function, style);
	endCell ();

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startLayer (Vst::ParameterInfo& info, FIDString _function)
{
	return startLayer (info, _function, false);
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startLayer (Vst::ParameterInfo& info, FIDString _function, bool ended)
{
	FIDString style = 0;
	int32 type = Vst::LayerType::kKnob;
	if (info.flags & Vst::ParameterInfo::kIsReadOnly)
		type = Vst::LayerType::kLED;
	else if (info.stepCount == 1)
	{
		type = Vst::LayerType::kSwitch;
		style = Vst::AttributesStyle::kSwitchPushIncLoopedStyle;
	}

	return startLayer (type, info.id, _function, style, ended);
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndLayer (Vst::ParameterInfo& info, FIDString _function)
{
	return startLayer (info, _function, true);
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndCellOneLayer (Vst::ParameterInfo& info, FIDString _function)
{
	if (!startCell ())
		return false;
	startEndLayer (info, _function);
	endCell ();

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndCellOneLayerWithParamName (Vst::ParameterInfo& info, FIDString _function /*= 0*/)
{
	if (!startCell ())
		return false;
	startLayer (info, _function, false);
	startEndTitleDisplay (info);
	endLayer ();
	endCell ();

	return true;
}

//------------------------------------------------------------------------
bool XmlRepresentationHelper::startEndTitleDisplay (Vst::ParameterInfo& info)
{
	String nameString (info.title);

	if (nameString.isEmpty ())
		return false;

	if (!checkState (kInTitleDisplay))
		return false;

	StringWriter writer (stream);
	String string;

	string.printf ("<%s>", TITLEDISPLAY_TAG);
	writer.write (string);
	writer.write (ENDLINE_A);

	// start of name scope

	if (!checkState (kInName))
	{
		string.printf ("%s", END_TAG_STRING (TITLEDISPLAY_TAG));
		writer.write (string);
		writer.write (ENDLINE_A);
		return false;
	}

	string.printf ("<%s>%s</%s>", NAME_TAG, nameString.text8 (), NAME_TAG);
	writer.write (string);
	writer.write (ENDLINE_A);

	if (nameString.length () > MEDIUM_TITLE_LIMIT)
	{
		nameString.assign (info.shortTitle);

		if (! nameString.isEmpty ())
		{
			nameString.removeChars ();							// remove space

			if (nameString.length () > MEDIUM_TITLE_LIMIT)
				nameString.remove (MEDIUM_TITLE_LIMIT);			// Trimming the rest to get a short string

			string.printf ("<%s>%s</%s>", NAME_TAG, nameString.text8 (), NAME_TAG);
			writer.write (string);
			writer.write (ENDLINE_A);
		}
	}

	if (nameString.length () > SHORT_TITLE_LIMIT)
	{
		nameString.remove (SHORT_TITLE_LIMIT);					// Trimming the rest to get a short string

		string.printf ("<%s>%s</%s>", NAME_TAG, nameString.text8 (), NAME_TAG);
		writer.write (string);
		writer.write (ENDLINE_A);
	}

	if (!checkState (kInTitleDisplay))
		return false;

	// end of name scope

	string.printf ("%s", END_TAG_STRING (TITLEDISPLAY_TAG));
	writer.write (string);
	writer.write (ENDLINE_A);

	if (!checkState (kInLayer))
		return false;

	return true;
}

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg


text:
//------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstpresetfile.cpp
// Created by  : Steinberg, 03/2006
// Description : VST 3 Preset File Format
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#include "vstpresetfile.h"

#include <algorithm>

namespace Steinberg {
namespace Vst {

//------------------------------------------------------------------------
// Preset Chunk IDs
//------------------------------------------------------------------------
static const ChunkID commonChunks[kNumPresetChunks] =
{
	{'V', 'S', 'T', '3'},	// kHeader
	{'C', 'o', 'm', 'p'},	// kComponentState
	{'C', 'o', 'n', 't'},	// kControllerState
	{'P', 'r', 'o', 'g'},	// kProgramData
	{'I', 'n', 'f', 'o'},	// kMetaInfo
	{'L', 'i', 's', 't'}	// kChunkList
};

//------------------------------------------------------------------------
// Preset Header: header id + version + class id + list offset
static const int32 kFormatVersion = 1;
static const int32 kClassIDSize = 32; // ASCII-encoded FUID
static const int32 kHeaderSize = sizeof (ChunkID) + sizeof (int32) + kClassIDSize + sizeof (TSize);
static const int32 kListOffsetPos = kHeaderSize - sizeof (TSize);

//------------------------------------------------------------------------
const ChunkID& getChunkID (ChunkType type)
{
	return commonChunks[type];
}

#ifdef verify
#undef verify
#endif

//------------------------------------------------------------------------
inline bool verify (tresult result)
{
	return result == kResultOk || result == kNotImplemented;
}

//------------------------------------------------------------------------
// PresetFile
//------------------------------------------------------------------------
bool PresetFile::savePreset (IBStream* stream, const FUID& classID,
							 IComponent* component, IEditController* editController,
 							 const char* xmlBuffer, int32 xmlSize)
{
	PresetFile pf (stream);
	pf.setClassID (classID);
	if (!pf.writeHeader ())
		return false;

	if (!pf.storeComponentState (component))
		return false;

	if (editController && !pf.storeControllerState (editController))
		return false;

	if (xmlBuffer && !pf.writeMetaInfo (xmlBuffer, xmlSize))
		return false;

	return pf.writeChunkList ();
}

//------------------------------------------------------------------------
bool PresetFile::loadPreset (IBStream* stream, const FUID& classID, IComponent* component,
							 IEditController* editController, std::vector<FUID>* otherClassIDArray)
{
	PresetFile pf (stream);
	if (!pf.readChunkList ())
		return false;

	if (pf.getClassID () != classID)
	{
		if (otherClassIDArray)
		{
			// continue to load only if found in supported ID else abort load
			if (std::find (otherClassIDArray->begin (), otherClassIDArray->end (),
			               pf.getClassID ()) == otherClassIDArray->end ())
				return false;
		}
		else
			return false;
	}

	if (!pf.restoreComponentState (component))
		return false;

	if (editController)
	{
		// assign component state to controller
		if (!pf.restoreComponentState (editController))
			return false;

		// restore controller-only state (if present)
		if (pf.contains (kControllerState) && !pf.restoreControllerState (editController))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
PresetFile::PresetFile (IBStream* stream)
: stream (stream)
, entryCount (0)
{
	memset (entries, 0, sizeof (entries));

	if (stream)
		stream->addRef ();
}

//------------------------------------------------------------------------
PresetFile::~PresetFile ()
{
	if (stream)
		stream->release ();
}

//------------------------------------------------------------------------
const PresetFile::Entry* PresetFile::getEntry (ChunkType which) const
{
	const ChunkID& id = getChunkID (which);
	for (int32 i = 0; i < entryCount; i++)
		if (isEqualID (entries[i].id, id))
			return &entries[i];
	return 0;
}

//------------------------------------------------------------------------
const PresetFile::Entry* PresetFile::getLastEntry () const
{
	return entryCount > 0 ? &entries[entryCount - 1] : 0;
}

//------------------------------------------------------------------------
bool PresetFile::readID (ChunkID id)
{
	int32 numBytesRead = 0;
	stream->read (id, sizeof (ChunkID), &numBytesRead);
	return numBytesRead == sizeof (ChunkID);
}

//------------------------------------------------------------------------
bool PresetFile::writeID (const ChunkID id)
{
	int32 numBytesWritten = 0;
	stream->write ((void*)id, sizeof (ChunkID), &numBytesWritten);
	return numBytesWritten == sizeof (ChunkID);
}

//------------------------------------------------------------------------
bool PresetFile::readEqualID (const ChunkID id)
{
	ChunkID temp = {0};
	return readID (temp) && isEqualID (temp, id);
}

//------------------------------------------------------------------------
bool PresetFile::readSize (TSize& size)
{
	int32 numBytesRead = 0;
	stream->read (&size, sizeof (TSize), &numBytesRead);
#if BYTEORDER == kBigEndian
	SWAP_64 (size)
#endif
	return numBytesRead == sizeof (TSize);
}

//------------------------------------------------------------------------
bool PresetFile::writeSize (TSize size)
{
#if BYTEORDER == kBigEndian
	SWAP_64 (size)
#endif
	int32 numBytesWritten = 0;
	stream->write (&size, sizeof (TSize), &numBytesWritten);
	return numBytesWritten == sizeof (TSize);
}

//------------------------------------------------------------------------
bool PresetFile::readInt32 (int32& value)
{
	int32 numBytesRead = 0;
	stream->read (&value, sizeof (int32), &numBytesRead);
#if BYTEORDER == kBigEndian
	SWAP_32 (value)
#endif
	return numBytesRead == sizeof (int32);
}

//------------------------------------------------------------------------
bool PresetFile::writeInt32 (int32 value)
{
#if BYTEORDER == kBigEndian
	SWAP_32 (value)
#endif
	int32 numBytesWritten = 0;
	stream->write (&value, sizeof (int32), &numBytesWritten);
	return numBytesWritten == sizeof (int32);
}

//------------------------------------------------------------------------
bool PresetFile::seekTo (TSize offset)
{
	int64 result = -1;
	stream->seek (offset, IBStream::kIBSeekSet, &result);
	return result == offset;
}

//------------------------------------------------------------------------
bool PresetFile::readChunkList ()
{
	seekTo (0);
	entryCount = 0;

	char8 classString[kClassIDSize + 1] = {0};

	// Read header
	int32 version = 0;
	TSize listOffset = 0;
	if (!(readEqualID (getChunkID (kHeader)) &&
		 readInt32 (version) &&
		 verify (stream->read (classString, kClassIDSize)) &&
		 readSize (listOffset) &&
		 listOffset > 0 &&
		 seekTo (listOffset)))
		return false;

	classID.fromString (classString);

	// Read list
	int32 count = 0;
	if (!readEqualID (getChunkID (kChunkList)))
		return false;
	if (!readInt32 (count))
		return false;

	if (count > kMaxEntries)
		count = kMaxEntries;

	for (int32 i = 0; i < count; i++)
	{
		Entry& e = entries[i];
		if (!(readID (e.id) &&
			 readSize (e.offset) &&
			 readSize (e.size)))
			break;

		entryCount++;
	}

	return entryCount > 0;
}

//------------------------------------------------------------------------
bool PresetFile::writeHeader ()
{
	// header id + version + class id + list offset (unknown yet)

	char8 classString[kClassIDSize + 1] = {0};
	classID.toString (classString);

	return	seekTo (0) &&
			writeID (getChunkID (kHeader)) &&
			writeInt32 (kFormatVersion) &&
			verify (stream->write (classString, kClassIDSize)) &&
			writeSize (0);
}

//------------------------------------------------------------------------
bool PresetFile::writeChunkList ()
{
	// Update list offset
	TSize pos = 0;
	stream->tell (&pos);
	if (!(seekTo (kListOffsetPos) &&
		 writeSize (pos) &&
		 seekTo (pos)))
		return false;

	// Write list
	if (!writeID (getChunkID (kChunkList)))
		return false;
	if (!writeInt32 (entryCount))
		return false;

	for (int32 i = 0; i < entryCount; i++)
	{
		Entry& e = entries[i];
		if (!(writeID (e.id) &&
			 writeSize (e.offset) &&
			 writeSize (e.size)))
			 return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool PresetFile::beginChunk (Entry& e, ChunkType which)
{
	if (entryCount >= kMaxEntries)
		return false;

	const ChunkID& id = getChunkID (which);
	memcpy (e.id, &id, sizeof (ChunkID));
	stream->tell (&e.offset);
	e.size = 0;
	return true;
}

//------------------------------------------------------------------------
bool PresetFile::endChunk (Entry& e)
{
	if (entryCount >= kMaxEntries)
		return false;

	TSize pos = 0;
	stream->tell (&pos);
	e.size = pos - e.offset;
	entries[entryCount++] = e;
	return true;
}

//------------------------------------------------------------------------
bool PresetFile::readMetaInfo (char* xmlBuffer, int32& size)
{
	bool result = false;
	const Entry* e = getEntry (kMetaInfo);
	if (e)
	{
		if (xmlBuffer)
		{
			result = seekTo (e->offset) &&
					 verify (stream->read (xmlBuffer, size, &size));
		}
		else
		{
			size = (int32)e->size;
			result = size > 0;
		}
	}
	return result;
}

//------------------------------------------------------------------------
bool PresetFile::writeMetaInfo (const char* xmlBuffer, int32 size, bool forceWriting)
{
	if (contains (kMetaInfo)) // already exists!
	{
		if (!forceWriting)
			return false;
	}
	if (!prepareMetaInfoUpdate ())
		return false;

	if (size == -1)
		size = (int32)strlen (xmlBuffer);

	Entry e = {0};
	return	beginChunk (e, kMetaInfo) &&
			verify (stream->write ((void*)xmlBuffer, size)) &&
			endChunk (e);
}

//------------------------------------------------------------------------
bool PresetFile::prepareMetaInfoUpdate ()
{
	TSize writePos = 0;
	const Entry* e = getEntry (kMetaInfo);
	if (e)
	{
		// meta info must be the last entry!
		if (e != getLastEntry ())
			return false;

		writePos = e->offset;
		entryCount--;
	}
	else
	{
		// entries must be sorted ascending by offset!
		e = getLastEntry ();
		writePos = e ? e->offset + e->size : kHeaderSize;
	}

	return seekTo (writePos);
}

//------------------------------------------------------------------------
bool PresetFile::writeChunk (const void* data, int32 size, ChunkType which)
{
	if (contains (which)) // already exists!
		return false;

	Entry e = {0};
	return	beginChunk (e, which) &&
			verify (stream->write ((void*)data, size)) &&
			endChunk (e);
}

//------------------------------------------------------------------------
bool PresetFile::seekToComponentState ()
{
	const Entry* e = getEntry (kComponentState);
	return e && seekTo (e->offset);
}

//------------------------------------------------------------------------
bool PresetFile::storeComponentState (IComponent* component)
{
	if (contains (kComponentState)) // already exists!
		return false;

	Entry e = {0};
	return	beginChunk (e, kComponentState) &&
			verify (component->getState (stream)) &&
			endChunk (e);
}

//------------------------------------------------------------------------
bool PresetFile::restoreComponentState (IComponent* component)
{
	const Entry* e = getEntry (kComponentState);
	if (e)
	{
		ReadOnlyBStream* readOnlyBStream = new ReadOnlyBStream (stream, e->offset, e->size);
		FReleaser readOnlyBStreamReleaser (readOnlyBStream);
		return verify (component->setState (readOnlyBStream));
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::restoreComponentState (IEditController* editController)
{
	const Entry* e = getEntry (kComponentState);
	if (e)
	{
		ReadOnlyBStream* readOnlyBStream = new ReadOnlyBStream (stream, e->offset, e->size);
		FReleaser readOnlyBStreamReleaser (readOnlyBStream);
		return verify (editController->setComponentState (readOnlyBStream));
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::seekToControllerState ()
{
	const Entry* e = getEntry (kControllerState);
	return e && seekTo (e->offset);
}

//------------------------------------------------------------------------
bool PresetFile::storeControllerState (IEditController* editController)
{
	if (contains (kControllerState)) // already exists!
		return false;

	Entry e = {0};
	return	beginChunk (e, kControllerState) &&
			verify (editController->getState (stream)) &&
			endChunk (e);
}

//------------------------------------------------------------------------
bool PresetFile::restoreControllerState (IEditController* editController)
{
	const Entry* e = getEntry (kControllerState);
	if (e)
	{
		ReadOnlyBStream* readOnlyBStream = new ReadOnlyBStream (stream, e->offset, e->size);
		FReleaser readOnlyBStreamReleaser (readOnlyBStream);
		return verify (editController->setState (readOnlyBStream));
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::storeProgramData (IBStream* inStream, ProgramListID listID)
{
	if (contains (kProgramData)) // already exists!
		return false;

	writeHeader ();

	Entry e = {0};
	if (beginChunk (e, kProgramData))
	{
		if (writeInt32 (listID))
		{
			int8 buffer[8192];
			int32 read = 0;
			int32 written = 0;
			while (inStream->read (buffer, 8192, &read) == kResultTrue && read > 0)
			{
				if (stream->write (buffer, read, &written) != kResultTrue)
				{
					return false;
				}
			}
			return endChunk (e);
		}
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::storeProgramData (IProgramListData* programListData, ProgramListID listID, int32 programIndex)
{
	if (contains (kProgramData)) // already exists!
		return false;

	writeHeader ();

	Entry e = {0};
	return	beginChunk (e, kProgramData) &&
			writeInt32 (listID) &&
			verify (programListData->getProgramData (listID, programIndex, stream)) &&
			endChunk (e);
}

//------------------------------------------------------------------------
bool PresetFile::restoreProgramData (IProgramListData* programListData, ProgramListID* programListID, int32 programIndex)
{
	const Entry* e = getEntry (kProgramData);
	ProgramListID savedProgramListID = -1;
	if (e && seekTo (e->offset))
	{
		if (readInt32 (savedProgramListID))
		{
			if (programListID && *programListID != savedProgramListID)
				return false;

			int32 alreadyRead = sizeof (int32);
			ReadOnlyBStream* readOnlyBStream = new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead);
			FReleaser readOnlyBStreamReleaser (readOnlyBStream);
			return programListData && verify (programListData->setProgramData (savedProgramListID, programIndex, readOnlyBStream));
		}
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::storeProgramData (IUnitData* unitData, UnitID unitID)
{
	if (contains (kProgramData)) // already exists!
		return false;

	writeHeader ();

	Entry e = {0};
	return	beginChunk (e, kProgramData) &&
			writeInt32 (unitID) &&
			verify (unitData->getUnitData (unitID, stream)) &&
			endChunk (e);
}

//------------------------------------------------------------------------
bool PresetFile::restoreProgramData (IUnitData* unitData, UnitID* unitId)
{
	const Entry* e = getEntry (kProgramData);
	UnitID savedUnitID = -1;
	if (e && seekTo (e->offset))
	{
		if (readInt32 (savedUnitID))
		{
			if (unitId && *unitId != savedUnitID)
				return false;

			int32 alreadyRead = sizeof (int32);
			ReadOnlyBStream* readOnlyBStream = new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead);
			FReleaser readOnlyStreamReleaser (readOnlyBStream);
			return (unitData && verify (unitData->setUnitData (savedUnitID, readOnlyBStream)));
		}
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::restoreProgramData (IUnitInfo* unitInfo, int32 unitProgramListID, int32 programIndex)
{
	const Entry* e = getEntry (kProgramData);
	int32 savedProgramListID = -1;
	if (e && seekTo (e->offset))
	{
		if (readInt32 (savedProgramListID))
		{
			if (unitProgramListID != savedProgramListID)
				return false;

			int32 alreadyRead = sizeof (int32);
			ReadOnlyBStream* readOnlyBStream = new ReadOnlyBStream (stream, e->offset + alreadyRead, e->size - alreadyRead);
			FReleaser readOnlyStreamReleaser (readOnlyBStream);
			return (unitInfo && unitInfo->setUnitProgramData (unitProgramListID, programIndex, readOnlyBStream));
		}
	}
	return false;
}

//------------------------------------------------------------------------
bool PresetFile::getUnitProgramListID (int32& unitProgramListID)
{
	const Entry* e = getEntry (kProgramData);
	if (e && seekTo (e->offset))
	{
		if (readInt32 (unitProgramListID))
		{
			return true;
		}
	}
	return false;
}

//------------------------------------------------------------------------
// FileStream implementation
//------------------------------------------------------------------------
IBStream* FileStream::open (const char* filename, const char* mode)
{
	FILE* file = fopen (filename, mode);
	return file ? new FileStream (file) : 0;
}

//------------------------------------------------------------------------
FileStream::FileStream (FILE* file)
: file (file)
{
	FUNKNOWN_CTOR
}

//------------------------------------------------------------------------
FileStream::~FileStream ()
{
	fclose (file);
	FUNKNOWN_DTOR
}

//------------------------------------------------------------------------
IMPLEMENT_FUNKNOWN_METHODS (FileStream, IBStream, IBStream::iid)

//------------------------------------------------------------------------
tresult PLUGIN_API FileStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
{
	size_t result = fread (buffer, 1, numBytes, file);
	if (numBytesRead)
		*numBytesRead = (int32)result;
	return result == numBytes ? kResultOk : kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API FileStream::write (void* buffer, int32 numBytes, int32* numBytesWritten)
{
	size_t result = fwrite (buffer, 1, numBytes, file);
	if (numBytesWritten)
		*numBytesWritten = (int32)result;
	return result == numBytes ? kResultOk : kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API FileStream::seek (int64 pos, int32 mode, int64* result)
{
	if (fseek (file, (int32)pos, mode) == 0)
	{
		if (result)
			*result = ftell (file);
		return kResultOk;
	}
	return kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API FileStream::tell (int64* pos)
{
	if (pos)
		*pos = ftell (file);
	return kResultOk;
}

//------------------------------------------------------------------------
// ReadOnlyBStream implementation
//------------------------------------------------------------------------

IMPLEMENT_REFCOUNT (ReadOnlyBStream)

//------------------------------------------------------------------------
ReadOnlyBStream::ReadOnlyBStream (IBStream* sourceStream, TSize sourceOffset, TSize sectionSize)
: sourceStream (sourceStream)
, sourceOffset (sourceOffset)
, sectionSize (sectionSize)
, seekPosition (0)
{
	FUNKNOWN_CTOR
	if (sourceStream)
		sourceStream->addRef ();
}

//------------------------------------------------------------------------
ReadOnlyBStream::~ReadOnlyBStream ()
{
	if (sourceStream)
		sourceStream->release ();

	FUNKNOWN_DTOR
}

//------------------------------------------------------------------------
tresult PLUGIN_API ReadOnlyBStream::queryInterface (const TUID iid, void** obj)
{
	return sourceStream ? sourceStream->queryInterface (iid, obj) : kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API ReadOnlyBStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
{
	if (numBytesRead)
		*numBytesRead = 0;

	if (!sourceStream)
		return kNotInitialized;

	int32 maxBytesToRead = (int32)(sectionSize - seekPosition);
	if (numBytes > maxBytesToRead)
		numBytes = maxBytesToRead;
	if (numBytes <= 0)
		return kResultOk;

	tresult result = sourceStream->seek (sourceOffset + seekPosition, kIBSeekSet);
	if (result != kResultOk)
		return result;

	int32 numRead = 0;
	result = sourceStream->read (buffer, numBytes, &numRead);

	if (numRead > 0)
		seekPosition += numRead;
	if (numBytesRead)
		*numBytesRead = numRead;

	return result;
}

//------------------------------------------------------------------------
tresult PLUGIN_API ReadOnlyBStream::write (void* /*buffer*/, int32 /*numBytes*/, int32* numBytesWritten)
{
	if (numBytesWritten)
		*numBytesWritten = 0;

	return kNotImplemented;
}

//------------------------------------------------------------------------
tresult PLUGIN_API ReadOnlyBStream::seek (int64 pos, int32 mode, int64* result)
{
	switch (mode)
	{
		case kIBSeekSet :
			seekPosition = pos;
			break;

		case kIBSeekCur :
			seekPosition += pos;
			break;

		case kIBSeekEnd :
			seekPosition = sectionSize + pos;
			break;
	}

	if (seekPosition < 0)
		seekPosition = 0;
	if (seekPosition > sectionSize)
		seekPosition = sectionSize;

	if (result)
		*result = seekPosition;
	return kResultOk;
}

//------------------------------------------------------------------------
tresult PLUGIN_API ReadOnlyBStream::tell (int64* pos)
{
	if (pos)
		*pos = seekPosition;
	return kResultOk;
}

//------------------------------------------------------------------------
// BufferStream implementation
//------------------------------------------------------------------------
IMPLEMENT_FUNKNOWN_METHODS (BufferStream, IBStream, IBStream::iid)

//------------------------------------------------------------------------
BufferStream::BufferStream ()
{
	FUNKNOWN_CTOR
}

//------------------------------------------------------------------------
BufferStream::~BufferStream ()
{
	FUNKNOWN_DTOR
}

//------------------------------------------------------------------------
tresult PLUGIN_API BufferStream::read (void* buffer, int32 numBytes, int32* numBytesRead)
{
	uint32 size = mBuffer.get (buffer, numBytes);
	if (numBytesRead)
		*numBytesRead = size;

	return kResultTrue;
}

//------------------------------------------------------------------------
tresult PLUGIN_API BufferStream::write (void* buffer, int32 numBytes, int32* numBytesWritten)
{
	bool res = mBuffer.put (buffer, numBytes);
	if (numBytesWritten)
		*numBytesWritten = res ? numBytes : 0;

	return res ? kResultTrue : kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API BufferStream::seek (int64 pos, int32 mode, int64* result)
{
	bool res = false;
	switch (mode)
	{
		//--- -----------------
		case IBStream::kIBSeekSet:
		{
			int64 tmp = pos;
			if (tmp < 0)
				tmp = 0;
			res = mBuffer.setFillSize (static_cast<uint32> (tmp));
		}
		break;

		//--- -----------------
		case IBStream::kIBSeekCur:
		{
			int64 tmp = mBuffer.getFillSize () + pos;
			if (tmp < 0)
				tmp = 0;
			res = mBuffer.setFillSize (static_cast<uint32> (tmp));
		}
		break;

		//--- -----------------
		case IBStream::kIBSeekEnd:
		{
			int64 tmp = mBuffer.getSize () - pos;
			if (tmp < 0)
				tmp = 0;
			res = mBuffer.setFillSize (static_cast<uint32> (tmp));
		}
		break;
	}
	if (res && result)
		*result = mBuffer.getFillSize ();

	return res ? kResultTrue : kResultFalse;
}

//------------------------------------------------------------------------
tresult PLUGIN_API BufferStream::tell (int64* pos)
{
	if (pos)
		*pos = mBuffer.getFillSize ();
	return pos ? kResultTrue : kResultFalse;
}

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg


text:
//------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstrepresentation.h
// Created by  : Steinberg, 08/2010
// Description : VST Representation Helper
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#include "pluginterfaces/vst/ivstrepresentation.h"
#include "pluginterfaces/vst/ivsteditcontroller.h"

//------------------------------------------------------------------------
namespace Steinberg {
class IBStreamer;

namespace Vst {

//------------------------------------------------------------------------
/** Helper for XML Representation creation.
\ingroup vstClasses

Here an example of how to use this helper:
\n
\code

// here the parameter ids used by this example
enum {
	kGain = 129,
	kSize,
	kCutoff,
	kResonance,
	kMaster,
	kEnable1,
	kEnable2,
	kFrequency1,
	kFrequency2,
	kGain1,
	kGain2,
};

//------------------------------------------------------------------------
tresult PLUGIN_API MyPlugInController::getXmlRepresentationStream (Vst::RepresentationInfo& info, IBStream* stream)
{
	String name (info.name);
	if (name == GENERIC_8_CELLS)
	{
		Vst::XmlRepresentationHelper helper (info, "My Company Name", "My Product Name", gPlugProcessorClassID, stream);

		helper.startPage ("Main Page");
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kGain);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kSize);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kMaster);
		helper.startEndCell ();	// empty cell
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kCutoff);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kResonance);
		helper.startEndCell ();	// empty cell
		helper.startEndCell ();	// empty cell
		helper.endPage ();

		helper.startPage ("Page 2");
		helper.startEndCellOneLayer (Vst::LayerType::kSwitch, kEnable1);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kFrequency1);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kGain1);
		helper.startEndCell ();	// empty
		helper.startEndCellOneLayer (Vst::LayerType::kSwitch, kEnable2);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kFrequency2);
		helper.startEndCellOneLayer (Vst::LayerType::kKnob, kGain2);
		helper.startEndCell ();	// empty
		helper.endPage ();

		return kResultTrue;
	}
	return kResultFalse;
}
\endcode
*/
//------------------------------------------------------------------------
class XmlRepresentationHelper
{
public:
	XmlRepresentationHelper (const RepresentationInfo& info, const FIDString companyName, const FIDString pluginName, const TUID& pluginUID, IBStream* stream);
	virtual ~XmlRepresentationHelper ();

	bool startPage (FIDString name, int32 unitID = -1);	///< Starts a Page before adding a Cell.
	bool endPage ();									///< Ends a Page before opening a new one.
	bool startCell ();									///< Starts a Cell before adding a Layer.
	bool endCell ();									///< Ends a Cell when no more layer needed.
	bool startEndCell ();								///< Creates an empty cell (alignment for example).

	/** Starts a layer for a given type (Vst::LayerType), a parameter id, optionally a function (Vst::AttributesFunction)
		and a style (Vst::AttributesStyle). */
	bool startLayer (int32 type, int32 id, FIDString _function = 0, FIDString style = 0);

	/** Ends a layer before adding new one */
	bool endLayer ();

	/** Same than startLayer except that the layer will be ended automatically (no need to call endLayer). */
	bool startEndLayer (int32 type, int32 id, FIDString _function = 0, FIDString style = 0);

	/** Creates a Cell with 1 Layer and end it, could be only call after a call to startPage */
	bool startEndCellOneLayer (int32 type, int32 id, FIDString _function = 0, FIDString style = 0);

	/** Starts a layer for a given parameter info and an optional function (Vst::AttributesFunction). */
	bool startLayer (Vst::ParameterInfo& info, FIDString _function = 0);

	/** Same than startLayer with end created automatically. */
	bool startEndLayer (Vst::ParameterInfo& info, FIDString _function = 0);

	/** Creates a Cell with 1 Layer and end it, could be only call after a call to startPage. */
	bool startEndCellOneLayer (Vst::ParameterInfo& info, FIDString _function = 0);

	/** Creates a Cell with 1 Layer (with name) and end it, could be only call after a call to startPage. */
	bool startEndCellOneLayerWithParamName (Vst::ParameterInfo& info, FIDString _function = 0);

protected:
	enum {
		kInRepresentation = 0,
		kInPage,
		kInCell,
		kInLayer,
		kInTitleDisplay,
		kInName
	};

	bool startLayer (int32 type, int32 id, FIDString _function, FIDString style, bool ended);
	bool startLayer (Vst::ParameterInfo& info, FIDString _function, bool ended);

	bool startEndTitleDisplay (Vst::ParameterInfo& info);

	bool checkState (int32 newState);

	IPtr<IBStream> stream;
	int32 state;
};

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstinitiids.cpp
// Created by  : Steinberg, 10/2009
// Description : Interface symbols file
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#include "pluginterfaces/base/funknown.h"

#include "pluginterfaces/vst/ivsteditcontroller.h"
#include "pluginterfaces/vst/ivstmessage.h"
#include "pluginterfaces/vst/ivstunits.h"
#include "pluginterfaces/vst/ivstaudioprocessor.h"
#include "pluginterfaces/vst/ivstparameterchanges.h"
#include "pluginterfaces/vst/ivstevents.h"
#include "pluginterfaces/vst/ivsthostapplication.h"
#include "pluginterfaces/vst/ivstplugview.h"
#include "pluginterfaces/vst/ivstcontextmenu.h"
#include "pluginterfaces/vst/ivstrepresentation.h"
#include "pluginterfaces/vst/ivstinterappaudio.h"
#include "pluginterfaces/vst/ivstchannelcontextinfo.h"
#include "pluginterfaces/vst/ivstprefetchablesupport.h"
#include "pluginterfaces/vst/ivstautomationstate.h"

namespace Steinberg {
namespace Vst {

	//----VST 3.0--------------------------------
	DEF_CLASS_IID (IComponent)
	DEF_CLASS_IID (IAudioProcessor)
	DEF_CLASS_IID (IUnitData)
	DEF_CLASS_IID (IProgramListData)

	DEF_CLASS_IID (IEditController)
	DEF_CLASS_IID (IUnitInfo)

	DEF_CLASS_IID (IConnectionPoint)

	DEF_CLASS_IID (IComponentHandler)
	DEF_CLASS_IID (IUnitHandler)

	DEF_CLASS_IID (IParamValueQueue)
	DEF_CLASS_IID (IParameterChanges)

	DEF_CLASS_IID (IEventList)
	DEF_CLASS_IID (IMessage)

	DEF_CLASS_IID (IHostApplication)
	DEF_CLASS_IID (IAttributeList)

	//----VST 3.0.1--------------------------------
	DEF_CLASS_IID (IMidiMapping)

	//----VST 3.0.2--------------------------------
	DEF_CLASS_IID (IParameterFinder)

	//----VST 3.1----------------------------------
	DEF_CLASS_IID (IComponentHandler2)
	DEF_CLASS_IID (IEditController2)
	DEF_CLASS_IID (IAudioPresentationLatency)

	//---VST 3.1 for AU and VST 2 Wrapper-----------
	DEF_CLASS_IID (IVst3ToVst2Wrapper)
	DEF_CLASS_IID (IVst3ToAUWrapper)

	//----VST 3.5----------------------------------
	DEF_CLASS_IID (INoteExpressionController)
	DEF_CLASS_IID (IKeyswitchController)
	DEF_CLASS_IID (IContextMenuTarget)
	DEF_CLASS_IID (IContextMenu)
	DEF_CLASS_IID (IComponentHandler3)
	DEF_CLASS_IID (IEditControllerHostEditing)
	DEF_CLASS_IID (IXmlRepresentationController)

	//----VST 3.6----------------------------------
	DEF_CLASS_IID (IInterAppAudioHost)
	DEF_CLASS_IID (IInterAppAudioConnectionNotification)
	DEF_CLASS_IID (IInterAppAudioPresetManager)
	DEF_CLASS_IID (IStreamAttributes)

	//----VST 3.6.5--------------------------------
	DEF_CLASS_IID (ChannelContext::IInfoListener)
	DEF_CLASS_IID (IPrefetchableSupport)
	DEF_CLASS_IID (IUnitHandler2)
	DEF_CLASS_IID (IAutomationState)
}
}


text:
//-----------------------------------------------------------------------------
// Project     : VST SDK
//
// Category    : Helpers
// Filename    : public.sdk/source/vst/vstpresetfile.h
// Created by  : Steinberg, 03/2006
// Description : VST 3 Preset File Format
//
//-----------------------------------------------------------------------------
// LICENSE
// (c) 2017, Steinberg Media Technologies GmbH, All Rights Reserved
//-----------------------------------------------------------------------------
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of the Steinberg Media Technologies nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE  OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//-----------------------------------------------------------------------------

#pragma once

#include "pluginterfaces/vst/ivstcomponent.h"
#include "pluginterfaces/vst/ivsteditcontroller.h"
#include "pluginterfaces/vst/ivstunits.h"

#include "pluginterfaces/base/ibstream.h"
#include "base/source/fbuffer.h"

#include <cstdio>
#include <vector>

//------------------------------------------------------------------------
/** \page vst3presetFileFormat VST 3 Preset File Format Definition
\code

   VST 3 Preset File Format Definition
   ===================================

0   +---------------------------+
    | HEADER                    |
    | header id ('VST3')        |       4 Bytes
    | version                   |       4 Bytes (int32)
    | ASCII-encoded class id    |       32 Bytes
 +--| offset to chunk list      |       8 Bytes (int64)
 |  +---------------------------+
 |  | DATA AREA                 |<-+
 |  | data of chunks 1..n       |  |
 |  ...                       ...  |
 |  |                           |  |
 +->+---------------------------+  |
    | CHUNK LIST                |  |
    | list id ('List')          |  |    4 Bytes
    | entry count               |  |    4 Bytes (int32)
    +---------------------------+  |
    |  1..n                     |  |
    |  +----------------------+ |  |
    |  | chunk id             | |  |    4 Bytes
    |  | offset to chunk data |----+    8 Bytes (int64)
    |  | size of chunk data   | |       8 Bytes (int64)
    |  +----------------------+ |
EOF +---------------------------+

\endcode
\see \ref Steinberg::Vst::PresetFile
*/
//------------------------------------------------------------------------

//------------------------------------------------------------------------
namespace Steinberg {
namespace Vst {

//------------------------------------------------------------------------
typedef char ChunkID[4];

//------------------------------------------------------------------------
enum ChunkType
{
	kHeader,
	kComponentState,
	kControllerState,
	kProgramData,
	kMetaInfo,
	kChunkList,
	kNumPresetChunks
};

//------------------------------------------------------------------------
extern const ChunkID& getChunkID (ChunkType type);

//------------------------------------------------------------------------
inline bool isEqualID (const ChunkID id1, const ChunkID id2)
{
	return memcmp (id1, id2, sizeof (ChunkID)) == 0;
}

//------------------------------------------------------------------------
/** Handler for a VST 3 Preset File.
\ingroup vstClasses
\see \ref vst3presetFileFormat */
//------------------------------------------------------------------------
class PresetFile
{
public:
//------------------------------------------------------------------------
	PresetFile (IBStream* stream);	///< Constructor of Preset file based on a stream
	virtual ~PresetFile ();

	/** Internal structure used for chunk handling */
	struct Entry
	{
		ChunkID id;
		TSize offset;
		TSize size;
	};

	IBStream* getStream () { return stream; }				///< Returns the associated stream.

	const FUID& getClassID () const { return classID; }		///< Returns the associated classID (component ID: Processor part (not the controller!)).
	void setClassID (const FUID& uid) { classID = uid; }	///< Sets the associated classID (component ID: Processor part (not the controller!)).

	const Entry* getEntry (ChunkType which) const;			///< Returns an entry for a given chunk type.
	const Entry* getLastEntry () const;						///< Returns the last available entry.
	int32 getEntryCount () const { return entryCount; }		///< Returns the number of total entries in the current stream.
	const Entry& at (int32 index) const { return entries[index]; }	///< Returns the entry at a given position.
	bool contains (ChunkType which) const { return getEntry (which) != 0; }	///< Checks if a given chunk type exist in the stream.

	bool readChunkList ();				///< Reads and build the chunk list (including the header chunk).
	bool writeHeader ();				///< Writes into the stream the main header.
	bool writeChunkList ();				///< Writes into the stream the chunk list (should be at the end).

	/** Reads the meta XML info and its size, the size could be retrieved by passing zero as xmlBuffer. */
	bool readMetaInfo (char* xmlBuffer, int32& size);

	/** Writes the meta XML info, -1 means null-terminated, forceWriting to true will force to rewrite the XML Info when the chunk already exists. */
	bool writeMetaInfo (const char* xmlBuffer, int32 size = -1, bool forceWriting = false);
	bool prepareMetaInfoUpdate ();		///< checks if meta info chunk is the last one and jump to correct position.

	/** Writes a given data of a given size as "which" chunk type. */
	bool writeChunk (const void* data, int32 size, ChunkType which = kComponentState);

	//-------------------------------------------------------------
	// for storing and restoring the whole Plug-in state (component and controller states)
	bool seekToComponentState ();									///< Seeks to the begin of the Component State.
	bool storeComponentState (IComponent* component);				///< Stores the component state (only one time).
	bool restoreComponentState (IComponent* component);				///< Restores the component state.

	bool seekToControllerState ();									///< Seeks to the begin of the Controller State.
	bool storeControllerState (IEditController* editController);	///< Stores the controller state (only one time).
	bool restoreControllerState (IEditController* editController);	///< Restores the controller state.

	bool restoreComponentState (IEditController* editController);	///< Restores the component state and apply it to the controller.

	//-------------------------------------------------------------
	/** Store program data or unit data from stream (including the header chunk).
	 \param listID could be ProgramListID or UnitID. */
	bool storeProgramData (IBStream* inStream, ProgramListID listID);

	//----when Plug-in uses IProgramListData-----------------------
	/** Stores a IProgramListData with a given identifier and index (including the header chunk). */
	bool storeProgramData (IProgramListData* programListData, ProgramListID programListID, int32 programIndex);
	/** Restores a IProgramListData with a given identifier and index. */
	bool restoreProgramData (IProgramListData* programListData, ProgramListID* programListID = 0, int32 programIndex = 0);

	//----when Plug-in uses IUnitData------------------------------
	/** Stores a IUnitData with a given unitID (including the header chunk). */
	bool storeProgramData (IUnitData* unitData, UnitID unitID);
	/** Restores a IUnitData with a given unitID (optional). */
	bool restoreProgramData (IUnitData* unitData, UnitID* unitID = 0);

	//-------------------------------------------------------------
	/** for keeping the Controller part in sync concerning preset data stream, unitProgramListID could be ProgramListID or UnitID. */
	bool restoreProgramData (IUnitInfo* unitInfo, int32 unitProgramListID, int32 programIndex = -1);

	/** Gets the unitProgramListID saved in the kProgramData chunk (if available). */
	bool getUnitProgramListID (int32& unitProgramListID);

	//------------------------------------------------------------------------
	/** Shortcut helper to create preset from component/controller state. classID is the FUID of the component (processor) part. */
	static bool savePreset (IBStream* stream,
							const FUID& classID,
							IComponent* component,
							IEditController* editController = 0,
							const char* xmlBuffer = 0,
							int32 xmlSize = -1);

	/** Shortcut helper to load preset with component/controller state. classID is the FUID of the component (processor) part. */
	static bool loadPreset (IBStream* stream,
							const FUID& classID,
							IComponent* component,
							IEditController* editController = 0,
							std::vector<FUID>* otherClassIDArray = 0);
//------------------------------------------------------------------------
protected:
	bool readID (ChunkID id);
	bool writeID (const ChunkID id);
	bool readEqualID (const ChunkID id);
	bool readSize (TSize& size);
	bool writeSize (TSize size);
	bool readInt32 (int32& value);
	bool writeInt32 (int32 value);
	bool seekTo (TSize offset);
	bool beginChunk (Entry& e, ChunkType which);
	bool endChunk (Entry& e);

	IBStream* stream;
	FUID classID;		///< classID is the FUID of the component (processor) part
	enum { kMaxEntries = 128 };
	Entry entries[kMaxEntries];
	int32 entryCount;
};

//------------------------------------------------------------------------
/** Stream implementation for a file using stdio. */
//------------------------------------------------------------------------
class FileStream: public IBStream
{
public:
//------------------------------------------------------------------------
	static IBStream* open (const char* filename, const char* mode);	///< open a stream using stdio function

	//---from FUnknown------------------
	DECLARE_FUNKNOWN_METHODS

	//---from IBStream------------------
	tresult PLUGIN_API read (void* buffer, int32 numBytes, int32* numBytesRead = 0) SMTG_OVERRIDE;
	tresult PLUGIN_API write (void* buffer, int32 numBytes, int32* numBytesWritten = 0) SMTG_OVERRIDE;
	tresult PLUGIN_API seek (int64 pos, int32 mode, int64* result = 0) SMTG_OVERRIDE;
	tresult PLUGIN_API tell (int64* pos) SMTG_OVERRIDE;

//------------------------------------------------------------------------
protected:
	FileStream (FILE* file);
	virtual ~FileStream ();

	FILE* file;
};

//------------------------------------------------------------------------
/** Stream representing a Read-Only subsection of its source stream. */
//------------------------------------------------------------------------
class ReadOnlyBStream: public IBStream
{
public:
//------------------------------------------------------------------------
	 ReadOnlyBStream (IBStream* sourceStream, TSize sourceOffset, TSize sectionSize);
	 virtual ~ReadOnlyBStream ();

	 //---from FUnknown------------------
	 DECLARE_FUNKNOWN_METHODS

	 //---from IBStream------------------
	 tresult PLUGIN_API read (void* buffer, int32 numBytes, int32* numBytesRead = 0) SMTG_OVERRIDE;
	 tresult PLUGIN_API write (void* buffer, int32 numBytes, int32* numBytesWritten = 0) SMTG_OVERRIDE;
	 tresult PLUGIN_API seek (int64 pos, int32 mode, int64* result = 0) SMTG_OVERRIDE;
	 tresult PLUGIN_API tell (int64* pos) SMTG_OVERRIDE;

//------------------------------------------------------------------------
protected:
	 IBStream* sourceStream;
	 TSize sourceOffset;
	 TSize sectionSize;
	 TSize seekPosition;
};

//------------------------------------------------------------------------
/** Stream implementation for a memory buffer. */
//------------------------------------------------------------------------
class BufferStream : public IBStream
{
public:
	BufferStream ();
	virtual ~BufferStream ();

	//---from FUnknown------------------
	DECLARE_FUNKNOWN_METHODS

	//---from IBStream------------------
	tresult PLUGIN_API read (void* buffer, int32 numBytes, int32* numBytesRead = 0) SMTG_OVERRIDE;
	tresult PLUGIN_API write (void* buffer, int32 numBytes, int32* numBytesWritten = 0) SMTG_OVERRIDE;
	tresult PLUGIN_API seek (int64 pos, int32 mode, int64* result = 0) SMTG_OVERRIDE;
	tresult PLUGIN_API tell (int64* pos) SMTG_OVERRIDE;

protected:
	Buffer mBuffer;
};

//------------------------------------------------------------------------
} // namespace Vst
} // namespace Steinberg