|
|
/*--------------------------------------------------------------------------* * * Microsoft Windows * Copyright (C) Microsoft Corporation, 1999 - 1999 * * File: bookmark.inl * * Contents: Implementation file for CBookmark * * History: 25-Oct-99 vivekj Created * *--------------------------------------------------------------------------*/
#include "uastrfnc.h" // from $(SHELL_INC_PATH), for unaligned string functions
/*+-------------------------------------------------------------------------* * UnalignedValueAt * * Returns the value at a potentially unaligned address. *--------------------------------------------------------------------------*/
template<typename T> T UnalignedValueAt (UNALIGNED T* pT) { return (*pT); }
//############################################################################ //############################################################################ // // Implementation of class CDynamicPathEntry // //############################################################################ //############################################################################ /*+-------------------------------------------------------------------------* * * CDynamicPathEntry::ScInitialize * * PURPOSE: Initializes the entry from a byte array read in from a console file. * * PARAMETERS: * bool bIs10Path : true if the path entry format is that of MMC1.0. * I iter: The byte array. * * RETURNS: * inline SC * *+-------------------------------------------------------------------------*/ inline SC CDynamicPathEntry::ScInitialize(bool bIs10Path, /*[IN,OUT]*/ByteVector::iterator &iter) { DECLARE_SC(sc, TEXT("CDynamicPathEntry::ScInitialize"));
if(bIs10Path) // an MMC1.0 path entry. Just the display name { m_type = NDTYP_STRING; m_strEntry = reinterpret_cast<LPCWSTR>(iter); iter += (m_strEntry.length() + 1) *sizeof(WCHAR); // bump up the iterator. } else // a 1.1 or 1.2 path. The first byte contains the type. { m_type = *iter++; // either NDTYP_STRING or NDTYP_CUSTOM switch(m_type) { default: sc = E_UNEXPECTED; break;
case NDTYP_STRING: { LPCWSTR pszEntry = reinterpret_cast<LPCWSTR>(iter); sc = ScCheckPointers(pszEntry); if(sc) return sc; #ifdef ALIGNMENT_MACHINE /* * Bug 128010: if our target machine requires data alignment and * the source is unaligned, make an aligned copy that we can * pass to std::wstring::operator=, which calls wcs* functions * expect aligned data */ if (!IS_ALIGNED (pszEntry)) { LPWSTR pszNew = (LPWSTR) alloca ((ualstrlenW(pszEntry) + 1) * sizeof(WCHAR)); sc = ScCheckPointers(pszNew); if(sc) return sc;
ualstrcpyW (pszNew, pszEntry); pszEntry = pszNew; } #endif m_strEntry = pszEntry; // bump the input pointer to the next element iter += (m_strEntry.length() + 1) * sizeof (WCHAR); break; }
case NDTYP_CUSTOM: const SNodeID* pNodeID = reinterpret_cast<const SNodeID*>(iter); // same binary layout as a SNodeID. if(!pNodeID) return (sc = E_UNEXPECTED);
/* * Bug 177492: pNodeID->cBytes may be unaligned, so make an aligned copy of it */ const DWORD cBytes = UnalignedValueAt (&pNodeID->cBytes);
m_byteVector.insert(m_byteVector.end(), pNodeID->id, pNodeID->id + cBytes); /*if(pNodeID->cBytes==0) m_dwFlags = MMC_NODEID_SLOW_RETRIEVAL; */ // shouldn't need this; should not be able to save such a bookmark.
iter += sizeof (pNodeID->cBytes) + cBytes; // bump up the pointer. break; }
}
return sc; }
inline bool CDynamicPathEntry::operator ==(const CDynamicPathEntry &rhs) const { // check the types if(!(m_type & rhs.m_type & (NDTYP_CUSTOM | NDTYP_STRING))) // bitwise OR - at least one type must be in common return false;
// if both types implement NDTYP_CUSTOM, use that preferentially. Else, compare based on display names. if(m_type & rhs.m_type & NDTYP_CUSTOM) return (m_byteVector == rhs.m_byteVector); else // (m_type & rhs.m_type & NDTYP_STRING) return (m_strEntry == rhs.m_strEntry); }
inline bool CDynamicPathEntry::operator < (const CDynamicPathEntry &rhs) const { // If both have NDTYP_CUSTOM in common, compare byte vector // else if both have NDTYP_STRING in common, compare strings. // Otherwise (have nothing in common), use m_type to impose the ordering if (rhs.m_type & m_type & NDTYP_CUSTOM) return std::lexicographical_compare(m_byteVector.begin(), m_byteVector.end(), rhs.m_byteVector.begin(), rhs.m_byteVector.end());
else if (rhs.m_type & m_type & NDTYP_STRING) return m_strEntry < rhs.m_strEntry;
else return (m_type < rhs.m_type); }
/*--------------------------------------------------------------------------* * InsertScalar * * Inserts a scalar value of type T into an output stream as a series of * the output stream's value_type. *--------------------------------------------------------------------------*/
template<typename Container, typename T> void InsertScalar (Container& c, const T& t) { Container::const_iterator itFrom = reinterpret_cast<Container::const_iterator>(&t); std::copy (itFrom, itFrom + sizeof (t), std::back_inserter(c)); }
//############################################################################ //############################################################################ // // Implementation of class CBookmark // //############################################################################ //############################################################################
inline bool CBookmark::operator ==(const CBookmark& other) const { return ((m_idStatic == other.m_idStatic) && (m_dynamicPath == other.m_dynamicPath)); }
inline bool CBookmark::operator!=(const CBookmark& other) const { return (!(*this == other)); }
inline bool CBookmark::operator<(const CBookmark& other) const { if (m_idStatic < other.m_idStatic) return true;
if (m_idStatic == other.m_idStatic) { return std::lexicographical_compare( m_dynamicPath.begin(), m_dynamicPath.end(), other.m_dynamicPath.begin(), other.m_dynamicPath.end() ); }
return false; }
/*+-------------------------------------------------------------------------* * * CBookmark::HBOOKMARK * * PURPOSE: Casts a bookmark into an HBOOKMARK * * RETURNS: * operator * *+-------------------------------------------------------------------------*/ inline CBookmark:: operator HBOOKMARK() const { return reinterpret_cast<HBOOKMARK>(this); }
/*+-------------------------------------------------------------------------* * * CBookmark::GetBookmark * * PURPOSE: Converts an HBOOKMARK to a CBookmark. * * PARAMETERS: * HBOOKMARK hbm : * * RETURNS: * CBookmark * * *+-------------------------------------------------------------------------*/ inline CBookmark * CBookmark::GetBookmark(HBOOKMARK hbm) { return reinterpret_cast<CBookmark *>(hbm); }
/*+-------------------------------------------------------------------------* * * CBookmark::Load * * PURPOSE: * * PARAMETERS: * IStream& stm : * * RETURNS: * inline IStream& * *+-------------------------------------------------------------------------*/ inline IStream& CBookmark::Load(IStream& stm) { // loading from a stream. Convert from one of the legacy formats.
// 1. Read the static node ID stm >> m_idStatic; m_dynamicPath.clear();
// 2. Read the dynamic path ByteVector vDynamicPath; ByteVector::iterator iter; stm >> vDynamicPath;
// 2a. If the dynamic path is empty, we're done. if(vDynamicPath.empty()) return (stm);
// 3. Strip out the unnecessary details like the signature, etc.
// 3a. Check for a signature iter = vDynamicPath.begin(); bool bIs10Path = true; if(memcmp (iter, BOOKMARK_CUSTOMSTREAMSIGNATURE, sizeof(BOOKMARK_CUSTOMSTREAMSIGNATURE)) == 0) { // throw away the signature and the following version bytes iter += (sizeof(BOOKMARK_CUSTOMSTREAMSIGNATURE) + sizeof(DWORD)); bIs10Path = false; //is a post-MMC1.0 path. }
// create new entries for each piece. while(iter != vDynamicPath.end()) { CDynamicPathEntry entry; entry.ScInitialize(bIs10Path, iter); //NOTE: iter is an in/out parameter. m_dynamicPath.push_back(entry); }
return (stm); } /*+-------------------------------------------------------------------------* * * CBookmark::Persist * * PURPOSE: Persists the bookmark * * PARAMETERS: * CPersistor & persistor : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ inline void CBookmark::Persist(CPersistor &persistor) { DECLARE_SC(sc, TEXT("CBookmark::Persist"));
// check and persist only valid node ids if (persistor.IsStoring() && (m_idStatic == ID_Unknown)) sc.Throw(E_UNEXPECTED);
persistor.PersistAttribute(XML_ATTR_BOOKMARK_STATIC, m_idStatic);
bool bPersistList = persistor.IsLoading() ? (persistor.HasElement(XML_ATTR_BOOKMARK_DYNAMIC_PATH, NULL)) : (m_dynamicPath.size() > 0);
if (bPersistList) persistor.PersistList(XML_ATTR_BOOKMARK_DYNAMIC_PATH, NULL, m_dynamicPath); }
/*+-------------------------------------------------------------------------* * * CDynamicPathEntry::Persist * * PURPOSE: Persists the dynamic path entry of the bookmark * * PARAMETERS: * CPersistor & persistor : * * RETURNS: * void * *+-------------------------------------------------------------------------*/ inline void CDynamicPathEntry::Persist(CPersistor &persistor) { DECLARE_SC(sc, TEXT("CDynamicPathEntry::Persist"));
if ( (m_type & NDTYP_STRING) || persistor.IsLoading()) persistor.PersistAttribute(XML_ATTR_BOOKMARK_DYN_STRING, m_strEntry, attr_optional);
if ( (m_type & NDTYP_CUSTOM) || persistor.IsLoading()) { CXMLAutoBinary binData; if (persistor.IsStoring()) { if (m_byteVector.size()) { sc = binData.ScAlloc(m_byteVector.size()); if (sc) sc.Throw();
CXMLBinaryLock sLock(binData); // unlocks on destructor
LPBYTE pData = NULL; sc = sLock.ScLock(&pData); if (sc) sc.Throw();
std::copy(m_byteVector.begin(), m_byteVector.end(), pData); } } persistor.PersistAttribute(XML_ATTR_BOOKMARK_DYN_CUSTOM, binData, attr_optional); if (persistor.IsLoading()) { m_byteVector.clear(); if (binData.GetSize()) // if there is nothing to read it won't be allocated { CXMLBinaryLock sLock(binData); // unlocks on destructor
LPBYTE pData = NULL; sc = sLock.ScLock(&pData); if (sc) sc.Throw();
m_byteVector.assign( pData, pData + binData.GetSize() ); } } } if (persistor.IsLoading()) // determine the format(s) available { m_type = 0;
if(m_strEntry.size() > 0) m_type |= NDTYP_STRING;
if(m_byteVector.size()) m_type |= NDTYP_CUSTOM;
} }
|