//---------------------------------------------------------------
//
//  For conditions of distribution and use, see copyright notice
//  in Flashpix.h 
// 
//  Copyright (c) 1999 Digital Imaging Group, Inc.
// 
//  Contents:   DocFile and MultiStream shared private definitions
//
//---------------------------------------------------------------

#ifndef __DFMSP_HXX__
#define __DFMSP_HXX__

#include "ref.hxx"
#include "ole.hxx"
#include "msf.hxx"
#include "owchar.h"
#include <memory.h>
#include <string.h>
#include "../time.hxx"

// Target-dependent things

//
//      x86 16-bit build optimizations
//
//      Some function parameters are always stack based pointers,
//      so we can let the compiler use near addressing via ss by
//      declaring the parameter stack based.
//

#define STACKBASED

//
//      x86 16-bit retail build optimizations
//
//      For the retail build, we group the code segments,
//      allowing us to make many calls near.
//

// Segmented memory model definitions
#define HUGEP

#ifndef LISet32
#define LISet32(li, v) \
    ((li).HighPart = ((LONG)(v)) < 0 ? -1 : 0, (li).LowPart = (v))
#endif
#ifndef ULISet32    
#define ULISet32(li, v) ((li).HighPart = 0, (li).LowPart = (v))
#endif    
#define LISetLow(li, v) ((li).LowPart = (v))
#define LISetHigh(li, v) ((li).HighPart = (v))
#define ULISetLow(li, v) ((li).LowPart = (v))
#define ULISetHigh(li, v) ((li).HighPart = (v))
#define LIGetLow(li) ((li).LowPart)
#define LIGetHigh(li) ((li).HighPart)
#define ULIGetLow(li) ((li).LowPart)
#define ULIGetHigh(li) ((li).HighPart)

// Fast safe increment/decrement
#define AtomicInc(lp) (++*(lp))
#define AtomicDec(lp) (--*(lp))


// Switchable ANSI/Unicode support
// Conversion routines assume null termination before max characters

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

// The name of this function might change, so encapsulate it
#define DfGetScode(hr) GetScode(hr)

//
// These function now just check for NULL values or are disabled
// -- system dependent
//
// We leave these functions in so that it is a good place to verify memory,
// if they can be implemented.
//
#define ValidateNotNull(x)  \
    ((x) ? S_OK : STG_E_INVALIDPOINTER)

#define ValidateBuffer(pv, n) \
    ValidateNotNull(pv)

#define ValidatePtrBuffer(pv) \
    ValidateNotNull(pv)

#define ValidateHugeBuffer(pv, n) \
    ValidateNotNull(pv)

#define ValidateOutBuffer(pv, n) \
    ValidateNotNull(pv)

#define ValidateOutPtrBuffer(pv) \
    ValidateNotNull(pv)

#define ValidateHugeOutBuffer(pv, n) \
    ValidateNotNull(pv)
 
#define ValidateIid(riid) S_OK   // disabled

#define ValidateInterface(punk,riid) \
    ValidateNotNull(punk)

#define ValidateWcs(pwcs, cwcMax) \
    ValdateNotNull(pwcs)

#define ValidateSz(psz, cchMax) S_OK \
    ValidateNotNull(psz)

#define ValidateNameW(pwcs, cchMax) \
    ((pwcs)?(S_OK):(STG_E_INVALIDNAME))

#define ValidateNameA(psz, cchMax) \
    ((psz)?(S_OK):(STG_E_INVALIDNAME))

// Enumeration for Get/SetTime
enum WHICHTIME
{
    WT_CREATION=0,
    WT_MODIFICATION,
    WT_ACCESS
};

// Signature for transactioning
typedef DWORD DFSIGNATURE;
#define DF_INVALIDSIGNATURE ((DFSIGNATURE)-1)

// Convenience macros for signature creation
#define LONGSIG(c1, c2, c3, c4) \
(((ULONG) (BYTE) (c1)) | \
 (((ULONG) (BYTE) (c2)) << 8) | \
 (((ULONG) (BYTE) (c3)) << 16) | \
 (((ULONG) (BYTE) (c4)) << 24))

#define DfAllocWC(cwc, ppwcs) (*ppwcs = new WCHAR[cwc], \
        (*ppwcs != NULL) ? S_OK: STG_E_INSUFFICIENTMEMORY)

#define DfAllocWCS(pwcs, ppwcs) DfAllocWC(wcslen(pwcs)+1, ppwcs)

