/*++ Copyright (c) 1997 Microsoft Corporation Module Name: pbagstm.h Abstract: This module contains the definition of the property bag stream Author: Keith Lau (keithlau@microsoft.com) Revision History: keithlau 07/09/97 created --*/ #ifndef _PBAGSTM_H_ #define _PBAGSTM_H_ #include "cpool.h" #define MAX_PROPERTY_NAME_LENGTH 256 typedef struct _TABLE_ENTRY { DWORD dwOffset; DWORD dwSize; DWORD dwNameSize; DWORD dwMaxSize; DWORD dwKey; WORD fFlags; WORD wIndex; } TABLE_ENTRY, *LPTABLE_ENTRY; typedef struct _STREAM_HEADER { DWORD dwSignature; WORD wVersionHigh; WORD wVersionLow; DWORD dwHeaderSize; DWORD dwProperties; DWORD dwDirectorySize; DWORD dwEndOfData; } STREAM_HEADER, *LPSTREAM_HEADER; #define _CACHE_SIZE 64 typedef enum _PROPERTY_BAG_CREATORS { PBC_NONE = 0, PBC_BUILDQ, PBC_DIRNOT, PBC_ENV, PBC_LOCALQ, PBC_MAILQ, PBC_REMOTEQ, PBC_RRETRYQ, PBC_SMTPCLI } PROPERTY_BAG_CREATORS; typedef enum _PROPERTY_FLAG_OPERATIONS { PFO_NONE = 0, PFO_OR, PFO_ANDNOT } PROPERTY_FLAG_OPERATIONS; ///////////////////////////////////////////////////////////////////////////// // CPropertyBagStream // class CPropertyBagStream { public: CPropertyBagStream(DWORD dwContext = 0); ~CPropertyBagStream(); static CPool Pool; // override the mem functions to use CPool functions void *operator new (size_t cSize) { return Pool.Alloc(); } void operator delete (void *pInstance) { Pool.Free(pInstance); } // Reference count methods ... ULONG AddRef(); ULONG Release(BOOL fDeleteIfZeroRef = FALSE); HRESULT SetStreamFileName(LPSTR szStreamFileName); LPSTR GetStreamFileName() { return(m_szStreamName); } // Mechanisms for locking and unlocking the property bag HRESULT Lock(); HRESULT Unlock(); // Force opens the stream file if it is not already opened. // This is useful in checking if a stream file exists. HRESULT OpenStreamFile(); // Access to properties as a whole HRESULT GetProperty(LPSTR pszName, LPVOID pvBuffer, LPDWORD pdwBufferLen); HRESULT SetProperty(LPSTR pszName, LPVOID pvBuffer, DWORD dwBufferLen); // Access to properties, providing specific access to // portions of the property data relative to the start // of the property data HRESULT GetPropertyAt(LPSTR pszName, DWORD dwOffsetFromStart, LPVOID pvBuffer, LPDWORD pdwBufferLen); HRESULT SetPropertyAt(LPSTR pszName, DWORD dwOffsetFromStart, LPVOID pvBuffer, DWORD dwBufferLen); // Ad-hoc function to allow access to a specific DWORD of // a property, treating the DWORD as a set of flags. The // dwOperation argument specifies what kind of binary operation // we would like to have performed on the original value. // If the property does not originally exist, this function // will fail. HRESULT UpdatePropertyFlagsAt(LPSTR pszName, DWORD dwOffsetFromStart, DWORD dwFlags, DWORD dwOperation); #ifdef USE_PROPERTY_ITEM_ISTREAM // Returns an IStream interface to the desired property // for random access HRESULT GetIStreamToProperty(LPSTR pszName, IStream **ppIStream); #endif BOOL DeleteStream(); private: BOOL ReleaseStream(); HRESULT Seek(DWORD dwOffset, DWORD dwMethod); HRESULT LoadIntoCache(DWORD dwStartIndex); LPTABLE_ENTRY FindFromCache(DWORD dwKey, LPDWORD pdwStartIndex); HRESULT FindFrom(LPSTR pszName, DWORD dwKey, DWORD dwStartIndex, BOOL fForward, LPVOID pvBuffer, LPDWORD pdwBufferLen, LPTABLE_ENTRY *ppEntry); HRESULT FindFromEx(LPSTR pszName, DWORD dwKey, DWORD dwStartIndex, BOOL fForward, DWORD dwOffsetFromStart, LPVOID pvBuffer, LPDWORD pdwBufferLen, LPTABLE_ENTRY *ppEntry); HRESULT GetRecordData(LPTABLE_ENTRY pEntry, LPVOID pvBuffer); HRESULT GetRecordName(LPTABLE_ENTRY pEntry, LPVOID pvBuffer); HRESULT GetRecordValue(LPTABLE_ENTRY pEntry, LPVOID pvBuffer); HRESULT GetRecordValueAt(LPTABLE_ENTRY pEntry, DWORD dwOffsetFromStart, LPVOID pvBuffer, DWORD dwBufferLen); HRESULT UpdateEntry(LPTABLE_ENTRY pEntry); HRESULT UpdateHeader(); HRESULT UpdateHeaderUsingHandle(HANDLE hStream); HRESULT FindProperty(LPSTR pszName, LPVOID pvBuffer, LPDWORD pdwBufferLen, LPTABLE_ENTRY *ppEntry = NULL); HRESULT FindPropertyEx(LPSTR pszName, DWORD dwOffsetFromStart, LPVOID pvBuffer, LPDWORD pdwBufferLen, LPTABLE_ENTRY *ppEntry = NULL); HRESULT SetRecordData(LPTABLE_ENTRY pEntry, LPSTR pszName, LPVOID pvBuffer, DWORD dwBufferLen); HRESULT SetRecordDataAt(LPTABLE_ENTRY pEntry, LPSTR pszName, DWORD dwOffsetFromStart, LPVOID pvBuffer, DWORD dwBufferLen, BOOL fNewRecord = FALSE); HRESULT RelocateRecordData(LPTABLE_ENTRY pEntry); HRESULT DetermineIfCacheValid(BOOL *pfCacheInvalid); DWORD CreateKey(LPSTR pszName) { CHAR cKey[9]; DWORD dwLen = 0; // Convert to lower case ... while (*pszName && (dwLen < 8)) if ((*pszName >= 'A') && (*pszName <= 'Z')) cKey[dwLen++] = *pszName++ - 'A' + 'a'; else cKey[dwLen++] = *pszName++; cKey[dwLen] = '\0'; dwLen = lstrlen(cKey); // Create the key if (dwLen < 4) return((DWORD)cKey[dwLen - 1]); else if (dwLen < 8) return(*(DWORD *)cKey); else return(~*(DWORD *)cKey ^ *(DWORD *)(cKey + 4)); } DWORD GetTotalHeaderSize() { return(sizeof(STREAM_HEADER) + (m_Header.dwDirectorySize * sizeof(TABLE_ENTRY))); } // Current context DWORD m_dwContext; // Base file name CHAR m_szStreamName[MAX_PATH + 1]; // Handle to stream HANDLE m_hStream; // Stream header STREAM_HEADER m_Header; // Directory caching TABLE_ENTRY m_Cache[_CACHE_SIZE]; DWORD m_dwCacheStart; DWORD m_dwCachedItems; // Reference counting LONG m_lRef; // This is a signature placed at the end to catch memory overwrite DWORD m_dwSignature; }; ///////////////////////////////////////////////////////////////////////////// // CPropertyItemStream // // // Not everyone wants to use the property IStream, so we don't expose // it if it's not wanted // #ifdef USE_PROPERTY_ITEM_ISTREAM class CPropertyItemStream : public IStream { public: CPropertyItemStream(LPSTR pszName, CPropertyBagStream *pBag) { m_cRef = 0; m_pParentBag = pBeg; m_szName = pszName; m_libOffset.QuadPart = (DWORDLONG)0; } ~CPropertyItemStream() { Cleanup(); } // IUnknown STDMETHODIMP QueryInterface(REFIID, void**); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); void Cleanup() {} HRESULT ReadOffset(void *pv, ULONG cb, ULONG *pcbRead, ULARGE_INTEGER *plibOffset); HRESULT WriteOffset(void const* pv, ULONG cb, ULONG *pcbWritten, ULARGE_INTEGER *plibOffset); HRESULT GetSize(ULARGE_INTEGER *plibSize); HRESULT CopyToOffset(IStream *pstm, ULARGE_INTEGER libOffset, ULARGE_INTEGER *plibRead, ULARGE_INTEGER *plibWritten, ULARGE_INTEGER *plibOffset); HRESULT CloneOffset(IStream **pstm, ULARGE_INTEGER libOffset); // IStream public: HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead); HRESULT STDMETHODCALLTYPE Write(void const* pv, ULONG cb, ULONG *pcbWritten); HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *pdlibNewPosition); HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize); HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten); HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags); HRESULT STDMETHODCALLTYPE Revert(void); HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType); HRESULT STDMETHODCALLTYPE Stat(STATSTG * pstatstg, DWORD grfStatFlag); HRESULT STDMETHODCALLTYPE Clone(IStream **pstm); private: CPropertyBagStream *m_pParentBag; LPSTR m_szName; ULARGE_INTEGER m_libOffset; long m_cRef; }; #endif // USE_PROPERTY_ISTREAM #endif