#if !defined(BRMEMMGR_H) && !defined(__BEDRC__)
#define BRMEMMGR_H
//========================================================================================
//
//     File:		BRMemMgr.h
//     Release Version:	$ 1.0d1 $
//
//     Creation Date:	10/1/92
//
//     COPYRIGHT 1992-93 SYMANTEC CORPORATION. ALL RIGHTS RESERVED. UNPUBLISHED -- RIGHTS
//     RESERVED UNDER THE COPYRIGHT LAWS OF THE UNITED STATES. USE OF COPYRIGHT NOTICE IS
//     PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION OR DISCLOSURE.
//
//     THIS SOFTWARE CONTAINS PROPRIETARY AND CONFIDENTIAL INFORMATION OF SYMANTEC
//     CORPORATION. USE, DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
//     EXPRESS WRITTEN PERMISSION OF SYMANTEC CORPORATION.
//
//     RESTRICTED RIGHTS LEGEND
//     Use, duplication, or disclosure by the Government is subject to restrictions as set
//     forth in subparagraph (c)(l)(ii) of the Rights in Technical Data and Computer
//     Software clause at DFARS 252.227-7013. Symantec Corporation, 10201 Torre Avenue,
//     Cupertino, CA 95014.
//
//========================================================================================

#include <stddef.h>

#ifndef BRSTDDEF_H
#include "BRStdDef.h"
#endif

#ifndef BRAUTODE_H
#include "BRAutoDe.h"
#endif

#ifndef   BRVIRMEM_H
#include "BRVM.h"
#endif

#ifndef BREXCLIB_H
#include "BRExcLib.h"
#endif

#ifndef   BRBEDEXC_H
#include "BRBedExc.h"
#endif

#if defined(BR_BUILD_MAC) && !defined(__MEMORY__)
#include <Memory.h>
#endif


//========================================================================================
// Type definitions
//========================================================================================

typedef void (*BR_PFVV)();	
	// Pointer to function returning void.
	// Used with set_new_handler.  See ARM, pp 280-81.

//========================================================================================
// Global procedure definitions
//========================================================================================

#ifdef __BORLANDC__
  void*   cdecl operator new(size_t size);
  void    cdecl operator delete(void* block);
#else
  void*         operator new(size_t size);
  void          operator delete(void* block);
#endif

BR_PFVV set_new_handler(BR_PFVV handler);
	// See ARM, pp 280-81.

#ifdef BR_BUILD_MAC
pascal long MacGrowZoneProc(Size /* cbNeeded */);
#endif


//========================================================================================
// CLASS BR_CMemoryManager -  (NOTE: See Work in progress notes below)
//========================================================================================

// Work in progress notes
// ----------------------
// This class provides a flat procedural API in a package, whose sole purpose is to allow
// the use of the Bedrock Utility Memory Manager API, but with BR_XMemory exceptions 
// thrown when appropriate.  The choice of a flat procedural API packaged in a manager is 
// not necessarily the fRight approach to use, and may disappear in the near future.
// fApplication developers are encouraged to refrain from using this interface if at all
// possible.  The preferred interface is simply C++ operator new and delete.

class BR_CMemoryManager		
{
public:

	// Utility routines for manipulating blocks of fMemory
	static void				CopyMemory(const void *const source, 
									   void *const destination, 
									   unsigned long bytesToMove);
	static void				SetMemory(void *aBlock,
									  unsigned long bytesToSet,
									  unsigned char byteValue);
	static void *			AddOffsetToPointer(void * pointer, unsigned long Offset);

	// when resizable, pointer-based blocks are needed:
	static void			   *AllocateBlock(unsigned long bytesRequested);
	static void 		   *ResizeBlock(void *aBlock, unsigned long bytesRequested);
	static void				FreeBlock(void *aBlock);
	static unsigned long	GetBlockSize(void *aBlock);

	// when platform specific handles are needed:
	static BR_PlatformHandle 	AllocateSystemHandle(unsigned long bytesRequested);
	static void 			ResizeSystemHandle(BR_PlatformHandle aHandle, 
											   unsigned long bytesRequested);
	static void				FreeSystemHandle(BR_PlatformHandle aHandle);
	static void			   *LockSystemHandle(BR_PlatformHandle aHandle);
	static void				UnlockSystemHandle(BR_PlatformHandle aHandle);
	static unsigned long	GetSystemHandleSize(BR_PlatformHandle aHandle);
	static BR_PlatformHandle		CopySystemHandle(BR_PlatformHandle aHandle);

	//internal methods
	// when resizable, pointer-based blocks are needed, no BR_DEBUG checking:
	static void			   *PrimitiveAllocateBlock(unsigned long bytesRequested);
	static void 		   *PrimitiveResizeBlock(void *aBlock, unsigned long bytesRequested);
	static void				PrimitiveFreeBlock(void *aBlock);
	static unsigned long	PrimitiveGetBlockSize(void *aBlock);

