//+--------------------------------------------------------------------------
//
//  For conditions of distribution and use, see copyright notice
//  in Flashpix.h 
// 
//  Copyright (c) 1999 Digital Imaging Group
// 
//  Contents:    PROPVARIANT manipulation code
//
//---------------------------------------------------------------------------

#ifndef _PROPVAR_HXX_
#define _PROPVAR_HXX_

#include "propset.hxx"


// forward declarations
class PMemoryAllocator;

SERIALIZEDPROPERTYVALUE *
RtlConvertVariantToProperty(
    IN PROPVARIANT const *pvar,
    IN USHORT CodePage,
    OUT SERIALIZEDPROPERTYVALUE *pprop,
    IN OUT ULONG *pcb,
    IN PROPID pid,
    IN BOOLEAN fVariantVector,
    OUT NTSTATUS *pstatus);

VOID
RtlConvertPropertyToVariant(
    IN SERIALIZEDPROPERTYVALUE const *pprop,
    IN USHORT CodePage,
    OUT PROPVARIANT *pvar,
    IN PMemoryAllocator *pma,
    OUT NTSTATUS *pstatus);

VOID
CleanupVariants(
    IN PROPVARIANT *pvar,
    IN ULONG cprop,
    IN PMemoryAllocator *pma);

/*+--------------------------------------------------------------------------
  Function:    SignalOverflow, SignalInvalidParameter, SignalStatus
  
  Synopsis:    ASSERT and raise data corrupt/overflow/specified error
  
  Arguments:   [szReason]              -- string explanation
               [Status]                -- Status to raise (SignalStatus only)
  Returns:     None
 +--------------------------------------------------------------------------*/


#define StatusOverflow(pstatus, szReason)           \
          *(pstatus) = STATUS_BUFFER_OVERFLOW;      \
          TraceStatus(szReason)

#define StatusAccessDenied(pstatus, szReason)   \
          *(pstatus) = STATUS_ACCESS_DENIED;        \
          TraceStatus(szReason);

#define StatusInvalidParameter(pstatus, szReason)   \
          *(pstatus) = STATUS_INVALID_PARAMETER;    \
          TraceStatus(szReason);

#define StatusNoMemory(pstatus, szReason)           \
          *(pstatus) = STATUS_INSUFFICIENT_RESOURCES;\
          TraceStatus(szReason);

#define StatusDiskFull(pstatus, szReason)           \
          *(pstatus) = STATUS_DISK_FULL;            \
          TraceStatus(szReason);

#define StatusError(pstatus, szReason, Status)      \
          *(pstatus) = Status;                      \
          TraceStatus(szReason);

#define StatusKBufferOverflow(pstatus, szReason) StatusNoMemory(pstatus, szReason)


#define KERNELSELECT(k, u)      u

#define DBGPROPASSERT   KERNELSELECT(DBGPROP, DBG)

#if DBGPROPASSERT
#define TraceStatus(szReason)                                   \
  {             \
      DebugTrace(0, DEBTRACE_ERROR, (szReason "\n"));     \
      PROPASSERTMSG(szReason, !(DebugLevel & DEBTRACE_WARN)); \
  }


#else
#define TraceStatus(szReason)
#endif



#define AssertVarField(field, cb) \
  PROPASSERT(FIELD_OFFSET(PROPVARIANT, iVal) == FIELD_OFFSET(PROPVARIANT, field) && \
   sizeof(((PROPVARIANT *) 0)->field) == (cb))

#define AssertVarVector(field, cbElem) \
  PROPASSERT(FIELD_OFFSET(PROPVARIANT, cai.cElems) == \
       FIELD_OFFSET(PROPVARIANT, field.cElems) && \
         FIELD_OFFSET(PROPVARIANT, cai.pElems) == \
       FIELD_OFFSET(PROPVARIANT, field.pElems) && \
   sizeof(((PROPVARIANT *) 0)->field.pElems[0]) == (cbElem))

#define AssertByteField(field)      AssertVarField(field, sizeof(BYTE))
#define AssertShortField(field)     AssertVarField(field, sizeof(SHORT))
#define AssertLongField(field)      AssertVarField(field, sizeof(LONG))
#define AssertLongLongField(field)  AssertVarField(field, sizeof(LONGLONG))
#define AssertStringField(field)    AssertVarField(field, sizeof(VOID *))

#define AssertByteVector(field)     AssertVarVector(field, sizeof(BYTE))
#define AssertShortVector(field)    AssertVarVector(field, sizeof(SHORT))
#define AssertLongVector(field)     AssertVarVector(field, sizeof(LONG))
#define AssertLongLongVector(field) AssertVarVector(field, sizeof(LONGLONG))
#define AssertStringVector(field)   AssertVarVector(field, sizeof(VOID *))
#define AssertVariantVector(field)  AssertVarVector(field, sizeof(PROPVARIANT))


#define BSTRLEN(bstrVal)  *((ULONG *) bstrVal - 1)


/*+-------------------------------------------------------------------
  Class:       CBufferAllocator, private
                                       
  Synopsis:    allocation from a buffer

  Notes:       The Summary catalog APIs use a single buffer to serialize row
  values on input and deserialize them on output.  This class
  encapsulates the memory allocation routines for these APIs.
-----------------------------------------------------------------------*/

class CBufferAllocator : public PMemoryAllocator
{
public:
    inline CBufferAllocator(ULONG cbBuffer, VOID *pvBuffer)
    {
  _cbFree = cbBuffer;
  _pvCur = _pvBuffer = pvBuffer;
#if _X86_ /* stack variables on x86 are not aligned*/
  PROPASSERT(((ULONG) _pvCur & (sizeof(LONG) - 1)) == 0);
#else /* RISC*/
  PROPASSERT(((ULONG) _pvCur & (sizeof(LONGLONG) - 1)) == 0);
#endif /* X86/RISC*/
    }

    VOID *Allocate(ULONG cbSize);
    VOID Free(VOID *pv) { }

    inline ULONG GetFreeSize(VOID) { return(_cbFree); }

private:
    ULONG  _cbFree;
    VOID  *_pvCur;
    VOID  *_pvBuffer;
};

/*+-------------------------------------------------------------------
  Member:      CBufferAllocator::Allocate, private
  
  Synopsis:    allocation from a buffer
  
  Arguments:   [cb] -- Count of bytes to be allocated.
  
  Returns:     pointer to 'allocated' memory -- NULL if no space left
----------------------------------------------------------------------*/

#define DEFINE_CBufferAllocator__Allocate     \
VOID *                \
CBufferAllocator::Allocate(ULONG cb)        \
{               \
    VOID *pv;             \
                \
    cb = (cb + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1); \
    if (cb > _cbFree)           \
    {               \
        return(NULL);           \
    }               \
    pv = _pvCur;            \
    _pvCur = (BYTE *) _pvCur + cb;        \
    _cbFree -= cb;            \
    return(pv);             \
}

#endif /* #ifndef _PROPVAR_HXX_ */
