text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fdebug.h
// Created by  : Steinberg, 1995
// Description : There are 2 levels of debugging messages:
//	             DEVELOPMENT               During development
//	             RELEASE                   Program is shipping.
//
//-----------------------------------------------------------------------------
// 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/fdebug.h
	Debugging tools.

	There are 2 levels of debugging messages:
	- DEVELOPMENT
	  - During development
	- RELEASE
	  - Program is shipping.
*/
//-----------------------------------------------------------------------------
#pragma once

#include "pluginterfaces/base/ftypes.h"
#include <string.h>

#if MAC
#include <new>
#endif

//-----------------------------------------------------------------------------
// development / release
//-----------------------------------------------------------------------------
#if !defined (DEVELOPMENT) && !defined (RELEASE)
	#ifdef _DEBUG
		#define DEVELOPMENT 1
	#elif defined (NDEBUG)
		#define RELEASE 1
	#else
		#error DEVELOPMENT, RELEASE, _DEBUG, or NDEBUG  must be defined!
	#endif
#endif

//-----------------------------------------------------------------------------
#if WINDOWS

#undef ASSERT

/** Disable compiler warning:
  * C4291: "No matching operator delete found; memory will not be freed if initialization throws an exception.
  *        A placement new is used for which there is no placement delete." */
#if DEVELOPMENT && defined (_MSC_VER)
#pragma warning(disable:4291)
#pragma warning(disable:4985)
#endif

#endif // WINDOWS

#if DEVELOPMENT
  //-----------------------------------------------------------------------------
    /** If "f" is not true and a debugger is present, send an error string to the debugger for display and
		cause a breakpoint exception to occur in the current process. ASSERT is removed completely in RELEASE configuration.
		So do not pass methods calls to this macro that are expected to exist in the RELEASE build (for method calls that need
		to be present in a RELEASE build, use the VERIFY macros instead)*/
	#define ASSERT(f)             if (!(f)) FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f);

	/** Send "comment" string to the debugger for display. */
	#define WARNING(comment)      FDebugPrint ("%s(%d) : %s\n", __FILE__, __LINE__, comment);

	/** Send the last error string to the debugger for display. */
	#define PRINTSYSERROR         FPrintLastError(__FILE__, __LINE__);

	/** If a debugger is present, send string "s" to the debugger for display and
		cause a breakpoint exception to occur in the current process. */
	#define DEBUGSTR(s)           FDebugBreak(s);

	/** Use VERIFY for calling methods "f" having a bool result (expecting them to return 'true')
	     The call of "f" is not removed in RELEASE builds, only the result verification. eg: VERIFY (isValid ()) */
	#define VERIFY(f)             ASSERT(f)

	/** Use VERIFY_IS for calling methods "f" and expect a certain result "r".
	    The call of "f" is not removed in RELEASE builds, only the result verification. eg: VERIFY_IS (callMethod (), kResultOK) */
	#define VERIFY_IS(f,r)        if ((f) != (r)) FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f);

	/** Use VERIFY_NOT for calling methods "f" and expect the result to be anything else but "r".
	     The call of "f" is not removed in RELEASE builds, only the result verification. eg: VERIFY_NOT (callMethod (), kResultError) */
	#define VERIFY_NOT(f,r)       if ((f) == (r)) FDebugBreak ("%s(%d) : Assert failed: %s\n", __FILE__, __LINE__, #f);

	/** @name Shortcut macros for sending strings to the debugger for display.

		First parameter is always the format string (printf like).
	*/
	///@{
	#define DBPRT0(a)             FDebugPrint(a);
	#define DBPRT1(a,b)           FDebugPrint(a,b);
	#define DBPRT2(a,b,c)         FDebugPrint(a,b,c);
	#define DBPRT3(a,b,c,d)       FDebugPrint(a,b,c,d);
	#define DBPRT4(a,b,c,d,e)     FDebugPrint(a,b,c,d,e);
	#define DBPRT5(a,b,c,d,e,f)   FDebugPrint(a,b,c,d,e,f);
	///@}

	/** @name Helper functions for the above defined macros.

		You shouldn't use them directly (if you do so, don't forget "#if DEVELOPMENT")!
		It is recommended to use the macros instead.
	*/
	///@{
	void FDebugPrint (const char *format, ...);
	void FDebugBreak (const char *format, ...);
	void FPrintLastError (const char* file, int line);
	///@}

	/** @name Provide a custom assertion handler
	*/
	///@{
	typedef bool (*AssertionHandler)(const char* message);
	extern AssertionHandler gAssertionHandler;
	///@}

	/** Definition of memory allocation macros:
		Use "NEW" to allocate storage for individual objects.
		Use "NEWVEC" to allocate storage for an array of objects. */
	#if MAC
		void* operator new (size_t, int, const char *, int);
		void* operator new [] (size_t, int, const char *, int);
		void operator delete (void* p, int, const char *file, int line);
		void operator delete[] (void* p, int, const char *file, int line);

		#ifndef NEW
		#define NEW new (1, __FILE__, __LINE__)
		#define NEWVEC new (1, __FILE__, __LINE__)
		#endif

		#define DEBUG_NEW DEBUG_NEW_LEAKS

	#elif WINDOWS && defined (_MSC_VER)
		#ifndef NEW
		void * operator new (size_t, int, const char *, int);
		#define NEW new (1, __FILE__, __LINE__)
		#define NEWVEC new (1, __FILE__, __LINE__)
		#endif

	#else
		#ifndef NEW
		#define NEW new
		#define NEWVEC new
		#endif
	#endif

#else
	/** if DEVELOPMENT is not set, these macros will do nothing. */
 	#define ASSERT(f)
	#define WARNING(s)
	#define PRINTSYSERROR
	#define DEBUGSTR(s)
	#define VERIFY(f) f;
	#define VERIFY_IS(f,r) f;
	#define VERIFY_NOT(f,r) f;

	#define DBPRT0(a)
	#define DBPRT1(a,b)
	#define DBPRT2(a,b,c)
	#define DBPRT3(a,b,c,d)
	#define DBPRT4(a,b,c,d,e)
	#define DBPRT5(a,b,c,d,e,f)

	#ifndef NEW
	#define NEW new
	#define NEWVEC new
	#endif
#endif

#if SMTG_CPPUNIT_TESTING
#define SMTG_IS_TEST true
#else
#define SMTG_IS_TEST false
#endif

repo_name: fedden/RenderMan

mime_type: text/x-c++


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fstring.h
// Created by  : Steinberg, 2008
// Description : String class
//
//-----------------------------------------------------------------------------
// 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/ftypes.h"
#include "pluginterfaces/base/fstrdefs.h"
#include "pluginterfaces/base/istringresult.h"
#include "pluginterfaces/base/ipersistent.h"

#include "base/source/fobject.h"

#include <stdarg.h>

namespace Steinberg {

class FVariant;
class String;

#ifdef UNICODE
static const bool kWideStringDefault = true;
#else
static const bool kWideStringDefault = false;
#endif

static const uint16 kBomUtf16 = 0xFEFF;					///< UTF16 Byte Order Mark
static const char8* const kBomUtf8 = "\xEF\xBB\xBF";	///< UTF8 Byte Order Mark
static const int32 kBomUtf8Length = 3;

enum MBCodePage
{
	kCP_ANSI = 0,			///< Default ANSI codepage.
	kCP_MAC_ROMAN = 2,		///< Default Mac codepage.

	kCP_ANSI_WEL = 1252,	///< West European Latin Encoding.
	kCP_MAC_CEE = 10029,	///< Mac Central European Encoding.
	kCP_Utf8 = 65001,		///< UTF8 Encoding.
	kCP_ShiftJIS = 932,		///< Shifted Japan Industrial Standard Encoding.
	kCP_US_ASCII = 20127,	///< US-ASCII (7-bit).

	kCP_Default = kCP_ANSI	///< Default ANSI codepage.
};

enum UnicodeNormalization
{
	kUnicodeNormC,	///< Unicode normalization Form C, canonical composition.
	kUnicodeNormD,	///< Unicode normalization Form D, canonical decomposition.
	kUnicodeNormKC,	///< Unicode normalization form KC, compatibility composition.
	kUnicodeNormKD 	///< Unicode normalization form KD, compatibility decomposition.
};

//------------------------------------------------------------------------
// Helper functions to create hash codes from string data.
//------------------------------------------------------------------------
extern uint32 hashString8 (const char8* s, uint32 m);
extern uint32 hashString16 (const char16* s, uint32 m);
inline uint32 hashString (const tchar* s, uint32 m)
{
#ifdef UNICODE
	return hashString16 (s, m);
#else
	return hashString8 (s, m);
#endif
}

//-----------------------------------------------------------------------------
/** Invariant String.
@ingroup adt

A base class which provides methods to work with its
member string. Neither of the operations allows modifying the member string and
that is why all operation are declared as const.

There are operations for access, comparison, find, numbers and conversion.

Almost all operations exist in three versions for char8, char16 and the
polymorphic type tchar. The type tchar can either be char8 or char16 depending
on whether UNICODE is activated or not.*/
//-----------------------------------------------------------------------------
class ConstString
{
public:
//-----------------------------------------------------------------------------
	ConstString (const char8* str, int32 length = -1);	///< Assign from string of type char8 (length=-1: all)
	ConstString (const char16* str, int32 length = -1);	///< Assign from string of type char16 (length=-1: all)
	ConstString (const ConstString& str, int32 offset = 0, int32 length = -1); ///< Copy constructor (length=-1: all).
	ConstString (const FVariant& var);	///< Assign a string from FVariant
	ConstString ();
	virtual ~ConstString () {}			///< Destructor.

	// access -----------------------------------------------------------------
	virtual int32 length () const {return len;} 					///< Return length of string
	inline bool isEmpty () const {return buffer == 0 || len == 0;} 	///< Return true if sting is empty