	// For BR_CMemDebug processing of fMemory blocks
	static void				PreResizeBlock(void *&aBlock);
	static void				PostResizeBlock(void *&aBlock);
	static void				InitializeRawBlock(void *aBlock, unsigned long sizeBlock);

private:
	BR_CMemoryManager() {};	// abstract class.  Note that all methods are statics.
	
};

//========================================================================================
// CLASS BR_XMemoryExhausted
//
//	An exception class for free store exhausted errors.
//========================================================================================

// Work In Progress: ???JEL
// Some names are too long.  I suggest the following name changes:
//
//		fSizeRequestedAvailability -> fHasSizeRequested
//		SizeRequestedAvailability -> BR_Boolean
//
//	See the inline for BR_XMemoryExhausted::HasSizeRequested below

class BR_XMemoryExhausted : public BR_XBedException
{
public:
	enum SizeRequestedAvailability
	{
		kSizeRequestedNotAvailable,
		kSizeRequestedAvailable
	};
	BR_XMemoryExhausted();
	BR_XMemoryExhausted(unsigned long requestedSize);
	virtual ~BR_XMemoryExhausted();
	unsigned long GetRequestedSize() const;
	SizeRequestedAvailability HasSizeRequested() const;

	_BR_EXCEPTION_DEFINE(BR_XMemoryExhausted);
private:
	const unsigned long fRequestedSize;
	const SizeRequestedAvailability fSizeRequestedAvailability;
};

//========================================================================================
// BR_XMemoryExhausted inline member functions
//========================================================================================

//----------------------------------------------------------------------------------------
//	BR_XMemoryExhausted::BR_XMemoryExhausted
//----------------------------------------------------------------------------------------

inline BR_XMemoryExhausted::BR_XMemoryExhausted() :
	BR_XBedException(),
	fSizeRequestedAvailability(kSizeRequestedNotAvailable),
	fRequestedSize(0)
{
}

//----------------------------------------------------------------------------------------
//	BR_XMemoryExhausted::BR_XMemoryExhausted
//----------------------------------------------------------------------------------------

inline BR_XMemoryExhausted::BR_XMemoryExhausted(unsigned long requestedSize) :
	BR_XBedException(),
	fSizeRequestedAvailability(kSizeRequestedAvailable),
	fRequestedSize(requestedSize)
{
}

//----------------------------------------------------------------------------------------
//	BR_XMemoryExhausted::GetRequestedSize
//----------------------------------------------------------------------------------------

inline unsigned long BR_XMemoryExhausted::GetRequestedSize() const
{
	return fRequestedSize;
}

//----------------------------------------------------------------------------------------
//	BR_XMemoryExhausted::HasSizeRequested
//----------------------------------------------------------------------------------------

inline BR_XMemoryExhausted::SizeRequestedAvailability BR_XMemoryExhausted::HasSizeRequested() const
{
	return fSizeRequestedAvailability;
}

//========================================================================================
// CLASS BR_CAcquireLockedSystemHandle
//
//	A resource acquisition helper object for locking a system handle within a scope.
//========================================================================================

class BR_CAcquireLockedSystemHandle : public _BR_CAutoDestructObject
{
public:
	BR_CAcquireLockedSystemHandle(BR_PlatformHandle aSystemHandle);
	virtual ~BR_CAcquireLockedSystemHandle();
	char *const GetPointer() const;
private:
	BR_PlatformHandle	fLockedSystemHandle;
	char *const 	fLockedPointer;
};

//========================================================================================
// CLASS BR_CAcquireTemporarySystemHandle
//
//	A resource acquisition helper object for allocating and locking a system handle
//  within a scope.  You can transfer ownership of the handle by setting fFree to FALSE.
//========================================================================================

class BR_CAcquireTemporarySystemHandle : public _BR_CAutoDestructObject
{
public:
	BR_CAcquireTemporarySystemHandle(unsigned long size);
	virtual ~BR_CAcquireTemporarySystemHandle();

	BR_PlatformHandle fTemporarySystemHandle;
	void *fMemoryPointer;

	BR_Boolean fFree;						// If TRUE, the dtor will free the fMemory
};



//========================================================================================
// BR_CMemoryManager inline member functions
//========================================================================================

#ifdef BR_BUILD_MAC
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::AddOffsetToPointer
//----------------------------------------------------------------------------------------

inline void *BR_CMemoryManager::AddOffsetToPointer(void *pointer, unsigned long Offset)
{
	return (void *)((char *)pointer + Offset);
}
#endif

#ifndef USENATIVEALLOC
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveAllocateBlock
//----------------------------------------------------------------------------------------