// Docfile locally unique identity
// Every entry in a multistream has a LUID generated and stored for it
typedef DWORD DFLUID;
#define DF_NOLUID 0

typedef WCHAR **SNBW;

#ifndef _UNICODE
typedef struct
{
    WCHAR *pwcsName;
    DWORD type;
    ULARGE_INTEGER cbSize;
    FILETIME mtime;
    FILETIME ctime;
    FILETIME atime;
    DWORD grfMode;
    DWORD grfLocksSupported;
    CLSID clsid;
    DWORD grfStateBits;
    DWORD reserved;
} STATSTGW;
#else  // if _UNICODE
typedef STATSTG STATSTGW;
#endif // ! _UNICODE

#define TSTDMETHODIMP SCODE
#define TSTDAPI(name) SCODE name##W

#define CBSTORAGENAME (CWCSTORAGENAME*sizeof(WCHAR))

// A Unicode case-insensitive compare
// No such thing really exists so we use our own
#define dfwcsnicmp(wcsa, wcsb, len) wcsnicmp(wcsa, wcsb, len)


// A name for a docfile element
class CDfName
{
private:
    BYTE _ab[CBSTORAGENAME];
    WORD _cb;

public:
    CDfName(void)               { _cb = 0; }

    void Set(WORD const cb, BYTE const *pb)
    {
  _cb = cb;
  if (pb)
      memcpy(_ab, pb, cb);
    }
    void Set(WCHAR const *pwcs) 
    { 
        Set( (WORD) ((wcslen(pwcs)+1)*sizeof(WCHAR)), (BYTE const *)pwcs); 
    }

    // Special method for names with prepended character
    void Set(WCHAR const wcLead, WCHAR const *pwcs)
    {
        olAssert((wcslen(pwcs)+2)*sizeof(WCHAR) < CBSTORAGENAME);
        _cb = (USHORT) ((wcslen(pwcs)+2)*sizeof(WCHAR));
        *(WCHAR *)_ab = wcLead;
        wcscpy((WCHAR *)_ab+1, pwcs);
    }

    inline void Set(CDfName const *pdfn);

    CDfName(WORD const cb, BYTE const *pb)      { Set(cb, pb); }
    CDfName(WCHAR const *pwcs)  { Set(pwcs); }
//    CDfName(char const *psz)    { Set(psz); }

    WORD GetLength(void) const  { return _cb; }
    BYTE *GetBuffer(void) const { return (BYTE *) _ab; }

    BOOL IsEqual(CDfName const *dfn) const
    {
  // This assumes that all DfNames are actually Unicode strings
  return _cb == dfn->_cb &&
      dfwcsnicmp((WCHAR *)_ab, (WCHAR *)dfn->GetBuffer(), _cb) == 0;
    }
    
    inline void ByteSwap(void);
};

inline void CDfName::Set(CDfName const *pdfn)
{
    Set(pdfn->GetLength(), pdfn->GetBuffer());
}

inline void CDfName::ByteSwap(void)
{
    // assume all names are wide characters, we swap each word
    WCHAR *awName = (WCHAR*) _ab;
    ::ByteSwap(&_cb);    
    for (unsigned int i=0; i<CBSTORAGENAME/sizeof(WCHAR); i++)
    {
        ::ByteSwap(awName);        
        awName++;
    }
}

// Fast, fixed space iterator structure
struct SIterBuffer
{
    CDfName dfnName;
    DWORD type;
};

//SID is a Stream Identifier
typedef ULONG SID;

// IsEntry entry information
struct SEntryBuffer
{
    DFLUID luid;
    DWORD  dwType;
    SID    sid;
};

// Destroy flags
#define DESTROY_FROM_HANDLE     0
#define DESTROY_FROM_ENTRY      1
#define DESTROY_FROM            0x01
#define DESTROY_SELF            0x40
#define DESTROY_RECURSIVE       0x80

#define DESTROY_HANDLE          (DESTROY_FROM_HANDLE | DESTROY_SELF)
#define DESTROY_ENTRY           (DESTROY_FROM_ENTRY | DESTROY_SELF)

// Root startup flags
#define RSF_OPEN                0x00
#define RSF_CONVERT             0x01
#define RSF_TRUNCATE            0x02
#define RSF_CREATE              0x04
#define RSF_DELAY               0x08
#define RSF_DELETEONRELEASE     0x10
#define RSF_OPENCREATE          0x20
#define RSF_RESERVE_HANDLE      0x40