	operator const char8* () const {return text8 ();} 							///< Returns pointer to string of type char8 (no modification allowed)
	operator const char16* () const {return text16 ();}							///< Returns pointer to string of type char16(no modification allowed)
	inline tchar operator[] (short idx) const {return getChar (idx);}			///< Returns character at 'idx'
	inline tchar operator[] (long idx) const {return getChar (static_cast<uint32>(idx));}
	inline tchar operator[] (int idx) const {return getChar (idx);}
	inline tchar operator[] (unsigned short idx) const {return getChar (idx);}
	inline tchar operator[] (unsigned long idx) const {return getChar (static_cast<uint32>(idx));}
	inline tchar operator[] (unsigned int idx) const {return getChar (idx);}

	inline virtual const char8* text8 () const;		///< Returns pointer to string of type char8
	inline virtual const char16* text16 () const;	///< Returns pointer to string of type char16
	inline virtual const tchar* text () const;		///< Returns pointer to string of type tchar
	inline virtual const void* ptr () const {return buffer;}	///< Returns pointer to string of type void

	inline virtual char8 getChar8 (uint32 index) const;		///< Returns character of type char16 at 'index'
	inline virtual char16 getChar16 (uint32 index) const;	///< Returns character of type char8 at 'index'
	inline tchar getChar (uint32 index) const;				///< Returns character of type tchar at 'index'
	inline tchar getCharAt (uint32 index) const;			///< Returns character of type tchar at 'index', no conversion!

	bool testChar8 (uint32 index, char8 c) const;			///< Returns true if character is equal at position 'index'
	bool testChar16 (uint32 index, char16 c) const;
	inline bool testChar (uint32 index, char8 c) const {return testChar8 (index, c);}
	inline bool testChar (uint32 index, char16 c) const {return testChar16 (index, c);}

	bool extract (String& result, uint32 idx, int32 n = -1) const;		///< Get n characters long substring starting at index (n=-1: until end)
	int32 copyTo8 (char8* str, uint32 idx = 0, int32 n = -1) const;
	int32 copyTo16 (char16* str, uint32 idx = 0, int32 n = -1) const;
	int32 copyTo (tchar* str, uint32 idx = 0, int32 n = -1) const;
	void copyTo (IStringResult* result) const;							///< Copies whole member string
	void copyTo (IString& string) const;							    ///< Copies whole member string

	inline uint32 hash (uint32 tsize) const
	{
		return isWide ? hashString16 (buffer16, tsize) : hashString8 (buffer8, tsize) ;
	}
	//-------------------------------------------------------------------------

	// compare ----------------------------------------------------------------
	enum CompareMode
	{
		kCaseSensitive,		///< Comparison is done with regard to character's case
		kCaseInsensitive	///< Comparison is done without regard to character's case
	};

	int32 compareAt (uint32 index, const ConstString& str, int32 n = -1, CompareMode m = kCaseSensitive) const; 				///< Compare n characters of str with n characters of this starting at index (return: see above)
	int32 compare (const ConstString& str, int32 n, CompareMode m = kCaseSensitive) const;										///< Compare n characters of str with n characters of this (return: see above)
	int32 compare (const ConstString& str, CompareMode m = kCaseSensitive) const;												///< Compare all characters of str with this (return: see above)

	int32 naturalCompare (const ConstString& str, CompareMode mode = kCaseSensitive) const;

	bool startsWith (const ConstString& str, CompareMode m = kCaseSensitive) const;												///< Check if this starts with str
	bool endsWith (const ConstString& str, CompareMode m = kCaseSensitive) const;												///< Check if this ends with str
	bool contains (const ConstString& str, CompareMode m = kCaseSensitive) const;												///< Check if this contains str

	// static methods
	static bool isCharSpace (char8 character);	   ///< Returns true if character is a space
	static bool isCharSpace (char16 character);    ///< @copydoc isCharSpace(const char8)
	static bool isCharAlpha (char8 character);	   ///< Returns true if character is an alphabetic character
	static bool isCharAlpha (char16 character);    ///< @copydoc isCharAlpha(const char8)
	static bool isCharAlphaNum (char8 character);  ///< Returns true if character is an alphanumeric character
	static bool isCharAlphaNum (char16 character); ///< @copydoc isCharAlphaNum(const char8)
	static bool isCharDigit (char8 character);	   ///< Returns true if character is a number
	static bool isCharDigit (char16 character);    ///< @copydoc isCharDigit(const char8)
	static bool isCharAscii (char8 character);     ///< Returns true if character is in ASCII range
	static bool isCharAscii (char16 character);    ///< Returns true if character is in ASCII range
	static bool isCharUpper (char8 character);
	static bool isCharUpper (char16 character);
	static bool isCharLower (char8 character);
	static bool isCharLower (char16 character);
	//-------------------------------------------------------------------------

	/** @name Find first occurrence of n characters of str in this (n=-1: all) ending at endIndex (endIndex = -1: all)*/
	///@{
	inline int32 findFirst (const ConstString& str, int32 n = -1, CompareMode m = kCaseSensitive, int32 endIndex = -1) const {return findNext (0, str, n, m, endIndex);}
	inline int32 findFirst (char8 c, CompareMode m = kCaseSensitive, int32 endIndex = -1) const {return findNext (0, c, m, endIndex);}
	inline int32 findFirst (char16 c, CompareMode m = kCaseSensitive, int32 endIndex = -1) const {return findNext (0, c, m, endIndex);}
	///@}
	/** @name Find next occurrence of n characters of str starting at startIndex in this (n=-1: all) ending at endIndex (endIndex = -1: all)*/
	///@{
	int32 findNext (int32 startIndex, const ConstString& str, int32 n = -1, CompareMode = kCaseSensitive, int32 endIndex = -1) const;
	int32 findNext (int32 startIndex, char8 c, CompareMode = kCaseSensitive, int32 endIndex = -1) const;
	int32 findNext (int32 startIndex, char16 c, CompareMode = kCaseSensitive, int32 endIndex = -1) const;
	///@}
	/** @name Find previous occurrence of n characters of str starting at startIndex in this (n=-1: all) */
	///@{
	int32 findPrev (int32 startIndex, const ConstString& str, int32 n = -1, CompareMode = kCaseSensitive) const;
	int32 findPrev (int32 startIndex, char8 c, CompareMode = kCaseSensitive) const;
	int32 findPrev (int32 startIndex, char16 c, CompareMode = kCaseSensitive) const;
	///@}

	inline int32 findLast (const ConstString& str, int32 n = -1, CompareMode m = kCaseSensitive) const {return findPrev (-1, str, n, m);}	///< Find last occurrence of n characters of str in this (n=-1: all)
	inline int32 findLast (char8 c, CompareMode m = kCaseSensitive) const {return findPrev (-1, c, m);}
	inline int32 findLast (char16 c, CompareMode m = kCaseSensitive) const {return findPrev (-1, c, m);}

	int32 countOccurences (char8 c, uint32 startIndex, CompareMode = kCaseSensitive) const; ///< Counts occurences of c within this starting at index
	int32 countOccurences (char16 c, uint32 startIndex, CompareMode = kCaseSensitive) const;
	int32 getFirstDifferent (const ConstString& str, CompareMode = kCaseSensitive) const;	///< Returns position of first different character
	//-------------------------------------------------------------------------

	// numbers ----------------------------------------------------------------
	bool isDigit (uint32 index) const;	///< Returns true if character at position is a digit
	bool scanFloat (double& value, uint32 offset = 0, bool scanToEnd = true) const;		///< Converts string to double value starting at offset
	bool scanInt64 (int64& value, uint32 offset = 0, bool scanToEnd = true) const;		///< Converts string to int64 value starting at offset
	bool scanUInt64 (uint64& value, uint32 offset = 0, bool scanToEnd = true) const;	///< Converts string to uint64 value starting at offset
	bool scanInt32 (int32& value, uint32 offset = 0, bool scanToEnd = true) const;		///< Converts string to int32 value starting at offset
	bool scanUInt32 (uint32& value, uint32 offset = 0, bool scanToEnd = true) const;	///< Converts string to uint32 value starting at offset
	bool scanHex (uint8& value, uint32 offset = 0, bool scanToEnd = true) const;		///< Converts string to hex/uint8 value starting at offset

	int32 getTrailingNumberIndex (uint32 width = 0) const;	///< Returns start index of trailing number
	int64 getTrailingNumber (int64 fallback = 0) const;		///< Returns result of scanInt64 or the fallback
	int64 getNumber () const;								///< Returns result of scanInt64

	// static methods
	static bool scanInt64_8 (const char8* text, int64& value, bool scanToEnd = true);	///< Converts string of type char8 to int64 value
	static bool scanInt64_16 (const char16* text, int64& value, bool scanToEnd = true);	///< Converts string of type char16 to int64 value
	static bool scanInt64 (const tchar* text, int64& value, bool scanToEnd = true);		///< Converts string of type tchar to int64 value

	static bool scanUInt64_8 (const char8* text, uint64& value, bool scanToEnd = true);		///< Converts string of type char8 to uint64 value
	static bool scanUInt64_16 (const char16* text, uint64& value, bool scanToEnd = true);	///< Converts string of type char16 to uint64 value
	static bool scanUInt64 (const tchar* text, uint64& value, bool scanToEnd = true);		///< Converts string of type tchar to uint64 value

	static bool scanInt32_8 (const char8* text, int32& value, bool scanToEnd = true);		///< Converts string of type char8 to int32 value
	static bool scanInt32_16 (const char16* text, int32& value, bool scanToEnd = true);		///< Converts string of type char16 to int32 value
	static bool scanInt32 (const tchar* text, int32& value, bool scanToEnd = true);			///< Converts string of type tchar to int32 value

	static bool scanUInt32_8 (const char8* text, uint32& value, bool scanToEnd = true);		///< Converts string of type char8 to int32 value
	static bool scanUInt32_16 (const char16* text, uint32& value, bool scanToEnd = true);		///< Converts string of type char16 to int32 value
	static bool scanUInt32 (const tchar* text, uint32& value, bool scanToEnd = true);			///< Converts string of type tchar to int32 value