inline void*  BR_CMemoryManager::PrimitiveAllocateBlock(unsigned long n)
{
	return ::BR_VMNonRelocatableAllocate((long) n);
}
#endif

#ifndef USENATIVEALLOC
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveResizeBlock
//----------------------------------------------------------------------------------------

inline void*  BR_CMemoryManager::PrimitiveResizeBlock(void* p, unsigned long n)
{
	return ::BR_VMNonRelocatableResizeMove(p, (long) n);
}
#endif

#ifndef USENATIVEALLOC
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveGetBlockSize
//----------------------------------------------------------------------------------------

inline unsigned long  BR_CMemoryManager::PrimitiveGetBlockSize(void* p)
{
	return ::BR_VMNonRelocatableGetSize(p);
}
#endif

#ifndef USENATIVEALLOC
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::AddOffsetToPointer
//----------------------------------------------------------------------------------------

inline void   BR_CMemoryManager::PrimitiveFreeBlock(void* p)
{
	if (p) ::BR_VMNonRelocatableFree(p);
}
#endif

#if defined(BR_BUILD_MAC) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveAllocateBlock
//----------------------------------------------------------------------------------------

inline void*  BR_CMemoryManager::PrimitiveAllocateBlock(unsigned long n)
{
	return ::NewPtr((long) n);
}
#endif

#if defined(BR_BUILD_MAC) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveAllocateBlock
//----------------------------------------------------------------------------------------

inline void*  BR_CMemoryManager::PrimitiveResizeBlock(void* p, unsigned long n)
{
	// We're probably dreaming to think this will inline ... ???JEL
	void *q = p;
	::SetPtrSize((Ptr) q, n);
	if (MemError() != noErr)
	{
		q = PrimitiveAllocateBlock(n);
		if (q)
		{
			CopyMemory(p, q, n);
			PrimitiveFreeBlock(p);
		}
	}
	return q;
}
#endif

#if defined(BR_BUILD_MAC) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveAllocateBlock
//----------------------------------------------------------------------------------------

inline unsigned long  BR_CMemoryManager::PrimitiveGetBlockSize(void* p)
{
	return ::GetPtrSize(p);
}
#endif

#if defined(BR_BUILD_MAC) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveAllocateBlock
//----------------------------------------------------------------------------------------

inline void   BR_CMemoryManager::PrimitiveFreeBlock(void* p)
{
	if (p) ::DisposPtr(p);
}
#endif

#if defined(BR_BUILD_WIN) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// GetPointer
//
//	???JEL If we could use Windows.h and WindowsX.h, we could use Microsoft's macros
//----------------------------------------------------------------------------------------

inline void*  GetPointer(HANDLE h)
{
	return (void*)::GlobalLock(h);
}
#endif

#if defined(BR_BUILD_WIN) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// GetHandle
//
//	???JEL If we could use Windows.h and WindowsX.h, we could use Microsoft's macros
//----------------------------------------------------------------------------------------

inline HANDLE GetHandle(void* p)
{
	return p != NULL ? LOWORD(::GlobalHandle(HIWORD(p))) : NULL;
}
#endif

#if defined(BR_BUILD_WIN) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveAllocateBlock
//
//	???JEL If we could use Windows.h and WindowsX.h, we could use GlobalAllocPtr
//----------------------------------------------------------------------------------------

inline void*  BR_CMemoryManager::PrimitiveAllocateBlock(unsigned long fFontSize)
{
	return GetPointer(::GlobalAlloc(GHND, fFontSize));
}
#endif

#if defined(BR_BUILD_WIN) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveResizeBlock
//
//	???JEL If we could use Windows.h and WindowsX.h, we could use GlobalReAllocPtr
//----------------------------------------------------------------------------------------

inline void*  BR_CMemoryManager::PrimitiveResizeBlock(void* p, unsigned long n)
{
	HANDLE h  = GetHandle(p);
	::GlobalUnlock(h);
	HANDLE h2 = ::GlobalReAlloc(h, n, GHND);
	
	if(h2 != NULL)
		return GetPointer(h2) ;
	  
	GetPointer(h);
	return NULL;
}
#endif

#if defined(BR_BUILD_WIN) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveGetBlockSize
//	???JEL If we could use Windows.h and WindowsX.h, we could use GlobalSize(GlobalPtrHandle())
//----------------------------------------------------------------------------------------

inline unsigned long  BR_CMemoryManager::PrimitiveGetBlockSize(void* p)
{
	HANDLE h  = GetHandle(p);
	return ::GlobalSize(h);
}
#endif

#if defined(BR_BUILD_WIN) && defined(USENATIVEALLOC)
//----------------------------------------------------------------------------------------
// BR_CMemoryManager::PrimitiveFreeBlock
//	???JEL If we could use Windows.h and WindowsX.h, we could use GlobalFreePtr()
//----------------------------------------------------------------------------------------

