home *** CD-ROM | disk | FTP | other *** search
- // This is a part of the Microsoft Foundation Classes C++ library.
- // Copyright (C) 1992 Microsoft Corporation
- // All rights reserved.
- //
- // This source code is only intended as a supplement to the
- // Microsoft Foundation Classes Reference and Microsoft
- // QuickHelp and/or WinHelp documentation provided with the library.
- // See these sources for detailed information regarding the
- // Microsoft Foundation Classes product.
-
- #include "stdafx.h"
-
- #ifdef AFX_AUX_SEG
- #pragma code_seg(AFX_AUX_SEG)
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char BASED_CODE THIS_FILE[] = __FILE__;
- #endif
-
- #define new DEBUG_NEW
-
- ////////////////////////////////////////////////////////////////////////////
- // Archive support for polymorphic reading/writing of CObjects
-
- // Pointer mapping constants
- #define wNullTag ((WORD)0)
- #define wNewClassTag ((WORD)-1)
- #define wOldClassTag ((WORD)-32768) /* 0x8000 or the class index with this */
- #define nMaxMapCount ((WORD)32766) /* 0x7FFE last valid mapCount */
-
- // amount to grow m_loadArray upon insert
- enum { nGrowSize = 10 };
-
- ////////////////////////////////////////////////////////////////////////////
-
- void CArchive::WriteObject(const CObject* pOb)
- {
- // object can be NULL
- ASSERT(IsStoring()); // proper direction
- ASSERT(m_lpBufStart != NULL);
- ASSERT(m_lpBufCur != NULL);
-
- if (m_pStoreMap == NULL)
- {
- // initialize the storage map
- m_pStoreMap = new CMapPtrToWord;
- m_pStoreMap->SetAt(NULL, wNullTag);
- m_nMapCount = 1;
- }
-
- WORD nObIndex;
- ASSERT(sizeof(nObIndex) == 2);
- ASSERT(sizeof(wNullTag) == 2);
- ASSERT(sizeof(wNewClassTag) == 2);
-
- if (pOb == NULL)
- {
- // save out null tag to represent NULL pointer
- *this << wNullTag;
- }
- else if (!(pOb->IsSerializable()))
- {
- // can not save object if it does not have a schema number
- AfxThrowNotSupportedException();
- }
- else if ((nObIndex = (*m_pStoreMap)[(CObject*)pOb]) != 0)
- // assumes initialized to 0 map
- {
- // save out index of already stored object
- *this << nObIndex;
- }
- else
- {
- CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
- WORD nClassIndex;
-
- // write out class id of pOb, with high bit set to indicate
- // new object follows
-
- // ASSUME: initialized to 0 map
- if ((nClassIndex = (*m_pStoreMap)[pClassRef]) != 0)
- {
- // previously seen class, write out the index tagged by high bit
- *this << (WORD)(wOldClassTag | nClassIndex);
- }
- else
- {
- // new class
- *this << wNewClassTag;
- pClassRef->Store(*this);
-
- (*m_pStoreMap)[pClassRef] = (WORD) m_nMapCount++;
- if (m_nMapCount > nMaxMapCount)
- AfxThrowArchiveException(CArchiveException::badIndex);
- }
- // enter in stored object table and output
- (*m_pStoreMap)[(CObject*)pOb] = (WORD)m_nMapCount++;
- if (m_nMapCount > nMaxMapCount)
- AfxThrowArchiveException(CArchiveException::badIndex);
-
- ((CObject*)pOb)->Serialize(*this);
- }
- }
-
-
- CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
- {
- ASSERT(pClassRefRequested == NULL || AfxIsValidAddress(pClassRefRequested, sizeof(struct CRuntimeClass), FALSE));
- ASSERT(IsLoading()); // proper direction
- ASSERT(wNullTag == 0);
- ASSERT(m_lpBufStart != NULL);
- ASSERT(m_lpBufCur != NULL);
-
- CRuntimeClass* pClassRef;
- WORD obTag;
- WORD wSchema;
-
- if (pClassRefRequested && (pClassRefRequested->m_wSchema == 0xFFFF))
- AfxThrowNotSupportedException();
-
- if (m_pLoadArray == NULL)
- {
- // initialize the loaded object pointer array and set special values
- m_pLoadArray = new CPtrArray;
- ASSERT(nGrowSize > 0);
- m_pLoadArray->SetSize(nGrowSize, nGrowSize);
- ASSERT(wNullTag == 0);
- m_pLoadArray->SetAt(wNullTag, NULL);
- m_nMapCount = 1;
- }
-
- *this >> obTag;
-
- //NOTE: this relies on signed testing of the tag values
- if ((short)obTag >= (short)wNullTag)
- {
- if (obTag > (WORD)m_pLoadArray->GetUpperBound())
- {
- // tag is too large for the number of objects read so far
- AfxThrowArchiveException(CArchiveException::badIndex);
- }
-
- CObject* pOb = (CObject*)m_pLoadArray->GetAt(obTag);
-
- if (pOb != NULL && pClassRefRequested != NULL &&
- !pOb->IsKindOf(pClassRefRequested))
- {
- // loaded an object but of the wrong class
- AfxThrowArchiveException(CArchiveException::badClass);
- }
- return pOb;
- }
-
-
- if (obTag == wNewClassTag)
- {
- // new object follows a new class id
- if (m_nMapCount > nMaxMapCount)
- AfxThrowArchiveException(CArchiveException::badIndex);
-
- if ((pClassRef = CRuntimeClass::Load(*this, (UINT*)&wSchema)) == NULL)
- {
- AfxThrowArchiveException(CArchiveException::badClass);
- return NULL;
- }
- if (pClassRef->m_wSchema != wSchema)
- {
- AfxThrowArchiveException(CArchiveException::badSchema);
- return NULL;
- }
- m_pLoadArray->InsertAt(m_nMapCount++, pClassRef, 1);
- ASSERT(m_nMapCount < (UINT)0x7FFF);
- }
- else
- {
- // existing class index in obTag followed by new object
-
- WORD nClassIndex = (WORD)(obTag & (WORD)~wOldClassTag);
- ASSERT(sizeof(nClassIndex) == 2);
-
- if (nClassIndex & 0x8000 ||
- nClassIndex > (WORD)m_pLoadArray->GetUpperBound())
- AfxThrowArchiveException(CArchiveException::badIndex);
-
- pClassRef = (CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex);
- }
-
- // allocate a new object based on the class just acquired
- CObject* pOb = pClassRef->CreateObject();
- ASSERT(pOb != NULL);
-
- // Add to mapping array BEFORE de-serializing
- m_pLoadArray->InsertAt(m_nMapCount++, pOb, 1);
-
- pOb->Serialize(*this);
-
- ASSERT(pOb != NULL);
- if (pClassRefRequested && !pOb->IsKindOf(pClassRefRequested))
- AfxThrowArchiveException(CArchiveException::badClass);
-
- return pOb;
- }
-
-
- ////////////////////////////////////////////////////////////////////////////
-