	static bool scanHex_8 (const char8* text, uint8& value, bool scanToEnd = true);		///< Converts string of type char8 to hex/unit8 value
	static bool scanHex_16 (const char16* text, uint8& value, bool scanToEnd = true);	///< Converts string of type char16 to hex/unit8 value
	static bool scanHex (const tchar* text, uint8& value, bool scanToEnd = true);		///< Converts string of type tchar to hex/unit8 value
	//-------------------------------------------------------------------------

	// conversion -------------------------------------------------------------
	void toVariant (FVariant& var) const;

	static char8 toLower (char8 c);		///< Converts to lower case
	static char8 toUpper (char8 c);		///< Converts to upper case
	static char16 toLower (char16 c);
	static char16 toUpper (char16 c);

	static int32 multiByteToWideString (char16* dest, const char8* source, int32 wcharCount, uint32 sourceCodePage = kCP_Default);	///< If dest is zero, this returns the maximum number of bytes needed to convert source
	static int32 wideStringToMultiByte (char8* dest, const char16* source, int32 char8Count, uint32 destCodePage = kCP_Default);	///< If dest is zero, this returns the maximum number of bytes needed to convert source

	bool isWideString () const {return isWide != 0;}	///< Returns true if string is wide
	bool isAsciiString () const; 						///< Checks if all characters in string are in ascii range

	bool isNormalized (UnicodeNormalization = kUnicodeNormC); ///< On PC only kUnicodeNormC is working

#if MAC
	virtual void* toCFStringRef (uint32 encoding = 0xFFFF, bool mutableCFString = false) const;	///< CFString conversion
#endif
//-------------------------------------------------------------------------

//-----------------------------------------------------------------------------
protected:

	union
	{
		void* buffer;
		char8* buffer8;
		char16* buffer16;
	};
	uint32 len : 30;
	uint32 isWide : 1;
};

//-----------------------------------------------------------------------------
/** String.
@ingroup adt

Extends class ConstString by operations which allow modifications.

\see ConstString */
//-----------------------------------------------------------------------------
class String : public ConstString
{
public:
//-----------------------------------------------------------------------------
	String ();
	String (const char8* str, MBCodePage codepage, int32 n = -1, bool isTerminated = true);							///< assign n characters of str and convert to wide string by using the specified codepage
	String (const char8* str, int32 n = -1, bool isTerminated = true);	///< assign n characters of str (-1: all)
	String (const char16* str, int32 n = -1, bool isTerminated = true);	///< assign n characters of str (-1: all)
	String (const String& str, int32 n = -1);							///< assign n characters of str (-1: all)
	String (const ConstString& str, int32 n = -1);		///< assign n characters of str (-1: all)
	String (const FVariant& var);						///< assign from FVariant
	String (IString* str);						///< assign from IString
	~String ();

#if SMTG_CPP11_STDLIBSUPPORT
	String (String&& str);
	String& operator= (String&& str);
#endif

	// access------------------------------------------------------------------
	void updateLength (); ///< Call this when the string is truncated outside (not recommended though)
	virtual const char8* text8 () const SMTG_OVERRIDE;
	virtual const char16* text16 () const SMTG_OVERRIDE;
	virtual char8 getChar8 (uint32 index) const SMTG_OVERRIDE;
	virtual char16 getChar16 (uint32 index) const SMTG_OVERRIDE;

	bool setChar8 (uint32 index, char8 c);
	bool setChar16 (uint32 index, char16 c);
	inline bool setChar (uint32 index, char8 c) {return setChar8 (index, c);}
	inline bool setChar (uint32 index, char16 c) {return setChar16 (index, c);}
	//-------------------------------------------------------------------------

	// assignment--------------------------------------------------------------
	String& operator= (const char8* str) {return assign (str);}	///< Assign from a string of type char8
	String& operator= (const char16* str) {return assign (str);}
	String& operator= (const ConstString& str) {return assign (str);}
	String& operator= (const String& str) {return assign (str);}
	String& operator= (char8 c) {return assign (c);}
	String& operator= (char16 c) {return assign (c);}

	String& assign (const ConstString& str, int32 n = -1);			///< Assign n characters of str (-1: all)
	String& assign (const char8* str, int32 n = -1, bool isTerminated = true);			///< Assign n characters of str (-1: all)
	String& assign (const char16* str, int32 n = -1, bool isTerminated = true);			///< Assign n characters of str (-1: all)
	String& assign (char8 c, int32 n = 1);
	String& assign (char16 c, int32 n = 1);
	//-------------------------------------------------------------------------

	// concat------------------------------------------------------------------
	String& append (const ConstString& str, int32 n = -1);		///< Append n characters of str to this (n=-1: all)
	String& append (const char8* str, int32 n = -1);			///< Append n characters of str to this (n=-1: all)
	String& append (const char16* str, int32 n = -1);			///< Append n characters of str to this (n=-1: all)
	String& append (const char8 c, int32 n = 1);                ///< Append char c n times
	String& append (const char16 c, int32 n = 1);               ///< Append char c n times

	String& insertAt (uint32 idx, const ConstString& str, int32 n = -1);	///< Insert n characters of str at position idx (n=-1: all)
	String& insertAt (uint32 idx, const char8* str, int32 n = -1);	///< Insert n characters of str at position idx (n=-1: all)
	String& insertAt (uint32 idx, const char16* str, int32 n = -1);	///< Insert n characters of str at position idx (n=-1: all)
	String& insertAt (uint32 idx, char8 c) {char8 str[] = {c, 0}; return insertAt (idx, str, 1);}
	String& insertAt (uint32 idx, char16 c) {char16 str[] = {c, 0}; return insertAt (idx, str, 1);}

	String& operator+= (const String& str) {return append (str);}
	String& operator+= (const ConstString& str) {return append (str);}
	String& operator+= (const char8* str) {return append (str);}
	String& operator+= (const char16* str) {return append (str);}
	String& operator+= (const char8 c) {return append (c);}
	String& operator+= (const char16 c) {return append (c);}
	//-------------------------------------------------------------------------

	// replace-----------------------------------------------------------------
	String& replace (uint32 idx, int32 n1, const ConstString& str, int32 n2 = -1);		///< Replace n1 characters of this (starting at idx) with n2 characters of str (n1,n2=-1: until end)
	String& replace (uint32 idx, int32 n1, const char8* str, int32 n2 = -1);			///< Replace n1 characters of this (starting at idx) with n2 characters of str (n1,n2=-1: until end)
	String& replace (uint32 idx, int32 n1, const char16* str, int32 n2 = -1);			///< Replace n1 characters of this (starting at idx) with n2 characters of str (n1,n2=-1: until end)

	int32 replace (const char8* toReplace, const char8* toReplaceWith, bool all = false, CompareMode m = kCaseSensitive);			///< Replace find string with replace string - returns number of replacements
	int32 replace (const char16* toReplace, const char16* toReplaceWith, bool all = false, CompareMode m = kCaseSensitive);		///< Replace find string with replace string - returns number of replacements

	bool replaceChars8 (const char8* toReplace, char8 toReplaceBy); ///< Returns true when any replacement was done
	bool replaceChars16 (const char16* toReplace, char16 toReplaceBy);
	inline bool replaceChars8 (char8 toReplace, char8 toReplaceBy)  {char8 str[] = {toReplace, 0}; return replaceChars8 (str, toReplaceBy);}
	inline bool replaceChars16 (char16 toReplace, char16 toReplaceBy)  {char16 str[] = {toReplace, 0}; return replaceChars16 (str, toReplaceBy);}
	inline bool replaceChars (char8 toReplace, char8 toReplaceBy) {return replaceChars8 (toReplace, toReplaceBy);}
	inline bool replaceChars (char16 toReplace, char16 toReplaceBy) {return replaceChars16 (toReplace, toReplaceBy);}
	inline bool replaceChars (const char8* toReplace, char8 toReplaceBy) {return replaceChars8 (toReplace, toReplaceBy);}
	inline bool replaceChars (const char16* toReplace, char16 toReplaceBy) {return replaceChars16 (toReplace, toReplaceBy);}
	//-------------------------------------------------------------------------

	// remove------------------------------------------------------------------
	String& remove (uint32 index = 0, int32 n = -1);		///< Remove n characters from string starting at index (n=-1: until end)
	enum CharGroup {kSpace, kNotAlphaNum, kNotAlpha};
	bool trim (CharGroup mode = kSpace);					///< Trim lead/trail.
	void removeChars (CharGroup mode = kSpace);				///< Removes all of group.
	bool removeChars8 (const char8* which);					///< Remove all occurrences of each char in 'which'
	bool removeChars16 (const char16* which);				///< Remove all occurrences of each char in 'which'
	inline bool removeChars8 (const char8 which) {char8 str[] = {which, 0}; return removeChars8 (str); }
	inline bool removeChars16 (const char16 which) {char16 str[] = {which, 0}; return removeChars16 (str); }
	inline bool removeChars (const char8* which) {return removeChars8 (which);}
	inline bool removeChars (const char16* which) {return removeChars16 (which);}
	inline bool removeChars (const char8 which) {return removeChars8 (which);}
	inline bool removeChars (const char16 which) {return removeChars16 (which);}
	bool removeSubString (const ConstString& subString, bool allOccurences = true);
	//-------------------------------------------------------------------------

	// print-------------------------------------------------------------------
	String& printf (const char8* format, ...);					///< Print formatted data into string
	String& printf (const char16* format, ...);					///< Print formatted data into string
	String& vprintf (const char8* format, va_list args);
	String& vprintf (const char16* format, va_list args);
	//-------------------------------------------------------------------------

	// numbers-----------------------------------------------------------------
	String& printInt64 (int64 value);
	String& printFloat (double value);
	/** Increment the trailing number if present else start with minNumber, width specifies the string width format (width 2 for number 3 is 03),
		applyOnlyFormat set to true will only format the string to the given width without incrementing the founded trailing number */
	bool incrementTrailingNumber (uint32 width = 2, tchar separator = STR (' '), uint32 minNumber = 1, bool applyOnlyFormat = false);
	//-------------------------------------------------------------------------