inline void   BR_CMemoryManager::PrimitiveFreeBlock(void* p)
{
	// GlobalAlloc() will return a pointer whose low word is 0. If the
	// low word is not null then do not delete it.
	if(!LOWORD(p))
	{
		const HANDLE h = GetHandle(p);
		
		// Get a handle on the fMemory allocated.
		if(h != NULL)
		{
			// Free up the fMemory allocated.
			::GlobalUnlock(h);
			::GlobalFree(h);
		}
	}
}
#endif

//========================================================================================
// Memory debugging stuff
//========================================================================================

#if defined(BR_BUILD_MAC) || !defined(BR_DEBUG)
#define BCL_MEMHEADER               0
#endif

#if defined(BR_DEBUG) && defined(BR_BUILD_WIN)

const unsigned short    BCL_BT_OBJECT       = 101;
const unsigned short    BCL_BT_RAWBLOCK     = 105;

//========================================================================================
// STRUCT BR_SBedMemHeader
//========================================================================================

struct BR_SBedMemHeader
{
	enum BlockType
	{
		kObject	= 101,
		kRawBlock = 105
	};
	
    BlockType       fBlockType; // bcl C++ object or a raw block
                                // The function that allocated the block:
    HANDLE          fModule;    // Module handle
    WORD            fSegment;   // Segment number
    WORD            fOffset;    // Offset within the segment
    BR_SBedMemHeader*  fNext;   // Points to the fNext block, NULL if none


    void*           GetUserPtr() const;
    BR_SBedMemHeader* 	GetNext() const;
    void            SetNext(BR_SBedMemHeader* pNextBlock);
};

//
// If you use your own fMemory allocators, allocate this more than you need
//  before calling BCLMemLinkIn()
//

#define BCL_MEMHEADER   sizeof(BR_SBedMemHeader)

//----------------------------------------------------------------------------------------
// BR_SBedMemHeader::GetUserPtr
//----------------------------------------------------------------------------------------

inline void* BR_SBedMemHeader::GetUserPtr() const
{
	return ((char*)this + BCL_MEMHEADER);
}

//----------------------------------------------------------------------------------------
// BR_SBedMemHeader::GetUserPtr
//----------------------------------------------------------------------------------------

inline BR_SBedMemHeader* BR_SBedMemHeader::GetNext() const
{
	return (fNext);
}

//----------------------------------------------------------------------------------------
// BR_SBedMemHeader::SetNext
//----------------------------------------------------------------------------------------

inline void BR_SBedMemHeader::SetNext(BR_SBedMemHeader* pNextBlock)
{
	fNext = pNextBlock;
}

//========================================================================================
// CLASS BR_SBedMemHeader
//========================================================================================

class BR_CMemDebug
{
public:

	// All public methods take the pointer to the user part of a block, 
	// i.e., ptr past the header

	static void LinkIn(void* fMemoryPtr);
		// Links the block into the task's list of valid blocks

	static void UnLink(void* fMemoryPtr);
    	// Unlinks the block from the list of valid blocks

	static void InitBlock(void* fMemoryPtr, BR_SBedMemHeader::BlockType fBlockType);
    	// Walks the stack and fills the block header with caller's address & fModule
    
	static BR_Boolean IsValidBlock(void* fMemoryPtr);
		// Checks if the block is in the task's list of valid blocks.
		// If not, displays an alert

	static void CheckLostBlocks();
		// Should be called from DeleteTask().
		// Checks the list of fMemory blocks for any lost blocks.
	  
	static unsigned long VerifyHeap();
		// Verifies the fQueueHeap; returns the number of allocated blocks.
	
	static void DumpHeap();
		// Dumps the fQueueHeap block addresses with ::OutputDebugString()
	
	static void SetAutoVerify(BR_Boolean autoVerify);
		// Force a call to VerifyHeap in LinkIn and UnLink.
	  
	static void Enable();
		// Enable fMemory leak tracking.
	 
	static void Disable();
		// Disabled fMemory leak tracking.
	  
	static unsigned long GetBlockCount();
		// Returns the number of fMemory blocks allocated by this task.

private:
	static BR_SBedMemHeader* GetCurrentHeadPtr();
		// All valid blocks are kept in a linked list whose head is in the task's
		// globals structure.  This function returns NULL if no globals are installed yet
	  	// or if fMemory debugging is disabled.
	
	static BR_SBedMemHeader* GetBlock(void* fMemoryPtr);
	static BR_Boolean FindBlock(BR_SBedMemHeader*& pPrev, void* fMemoryPtr);
						  
	static BR_Boolean GetAutoVerify();
	static void SetBlockCount(unsigned long blockCount);
};

#endif


#endif