#define RSF_CREATEFLAGS (RSF_CREATE | RSF_TRUNCATE | RSF_OPENCREATE)

// Stream copy buffer size
ULONG const STREAMBUFFERSIZE = 8192;

// ILockBytes copy buffer size
ULONG const LOCKBYTESBUFFERSIZE = 16384;

// Docfile flags for permissions and other information kept
// on streams and docfiles
typedef WORD DFLAGS;

#define DF_TRANSACTEDSELF       0x0001

#define DF_TRANSACTED           0x0002
#define DF_DIRECT               0x0000

#define DF_INDEPENDENT          0x0004
#define DF_DEPENDENT            0x0000

#define DF_COMMIT               0x0008
#define DF_ABORT                0x0000

#define DF_INVALID              0x0010

#define DF_REVERTED             0x0020
#define DF_NOTREVERTED          0x0000

#define DF_READ                 0x0040
#define DF_WRITE                0x0080
#define DF_READWRITE            (DF_READ | DF_WRITE)

#define DF_DENYREAD             0x0100
#define DF_DENYWRITE            0x0200
#define DF_DENYALL              (DF_DENYREAD | DF_DENYWRITE)

#define DF_PRIORITY             0x0400
#define DF_CREATE               0x0800
#define DF_CACHE                0x1000
#define DF_NOUPDATE             0x2000

// Shift required to translate from DF_READWRITE to DF_DENYALL
#define DF_DENIALSHIFT          2

// Permission abstraction macros
// These only work with DF_* flags
#define P_READ(f)       ((f) & DF_READ)
#define P_WRITE(f)      ((f) & DF_WRITE)
#define P_READWRITE(f)  (((f) & (DF_READ | DF_WRITE)) == (DF_READ | DF_WRITE))
#define P_DENYREAD(f)   ((f) & DF_DENYREAD)
#define P_DENYWRITE(f)  ((f) & DF_DENYWRITE)
#define P_DENYALL(f)    (((f) & (DF_DENYREAD | DF_DENYWRITE)) == \
       (DF_DENYREAD | DF_DENYWRITE))
#define P_PRIORITY(f)   ((f) & DF_PRIORITY)
#define P_TRANSACTED(f) ((f) & DF_TRANSACTED)
#define P_DIRECT(f)     (!P_TRANSACTED(f))
#define P_INDEPENDENT(f) ((f) & DF_INDEPENDENT)
#define P_DEPENDENT(f)  (!P_INDEPENDENT(f))
#define P_TSELF(f)      ((f) & DF_TRANSACTEDSELF)
#define P_INVALID(f)    ((f) & DF_INVALID)
#define P_REVERTED(f)   ((f) & DF_REVERTED)
#define P_COMMIT(f)     ((f) & DF_COMMIT)
#define P_ABORT(f)      (!P_COMMIT(f))
#define P_CREATE(f)     ((f) & DF_CREATE)
#define P_CACHE(f)      ((f) & DF_CACHE)
#define P_NOUPDATE(f)   ((f) & DF_NOUPDATE)

// Translation functions
DFLAGS ModeToDFlags(DWORD const dwModeFlags);
DWORD DFlagsToMode(DFLAGS const df);

// Flags for what state has been dirtied
#define DIRTY_CREATETIME  0x0001
#define DIRTY_MODIFYTIME  0x0002
#define DIRTY_ACCESSTIME  0x0004
#define DIRTY_CLASS       0x0008
#define DIRTY_STATEBITS   0x0010

// Allow text in asserts
#define aMsg(s) (s)

#define STGTY_REAL (STGTY_STORAGE | STGTY_STREAM | STGTY_LOCKBYTES)

#define REAL_STGTY(f) (f)

extern void *DfMemAlloc(DWORD dwFlags, size_t size);
extern void DfMemFree(void *mem);

extern void *TaskMemAlloc(size_t size);
extern void TaskMemFree(void *mem);

// Buffer management
#define CB_LARGEBUFFER 32768
#define CB_PAGEBUFFER 4096
#define CB_SMALLBUFFER 512

extern SCODE GetBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb,
                       USHORT *pcbActual);
extern void GetSafeBuffer(USHORT cbMin, USHORT cbMax, BYTE **ppb,
                          USHORT *pcbActual);
extern void FreeBuffer(BYTE *pb);

#endif // #ifndef __DFMSP_HXX__