	// conversion--------------------------------------------------------------
	bool fromVariant (const FVariant& var);		///< Assigns string from FVariant
	void toVariant (FVariant& var) const;
	bool fromAttributes (IAttributes* a, IAttrID attrID);	///< Assigns string from FAttributes
	bool toAttributes (IAttributes* a, IAttrID attrID);

	void swapContent (String& s); 								///< Swaps ownership of the strings pointed to
	void take (String& str);      								///< Take ownership of the string of 'str'
	void take (void* _buffer, bool wide);      					///< Take ownership of buffer
	void* pass ();
	void passToVariant (FVariant& var);							///< Pass ownership of buffer to Variant - sets Variant ownership

	void toLower (uint32 index);								///< Lower case the character.
	void toLower ();											///< Lower case the string.
	void toUpper (uint32 index);								///< Upper case the character.
	void toUpper ();											///< Upper case the string.

	unsigned char* toPascalString (unsigned char* buf);			///< Pascal string conversion
	const String& fromPascalString (const unsigned char* buf);	///< Pascal string conversion

	bool toWideString (uint32 sourceCodePage = kCP_Default);	///< Converts to wide string according to sourceCodePage
	bool toMultiByte (uint32 destCodePage = kCP_Default);

	void fromUTF8 (const char8* utf8String);				///< Assigns from UTF8 string
	bool normalize (UnicodeNormalization = kUnicodeNormC);	///< On PC only kUnicodeNormC is working

#if MAC
	virtual bool fromCFStringRef (const void*, uint32 encoding = 0xFFFF);	///< CFString conversion
#endif
	//-------------------------------------------------------------------------

