//----------------------------------------------------------------------------- // SSBuf.h // // Copyright (C) 1995, Microsoft Corporation // // Purpose: // Subclass Map, Set, and Array templates to handle versioning and // reloading directly from a stream. // // Revision History: // // [] 13-Jan-1995 Dans Created // [] 16-Apr-1995 Dans Added ArrayVer<> template // //----------------------------------------------------------------------------- #if !defined(_ssbuf_h) #define _ssbuf_h 1 // Depends on buffer.h #include #include #include #include #include #include // // All streams and sub-streams hav this header followed by the // stream specific data // struct STRMHDR { DWORD dwSig; union { DWORD cEntries; DWORD cb; }; long lVer; DWORD dwReserved; }; template struct UserHdr { unsigned __int32 cb; BYTE rgb[ _cbExtra ]; }; // // Versioned Maps // template class MapVer : public Map { private: enum { sig = sigMagic }; typedef Map BaseClass; typedef UserHdr<_cbExtra> UsrHdr; long m_lVer; UsrHdr m_usrhdr; public: MapVer ( long lVer ) { m_lVer = lVer; m_usrhdr.cb = _cbExtra; memset ( m_usrhdr.rgb, 0, _cbExtra ); } // overload the relevant functions to handle the versioning CB cbSave() const; BOOL save ( Buffer * ); BOOL reload ( PB * ); // couple of supporting functions for user headers and direct // to stream ops. BOOL reloadStream ( Stream * ); BYTE * PbUserData(); }; template inline CB MapVer::cbSave() const { return sizeof STRMHDR + sizeof UsrHdr + BaseClass::cbSave(); } template BOOL MapVer::save ( Buffer * pbuf ) { STRMHDR hdr = { sig, cbSave(), m_lVer, 0 }; assert ( m_usrhdr.cb == _cbExtra ); return pbuf->Append ( PB(&hdr), sizeof(hdr) ) && pbuf->Append ( PB(&m_usrhdr), sizeof(m_usrhdr) ) && BaseClass::save ( pbuf ); } template BOOL MapVer::reload ( PB * ppb ) { STRMHDR hdr; BOOL fRet = fFalse; debug(PB pbT = *ppb;) hdr = *(STRMHDR UNALIGNED *) *ppb; if ( hdr.dwSig == sig && hdr.cb > sizeof(hdr) && hdr.lVer == m_lVer ) { *ppb += sizeof(hdr); // reload the user data unsigned __int32 cbUser; cbUser = __min ( *(unsigned __int32 UNALIGNED *)*ppb, _cbExtra ); *ppb += sizeof(unsigned __int32); memcpy ( &m_usrhdr.rgb[0], *ppb, cbUser ); *ppb += _cbExtra; // now do the actual map class fRet = BaseClass::reload ( ppb ); assert ( pbT + hdr.cb == *ppb ); } else { // something bogus is going on, skip the header... *ppb += max ( hdr.cb, sizeof(hdr) ); } return fRet; } template BOOL MapVer::reloadStream ( Stream * pstream ) { PB pb; CB cb = pstream->QueryCb(); BOOL fRet = fFalse; if ( cb > 0 ) { Buffer buf; if ( buf.Reserve ( cb, &pb ) ) { if ( pstream->Read2 ( 0, pb, cb ) ) { fRet = reload ( &pb ); } } } else { fRet = fTrue; } return fRet; } template inline BYTE * MapVer::PbUserData() { //precondition ( _cbExtra ); return _cbExtra ? &m_usrhdr.rgb[0] : NULL; } // // Versioned Sets // template class SetVer : public Set { private: enum { sig = sigMagic }; typedef Set BaseClass; typedef UserHdr<_cbExtra> UsrHdr; long m_lVer; UsrHdr m_usrhdr; public: SetVer ( long lVer ) { m_lVer = lVer; m_usrhdr.cb = _cbExtra; } // overload the relevant functions to handle the versioning CB cbSave() const; BOOL save ( Buffer * ); BOOL reload ( PB * ); // couple of supporting functions for user headers and direct // to stream ops. BOOL reloadStream ( Stream * ); BYTE * PbUserData(); }; template inline CB SetVer::cbSave() const { return sizeof STRMHDR + sizeof UsrHdr + BaseClass::cbSave(); } template inline BOOL SetVer::save ( Buffer * pbuf ) { STRMHDR hdr = { sig, cbSave(), m_lVer, 0 }; assert ( m_usrhdr.cb == _cbExtra ); return pbuf->Append ( PB(&hdr), sizeof(hdr) ) && pbuf->Append ( PB(&m_usrhdr), sizeof(m_usrhdr) ) && BaseClass::save ( pbuf ); } template BOOL SetVer::reload ( PB * ppb ) { STRMHDR hdr; BOOL fRet = fFalse; debug(PB pbT = *ppb;) hdr = *(STRMHDR UNALIGNED *) *ppb; if ( hdr.dwSig == sig && hdr.cb > sizeof(hdr) && hdr.lVer == m_lVer ) { *ppb += sizeof(hdr); // reload the user data unsigned __int32 cbUser; cbUser = __min ( *(unsigned __int32 UNALIGNED *)*ppb, _cbExtra ); *ppb += sizeof(unsigned __int32); memcpy ( &m_usrhdr.rgb[0], *ppb, cbUser ); *ppb += _cbExtra; // now do the actual set class fRet = BaseClass::reload ( ppb ); assert ( pbT + hdr.cb == *ppb ); } else { // something bogus is going on, skip the header... *ppb += max(hdr.cb, sizeof(hdr)); } return fRet; } template BOOL SetVer::reloadStream ( Stream * pstream ) { PB pb; CB cb = pstream->QueryCb(); BOOL fRet = fFalse; if ( cb > 0 ) { Buffer buf; if ( buf.Reserve ( cb, &pb ) ) { if ( pstream->Read2 ( 0, pb, cb ) ) { fRet = reload ( &pb ); } } } else { fRet = fTrue; } return fRet; } template inline BYTE * SetVer::PbUserData() { precondition ( _cbExtra ); return _cbExtra ? &m_usrhdr.rgb[0] : NULL; } // // Versioned arrays // template class ArrayVer : public Array { private: enum { sig = sigMagic }; typedef Array BaseClass; typedef UserHdr<_cbExtra> UsrHdr; long m_lVer; UsrHdr m_usrhdr; public: ArrayVer ( long lVer ) { m_lVer = lVer; m_usrhdr.cb = _cbExtra; memset ( m_usrhdr.rgb, 0, _cbExtra ); } // overload the relevant functions to handle the versioning CB cbSave() const; BOOL save ( Buffer * ); BOOL reload ( PB * ); // couple of supporting functions for user headers and direct // to stream ops. BOOL reloadStream ( Stream * ); BYTE * PbUserData(); }; template inline CB ArrayVer::cbSave() const { return sizeof STRMHDR + sizeof UsrHdr + BaseClass::cbSave(); } template BOOL ArrayVer::save ( Buffer * pbuf ) { STRMHDR hdr = { sig, cbSave(), m_lVer, 0 }; assert ( m_usrhdr.cb == _cbExtra ); return pbuf->Append ( PB(&hdr), sizeof(hdr) ) && pbuf->Append ( PB(&m_usrhdr), sizeof(m_usrhdr) ) && BaseClass::save ( pbuf ); } template BOOL ArrayVer::reload ( PB * ppb ) { STRMHDR hdr; BOOL fRet = fFalse; debug(PB pbT = *ppb;) hdr = *(STRMHDR UNALIGNED *) *ppb; if ( hdr.dwSig == sig && hdr.cb > sizeof(hdr) && hdr.lVer == m_lVer ) { *ppb += sizeof(hdr); // reload the user data unsigned __int32 cbUser; cbUser = __min ( *(unsigned __int32 UNALIGNED *)*ppb, _cbExtra ); *ppb += sizeof(unsigned __int32); memcpy ( &m_usrhdr.rgb[0], *ppb, cbUser ); *ppb += _cbExtra; // now do the actual array fRet = BaseClass::reload ( ppb ); assert ( pbT + hdr.cb == *ppb ); } else { // something bogus is going on, skip the header... *ppb += max ( hdr.cb, sizeof(hdr) ); } return fRet; } template BOOL ArrayVer::reloadStream ( Stream * pstream ) { PB pb; CB cb = pstream->QueryCb(); BOOL fRet = fFalse; if ( cb > 0 ) { Buffer buf; if ( buf.Reserve ( cb, &pb ) ) { if ( pstream->Read2 ( 0, pb, cb ) ) { fRet = reload ( &pb ); } } } else { fRet = fTrue; } return fRet; } template BYTE * ArrayVer::PbUserData() { //precondition ( _cbExtra ); return _cbExtra ? &m_usrhdr.rgb[0] : NULL; } #endif