text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fstreamer.cpp
// Created by  : Steinberg, 15.12.2005
// Description : Extract of typed stream i/o methods from FStream
//
//-----------------------------------------------------------------------------
// 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 "fstreamer.h"

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

#ifndef UNICODE
#include "pluginterfaces/base/futils.h"
#endif

namespace Steinberg {

//------------------------------------------------------------------------
// IBStreamer
//------------------------------------------------------------------------
IBStreamer::IBStreamer (IBStream* stream, int16 _byteOrder)
: FStreamer (_byteOrder)
, stream (stream)
{}

//------------------------------------------------------------------------
TSize IBStreamer::readRaw (void* buffer, TSize size)
{
	int32 numBytesRead = 0;
	stream->read (buffer, (int32)size, &numBytesRead);
	return numBytesRead;
}

//------------------------------------------------------------------------
TSize IBStreamer::writeRaw (const void* buffer, TSize size)
{
	int32 numBytesWritten = 0;
	stream->write ((void*)buffer, (int32)size, &numBytesWritten);
	return numBytesWritten;
}

//------------------------------------------------------------------------
int64 IBStreamer::seek (int64 pos, FSeekMode mode)
{
	int64 result = -1;
	stream->seek (pos, mode, &result);
	return result;
}

//------------------------------------------------------------------------
int64 IBStreamer::tell ()
{
	int64 pos = 0;
	stream->tell (&pos);
	return pos;
}

//------------------------------------------------------------------------
// FStreamSizeHolder Implementation
//------------------------------------------------------------------------
FStreamSizeHolder::FStreamSizeHolder (FStreamer &s)
: stream (s), sizePos (-1)
{}

//------------------------------------------------------------------------
void FStreamSizeHolder::beginWrite ()
{
	sizePos = stream.tell ();
	stream.writeInt32 (0L);
}

//------------------------------------------------------------------------
int32 FStreamSizeHolder::endWrite ()
{
	if (sizePos < 0)
		return 0;

	int64 currentPos = stream.tell ();

	stream.seek (sizePos, kSeekSet);
	int32 size = int32 (currentPos - sizePos - sizeof (int32));
	stream.writeInt32 (size);

	stream.seek (currentPos, kSeekSet);
	return size;
}

//------------------------------------------------------------------------
int32 FStreamSizeHolder::beginRead ()
{
	sizePos = stream.tell ();
	int32 size = 0;
	stream.readInt32 (size);
	sizePos += size + sizeof (int32);
	return size;
}

//------------------------------------------------------------------------
void FStreamSizeHolder::endRead ()
{
	if (sizePos >= 0)
		stream.seek (sizePos, kSeekSet);
}

//------------------------------------------------------------------------
// FStreamer
//------------------------------------------------------------------------
FStreamer::FStreamer (int16 _byteOrder)
: byteOrder (_byteOrder)
{}

// int8 / char -----------------------------------------------------------
//------------------------------------------------------------------------
bool FStreamer::writeChar8 (char8 c)
{
	return writeRaw ((void*)&c, sizeof (char8)) == sizeof (char8);
}

//------------------------------------------------------------------------
bool FStreamer::readChar8 (char8& c)
{
	return readRaw ((void*)&c, sizeof (char8)) == sizeof (char8);
}

//------------------------------------------------------------------------
bool FStreamer::writeUChar8 (unsigned char c)
{
	return writeRaw ((void*)&c, sizeof (unsigned char)) == sizeof (unsigned char);
}

//------------------------------------------------------------------------
bool FStreamer::readUChar8 (unsigned char& c)
{
	return readRaw ((void*)&c, sizeof (unsigned char)) == sizeof (unsigned char);
}

//------------------------------------------------------------------------
bool FStreamer::writeChar16 (char16 c)
{
	if (BYTEORDER != byteOrder)
		SWAP_16 (c);
	return writeRaw ((void*)&c, sizeof (char16)) == sizeof (char16);
}

//------------------------------------------------------------------------
bool FStreamer::readChar16 (char16& c)
{
	if (readRaw ((void*)&c, sizeof (char16)) == sizeof (char16))
	{
		if (BYTEORDER != byteOrder)
			SWAP_16 (c);
		return true;
	}
	c = 0;
	return false;
}

// int16 -----------------------------------------------------------------
//------------------------------------------------------------------------
bool FStreamer::writeInt16 (int16 i)
{
	if (BYTEORDER != byteOrder)
		SWAP_16 (i);
	return writeRaw ((void*)&i, sizeof (int16)) == sizeof (int16);
}

//------------------------------------------------------------------------
bool FStreamer::readInt16 (int16& i)
{
	if (readRaw ((void*)&i, sizeof (int16)) == sizeof (int16))
	{
		if (BYTEORDER != byteOrder)
			SWAP_16 (i);
		return true;
	}
	i = 0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt16Array (const int16* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeInt16 (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readInt16Array (int16* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readInt16 (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt16u (uint16 i)
{
	if (BYTEORDER != byteOrder)
		SWAP_16 (i);
	return writeRaw ((void*)&i, sizeof (uint16)) == sizeof (uint16);
}

//------------------------------------------------------------------------
bool FStreamer::readInt16u (uint16& i)
{
	if (readRaw ((void*)&i, sizeof (uint16)) == sizeof (uint16))
	{
		if (BYTEORDER != byteOrder)
			SWAP_16 (i);
		return true;
	}
	i = 0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt16uArray (const uint16* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeInt16u (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readInt16uArray (uint16* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readInt16u (array[i]))
			return false;
	}
	return true;
}

// int32 -----------------------------------------------------------------
//------------------------------------------------------------------------
bool FStreamer::writeInt32 (int32 i)
{
	if (BYTEORDER != byteOrder)
		SWAP_32 (i);
	return writeRaw ((void*)&i, sizeof (int32)) == sizeof (int32);
}

//------------------------------------------------------------------------
bool FStreamer::readInt32 (int32& i)
{
	if (readRaw ((void*)&i, sizeof (int32)) == sizeof (int32))
	{
		if (BYTEORDER != byteOrder)
			SWAP_32 (i);
		return true;
	}
	i = 0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt32Array (const int32* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeInt32 (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readInt32Array (int32* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readInt32 (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt32u (uint32 i)
{
	if (BYTEORDER != byteOrder)
		SWAP_32 (i);
	return writeRaw ((void*)&i, sizeof (uint32)) == sizeof (uint32);
}

//------------------------------------------------------------------------
bool FStreamer::readInt32u (uint32& i)
{
	if (readRaw ((void*)&i, sizeof (uint32)) == sizeof (uint32))
	{
		if (BYTEORDER != byteOrder)
			SWAP_32 (i);
		return true;
	}
	i = 0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt32uArray (const uint32* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeInt32u (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readInt32uArray (uint32* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readInt32u (array[i]))
			return false;
	}
	return true;
}

// int64 -----------------------------------------------------------------
//------------------------------------------------------------------------
bool FStreamer::writeInt64 (int64 i)
{
	if (BYTEORDER != byteOrder)
		SWAP_64 (i);
	return writeRaw ((void*)&i, sizeof (int64)) == sizeof (int64);
}

//------------------------------------------------------------------------
bool FStreamer::readInt64 (int64& i)
{
	if (readRaw ((void*)&i, sizeof (int64)) == sizeof (int64))
	{
		if (BYTEORDER != byteOrder)
			SWAP_64 (i);
		return true;
	}
	i = 0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt64Array (const int64* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeInt64 (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readInt64Array (int64* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readInt64 (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt64u (uint64 i)
{
	if (BYTEORDER != byteOrder)
		SWAP_64 (i);
	return writeRaw ((void*)&i, sizeof (uint64)) == sizeof (uint64);
}

//------------------------------------------------------------------------
bool FStreamer::readInt64u (uint64& i)
{
	if (readRaw ((void*)&i, sizeof (uint64)) == sizeof (uint64))
	{
		if (BYTEORDER != byteOrder)
			SWAP_64 (i);
		return true;
	}
	i = 0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeInt64uArray (const uint64* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeInt64u (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readInt64uArray (uint64* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readInt64u (array[i]))
			return false;
	}
	return true;
}

// float / double --------------------------------------------------------
//------------------------------------------------------------------------
bool FStreamer::writeFloat (float f)
{
	if (BYTEORDER != byteOrder)
		SWAP_32 (f);
	return writeRaw ((void*)&f, sizeof (float)) == sizeof (float);
}

//------------------------------------------------------------------------
bool FStreamer::readFloat (float& f)
{
	if (readRaw ((void*)&f, sizeof (float)) == sizeof (float))
	{
		if (BYTEORDER != byteOrder)
			SWAP_32 (f);
		return true;
	}
	f = 0.f;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeFloatArray (const float* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeFloat (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readFloatArray (float* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readFloat (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::writeDouble (double d)
{
	if (BYTEORDER != byteOrder)
		SWAP_64 (d);
	return writeRaw ((void*)&d, sizeof (double)) == sizeof (double);
}

//------------------------------------------------------------------------
bool FStreamer::readDouble (double& d)
{
	if (readRaw ((void*)&d, sizeof (double)) == sizeof (double))
	{
		if (BYTEORDER != byteOrder)
			SWAP_64 (d);
		return true;
	}
	d = 0.0;
	return false;
}

//------------------------------------------------------------------------
bool FStreamer::writeDoubleArray (const double* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!writeDouble (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readDoubleArray (double* array, int32 count)
{
	for (int32 i = 0; i < count; i++)
	{
		if (!readDouble (array[i]))
			return false;
	}
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::readBool (bool& b)
{
	int16 v = 0;
	bool res = readInt16 (v);
	b = (v != 0);
	return res;
}

//------------------------------------------------------------------------
bool FStreamer::writeBool (bool b)
{
	return writeInt16 ((int16)b);
}

//------------------------------------------------------------------------
TSize FStreamer::writeString8 (const char8* ptr, bool terminate)
{
	TSize size = strlen (ptr);
	if (terminate) // write \0
		size++;

	return writeRaw ((void*)ptr, size);
}

//------------------------------------------------------------------------
TSize FStreamer::readString8 (char8* ptr, TSize size)
{
	TSize i = 0;
	char8 c = 0;
	while (i < size)
	{
		if (readRaw ((void*)&c, sizeof (char)) != sizeof (char))
			break;
		ptr[i] = c;
		i++;
		if (c == '\n' || c == '\0')
			break;
	}
	if (c == '\n' && ptr[i - 2] == '\r')
		ptr[i - 2] = 0;
	if (i < size)
		ptr[i] = 0;
	else
		ptr[size - 1] = 0;

	return strlen (ptr);
}

//------------------------------------------------------------------------
bool FStreamer::writeStringUtf8 (const tchar* ptr)
{
	bool isUtf8 = false;

	String str (ptr);
	if (str.isAsciiString () == false)
	{
		str.toMultiByte (kCP_Utf8);
		isUtf8 = true;
	}
	else
	{
		str.toMultiByte ();
	}

	if (isUtf8)
		if (writeRaw (kBomUtf8, kBomUtf8Length) != kBomUtf8Length)
			return false;

	TSize size = str.length () + 1;
	if (writeRaw (str.text8 (), size) != size)
		return false;

	return true;
}

//------------------------------------------------------------------------
int32 FStreamer::readStringUtf8 (tchar* ptr, int32 nChars)
{
	char8 c = 0;

	ptr [0] = 0;

	Buffer tmp;
	tmp.setDelta (1024);

	while (true)
	{
		if (readRaw ((void*)&c, sizeof (char)) != sizeof (char))
			break;
		tmp.put (c);
		if (c == '\0')
			break;
	}

	char8* source = tmp.int8Ptr ();
	uint32 codePage = kCP_Default; // for legacy take default page if no utf8 bom is present...
	if (tmp.getFillSize () > 2)
	{
		if (memcmp (source, kBomUtf8, kBomUtf8Length) == 0)
		{
			codePage = kCP_Utf8;
			source += 3;
		}
	}

	if (tmp.getFillSize () > 1)
	{
#ifdef UNICODE
		ConstString::multiByteToWideString (ptr, source, nChars, codePage);
#else
		if (codePage == kCP_Utf8)
		{
			Buffer wideBuffer (tmp.getFillSize () * 3);
			ConstString::multiByteToWideString (wideBuffer.wcharPtr (), source, wideBuffer.getSize () / 2, kCP_Utf8);
			ConstString::wideStringToMultiByte (ptr, wideBuffer.wcharPtr (), nChars);
		}
		else
		{
			memcpy (ptr, source, Min<TSize> (nChars, tmp.getFillSize ()));
		}
#endif
	}

	ptr[nChars - 1] = 0;
	return ConstString (ptr).length ();
}

//------------------------------------------------------------------------
bool FStreamer::writeStr8 (const char8* s)
{
	int32 length = (s) ? (int32) strlen (s) + 1 : 0;
	if (!writeInt32 (length))
		return false;

	if (length > 0)
		return writeRaw (s, sizeof (char8) * length) == sizeof (char8) * length;

	return true;
}

//------------------------------------------------------------------------
int32 FStreamer::getStr8Size (const char8* s)
{
	return sizeof (int32) + (int32)strlen (s) + 1;
}

//------------------------------------------------------------------------
char8* FStreamer::readStr8 ()
{
	int32 length;
	if (!readInt32 (length))
		return 0;

	// check corruption
	if (length > 262144)
		return 0;

	char8* s = (length > 0) ? NEWVEC char8[length] : 0;
	if (s)
		readRaw (s, length * sizeof (char8));
	return s;
}

//------------------------------------------------------------------------
bool FStreamer::skip (uint32 bytes)
{
    int8 tmp;
	while (bytes-- > 0)
	{
		if (readInt8 (tmp) == false)
			return false;
    }
	return true;
}

//------------------------------------------------------------------------
bool FStreamer::pad (uint32 bytes)
{
    while (bytes-- > 0)
	{
		if (writeInt8 (0) == false)
			return false;
	}
	return true;
}

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/baseidds.cpp
// Created by  : Steinberg, 01/2008
// Description : Basic Interface
//
//-----------------------------------------------------------------------------
// 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/base/istringresult.h"
#include "pluginterfaces/base/iupdatehandler.h"
#include "pluginterfaces/base/ipersistent.h"
#include "pluginterfaces/base/icloneable.h"
#include "pluginterfaces/base/ibstream.h"

namespace Steinberg {

DEF_CLASS_IID (FUnknown)
DEF_CLASS_IID (IString)
DEF_CLASS_IID (IStringResult)

DEF_CLASS_IID (IDependent)
DEF_CLASS_IID (IUpdateHandler)
DEF_CLASS_IID (IPersistent)
DEF_CLASS_IID (IAttributes)
DEF_CLASS_IID (IAttributes2)

DEF_CLASS_IID (ICloneable)

DEF_CLASS_IID (ISizeableStream)
//------------------------------------------------------------------------
} // namespace Steinberg

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fcleanup.h
// Created by  : Steinberg, 2008
// Description : Template classes for automatic resource cleanup
//
//-----------------------------------------------------------------------------
// 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 <stdlib.h>

namespace Steinberg {

/** Template definition for classes that help guarding against memory leaks.
A stack allocated object of this type automatically deletes an at construction time passed
dynamically allocated single object when it reaches the end of its scope. \n\n
Intended usage:
\code
    {
        int* pointerToInt = new int;
        Steinberg::FDeleter<int> deleter (pointerToInt);

        // Do something with the variable behind pointerToInt.

    } // No memory leak here, destructor of deleter cleans up the integer.
\endcode
*/
//------------------------------------------------------------------------
template <class T>
struct FDeleter
{
	/// Constructor. _toDelete is a pointer to the dynamically allocated object that is to be
	/// deleted when this FDeleter object's destructor is executed.
	FDeleter (T* _toDelete) : toDelete (_toDelete) {}
	/// Destructor. Calls delete on the at construction time passed pointer.
	~FDeleter ()
	{
		if (toDelete)
			delete toDelete;
	}
	T* toDelete; ///< Remembers the object that is to be deleted during destruction.
};

/** Template definition for classes that help guarding against memory leaks.
A stack allocated object of this type automatically deletes an at construction time passed
dynamically allocated array of objects when it reaches the end of its scope. \n\n
Intended usage:
\code
    {
        int* pointerToIntArray = new int[10];
        Steinberg::FArrayDeleter<int> deleter (pointerToIntArray);

        // Do something with the array behind pointerToIntArray.

    } // No memory leak here, destructor of deleter cleans up the integer array.
\endcode
*/
//------------------------------------------------------------------------
template <class T>
struct FArrayDeleter
{
	/// Constructor. _arrayToDelete is a pointer to the dynamically allocated array of objects that
	/// is to be deleted when this FArrayDeleter object's destructor is executed.
	FArrayDeleter (T* _arrayToDelete) : arrayToDelete (_arrayToDelete) {}

	/// Destructor. Calls delete[] on the at construction time passed pointer.
	~FArrayDeleter ()
	{
		if (arrayToDelete)
			delete[] arrayToDelete;
	}

	T* arrayToDelete; ///< Remembers the array of objects that is to be deleted during destruction.
};

/** Template definition for classes that help guarding against dangling pointers.
A stack allocated object of this type automatically resets an at construction time passed
pointer to null when it reaches the end of its scope. \n\n
Intended usage:
\code
    int* pointerToInt = 0;
    {
        int i = 1;
        pointerToInt = &i;
        Steinberg::FPtrNuller<int> ptrNuller (pointerToInt);

        // Do something with pointerToInt.

    } // No dangling pointer here, pointerToInt is reset to 0 by destructor of ptrNuller.
\endcode
*/
//------------------------------------------------------------------------
template <class T>
struct FPtrNuller
{
	/// Constructor. _toNull is a reference to the pointer that is to be reset to NULL when this
	/// FPtrNuller object's destructor is executed.
	FPtrNuller (T*& _toNull) : toNull (_toNull) {}
	/// Destructor. Calls delete[] on the at construction time passed pointer.
	~FPtrNuller () { toNull = 0; }

	T*& toNull; ///< Remembers the pointer that is to be set to NULL during destruction.
};

/** Template definition for classes that help resetting an object's value.
A stack allocated object of this type automatically resets the value of an at construction time
passed object to null when it reaches the end of its scope. \n\n Intended usage: \code int theObject
= 0;
    {
        Steinberg::FNuller<int> theNuller (theObject);

        theObject = 1;

    } // Here the destructor of theNuller resets the value of theObject to 0.
\endcode
*/
//------------------------------------------------------------------------
template <class T>
struct FNuller
{
	/// Constructor. _toNull is a reference to the object that is to be assigned 0 when this FNuller
	/// object's destructor is executed.
	FNuller (T& _toNull) : toNull (_toNull) {}
	/// Destructor. Assigns 0 to the at construction time passed object reference.
	~FNuller () { toNull = 0; }

	T& toNull; ///< Remembers the object that is to be assigned 0 during destruction.
};

/** Class definition for objects that help resetting boolean variables.
A stack allocated object of this type automatically sets an at construction time passed
boolean variable immediately to TRUE and resets the same variable to FALSE when it
reaches the end of its own scope. \n\n
Intended usage:
\code
    bool theBoolean = false;
    {
        Steinberg::FBoolSetter theBoolSetter (theBoolean);
        // Here the constructor of theBoolSetter sets theBoolean to TRUE.

        // Do something.

    } // Here the destructor of theBoolSetter resets theBoolean to FALSE.
\endcode
*/
//------------------------------------------------------------------------
template <class T>
struct FBooleanSetter
{
	/// Constructor. _toSet is a reference to the boolean that is set to TRUE immediately in this
	/// constructor call and gets reset to FALSE when this FBoolSetter object's destructor is
	/// executed.
	FBooleanSetter (T& _toSet) : toSet (_toSet) { toSet = true; }
	/// Destructor. Resets the at construction time passed boolean to FALSE.
	~FBooleanSetter () { toSet = false; }

	T& toSet; ///< Remembers the boolean that is to be reset during destruction.
};

typedef FBooleanSetter<bool> FBoolSetter;

/** Class definition for objects that help setting boolean variables.
A stack allocated object of this type automatically sets an at construction time passed
boolean variable to TRUE if the given condition is met. At the end of its own scope the
stack object will reset the same boolean variable to FALSE, if it wasn't set so already. \n\n
Intended usage:
\code
    bool theBoolean = false;
    {
        bool creativityFirst = true;
        Steinberg::FConditionalBoolSetter theCBSetter (theBoolean, creativityFirst);
        // Here the constructor of theCBSetter sets theBoolean to the value of creativityFirst.

        // Do something.

    } // Here the destructor of theCBSetter resets theBoolean to FALSE.
\endcode
*/
//------------------------------------------------------------------------
struct FConditionalBoolSetter
{
	/// Constructor. _toSet is a reference to the boolean that is to be set. If the in the second
	/// parameter given condition is TRUE then also _toSet is set to TRUE immediately.
	FConditionalBoolSetter (bool& _toSet, bool condition) : toSet (_toSet)
	{
		if (condition)
			toSet = true;
	}
	/// Destructor. Resets the at construction time passed boolean to FALSE.
	~FConditionalBoolSetter () { toSet = false; }

	bool& toSet; ///< Remembers the boolean that is to be reset during destruction.
};

/** Template definition for classes that help closing resources.
A stack allocated object of this type automatically calls the close method of an at
construction time passed object when it reaches the end of its scope.
It goes without saying that the given type needs to have a close method. \n\n
Intended usage:
\code
    struct CloseableObject
    {
        void close() {};
    };

    {
        CloseableObject theObject;
        Steinberg::FCloser<CloseableObject> theCloser (&theObject);

        // Do something.

    } // Here the destructor of theCloser calls the close method of theObject.
\endcode
*/
template <class T>
struct FCloser
{
	/// Constructor. _obj is the pointer on which close is to be called when this FCloser object's
	/// destructor is executed.
	FCloser (T* _obj) : obj (_obj) {}
	/// Destructor. Calls the close function on the at construction time passed pointer.
	~FCloser ()
	{
		if (obj)
			obj->close ();
	}

	T* obj; ///< Remembers the pointer on which close is to be called during destruction.
};

/** Class definition for objects that help guarding against memory leaks.
A stack allocated object of this type automatically frees the "malloced" memory behind an at
construction time passed pointer when it reaches the end of its scope.
*/
//------------------------------------------------------------------------
/*! \class FMallocReleaser
 */
//------------------------------------------------------------------------
class FMallocReleaser
{
public:
	/// Constructor. _data is the pointer to the memory on which free is to be called when this
	/// FMallocReleaser object's destructor is executed.
	FMallocReleaser (void* _data) : data (_data) {}
	/// Destructor. Calls the free function on the at construction time passed pointer.
	~FMallocReleaser ()
	{
		if (data)
			free (data);
	}
//------------------------------------------------------------------------
protected:
	void* data; ///< Remembers the pointer on which free is to be called during destruction.
};

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

#if MAC
typedef const void* CFTypeRef;
extern "C" {
	extern void CFRelease (CFTypeRef cf);
}

namespace Steinberg {

/** Class definition for objects that helps releasing CoreFoundation objects.
A stack allocated object of this type automatically releases an at construction time
passed CoreFoundation object when it reaches the end of its scope.

Only available on Macintosh platform.
*/
//------------------------------------------------------------------------
/*! \class CFReleaser
*/
//------------------------------------------------------------------------
class CFReleaser
{
public:
	/// Constructor. _obj is the reference to an CoreFoundation object which is to be released when this CFReleaser object's destructor is executed.
	CFReleaser (CFTypeRef _obj) : obj (_obj) {}
	/// Destructor. Releases the at construction time passed object.
	~CFReleaser () { if (obj) CFRelease (obj); }
protected:
	CFTypeRef obj; ///< Remembers the object which is to be released during destruction.
};

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

#endif // MAC


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fdynlib.cpp
// Created by  : Steinberg, 1998
// Description : Dynamic library loading
//
//-----------------------------------------------------------------------------
// 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 "base/source/fdynlib.h"
#include "pluginterfaces/base/fstrdefs.h"
#include "base/source/fstring.h"

#if WINDOWS
#include <windows.h>

#elif MAC
#include <mach-o/dyld.h>
#include <CoreFoundation/CoreFoundation.h>

#if !TARGET_OS_IPHONE
static const Steinberg::tchar kUnixDelimiter = STR ('/');
#endif
#endif

namespace Steinberg {

#if MAC
#include <dlfcn.h>

// we ignore for the moment that the NSAddImage functions are deprecated
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"

static bool CopyProcessPath (Steinberg::String& name)
{
	Dl_info info;
	if (dladdr ((const void*)CopyProcessPath, &info))
	{
		if (info.dli_fname)
		{
			name.assign (info.dli_fname);
			#ifdef UNICODE
			name.toWideString ();
			#endif
			return true;
		}
	}
	return false;
}

#endif

//------------------------------------------------------------------------
// FDynLibrary
//------------------------------------------------------------------------
FDynLibrary::FDynLibrary (const tchar* n, bool addExtension)
: isloaded (false)
, instance (0)
{
	if (n)
		init (n, addExtension);
}

//------------------------------------------------------------------------
FDynLibrary::~FDynLibrary ()
{
	unload ();
}

//------------------------------------------------------------------------
bool FDynLibrary::init (const tchar* n, bool addExtension)
{
	if (isLoaded ())
		return true;

	Steinberg::String name (n);

#if WINDOWS
	if (addExtension)
		name.append (STR (".dll"));

	instance = LoadLibrary (name);
	if (instance)
		isloaded = true;

#elif MAC
	isBundle = false;
	// first check if it is a bundle
	if (addExtension)
		name.append (STR (".bundle"));
	if (name.getChar16 (0) != STR('/')) // no absoltue path
	{
		Steinberg::String p;
		if (CopyProcessPath (p))
		{
			Steinberg::int32 index = p.findLast (STR ('/'));
			p.remove (index+1);
			name = p + name;
		}
	}
	CFStringRef fsString = (CFStringRef)name.toCFStringRef ();
	CFURLRef url = CFURLCreateWithFileSystemPath (NULL, fsString, kCFURLPOSIXPathStyle, true);
	if (url)
	{
		CFBundleRef bundle = CFBundleCreate (NULL, url);
		if (bundle)
		{
			if (CFBundleLoadExecutable (bundle))
			{
				isBundle = true;
				instance = (void*)bundle;
			}
			else
				CFRelease (bundle);
		}
		CFRelease (url);
	}
	CFRelease (fsString);

	name.assign (n);

#if !TARGET_OS_IPHONE
	if (!isBundle)
	{
		// now we check for a dynamic library
		firstSymbol = NULL;
		if (addExtension)
		{
			name.append (STR (".dylib"));
		}
		// Only if name is a relative path we use the Process Path as root:
		if (name[0] != kUnixDelimiter)
		{
			Steinberg::String p;
			if (CopyProcessPath (p))
			{
				Steinberg::int32 index = p.findLast (STR ("/"));
				p.remove (index+1);
				p.append (name);
				p.toMultiByte (Steinberg::kCP_Utf8);
				instance = (void*) NSAddImage (p, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
			}
		}
		// Last but not least let the system search for it
		//
		if (instance == 0)
		{
			name.toMultiByte (Steinberg::kCP_Utf8);
			instance = (void*) NSAddImage (name, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
		}
	}
#endif // !TARGET_OS_IPHONE

	if (instance)
		isloaded = true;

#endif

	return isloaded;
}

//------------------------------------------------------------------------
bool FDynLibrary::unload ()
{
	if (!isLoaded ())
		return false;

#if WINDOWS
	FreeLibrary ((HINSTANCE)instance);

#elif MAC
	if (isBundle)
	{
		if (CFGetRetainCount ((CFTypeRef)instance) == 1)
			CFBundleUnloadExecutable ((CFBundleRef)instance);
		CFRelease ((CFBundleRef)instance);
	}
	else
	{
		// we don't use this anymore as the darwin dyld can't unload dynamic libraries yet and may crash
/*		if (firstSymbol)
		{
			NSModule module = NSModuleForSymbol ((NSSymbol)firstSymbol);
			if (module)
				NSUnLinkModule (module, NSUNLINKMODULE_OPTION_NONE);
		}*/
	}
#endif
	instance = 0;
	isloaded = false;
	return true;
}

//------------------------------------------------------------------------
void* FDynLibrary::getProcAddress (const char* name)
{
	if (!isloaded)
		return 0;

#if WINDOWS
	return (void*)GetProcAddress ((HINSTANCE)instance, name);

#elif MAC
	if (isBundle)
	{
		CFStringRef functionName = CFStringCreateWithCString (NULL, name, kCFStringEncodingASCII);
		void* result = CFBundleGetFunctionPointerForName ((CFBundleRef)instance, functionName);
		CFRelease (functionName);
		return result;
	}
#if !TARGET_OS_IPHONE
	else
	{
		char* symbolName = (char*) malloc (strlen (name) + 2);
		strcpy (symbolName, "_");
		strcat (symbolName, name);
		NSSymbol symbol;
		symbol = NSLookupSymbolInImage ((const struct mach_header*)instance, symbolName, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
		free (symbolName);
		if (symbol)
		{
			if (firstSymbol == NULL)
				firstSymbol = symbol;
			return NSAddressOfSymbol (symbol);
		}
	}
#endif // !TARGET_OS_IPHONE

#endif

	return 0;
}

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fstreamer.h
// Created by  : Steinberg, 12/2005
// Description : Extract of typed stream i/o methods from FStream
//
//-----------------------------------------------------------------------------
// 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/base/funknown.h"

namespace Steinberg {

//------------------------------------------------------------------------
enum FSeekMode
{
	kSeekSet,
	kSeekCurrent,
	kSeekEnd
};

//------------------------------------------------------------------------
// FStreamer
//------------------------------------------------------------------------
/** Byteorder-aware base class for typed stream i/o. */
//------------------------------------------------------------------------
class FStreamer
{
public:
//------------------------------------------------------------------------
	FStreamer (int16 byteOrder = BYTEORDER);
	virtual ~FStreamer () {}

	/** @name Implementing class must override. */
	///@{
	virtual TSize readRaw (void*, TSize) = 0;          ///< Read one buffer of size.
	virtual TSize writeRaw (const void*, TSize) = 0;   ///< Write one buffer of size.
	virtual int64 seek (int64, FSeekMode) = 0;         ///< Set file position for stream.
	virtual int64 tell () = 0;                         ///< Return current file position.
	///@}

	/** @name Streams are byteOrder aware. */
	///@{
	inline void setByteOrder (int32 e) { byteOrder = (int16)e; }
	inline int32 getByteOrder () { return byteOrder; }
	///@}

	/** @name read and write int8 and char. */
	///@{
	bool writeChar8 (char8);
	bool readChar8 (char8&);
	bool writeUChar8 (unsigned char);
	bool readUChar8 (unsigned char&);
	bool writeChar16 (char16 c);
	bool readChar16 (char16& c);

	bool writeInt8 (int8 c){return writeChar8 (c);}
	bool readInt8 (int8& c){return readChar8 (c);}
	bool writeInt8u (uint8 c){return writeUChar8 (c);}
	bool readInt8u (uint8& c){return readUChar8 (c);}
	///@}

	/** @name read and write int16. */
	///@{
	bool writeInt16 (int16);
	bool readInt16 (int16&);
	bool writeInt16Array (const int16* array, int32 count);
	bool readInt16Array (int16* array, int32 count);
	bool writeInt16u (uint16);
	bool readInt16u (uint16&);
	bool writeInt16uArray (const uint16* array, int32 count);
	bool readInt16uArray (uint16* array, int32 count);
	///@}

	/** @name read and write int32. */
	///@{
	bool writeInt32 (int32);
	bool readInt32 (int32&);
	bool writeInt32Array (const int32* array, int32 count);
	bool readInt32Array (int32* array, int32 count);
	bool writeInt32u (uint32);
	bool readInt32u (uint32&);
	bool writeInt32uArray (const uint32* array, int32 count);
	bool readInt32uArray (uint32* array, int32 count);
	///@}

	/** @name read and write int64. */
	///@{
	bool writeInt64 (int64);
	bool readInt64 (int64&);
	bool writeInt64Array (const int64* array, int32 count);
	bool readInt64Array (int64* array, int32 count);
	bool writeInt64u (uint64);
	bool readInt64u (uint64&);
	bool writeInt64uArray (const uint64* array, int32 count);
	bool readInt64uArray (uint64* array, int32 count);
	///@}

	/** @name read and write float and float array. */
	///@{
	bool writeFloat (float);
	bool readFloat (float&);
	bool writeFloatArray (const float* array, int32 count);
	bool readFloatArray (float* array, int32 count);
	///@}

	/** @name read and write double and double array. */
	///@{
	bool writeDouble (double);
	bool readDouble (double&);
	bool writeDoubleArray (const double* array, int32 count);
	bool readDoubleArray (double* array, int32 count);
	///@}

	/** @name read and write Boolean. */
	///@{
	bool writeBool (bool);                                   ///< Write one boolean
	bool readBool (bool&);                                   ///< Read one bool.
	///@}

	/** @name read and write Strings. */
	///@{
	TSize writeString8 (const char8* ptr, bool terminate = false); ///< a direct output function writing only one string (ascii 8bit)
	TSize readString8 (char8* ptr, TSize size);				///< a direct input function reading only one string (ascii) (ended by a \n or \0 or eof)

	bool writeStr8 (const char8* ptr);				       ///< write a string length (strlen) and string itself
	char8* readStr8 ();									   ///< read a string length and string text (The return string must be deleted when use is finished)

	static int32 getStr8Size (const char8* ptr);	       ///< returns the size of a saved string

	bool writeStringUtf8 (const tchar* ptr);               ///< always terminated, converts to utf8 if non ascii characters are in string
	int32 readStringUtf8 (tchar* ptr, int32 maxSize);      ///< read a UTF8 string
	///@}

	bool skip (uint32 bytes);
	bool pad (uint32 bytes);

//------------------------------------------------------------------------
protected:
	int16 byteOrder;
};

//------------------------------------------------------------------------
/** FStreamSizeHolder Declaration
	remembers size of stream chunk for backward compatibility.

	<b>Example:</b>
	@code
	externalize (a)
	{
		FStreamSizeHolder sizeHolder;
		sizeHolder.beginWrite ();	// sets start mark, writes dummy size
		a << ....
		sizeHolder.endWrite ();		// jumps to start mark, updates size, jumps back here
	}

	internalize (a)
	{
		FStreamSizeHolder sizeHolder;
		sizeHolder.beginRead ();	// reads size, mark
		a >> ....
		sizeHolder.endRead ();		// jumps forward if new version has larger size
	}
	@endcode
*/
//------------------------------------------------------------------------
class FStreamSizeHolder
{
public:
	FStreamSizeHolder (FStreamer &s);

	void beginWrite ();	///< remembers position and writes 0
	int32 endWrite ();	///< writes and returns size (since the start marker)
	int32 beginRead ();	///< returns size
	void endRead ();	///< jump to end of chunk

protected:
	FStreamer &stream;
	int64 sizePos;
};

class IBStream;

//------------------------------------------------------------------------
// IBStreamer
//------------------------------------------------------------------------
/** Wrapper class for typed reading/writing from or to IBStream.
	Can be used framework-independent in Plug-ins. */
//------------------------------------------------------------------------
class IBStreamer: public FStreamer
{
public:
//------------------------------------------------------------------------
	/** Constructor for a given IBSTream and a byteOrder. */
	IBStreamer (IBStream* stream, int16 byteOrder = BYTEORDER);

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

	// FStreamer overrides:
	TSize readRaw (void*, TSize) SMTG_OVERRIDE;				///< Read one buffer of size.
	TSize writeRaw (const void*, TSize) SMTG_OVERRIDE;		///< Write one buffer of size.
	int64 seek (int64, FSeekMode) SMTG_OVERRIDE;			///< Set file position for stream.
	int64 tell () SMTG_OVERRIDE;							///< Return current file position.
//------------------------------------------------------------------------
protected:
	IBStream* stream;
};

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fobject.cpp
// Created by  : Steinberg, 2008
// Description : Basic Object implementing FUnknown
//
//-----------------------------------------------------------------------------
// 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 "base/source/fobject.h"
#include "base/source/flock.h"

#include <vector>

namespace Steinberg {

IUpdateHandler* FObject::gUpdateHandler = 0;

//------------------------------------------------------------------------
const FUID FObject::iid;

//------------------------------------------------------------------------
struct FObjectIIDInitializer
{
	// the object iid is always generated so that different components
	// only can cast to their own objects
	// this initializer must be after the definition of FObject::iid, otherwise
	//  the default constructor of FUID will clear the generated iid
	FObjectIIDInitializer ()
	{
		const_cast<FUID&> (FObject::iid).generate ();
	}
} gFObjectIidInitializer;

//------------------------------------------------------------------------
uint32 PLUGIN_API FObject::addRef ()
{
	return FUnknownPrivate::atomicAdd (refCount, 1);
}

//------------------------------------------------------------------------
uint32 PLUGIN_API FObject::release ()
{
	if (FUnknownPrivate::atomicAdd (refCount, -1) == 0)
	{
		refCount = -1000;
		delete this;
		return 0;
	}
	return refCount;
}

//------------------------------------------------------------------------
tresult PLUGIN_API FObject::queryInterface (const TUID _iid, void** obj)
{
	QUERY_INTERFACE (_iid, obj, FUnknown::iid, FUnknown)
	QUERY_INTERFACE (_iid, obj, IDependent::iid, IDependent)
	QUERY_INTERFACE (_iid, obj, FObject::iid, FObject)
	*obj = 0;
	return kNoInterface;
}

//------------------------------------------------------------------------
void FObject::addDependent (IDependent* dep)
{
	if (gUpdateHandler)
		gUpdateHandler->addDependent (unknownCast (), dep);
}

//------------------------------------------------------------------------
void FObject::removeDependent (IDependent* dep)
{
	if (gUpdateHandler)
		gUpdateHandler->removeDependent (unknownCast (), dep);
}

//------------------------------------------------------------------------
void FObject::changed (int32 msg)
{
	if (gUpdateHandler)
		gUpdateHandler->triggerUpdates (unknownCast (), msg);
	else
		updateDone (msg);
}

//------------------------------------------------------------------------
void FObject::deferUpdate (int32 msg)
{
	if (gUpdateHandler)
		gUpdateHandler->deferUpdates (unknownCast (), msg);
	else
		updateDone (msg);
}

//------------------------------------------------------------------------
/** Automatic creation and destruction of singleton instances. */
//------------------------------------------------------------------------
namespace Singleton
{
	typedef std::vector<FObject**> ObjectVector;
	ObjectVector* singletonInstances = 0;
	bool singletonsTerminated = false;
	FLock* singletonsLock;

	bool isTerminated () {return singletonsTerminated;}

	void lockRegister ()
	{
		if (!singletonsLock) // assume first call not from multiple threads
			singletonsLock = NEW FLock;
		singletonsLock->lock ();
	}
	void unlockRegister ()
	{
		singletonsLock->unlock ();
	}

	void registerInstance (FObject** o)
	{
		ASSERT (singletonsTerminated == false)
		if (singletonsTerminated == false)
		{
			if (singletonInstances == 0)
				singletonInstances = NEW std::vector<FObject**>;
			singletonInstances->push_back (o);
		}
	}

	struct Deleter
	{
		~Deleter ()
		{
			singletonsTerminated = true;
			if (singletonInstances)
			{
				for (ObjectVector::iterator it = singletonInstances->begin (),
											end = singletonInstances->end ();
					 it != end; ++it)
				{
					FObject** obj = (*it);
					(*obj)->release ();
					obj = 0;
				}

				delete singletonInstances;
				singletonInstances = 0;
			}
			delete singletonsLock;
			singletonsLock = 0;
		}
	} deleter;
}

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fbuffer.cpp
// Created by  : Steinberg, 2008
// Description :
//
//-----------------------------------------------------------------------------
// 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 "base/source/fbuffer.h"
#include "base/source/fstring.h"
#include <stdlib.h>

namespace Steinberg {

//-------------------------------------------------------------------------------------
Buffer::Buffer ()
: buffer (0)
, memSize (0)
, fillSize (0)
, delta (defaultDelta)
{}

//-------------------------------------------------------------------------------------
Buffer::Buffer (uint32 s, uint8 initVal)
: buffer (0)
, memSize (s)
, fillSize (0)
, delta (defaultDelta)
{
 	if (memSize == 0)
		return;
	buffer = (int8*)::malloc (memSize);
	if (buffer)
		memset (buffer, initVal, memSize);
	else
		memSize = 0;
}

//-------------------------------------------------------------------------------------
Buffer::Buffer (uint32 s)
: buffer (0)
, memSize (s)
, fillSize (0)
, delta (defaultDelta)
{
 	if (memSize == 0)
		return;
 	buffer = (int8*)::malloc (memSize);
	if (!buffer)
		memSize = 0;
}

//-------------------------------------------------------------------------------------
Buffer::Buffer (const void* b , uint32 s)
: buffer (0)
, memSize (s)
, fillSize (s)
, delta (defaultDelta)
{
 	if (memSize == 0)
		return;
 	buffer = (int8*)::malloc (memSize);
 	if (buffer)
		memcpy (buffer, b, memSize);
	else
	{
		memSize = 0;
		fillSize = 0;
	}
}

//-------------------------------------------------------------------------------------
Buffer::Buffer (const Buffer& bufferR)
: buffer (0)
, memSize (bufferR.memSize)
, fillSize (bufferR.fillSize)
, delta (bufferR.delta)
{
 	if (memSize == 0)
		return;

 	buffer = (int8*)::malloc (memSize);
 	if (buffer)
		memcpy (buffer, bufferR.buffer, memSize);
	else
		memSize = 0;
}

//-------------------------------------------------------------------------------------
Buffer::~Buffer ()
{
 	if (buffer)
		::free (buffer);
 	buffer = 0;
}

//-------------------------------------------------------------------------------------
void Buffer::operator = (const Buffer& b2)
{
 	if (&b2 != this)
	{
		setSize (b2.memSize);
		if (b2.memSize > 0 && buffer)
			memcpy (buffer, b2.buffer, b2.memSize);
		fillSize = b2.fillSize;
		delta = b2.delta;
 	}
}

//-------------------------------------------------------------------------------------
bool Buffer::operator == (const Buffer& b2)const
{
	if (&b2 == this)
		return true;
	if (b2.getSize () != getSize ())
		return false;
	return memcmp (this->int8Ptr (), b2.int8Ptr (), getSize ()) == 0 ? true : false;
}

//-------------------------------------------------------------------------------------
uint32 Buffer::get (void* b, uint32 size)
{
	uint32 maxGet = memSize - fillSize;
	if (size > maxGet)
		size = maxGet;
	if (size > 0)
		memcpy (b, buffer + fillSize, size);
	fillSize += size;
	return size;
}

//-------------------------------------------------------------------------------------
bool Buffer::put (char16 c)
{
	return put ((const void*)&c, sizeof (c));
}

//-------------------------------------------------------------------------------------
bool Buffer::put (uint8 byte)
{
	if (grow (fillSize + 1) == false)
		return false;

  	buffer [fillSize++] = byte;
  	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::put (char c)
{
	if (grow (fillSize + 1) == false)
		return false;

  	buffer [fillSize++] = c;
  	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::put (const void* toPut, uint32 s)
{
	if (!toPut)
		return false;

	if (grow (fillSize + s) == false)
		return false;

	memcpy (buffer + fillSize, toPut, s);
	fillSize += s;
	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::put (const String& str)
{
	return put ((const void*)str.text () , (str.length () + 1) * sizeof (tchar));
}

//-------------------------------------------------------------------------------------
bool Buffer::appendString8 (const char8* s)
{
	if (!s)
		return false;

	uint32 len = (uint32) strlen (s);
	return put (s, len);
}

//-------------------------------------------------------------------------------------
bool Buffer::appendString16 (const char16* s)
{
	if (!s)
		return false;
	ConstString str (s);
	uint32 len = (uint32) str.length () * sizeof (char16);
	return put (s, len);
}

//-------------------------------------------------------------------------------------
bool Buffer::prependString8 (const char8* s)
{
	if (!s)
		return false;

	uint32 len = (uint32) strlen (s);

	if (len > 0)
	{
		shiftStart (len);
		memcpy (buffer, s, len);
		return true;
	}
	return false;
}

//-------------------------------------------------------------------------------------
bool Buffer::prependString16 (const char16* s)
{
	if (!s)
		return false;

	ConstString str (s);
	uint32 len = (uint32) str.length () * sizeof (char16);

	if (len > 0)
	{
		shiftStart (len);
		memcpy (buffer, s, len);
		return true;
	}
	return false;
}

//-------------------------------------------------------------------------------------
bool Buffer::prependString8 (char8 c)
{
	shiftStart (sizeof (char));
	char* b = (char*)buffer;
	b [0] = c;
	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::prependString16 (char16 c)
{
	shiftStart (sizeof (char16));
	char16* b = (char16*)buffer;
	b [0] = c;
	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::copy (uint32 from, uint32 to, uint32 bytes)
{
	if (from + bytes > memSize || bytes == 0)
		return false;

	if (to + bytes > memSize)
		setSize (to + bytes);

	if (from + bytes > to && from < to)
	{              // overlap
		Buffer tmp (buffer + from, bytes);
		memcpy (buffer + to, tmp, bytes);
	}
	else
		memcpy (buffer + to, buffer + from, bytes);
	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::makeHexString (String& result)
{
	unsigned char* data = uint8Ptr ();
	uint32 bytes = getSize ();

	if (data == 0 || bytes == 0)
		return false;

	char8* stringBuffer = (char8*)malloc ((bytes * 2) + 1);
	if (!stringBuffer)
		return false;

	int32 count = 0;
	while (bytes > 0)
	{
		unsigned char t1 = ((*data) >> 4) & 0x0F;
		unsigned char t2 = (*data) & 0x0F;
		if (t1 < 10)
			t1 += '0';
		else
			t1 = t1 - 10 + 'A';
		if (t2 < 10)
			t2 += '0';
		else
			t2 = t2 - 10 + 'A';

		stringBuffer [count++] = t1;
		stringBuffer [count++] = t2;
		data++;
		bytes--;
	}
	stringBuffer [count] = 0;

	result.take ((void*)stringBuffer, false);
	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::fromHexString (const char8* string)
{
	flush ();
	if (string == 0)
		return false;

	int32 len = strlen8 (string);
	if (len == 0 || ((len & 1) == 1)/*odd number*/ )
		return false;

	setSize (len / 2);
	unsigned char* data = uint8Ptr ();

	bool upper = true;
	int32 count = 0;
	while (count < len)
	{
		char c = string [count];

		unsigned char d = 0;
		if (c >= '0' && c <= '9')		d += c - '0';
		else if (c >= 'A' && c <= 'F')	d += c - 'A' + 10;
		else if (c >= 'a' && c <= 'f')	d += c - 'a' + 10;
		else return false; // no hex string

		if (upper)
			data [count >> 1] = d << 4;
		else
			data [count >> 1] += d;

		upper = !upper;
		count++;
	}
	setFillSize (len / 2);
	return true;
}

//------------------------------------------------------------------------
void Buffer::set (uint8 value)
{
	if (buffer)
		memset (buffer, value, memSize);
}

//-------------------------------------------------------------------------------------
bool Buffer::setFillSize (uint32 c)
{
	if (c <= memSize)
	{
		fillSize = c;
		return true;
	}
	return false;
}

//-------------------------------------------------------------------------------------
bool Buffer::truncateToFillSize ()
{
	if (fillSize < memSize)
		setSize (fillSize);

	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::grow (uint32 newSize)
{
	if (newSize > memSize)
	{
		if (delta == 0)
			delta = defaultDelta;
		uint32 s = ((newSize + delta - 1) / delta) * delta;
		return setSize (s);
	}
	return true;
}

//------------------------------------------------------------------------
void Buffer::shiftAt (uint32 position, int32 amount)
{
	if (amount > 0)
	{
		if (grow (fillSize + amount))
		{
			if (position < fillSize)
				memmove (buffer + amount + position, buffer + position, fillSize - position);

			fillSize += amount;
		}
	}
	else if (amount < 0 && fillSize > 0)
	{
		uint32 toRemove = -amount;

		if (toRemove < fillSize)
		{
			if (position < fillSize)
				memmove (buffer + position, buffer + toRemove + position, fillSize - position - toRemove);
			fillSize -= toRemove;
		}
	}
}

//-------------------------------------------------------------------------------------
void Buffer::move (int32 amount, uint8 initVal)
{
	if (memSize == 0)
		return;

	if (amount > 0)
	{
		if ((uint32)amount < memSize)
		{
			memmove (buffer + amount, buffer, memSize - amount);
			memset (buffer, initVal, amount);
		}
		else
			memset (buffer, initVal, memSize);
	}
	else
	{
		uint32 toRemove = -amount;
		if (toRemove < memSize)
		{
			memmove (buffer, buffer + toRemove, memSize - toRemove);
			memset (buffer + memSize - toRemove, initVal, toRemove);
		}
		else
			memset (buffer, initVal, memSize);
	}
}

//-------------------------------------------------------------------------------------
bool Buffer::setSize (uint32 newSize)
{
	if (memSize != newSize)
	{
 		if (buffer)
		{
			if (newSize > 0)
			{
				int8* newBuffer = (int8*) ::realloc (buffer, newSize);
				if (newBuffer == 0)
				{
					newBuffer = (int8*)::malloc (newSize);
					if (newBuffer)
					{
						uint32 tmp = newSize;
						if (tmp > memSize)
							tmp = memSize;
						memcpy (newBuffer, buffer, tmp);
						::free (buffer);
						buffer = newBuffer;
					}
					else
					{
						::free (buffer);
						buffer = 0;
					}
				}
				else
					buffer = newBuffer;
			}
			else
			{
				::free (buffer);
				buffer = 0;
			}
		}
		else
			buffer = (int8*)::malloc (newSize);

		if (newSize > 0 && !buffer)
			memSize = 0;
		else
			memSize = newSize;
		if (fillSize > memSize)
			fillSize = memSize;
	}

	return (newSize > 0) == (buffer != 0);
}

//-------------------------------------------------------------------------------------
void Buffer::fillup (uint8 value)
{
	if (getFree () > 0)
		memset (buffer + fillSize, value, getFree ());
}

//-------------------------------------------------------------------------------------
int8* Buffer::operator + (uint32 i)
{
	if (i < memSize)
		return buffer + i;
	else
	{
		static int8 eof;
		eof = 0;
		return &eof;
	}
}

//-------------------------------------------------------------------------------------
bool Buffer::swap (int16 swapSize)
{
	return swap (buffer, memSize, swapSize);
}

//-------------------------------------------------------------------------------------
bool Buffer::swap (void* buffer, uint32 bufferSize, int16 swapSize)
{
	if (swapSize != kSwap16 && swapSize != kSwap32 && swapSize != kSwap64)
		return false;

	if (swapSize == kSwap16)
	{
		for (uint32 count = 0 ; count < bufferSize ; count += 2)
		{
			SWAP_16 ( * (((int16*)buffer) + count) );
		}
	}
	else if (swapSize == kSwap32)
	{
		for (uint32 count = 0 ; count < bufferSize ; count += 4)
		{
			SWAP_32 ( * (((int32*)buffer) + count) );
		}
	}
	else if (swapSize == kSwap64)
	{
		for (uint32 count = 0 ; count < bufferSize ; count += 8)
		{
			SWAP_64 ( * (((int64*)buffer) + count) );
		}
	}

	return true;
}

//-------------------------------------------------------------------------------------
void Buffer::take (Buffer& from)
{
	setSize (0);
	memSize = from.memSize;
	fillSize = from.fillSize;
	buffer = from.buffer;
	from.buffer = 0;
	from.memSize = 0;
	from.fillSize = 0;
}

//-------------------------------------------------------------------------------------
int8* Buffer::pass ()
{
	int8* res = buffer;
	buffer = 0;
	memSize = 0;
	fillSize = 0;
	return res;
}

//-------------------------------------------------------------------------------------
bool Buffer::toWideString (int32 sourceCodePage)
{
	if (getFillSize () > 0)
	{
		if (str8 () [getFillSize () - 1] != 0) // multiByteToWideString only works with 0-terminated strings
			endString8 ();

		Buffer dest (getFillSize () * sizeof (char16));
		int32 result = String::multiByteToWideString (dest.str16 (), buffer, dest.getFree () / sizeof (char16), sourceCodePage);
		if (result > 0)
		{
			dest.setFillSize ((result - 1) * sizeof (char16));
			take (dest);
			return true;
		}
		return false;
	}
	return true;
}

//-------------------------------------------------------------------------------------
bool Buffer::toMultibyteString (int32 destCodePage)
{
	if (getFillSize () > 0)
	{
		int32 textLength = getFillSize () / sizeof (char16); // wideStringToMultiByte only works with 0-terminated strings
		if (str16 () [textLength - 1] != 0)
			endString16 ();

		Buffer dest (getFillSize ());
		int32 result = String::wideStringToMultiByte (dest.str8 (), str16 (), dest.getFree (), destCodePage);
		if (result > 0)
		{
			dest.setFillSize (result - 1);
			take (dest);
			return true;
		}
		return false;
	}
	return true;
}

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/updatehandler.h
// Created by  : Steinberg, 2008
// Description :
//
//-----------------------------------------------------------------------------
// 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 "base/source/fobject.h"
#include "base/source/flock.h"
#include "pluginterfaces/base/iupdatehandler.h"

namespace Steinberg {

/// @cond ignore
namespace Update { struct Table; }
/// @endcond

//------------------------------------------------------------------------
/** Handle Send and Cancel pending message for a given object*/
//------------------------------------------------------------------------
class IUpdateManager : public FUnknown
{
public:
//------------------------------------------------------------------------
	/** cancel pending messages send by \param object or by any if object is 0 */
	virtual tresult PLUGIN_API cancelUpdates (FUnknown* object) = 0;
	/** send pending messages send by \param object or by any if object is 0 */
	virtual tresult PLUGIN_API triggerDeferedUpdates (FUnknown* object = 0) = 0;
	static const FUID iid;
};

DECLARE_CLASS_IID (IUpdateManager, 0x030B780C, 0xD6E6418D, 0x8CE00BC2, 0x09C834D4)

//------------------------------------------------------------------------------
/**
UpdateHandler implements IUpdateManager and IUpdateHandler to handle dependencies
between objects to store and forward messages to dependent objects.

This implementation is thread save, so objects can send message, add or remove
dependents from different threads.
Do do so it uses mutex, so be aware of locking.
*/
//------------------------------------------------------------------------------
class UpdateHandler : public FObject, public IUpdateHandler, public IUpdateManager
{
public:
//------------------------------------------------------------------------------
	UpdateHandler ();
	~UpdateHandler ();

	// IUpdateHandler
	/** register \param dependent to get messages from \param object */
	virtual tresult PLUGIN_API addDependent (FUnknown* object, IDependent* dependent) SMTG_OVERRIDE;
	/** unregister \param dependent to get no messages from \param object */
	virtual tresult PLUGIN_API removeDependent (FUnknown* object,
	                                            IDependent* dependent) SMTG_OVERRIDE;
	/** send \param message to all dependents of \param object immediately */
	virtual tresult PLUGIN_API triggerUpdates (FUnknown* object, int32 message) SMTG_OVERRIDE;
	/** send \param message to all dependents of \param object when idle */
	virtual tresult PLUGIN_API deferUpdates (FUnknown* object, int32 message) SMTG_OVERRIDE;

	// IUpdateManager
	/** cancel pending messages send by \param object or by any if object is 0 */
	virtual tresult PLUGIN_API cancelUpdates (FUnknown* object) SMTG_OVERRIDE;
	/** send pending messages send by \param object or by any if object is 0 */
	virtual tresult PLUGIN_API triggerDeferedUpdates (FUnknown* object = 0) SMTG_OVERRIDE;

	/// @cond ignore
	// obsolete functions kept for compatibility
	void checkUpdates (FObject* object = 0) { triggerDeferedUpdates (object->unknownCast ()); }
	void flushUpdates (FObject* object) { cancelUpdates (object->unknownCast ()); }
	void deferUpdate (FObject* object, int32 message)
	{
		deferUpdates (object->unknownCast (), message);
	}
	void signalChange (FObject* object, int32 message, bool suppressUpdateDone = false)
	{
		doTriggerUpdates (object->unknownCast (), message, suppressUpdateDone);
	}
#if DEVELOPMENT
	bool checkDeferred (FUnknown* object);
	bool hasDependencies (FUnknown* object);
	void printForObject (FObject* object) const;
#endif
	/// @endcond

	OBJ_METHODS (UpdateHandler, FObject)
	FUNKNOWN_METHODS2 (IUpdateHandler, IUpdateManager, FObject)
	SINGLETON (UpdateHandler)
//------------------------------------------------------------------------------
private:
	tresult doTriggerUpdates (FUnknown* object, int32 message, bool suppressUpdateDone);

	FLock lock;
	Update::Table* table;
};

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/flock.h
// Created by  : Steinberg, 1995
// Description : locks
//
//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------

//----------------------------------------------------------------------------------
/** @file base/source/flock.h
	Locks. */
/** @defgroup baseLocks Locks */
//----------------------------------------------------------------------------------
#pragma once

#include "fobject.h"
#include "pluginterfaces/base/ftypes.h"

#if PTHREADS
#include <pthread.h>

#elif WINDOWS
struct CRITSECT							// CRITICAL_SECTION
{
	void* DebugInfo;					// PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
	Steinberg::int32 LockCount;			// LONG LockCount;
	Steinberg::int32 RecursionCount;	// LONG RecursionCount;
	void* OwningThread;					// HANDLE OwningThread
	void* LockSemaphore;				// HANDLE LockSemaphore
	Steinberg::int32 SpinCount;			// ULONG_PTR SpinCount
};
#endif

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

//------------------------------------------------------------------------
/** Lock interface declaration.
@ingroup baseLocks	*/
//------------------------------------------------------------------------
struct ILock
{
//------------------------------------------------------------------------
	virtual ~ILock () {}

	/** Enables lock.
	 */
	virtual void lock () = 0;

	/** Disables lock.
	 */
	virtual void unlock () = 0;

	/** Tries to disable lock.
	 */
	virtual bool trylock () = 0;

//------------------------------------------------------------------------
};

//------------------------------------------------------------------------
/**	FLock declaration.
@ingroup baseLocks	*/
//------------------------------------------------------------------------
class FLock : public ILock
{
public:
//------------------------------------------------------------------------

	/** Lock constructor.
	 *  @param name lock name
	 */
	FLock (const char8* name = "FLock");

	/** Lock destructor.
	 */
	~FLock ();

	//-- ILock -----------------------------------------------------------
	virtual void lock () SMTG_OVERRIDE;
	virtual void unlock () SMTG_OVERRIDE;
	virtual bool trylock () SMTG_OVERRIDE;
	//--------------------------------------------------------------------

//------------------------------------------------------------------------
protected:
#if PTHREADS
	pthread_mutex_t mutex;			///< Mutex object

#elif WINDOWS
	CRITSECT section;				///< Critical section object

#endif
};

//------------------------------------------------------------------------
/**	FLockObj declaration. Reference counted lock
@ingroup baseLocks	*/
//------------------------------------------------------------------------
class FLockObject : public FObject, public FLock
{
public:
	OBJ_METHODS (FLockObject, FObject)
};

//------------------------------------------------------------------------
/**	FGuard - automatic object for locks.
@ingroup baseLocks	*/
//------------------------------------------------------------------------
class FGuard
{
public:
//------------------------------------------------------------------------

	/** FGuard constructor.
	 *  @param _lock guard this lock
	 */
	FGuard (ILock& _lock) : lock (_lock) {lock.lock ();}

	/** FGuard destructor.
	 */
	~FGuard () {lock.unlock ();}

//------------------------------------------------------------------------
private:
	ILock& lock;			///< guarded lock
};

//------------------------------------------------------------------------
/**	Conditional Guard - Locks only if valid lock is passed.
@ingroup baseLocks	*/
//------------------------------------------------------------------------
class FConditionalGuard
{
public:
//------------------------------------------------------------------------

	/** FConditionGuard constructor.
	 *  @param _lock guard this lock
	 */
	FConditionalGuard (FLock* _lock) : lock (_lock) { if (lock) lock->lock (); }

	/** FConditionGuard destructor.
	 */
	~FConditionalGuard () { if (lock) lock->unlock (); }

//------------------------------------------------------------------------
private:
	FLock* lock;			///< guarded lock
};

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


text:
//-----------------------------------------------------------------------------
// Project     : SDK Core
//
// Category    : SDK Core Interfaces
// Filename    : pluginterfaces/base/istringresult.h
// Created by  : Steinberg, 01/2005
// Description : Strings Interface
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------

#pragma once

#include "pluginterfaces/base/funknown.h"

namespace Steinberg {

//------------------------------------------------------------------------
/** Interface to return an ascii string of variable size.
    In order to manage memory allocation and deallocation properly,
	this interface is used to transfer a string as result parameter of
	a method requires a string of unknown size.
[host imp] or [plug imp] \n
[released: SX 4] */
//------------------------------------------------------------------------
class IStringResult : public FUnknown
{
public:
//------------------------------------------------------------------------
	virtual void PLUGIN_API setText (const char8* text) = 0;

//------------------------------------------------------------------------
	static const FUID iid;
};

DECLARE_CLASS_IID (IStringResult, 0x550798BC, 0x872049DB, 0x84920A15, 0x3B50B7A8)

//------------------------------------------------------------------------
/** Interface to a string of variable size and encoding.
[host imp] or [plug imp] \n
[released: ] */
//------------------------------------------------------------------------
class IString : public FUnknown
{
public:
//------------------------------------------------------------------------
	/** Assign ASCII string */
	virtual void PLUGIN_API setText8 (const char8* text) = 0;
	/** Assign unicode string */
	virtual void PLUGIN_API setText16 (const char16* text) = 0;

	/** Return ASCII string. If the string is unicode so far, it will be converted.
	    So you need to be careful, because the conversion can result in data loss.
		It is save though to call getText8 if isWideString() returns false */
	virtual const char8* PLUGIN_API getText8 () = 0;
	/** Return unicode string. If the string is ASCII so far, it will be converted. */
	virtual const char16* PLUGIN_API getText16 () = 0;

	/** !Do not use this method! Early implementations take the given pointer as
	     internal string and this will cause problems because 'free' will be used to delete the passed memory.
		 Later implementations will redirect 'take' to setText8 and setText16 */
	virtual void PLUGIN_API take (void* s, bool isWide) = 0;

	/** Returns true if the string is in unicode format, returns false if the string is ASCII */
	virtual bool PLUGIN_API isWideString () const = 0;

//------------------------------------------------------------------------
	static const FUID iid;
};

DECLARE_CLASS_IID (IString, 0xF99DB7A3, 0x0FC14821, 0x800B0CF9, 0x8E348EDF)

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