	//-----------------------------------------------------------------------------
protected:
	bool resize (uint32 newSize, bool wide, bool fill = false);

private:
	void tryFreeBuffer ();
	bool checkToMultiByte (uint32 destCodePage = kCP_Default) const; // to remove debug code from inline - const_cast inside!!!
};

// String concatenation functions.
inline String operator+ (const ConstString& s1, const ConstString& s2) {return String (s1).append (s2);}
inline String operator+ (const ConstString& s1, const char8* s2) {return String (s1).append (s2);}
inline String operator+ (const ConstString& s1, const char16* s2) {return String (s1).append (s2);}
inline String operator+ (const char8* s1, const ConstString& s2) {return String (s1).append (s2);}
inline String operator+ (const char16* s1, const ConstString& s2) {return String (s1).append (s2);}
inline String operator+ (const ConstString& s1, const String& s2) {return String (s1).append (s2);}
inline String operator+ (const String& s1, const ConstString& s2) {return String (s1).append (s2);}
inline String operator+ (const String& s1, const String& s2) {return String (s1).append (s2);}
inline String operator+ (const String& s1, const char8* s2) {return String (s1).append (s2);}
inline String operator+ (const String& s1, const char16* s2) {return String (s1).append (s2);}
inline String operator+ (const char8* s1, const String& s2) {return String (s1).append (s2);}
inline String operator+ (const char16* s1, const String& s2) {return String (s1).append (s2);}

//-----------------------------------------------------------------------------
// ConstString
//-----------------------------------------------------------------------------
inline const tchar* ConstString::text () const
{
#ifdef UNICODE
	return text16 ();
#else
	return text8 ();
#endif
}

//-----------------------------------------------------------------------------
inline const char8* ConstString::text8 () const
{
	return (!isWide && buffer8) ? buffer8: kEmptyString8;
}

//-----------------------------------------------------------------------------
inline const char16* ConstString::text16 () const
{
	return (isWide && buffer16) ? buffer16 : kEmptyString16;
}

//-----------------------------------------------------------------------------
inline char8 ConstString::getChar8 (uint32 index) const
{
	if (index < len && buffer8 && !isWide)
		return buffer8[index];
	return 0;
}

//-----------------------------------------------------------------------------
inline char16 ConstString::getChar16 (uint32 index) const
{
	if (index < len && buffer16 && isWide)
		return buffer16[index];
	return 0;
}

//-----------------------------------------------------------------------------
inline tchar ConstString::getChar (uint32 index) const
{
#ifdef UNICODE
	return getChar16 (index);
#else
	return getChar8 (index);
#endif
}

//-----------------------------------------------------------------------------
inline tchar ConstString::getCharAt (uint32 index) const
{
#ifdef UNICODE
	if (isWide)
		return getChar16 (index);
#endif

	return getChar8 (index);
}

//-----------------------------------------------------------------------------
inline int64 ConstString::getNumber () const
{
	int64 tmp = 0;
	scanInt64 (tmp);
	return tmp;
}

//-----------------------------------------------------------------------------
inline bool ConstString::scanInt32_8 (const char8* text, int32& value, bool scanToEnd)
{
	int64 tmp;
	if (scanInt64_8 (text, tmp, scanToEnd))
	{
		value = (int32)tmp;
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
inline bool ConstString::scanInt32_16 (const char16* text, int32& value, bool scanToEnd)
{
	int64 tmp;
	if (scanInt64_16 (text, tmp, scanToEnd))
	{
		value = (int32)tmp;
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
inline bool ConstString::scanInt32 (const tchar* text, int32& value, bool scanToEnd)
{
	int64 tmp;
	if (scanInt64 (text, tmp, scanToEnd))
	{
		value = (int32)tmp;
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
inline bool ConstString::scanUInt32_8 (const char8* text, uint32& value, bool scanToEnd)
{
	uint64 tmp;
	if (scanUInt64_8 (text, tmp, scanToEnd))
	{
		value = (uint32)tmp;
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
inline bool ConstString::scanUInt32_16 (const char16* text, uint32& value, bool scanToEnd)
{
	uint64 tmp;
	if (scanUInt64_16 (text, tmp, scanToEnd))
	{
		value = (uint32)tmp;
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
inline bool ConstString::scanUInt32 (const tchar* text, uint32& value, bool scanToEnd)
{
	uint64 tmp;
	if (scanUInt64 (text, tmp, scanToEnd))
	{
		value = (uint32)tmp;
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
inline const char8* String::text8 () const
{
	if (isWide && !isEmpty ())
		checkToMultiByte (); // this should be avoided, since it can lead to information loss

	return ConstString::text8 ();
}

//-----------------------------------------------------------------------------
inline const char16* String::text16 () const
{
	if (!isWide && !isEmpty ())
	{
		const_cast<String&> (*this).toWideString ();
	}
	return ConstString::text16 ();
}

//-----------------------------------------------------------------------------
inline char8 String::getChar8 (uint32 index) const
{
	if (isWide && !isEmpty ())
		checkToMultiByte (); // this should be avoided, since it can lead to information loss

	return ConstString::getChar8 (index);
}

//-----------------------------------------------------------------------------
inline char16 String::getChar16 (uint32 index) const
{
	if (!isWide && !isEmpty ())
	{
		const_cast<String&> (*this).toWideString ();
	}
	return ConstString::getChar16 (index);
}

//-----------------------------------------------------------------------------

inline bool operator<  (const ConstString& s1, const ConstString& s2) {return (s1.compare (s2) < 0) ? true : false;}
inline bool operator<= (const ConstString& s1, const ConstString& s2) {return (s1.compare (s2) <= 0) ? true : false;}
inline bool operator>  (const ConstString& s1, const ConstString& s2) {return (s1.compare (s2) > 0) ? true : false;}
inline bool operator>= (const ConstString& s1, const ConstString& s2) {return (s1.compare (s2) >= 0) ? true : false;}
inline bool operator== (const ConstString& s1, const ConstString& s2) {return (s1.compare (s2) == 0) ? true : false;}
inline bool operator!= (const ConstString& s1, const ConstString& s2) {return (s1.compare (s2) != 0) ? true : false;}

inline bool operator<  (const ConstString& s1, const char8* s2) {return (s1.compare (s2) < 0) ? true : false;}
inline bool operator<= (const ConstString& s1, const char8* s2) {return (s1.compare (s2) <= 0) ? true : false;}
inline bool operator>  (const ConstString& s1, const char8* s2) {return (s1.compare (s2) > 0) ? true : false;}
inline bool operator>= (const ConstString& s1, const char8* s2) {return (s1.compare (s2) >= 0) ? true : false;}
inline bool operator== (const ConstString& s1, const char8* s2) {return (s1.compare (s2) == 0) ? true : false;}
inline bool operator!= (const ConstString& s1, const char8* s2) {return (s1.compare (s2) != 0) ? true : false;}
inline bool operator<  (const char8* s1, const ConstString& s2) {return (s2.compare (s1) > 0) ? true : false;}
inline bool operator<= (const char8* s1, const ConstString& s2) {return (s2.compare (s1) >= 0) ? true : false;}
inline bool operator>  (const char8* s1, const ConstString& s2) {return (s2.compare (s1) < 0) ? true : false;}
inline bool operator>= (const char8* s1, const ConstString& s2) {return (s2.compare (s1) <= 0) ? true : false;}
inline bool operator== (const char8* s1, const ConstString& s2) {return (s2.compare (s1) == 0) ? true : false;}
inline bool operator!= (const char8* s1, const ConstString& s2) {return (s2.compare (s1) != 0) ? true : false;}

inline bool operator<  (const ConstString& s1, const char16* s2) {return (s1.compare (s2) < 0) ? true : false;}
inline bool operator<= (const ConstString& s1, const char16* s2) {return (s1.compare (s2) <= 0) ? true : false;}
inline bool operator>  (const ConstString& s1, const char16* s2) {return (s1.compare (s2) > 0) ? true : false;}
inline bool operator>= (const ConstString& s1, const char16* s2) {return (s1.compare (s2) >= 0) ? true : false;}
inline bool operator== (const ConstString& s1, const char16* s2) {return (s1.compare (s2) == 0) ? true : false;}
inline bool operator!= (const ConstString& s1, const char16* s2) {return (s1.compare (s2) != 0) ? true : false;}
inline bool operator<  (const char16* s1, const ConstString& s2) {return (s2.compare (s1) > 0) ? true : false;}
inline bool operator<= (const char16* s1, const ConstString& s2) {return (s2.compare (s1) >= 0) ? true : false;}
inline bool operator>  (const char16* s1, const ConstString& s2) {return (s2.compare (s1) < 0) ? true : false;}
inline bool operator>= (const char16* s1, const ConstString& s2) {return (s2.compare (s1) <= 0) ? true : false;}
inline bool operator== (const char16* s1, const ConstString& s2) {return (s2.compare (s1) == 0) ? true : false;}
inline bool operator!= (const char16* s1, const ConstString& s2) {return (s2.compare (s1) != 0) ? true : false;}

// The following functions will only work with European Numbers!
// (e.g. Arabic, Tibetan, and Khmer digits are not supported)
extern int32 strnatcmp8 (const char8* s1, const char8* s2, bool caseSensitive = true);
extern int32 strnatcmp16 (const char16* s1, const char16* s2, bool caseSensitive = true);
inline int32 strnatcmp (const tchar* s1, const tchar* s2, bool caseSensitive = true)
{
#ifdef UNICODE
	return strnatcmp16 (s1, s2, caseSensitive);
#else
	return strnatcmp8 (s1, s2, caseSensitive);
#endif
}

//-----------------------------------------------------------------------------
/** StringObject implements IStringResult and IString methods.
    It can therefore be exchanged with other Steinberg objects using one or both of these
interfaces.

\see String, ConstString
*/
//-----------------------------------------------------------------------------
class StringObject : public FObject, public String, public IStringResult, public IString
{
public:
//-----------------------------------------------------------------------------
	StringObject () {}
	StringObject (const char16* str, int32 n = -1, bool isTerminated = true) : String (str, n, isTerminated) {}
	StringObject (const char8* str, int32 n = -1, bool isTerminated = true) : String (str, n, isTerminated) {}
	StringObject (const StringObject& str, int32 n = -1) : String (str, n) {}
	StringObject (const String& str, int32 n = -1) : String (str, n) {}
	StringObject (const FVariant& var) : String (var) {}

	using String::operator=;

	// IStringResult ----------------------------------------------------------
	virtual void PLUGIN_API setText (const char8* text) SMTG_OVERRIDE;
	//-------------------------------------------------------------------------

	// IString-----------------------------------------------------------------
	virtual void PLUGIN_API setText8 (const char8* text) SMTG_OVERRIDE;
	virtual void PLUGIN_API setText16 (const char16* text) SMTG_OVERRIDE;

	virtual const char8* PLUGIN_API getText8 () SMTG_OVERRIDE;
	virtual const char16* PLUGIN_API getText16 () SMTG_OVERRIDE;

	virtual void PLUGIN_API take (void* s, bool _isWide) SMTG_OVERRIDE;
	virtual bool PLUGIN_API isWideString () const SMTG_OVERRIDE;
	//-------------------------------------------------------------------------

	OBJ_METHODS (StringObject, FObject)
	FUNKNOWN_METHODS2 (IStringResult, IString, FObject)
};

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fobject.h
// 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.
//-----------------------------------------------------------------------------

//------------------------------------------------------------------------
/** @file base/source/fobject.h
	Basic Object implementing FUnknown. */
//------------------------------------------------------------------------
#pragma once

#include "pluginterfaces/base/funknown.h"
#include "pluginterfaces/base/iupdatehandler.h"
//#include "base/source/basefwd.h"
#include "base/source/fdebug.h" // NEW

namespace Steinberg {

//----------------------------------

typedef FIDString FClassID;

//------------------------------------------------------------------------
// Basic FObject - implements FUnknown + IDependent
//------------------------------------------------------------------------
/** Implements FUnknown and IDependent.

FObject is a polymorphic class that implements IDependent (of SKI module)
and therefore derived from FUnknown, which is the most abstract base class of all.

All COM-like virtual methods of FUnknown such as queryInterface(), addRef(), release()
are implemented here. On top of that, dependency-related methods are implemented too.

Pointer casting is done via the template methods FCast, either FObject to FObject or
FUnknown to FObject.

FObject supports a new singleton concept, therefore these objects are deleted automatically upon program termination.

- Runtime type information: An object can be queried at runtime, of what class
it is. To do this correctly, every class must override some methods. This
is simplified by using the OBJ_METHODS macros

@see
	- FUnknown
	- IDependent
	- IUpdateHandler
*/
//------------------------------------------------------------------------
class FObject : public IDependent
{
public:
	//------------------------------------------------------------------------
	FObject () : refCount (1) {}											///< default constructor...
	FObject (const FObject&) : refCount (1) {}								///< overloaded constructor...
	virtual ~FObject () {}													///< destructor...
	FObject& operator = (const FObject&) { return *this; }					///< overloads operator "=" as the reference assignment

	// OBJECT_METHODS
	static inline FClassID getFClassID () {return "FObject";}				///< return Class ID as an ASCII string (statically)
	virtual FClassID isA () const {return FObject::getFClassID ();}			///< a local alternative to getFClassID ()
	virtual bool isA (FClassID s) const {return isTypeOf (s, false);}		///< evaluates if the passed ID is of the FObject type
	virtual bool isTypeOf (FClassID s, bool /*askBaseClass*/ = true) const {return classIDsEqual (s, FObject::getFClassID ());}
																			///< evaluates if the passed ID is of the FObject type
	int32 getRefCount () {return refCount;}									///< returns the current interface reference count
	FUnknown* unknownCast () {return this;}									///< get FUnknown interface from object

	// FUnknown
	virtual tresult PLUGIN_API queryInterface (const TUID _iid, void** obj) SMTG_OVERRIDE; ///< please refer to FUnknown::queryInterface ()
	virtual uint32 PLUGIN_API addRef () SMTG_OVERRIDE;									///< please refer to FUnknown::addref ()
	virtual uint32 PLUGIN_API release () SMTG_OVERRIDE;									///< please refer to FUnknown::release ()

	// IDependent
	virtual void PLUGIN_API update (FUnknown* /*changedUnknown*/, int32 /*message*/) SMTG_OVERRIDE {}
																			///< empty virtual method that should be overridden by derived classes for data updates upon changes
	// IDependency
	virtual void addDependent (IDependent* dep);							///< adds dependency to the object
	virtual void removeDependent (IDependent* dep);							///< removes dependency from the object
	virtual void changed (int32 msg = kChanged);							///< Inform all dependents, that the object has changed.
	virtual void deferUpdate (int32 msg = kChanged);						///< Similar to triggerUpdates, except only delivered in idle (usefull in collecting updates).
	virtual void updateDone (int32 /* msg */) {}											///< empty virtual method that should be overridden by derived classes
	virtual bool isEqualInstance (IDependent* d) {return static_cast<IDependent*> (this) == d;}

	static void setUpdateHandler (IUpdateHandler* handler) {gUpdateHandler = handler;}	///< set method for the local attribute
	static IUpdateHandler* getUpdateHandler () {return gUpdateHandler;}					///< get method for the local attribute

	// static helper functions
	static inline bool classIDsEqual (FClassID ci1, FClassID ci2);			///< compares (evaluates) 2 class IDs
	static inline FObject* unknownToObject (FUnknown* unknown);				///< pointer conversion from FUnknown to FObject

	/** Special UID that is used to cast an FUnknown pointer to a FObject */
	static const FUID iid;

//------------------------------------------------------------------------
protected:
	int32 refCount;															///< COM-model local reference count

	static IUpdateHandler* gUpdateHandler;
};

//------------------------------------------------------------------------
// conversion from FUnknown to FObject
//------------------------------------------------------------------------
inline FObject* FObject::unknownToObject (FUnknown* unknown)
{
	FObject* object = 0;
	if (unknown)
	{
		unknown->queryInterface (FObject::iid, (void**)&object);
		if (object)
			object->release (); // queryInterface has added ref
	}
	return object;
}

//------------------------------------------------------------------------
inline bool FObject::classIDsEqual (FClassID ci1, FClassID ci2)
{
	return (ci1 && ci2) ? (strcmp (ci1, ci2) == 0) : false;
}

//-----------------------------------------------------------------------
/** FCast overload 1 - FObject to FObject */
//-----------------------------------------------------------------------
template <class C>
inline C* FCast (const FObject* object)
{
	if (object && object->isTypeOf (C::getFClassID (), true))
		return (C*) object;
	return 0;
}

//-----------------------------------------------------------------------
/** FCast overload 2 - FUnknown to FObject */
//-----------------------------------------------------------------------
template <class C>
inline C* FCast (FUnknown* unknown)
{
	FObject* object = FObject::unknownToObject (unknown);
	return FCast<C> (object);
}

//-----------------------------------------------------------------------
/** FUCast - casting from FUnknown to Interface */
//-----------------------------------------------------------------------
template <class C>
inline C* FUCast (FObject* object)
{
	return FUnknownPtr<C> (object ? object->unknownCast () : 0);
}

template <class C>
inline C* FUCast (FUnknown* object)
{
	return FUnknownPtr<C> (object);
}

//------------------------------------------------------------------------
/** @name Convenience methods that call release or delete respectively
	on a pointer if it is non-zero, and then set the pointer to zero.
	Note: you should prefer using IPtr or OPtr instead of these methods
	whenever possible.
	Examples:
	@code
	~Foo ()
	{
		// instead of ...
		if (somePointer)
		{
			somePointer->release ();
			somePointer = 0;
		}
		// ... just being lazy I write
		SafeRelease (somePointer)
	}
	@endcode
*/
///@{
//-----------------------------------------------------------------------
template <class I>
inline void SafeRelease (I *& ptr)
{
	if (ptr)
	{
		ptr->release ();
		ptr = 0;
	}
}

//-----------------------------------------------------------------------
template <class I>
inline void SafeRelease (IPtr & ptr)
{
	ptr = 0;
}

//-----------------------------------------------------------------------
template <class T>
inline void SafeDelete (T *& ptr)
{
	if (ptr)
	{
		delete ptr;
		ptr = 0;
	}
}
///@}

//-----------------------------------------------------------------------
template <class T>
inline void AssignShared (T*& dest, T* newPtr)
{
	if (dest == newPtr)
		return;

	if (dest)
		dest->release ();
	dest = newPtr;
	if (dest)
		dest->addRef ();
}

//-----------------------------------------------------------------------
template <class T>
inline void AssignSharedDependent (IDependent* _this, T*& dest, T* newPtr)
{
	if (dest == newPtr)
		return;

	if (dest)
		dest->removeDependent (_this);
	AssignShared (dest, newPtr);
	if (dest)
		dest->addDependent (_this);
}

//-----------------------------------------------------------------------
template <class T>
inline void AssignSharedDependent (IDependent* _this, IPtr<T>& dest, T* newPtr)
{
	if (dest == newPtr)
		return;

	if (dest)
		dest->removeDependent (_this);
	dest = newPtr;
	if (dest)
		dest->addDependent (_this);
}

//-----------------------------------------------------------------------
template <class T>
inline void SafeReleaseDependent (IDependent* _this, T*& dest)
{
	if (dest)
		dest->removeDependent (_this);
	SafeRelease (dest);
}

//-----------------------------------------------------------------------
template <class T>
inline void SafeReleaseDependent (IDependent* _this, IPtr<T>& dest)
{
	if (dest)
		dest->removeDependent (_this);
	SafeRelease (dest);
}

//------------------------------------------------------------------------
/** Automatic creation and destruction of singleton instances. */
namespace Singleton {
	/** registers an instance (type FObject) */
	void registerInstance (FObject** o);

	/** Returns true when singleton instances were already released. */
	bool isTerminated ();

	/** lock and unlock the singleton registration for multi-threading safety */
	void lockRegister ();
	void unlockRegister ();
}

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

//-----------------------------------------------------------------------
#define SINGLETON(ClassName)	\
	static ClassName* instance (bool create = true) \
	{ \
		static Steinberg::FObject* inst = nullptr; \
		if (inst == nullptr && create && Steinberg::Singleton::isTerminated () == false) \
		{	\
			Steinberg::Singleton::lockRegister (); \
			if (inst == nullptr) \
			{ \
				inst = NEW ClassName; \
				Steinberg::Singleton::registerInstance (&inst); \
			} \
			Steinberg::Singleton::unlockRegister (); \
		}	\
		return (ClassName*)inst; \
	}

//-----------------------------------------------------------------------
#define OBJ_METHODS(className, baseClass)								\
	static inline Steinberg::FClassID getFClassID () {return (#className);}		\
	virtual Steinberg::FClassID isA () const SMTG_OVERRIDE {return className::getFClassID ();}	\
	virtual bool isA (Steinberg::FClassID s) const SMTG_OVERRIDE {return isTypeOf (s, false);}	\
	virtual bool isTypeOf (Steinberg::FClassID s, bool askBaseClass = true) const SMTG_OVERRIDE	\
    {  return (classIDsEqual (s, #className) ? true : (askBaseClass ? baseClass::isTypeOf (s, true) : false)); }

//------------------------------------------------------------------------
/** Delegate refcount functions to BaseClass.
	BaseClase must implement ref counting.
*/
//------------------------------------------------------------------------
#define REFCOUNT_METHODS(BaseClass) \
virtual Steinberg::uint32 PLUGIN_API addRef ()SMTG_OVERRIDE{ return BaseClass::addRef (); } \
virtual Steinberg::uint32 PLUGIN_API release ()SMTG_OVERRIDE{ return BaseClass::release (); }

//------------------------------------------------------------------------
/** @name Macros to implement FUnknown::queryInterface ().

	Examples:
	@code
	class Foo : public FObject, public IFoo2, public IFoo3
	{
	    ...
		DEFINE_INTERFACES
	        DEF_INTERFACE (IFoo2)
	        DEF_INTERFACE (IFoo3)
	    END_DEFINE_INTERFACES (FObject)
	    REFCOUNT_METHODS(FObject)
	    // Implement IFoo2 interface ...
	    // Implement IFoo3 interface ...
	    ...
	};
	@endcode
*/
///@{
//------------------------------------------------------------------------
/** Start defining interfaces. */
//------------------------------------------------------------------------
#define DEFINE_INTERFACES \
Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID iid, void** obj) SMTG_OVERRIDE \
{

//------------------------------------------------------------------------
/** Add a interfaces. */
//------------------------------------------------------------------------
#define DEF_INTERFACE(InterfaceName) \
	QUERY_INTERFACE (iid, obj, InterfaceName::iid, InterfaceName)

//------------------------------------------------------------------------
/** End defining interfaces. */
//------------------------------------------------------------------------
#define END_DEFINE_INTERFACES(BaseClass) \
	return BaseClass::queryInterface (iid, obj); \
}
///@}

//------------------------------------------------------------------------
/** @name Convenient macros to implement Steinberg::FUnknown::queryInterface ().
	Examples:
	@code
	class Foo : public FObject, public IFoo2, public IFoo3
	{
	    ...
	    DEF_INTERFACES_2(IFoo2,IFoo3,FObject)
	    REFCOUNT_METHODS(FObject)
	    ...
	};
	@endcode
*/
///@{
//------------------------------------------------------------------------
#define DEF_INTERFACES_1(InterfaceName,BaseClass) \
DEFINE_INTERFACES \
DEF_INTERFACE (InterfaceName) \
END_DEFINE_INTERFACES (BaseClass)

//------------------------------------------------------------------------
#define DEF_INTERFACES_2(InterfaceName1,InterfaceName2,BaseClass) \
DEFINE_INTERFACES \
DEF_INTERFACE (InterfaceName1) \
DEF_INTERFACE (InterfaceName2) \
END_DEFINE_INTERFACES (BaseClass)

//------------------------------------------------------------------------
#define DEF_INTERFACES_3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
DEFINE_INTERFACES \
DEF_INTERFACE (InterfaceName1) \
DEF_INTERFACE (InterfaceName2) \
DEF_INTERFACE (InterfaceName3) \
END_DEFINE_INTERFACES (BaseClass)

//------------------------------------------------------------------------
#define DEF_INTERFACES_4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
	DEFINE_INTERFACES \
	DEF_INTERFACE (InterfaceName1) \
	DEF_INTERFACE (InterfaceName2) \
	DEF_INTERFACE (InterfaceName3) \
	DEF_INTERFACE (InterfaceName4) \
	END_DEFINE_INTERFACES (BaseClass)
///@}

//------------------------------------------------------------------------
/** @name Convenient macros to implement Steinberg::FUnknown methods.
	Examples:
	@code
	class Foo : public FObject, public IFoo2, public IFoo3
	{
	    ...
	    FUNKNOWN_METHODS2(IFoo2,IFoo3,FObject)
	    ...
	};
	@endcode
*/
///@{
#define FUNKNOWN_METHODS(InterfaceName,BaseClass) \
DEF_INTERFACES_1(InterfaceName,BaseClass) \
REFCOUNT_METHODS(BaseClass)

#define FUNKNOWN_METHODS2(InterfaceName1,InterfaceName2,BaseClass) \
DEF_INTERFACES_2(InterfaceName1,InterfaceName2,BaseClass) \
REFCOUNT_METHODS(BaseClass)

#define FUNKNOWN_METHODS3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
DEF_INTERFACES_3(InterfaceName1,InterfaceName2,InterfaceName3,BaseClass) \
REFCOUNT_METHODS(BaseClass)

#define FUNKNOWN_METHODS4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
DEF_INTERFACES_4(InterfaceName1,InterfaceName2,InterfaceName3,InterfaceName4,BaseClass) \
REFCOUNT_METHODS(BaseClass)
///@}

//------------------------------------------------------------------------
//------------------------------------------------------------------------
#if COM_COMPATIBLE
//------------------------------------------------------------------------
/** @name Macros to implement IUnknown interfaces with FObject.
	Examples:
	@code
	class MyEnumFormat : public FObject, IEnumFORMATETC
	{
	    ...
		COM_UNKNOWN_METHODS (IEnumFORMATETC, IUnknown)
	    ...
	};
	@endcode
*/
///@{
//------------------------------------------------------------------------
#define IUNKNOWN_REFCOUNT_METHODS(BaseClass) \
STDMETHOD_ (ULONG, AddRef) (void) {return BaseClass::addRef ();} \
STDMETHOD_ (ULONG, Release) (void) {return BaseClass::release ();}

//------------------------------------------------------------------------
#define COM_QUERY_INTERFACE(iid, obj, InterfaceName)     \
if (riid == __uuidof(InterfaceName))                     \
{                                                        \
	addRef ();                                           \
	*obj = (InterfaceName*)this;                         \
	return kResultOk;                                    \
}

//------------------------------------------------------------------------
#define COM_OBJECT_QUERY_INTERFACE(InterfaceName,BaseClass)        \
STDMETHOD (QueryInterface) (REFIID riid, void** object)            \
{                                                                  \
	COM_QUERY_INTERFACE (riid, object, InterfaceName)              \
	return BaseClass::queryInterface ((FIDString)&riid, object);   \
}

//------------------------------------------------------------------------
#define COM_UNKNOWN_METHODS(InterfaceName,BaseClass) \
COM_OBJECT_QUERY_INTERFACE(InterfaceName,BaseClass) \
IUNKNOWN_REFCOUNT_METHODS(BaseClass)
///@}

#endif // COM_COMPATIBLE


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/timer.cpp
// Created by  : Steinberg, 05/2006
// Description : Timer class for receiving triggers at regular intervals
//
//-----------------------------------------------------------------------------
// 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/timer.h"

namespace Steinberg {
static bool timersEnabled = true;

//------------------------------------------------------------------------
DisableDispatchingTimers::DisableDispatchingTimers ()
{
	oldState = timersEnabled;
	timersEnabled = false;
}

//------------------------------------------------------------------------
DisableDispatchingTimers::~DisableDispatchingTimers ()
{
	timersEnabled = oldState;
}

//------------------------------------------------------------------------
namespace SystemTime {

//------------------------------------------------------------------------
struct ZeroStartTicks
{
	static const uint64 startTicks;

	static int32 getTicks32 ()
	{
		return static_cast<int32> (SystemTime::getTicks64 () - startTicks);
	}
};
const uint64 ZeroStartTicks::startTicks = SystemTime::getTicks64 ();

//------------------------------------------------------------------------
int32 getTicks ()
{
	return ZeroStartTicks::getTicks32 ();
}

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

#if MAC
#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach_time.h>

#ifdef verify
#undef verify
#endif

namespace Steinberg {

namespace SystemTime {
	struct MachTimeBase {
	private:
		struct mach_timebase_info timebaseInfo;

		MachTimeBase ()
		{
			mach_timebase_info (&timebaseInfo);
		}

		static const MachTimeBase& instance ()
		{
			static MachTimeBase gInstance;
			return gInstance;
		}
	public:
		static double getTimeNanos ()
		{
			const MachTimeBase& timeBase = instance ();
			double absTime = static_cast<double> (mach_absolute_time ());
			double d = (absTime / timeBase.timebaseInfo.denom) * timeBase.timebaseInfo.numer;	// nano seconds
			return d;
		}
	};

	//------------------------------------------------------------------------
	uint64 getTicks64 ()
	{
		return static_cast<uint64> (MachTimeBase::getTimeNanos () / 1000000.);
	}
} // namespace SystemTime

//------------------------------------------------------------------------
class MacPlatformTimer : public Timer
{
public:
	MacPlatformTimer (ITimerCallback* callback, uint32 milliseconds);
	~MacPlatformTimer ();

	void stop ();
	bool verify () const { return platformTimer != 0; }

	static void timerCallback (CFRunLoopTimerRef timer, void *info);
protected:
	CFRunLoopTimerRef platformTimer;
	ITimerCallback* callback;
};

//------------------------------------------------------------------------
MacPlatformTimer::MacPlatformTimer (ITimerCallback* callback, uint32 milliseconds)
: platformTimer (0)
, callback (callback)
{
	if (callback)
	{
		CFRunLoopTimerContext timerContext = {0};
		timerContext.info = this;
		platformTimer = CFRunLoopTimerCreate (kCFAllocatorDefault, CFAbsoluteTimeGetCurrent () + milliseconds * 0.001, milliseconds * 0.001f, 0, 0, timerCallback, &timerContext);
		if (platformTimer)
			CFRunLoopAddTimer (CFRunLoopGetMain (), platformTimer, kCFRunLoopCommonModes);
	}
}

//------------------------------------------------------------------------
MacPlatformTimer::~MacPlatformTimer ()
{
	stop ();
}

//------------------------------------------------------------------------
void MacPlatformTimer::stop ()
{
	if (platformTimer)
	{
		CFRunLoopRemoveTimer (CFRunLoopGetMain (), platformTimer, kCFRunLoopCommonModes);
		CFRelease (platformTimer);
		platformTimer = 0;
	}
}

//------------------------------------------------------------------------
void MacPlatformTimer::timerCallback (CFRunLoopTimerRef , void *info)
{
	if (timersEnabled)
	{
		MacPlatformTimer* timer = (MacPlatformTimer*)info;
		if (timer)
		{
			timer->callback->onTimer (timer);
		}
	}
}

//------------------------------------------------------------------------
Timer* Timer::create (ITimerCallback* callback, uint32 milliseconds)
{
	MacPlatformTimer* timer = NEW MacPlatformTimer (callback, milliseconds);
	if (timer->verify ())
		return timer;
	timer->release ();
	return 0;
}

}

#elif WINDOWS

#include <windows.h>
#include <list>
#include <algorithm>

namespace Steinberg {
namespace SystemTime {
/*
    @return the current system time in milliseconds
*/
uint64 getTicks64 ()
{
	return GetTickCount64 ();
}
}

class WinPlatformTimer;
typedef std::list<WinPlatformTimer*> WinPlatformTimerList;

//------------------------------------------------------------------------
// WinPlatformTimer
//------------------------------------------------------------------------
class WinPlatformTimer : public Timer
{
public:
//------------------------------------------------------------------------
	WinPlatformTimer (ITimerCallback* callback, uint32 milliseconds);
	~WinPlatformTimer ();

	void stop ();
	bool verify () const {return id != 0;}

//------------------------------------------------------------------------
private:
	UINT_PTR id;
	ITimerCallback* callback;

	static void addTimer (WinPlatformTimer* t);
	static void removeTimer (WinPlatformTimer* t);

	static void CALLBACK TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
	static WinPlatformTimerList* timers;
};

//------------------------------------------------------------------------
WinPlatformTimerList* WinPlatformTimer::timers = 0;

//------------------------------------------------------------------------
WinPlatformTimer::WinPlatformTimer (ITimerCallback* callback, uint32 milliseconds)
: callback (callback)
{
	id = SetTimer (0, 0, milliseconds, TimerProc);
	if (id)
		addTimer (this);
}

//------------------------------------------------------------------------
WinPlatformTimer::~WinPlatformTimer ()
{
	stop ();
}

//------------------------------------------------------------------------
void WinPlatformTimer::addTimer (WinPlatformTimer* t)
{
	if (timers == 0)
		timers = NEW WinPlatformTimerList;
	timers->push_back (t);
}

//------------------------------------------------------------------------
void WinPlatformTimer::removeTimer (WinPlatformTimer* t)
{
	if (!timers)
		return;

	WinPlatformTimerList::iterator it = std::find (timers->begin (), timers->end (), t);
	if (it != timers->end ())
		timers->erase (it);
	if (timers->empty ())
	{
		delete timers;
		timers = 0;
	}
}

//------------------------------------------------------------------------
void WinPlatformTimer::stop ()
{
	if (!id)
		return;

	KillTimer (0, id);
	removeTimer (this);
	id = 0;
}

//------------------------------------------------------------------------
void CALLBACK WinPlatformTimer::TimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
	if (timersEnabled && timers)
	{
		WinPlatformTimerList::const_iterator it = timers->cbegin ();
		while (it != timers->cend ())
		{
			WinPlatformTimer* timer = *it;
			if (timer->id == idEvent)
			{
				if (timer->callback)
					timer->callback->onTimer (timer);
				return;
			}
		}
	}
}

//------------------------------------------------------------------------
Timer* Timer::create (ITimerCallback* callback, uint32 milliseconds)
{
	WinPlatformTimer* platformTimer = NEW WinPlatformTimer (callback, milliseconds);
	if (platformTimer->verify ())
		return platformTimer;
	platformTimer->release ();
	return 0;
}

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

#elif LINUX
#warning DEPRECATED No Linux implementation
#endif


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fdebug.cpp
// Created by  : Steinberg, 1995
// Description : There are 2 levels of debugging messages:
//	             DEVELOPMENT               During development
//	             RELEASE                   Program is shipping.
//
//-----------------------------------------------------------------------------
// 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/fdebug.h"

#if DEVELOPMENT

#include <cstdio>
#include <cstdarg>

#if WINDOWS
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#include <windows.h>
#include <intrin.h>
#define vsnprintf _vsnprintf

#elif MAC
#include <mach/mach_time.h>
#include <mach/mach_init.h>
#include <errno.h>
#include <new>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <signal.h>

static bool AmIBeingDebugged (void);

#define THREAD_ALLOC_WATCH 0		// check allocations on specific threads

	#if THREAD_ALLOC_WATCH
		mach_port_t watchThreadID = 0;
	#endif

#endif

AssertionHandler gAssertionHandler = 0;

//--------------------------------------------------------------------------
static const int kDebugPrintfBufferSize = 10000;
static bool neverDebugger = false;	// so I can switch it off in the debugger...

//--------------------------------------------------------------------------
static void printDebugString (const char* string)
{
	if (!string)
		return;

	#if MAC
	fprintf (stderr, "%s", string);

	#elif WINDOWS
	OutputDebugStringA (string);
	#endif
}

//--------------------------------------------------------------------------
//	printf style debugging output
//--------------------------------------------------------------------------
void FDebugPrint (const char *format, ...)
{
	char string[kDebugPrintfBufferSize];
	va_list marker;
	va_start (marker, format);
	vsnprintf (string, kDebugPrintfBufferSize, format, marker);

	printDebugString (string);
}

#if WINDOWS
#define AmIBeingDebugged IsDebuggerPresent
#endif

#if LINUX
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
//--------------------------------------------------------------------------
static inline bool AmIBeingDebugged ()
{
// TODO: check if GDB or LLDB is attached
	return true;
}
#endif

//--------------------------------------------------------------------------
//	printf style debugging output
//--------------------------------------------------------------------------
void FDebugBreak (const char *format, ...)
{
	char string[kDebugPrintfBufferSize];
	va_list marker;
	va_start (marker, format);
	vsnprintf (string, kDebugPrintfBufferSize, format, marker);

	printDebugString (string);

	if (neverDebugger)
		return;
	if (AmIBeingDebugged ())
	{
		// do not crash if no debugger present
		// If there  is an assertion handler defined then let this override the UI
		// and tell us whether we want to break into the debugger
		bool breakIntoDebugger = true;
		if (gAssertionHandler && gAssertionHandler (string) == false)
		{
			breakIntoDebugger = false;
		}

		if (breakIntoDebugger)
		{
#if WINDOWS
			__debugbreak (); // intrinsic version of DebugBreak()
#elif __ppc64__ || __ppc__ || __arm__
			kill (getpid (), SIGINT);
#elif __i386__ || __x86_64__
			{ __asm__ volatile ("int3"); }
#endif
		}
	}
}

//--------------------------------------------------------------------------
void FPrintLastError (const char* file, int line)
{
	#if WINDOWS
	LPVOID lpMessageBuffer;
	FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(LPSTR) &lpMessageBuffer, 0, NULL);
	FDebugPrint ("%s(%d) : %s\n", file, line, lpMessageBuffer);
	LocalFree (lpMessageBuffer);
	#endif

	#if MAC
		#if !__MACH__
		extern int errno;
		#endif
	FDebugPrint ("%s(%d) : Errno %d\n", file, line, errno);
	#endif
}

#if MAC

//------------------------------------------------------------------------
void* operator new (size_t size, int, const char *file, int line)
{
	#if THREAD_ALLOC_WATCH
	mach_port_t threadID = mach_thread_self ();
	if (watchThreadID == threadID)
	{
		FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
	}
	#endif
	try {
	return ::operator new (size);
	} catch (std::bad_alloc exception) { FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line); }
	return (void*)-1;
}

//------------------------------------------------------------------------
void* operator new [](size_t size, int, const char *file, int line)
{
	#if THREAD_ALLOC_WATCH
	mach_port_t threadID = mach_thread_self ();
	if (watchThreadID == threadID)
	{
		FDebugPrint ("Watched Thread Allocation : %s (Line:%d)\n", file ? file : "Unknown", line);
	}
	#endif
	try {
	return ::operator new [](size);
	} catch (std::bad_alloc exception) { FDebugPrint ("bad_alloc exception : %s (Line:%d)", file ? file : "Unknown", line);}
	return (void*)-1;
}

//------------------------------------------------------------------------
void operator delete(void* p, int, const char *file, int line)
{
    ::operator delete (p);
}

//------------------------------------------------------------------------
void operator delete[](void* p, int, const char *file, int line)
{
    ::operator delete[] (p);
}

//------------------------------------------------------------------------
// from Technical Q&A QA1361 (http://developer.apple.com/qa/qa2004/qa1361.html)
//------------------------------------------------------------------------
bool AmIBeingDebugged(void)
    // Returns true if the current process is being debugged (either
    // running under the debugger or has a debugger attached post facto).
{
    int                 mib[4];
    struct kinfo_proc   info;
    size_t              size;

    // Initialize the flags so that, if sysctl fails for some bizarre
    // reason, we get a predictable result.

    info.kp_proc.p_flag = 0;

    // Initialize mib, which tells sysctl the info we want, in this case
    // we're looking for information about a specific process ID.

    mib[0] = CTL_KERN;
    mib[1] = KERN_PROC;
    mib[2] = KERN_PROC_PID;
    mib[3] = getpid();

    // Call sysctl.

    size = sizeof(info);
    sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);

    // We're being debugged if the P_TRACED flag is set.

    return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
}

#endif // MAC

#endif // DEVELOPMENT


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/timer.h
// Created by  : Steinberg, 05/2006
// Description : Timer class for receiving tiggers at regular intervals
//
//-----------------------------------------------------------------------------
// 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 "fobject.h"
#include <limits>

namespace Steinberg {
class Timer;

//------------------------------------------------------------------------
namespace SystemTime {

uint64 getTicks64 ();

inline uint64 getTicksDuration (uint64 old, uint64 now)
{
	if (old > now)
		return (std::numeric_limits<uint64>::max) () - old + now;
	return now - old;
}

int32 getTicks (); ///< deprecated, use getTicks64 ()

//------------------------------------------------------------------------
} // SystemTime

//------------------------------------------------------------------------
/** @class ITimerCallback

    Implement this callback interface to receive triggers from a timer.
    Note: This interface is intended as a mix-in class and therefore does not provide refcounting.

    @see Timer */
//------------------------------------------------------------------------
class ITimerCallback
{
public:
	virtual ~ITimerCallback () {}
	/** This method is called at the end of each interval.

	    \param timer The timer which calls.
	*/
	virtual void onTimer (Timer* timer) = 0;
};

template <typename Call>
ITimerCallback* newTimerCallback (const Call& call)
{
	struct Callback : public ITimerCallback
	{
		Callback (const Call& call) : call (call) {}
		void onTimer (Timer* timer) SMTG_OVERRIDE { call (timer); }
		Call call;
	};
	return NEW Callback (call);
}

// -----------------------------------------------------------------
/** @class Timer

    Timer is a class that allows you to receive triggers at regular intervals.

    Note: The timer class is an abstract base class with (hidden) platform specific subclasses.

    Usage:
    @code
    class TimerReceiver : public FObject, public ITimerCallback
    {
        ...
        virtual void onTimer (Timer* timer)
        {
            // do stuff
        }
        ...
    };

    TimerReceiver* receiver =  new TimerReceiver ();
    Timer* myTimer = Timer::create (receiver, 100); // interval: every 100ms

    ...
    ...

    if (myTimer)
        myTimer->release ();
    if (receiver)
        receiver->release ();
    @endcode

    @see ITimerCallback
    */
// -----------------------------------------------------------------
class Timer : public FObject
{
public:
	/** Create a timer with a given interval
	    \param callback The receiver of the timer calls.
	    \param intervalMilliseconds The timer interval in milliseconds.
	    \return The created timer if any, callers owns the timer. The timer starts immediately.
	*/
	static Timer* create (ITimerCallback* callback, uint32 intervalMilliseconds);

	virtual void stop () = 0; ///< Stop the timer.
};

// -----------------------------------------------------------------
/** @class DisableDispatchingTimers

    Disables dispatching of timers for the live time of this object

    */
// -----------------------------------------------------------------
class DisableDispatchingTimers
{
public:
	DisableDispatchingTimers ();
	~DisableDispatchingTimers ();

private:
	bool oldState;
};

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


text:
//------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category    : Helpers
// Filename    : base/source/fdynlib.h
// 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.
//-----------------------------------------------------------------------------

//------------------------------------------------------------------------
/** @file base/source/fdynlib.h
	Platform independent dynamic library loading. */
//------------------------------------------------------------------------
#pragma once

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

namespace Steinberg {

//------------------------------------------------------------------------
/** Platform independent dynamic library loader. */
//------------------------------------------------------------------------
class FDynLibrary : public FObject
{
public:
//------------------------------------------------------------------------
	/** Constructor.

		Loads the specified dynamic library.

		@param[in] name the path of the library to load.
		@param[in] addExtension if @c true append the platform dependent default extension to @c name.

		@remarks
		- If @c name specifies a full path, the FDynLibrary searches only that path for the library.
		- If @c name specifies a relative path or a name without path,
		  FDynLibrary uses a standard search strategy of the current platform to find the library;
		- If @c name is @c NULL the library is not loaded.
		  - Use init() to load the library. */
	FDynLibrary (const tchar* name = 0, bool addExtension = true);

	/** Destructor.
		The destructor unloads the library.*/
	~FDynLibrary ();

	/** Loads the library if not already loaded.
		This function is normally called by FDynLibrary().
		@remarks If the library is already loaded, this call has no effect. */
	bool init (const tchar* name, bool addExtension = true);

	/** Returns the address of the procedure @c name */
	void* getProcAddress (const char* name);

	/** Returns true when the library was successfully loaded. */
	bool isLoaded () {return isloaded;}

	/** Unloads the library if it is loaded.
		This function is called by ~FDynLibrary (). */
	bool unload ();

	/** Returns the platform dependent representation of the library instance. */
	void* getPlatformInstance () const { return instance; }

#if MAC
	/** Returns @c true if the library is a bundle (Mac only). */
	bool isBundleLib () const {return isBundle;}
#endif

//------------------------------------------------------------------------
	OBJ_METHODS(FDynLibrary, FObject)
protected:
	bool isloaded;

	void* instance;

#if MAC
	void* firstSymbol;
	bool isBundle;
#endif
};

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


text:
//-------------------------------------------------------------------------------------
// Project     : SDK Base
// Version     : 1.0
//
// Category	   : Helpers
// Filename	   : base/source/hexbinary.h
// Created by  : Steinberg, 1/2012
// Description : HexBinary encoding and decoding
//
//-----------------------------------------------------------------------------
// 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/hexbinary.h
 HexBinary encoding and decoding. */
//----------------------------------------------------------------------------------
#pragma once

#include "base/source/fbuffer.h"

namespace Steinberg {

//------------------------------------------------------------------------------
namespace HexBinary
{
	//------------------------------------------------------------------------------
	/** convert the HexBinary input buffer to binary. Note that it is appended to the result buffer. */
	//------------------------------------------------------------------------------
	inline bool decode (const void* input, int32 inputSize, Buffer& result)
	{
		if ((inputSize & 1) == 1)
			return false;

		result.grow (result.getSize () + inputSize / 2);

		const char8* ptr = (const char8*)input;
		uint8 current = 0;
		for (int32 i = 0; i < inputSize; i++, ptr++)
		{
			current *= 16;
			if (*ptr >= 48 && *ptr <= 57) // 0, 1, 2, .., 9
			{
				current += *ptr - 48;
			}
			else if (*ptr >= 65 && *ptr <= 70) // A, B, .., F
			{
				current += *ptr - 55;
			}
			else if (*ptr >= 97 && *ptr <= 102) // a, b, .., f
			{
				current += *ptr - 87;
			}
			else
			{
				// malformed
				return false;
			}
			if (i % 2)
			{
				if (result.put (current) == false)
					return false;
				current = 0;
			}
		}
		return true;
	}

	//------------------------------------------------------------------------------
	/** convert the binary input buffer to HexBinary. Note that it is appended to the result buffer. */
	//------------------------------------------------------------------------------
	inline bool encode (const void* input, int32 inputSize, Buffer& result)
	{
		result.grow (result.getSize () + inputSize * 2);

		const char8* ptr = (const char8*)input;
		for (int32 i = 0; i < inputSize; i++, ptr++)
		{
			char8 high = (*ptr & 0xF0) >> 4;
			char8 low  = (*ptr & 0x0F);
			if (high > 9)
			{
				if (result.put ((char8)(high + 55)) == false)
					return false;
			}
			else
			{
				if (result.put ((char8)(high + 48)) == false)
					return false;
			}
			if (low > 9)
			{
				if (result.put ((char8)(low + 55)) == false)
					return false;
			}
			else
			{
				if (result.put ((char8)(low + 48)) == false)
					return false;
			}
		}
		return true;
	}
//------------------------------------------------------------------------
} // namespace HexBinary
} // namespace Steinberg