home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 19.ddi / MFC / SRC / ARCOBJ.CP_ / ARCOBJ.CP
Encoding:
Text File  |  1993-02-08  |  5.7 KB  |  208 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library. 
  2. // Copyright (C) 1992 Microsoft Corporation 
  3. // All rights reserved. 
  4. //  
  5. // This source code is only intended as a supplement to the 
  6. // Microsoft Foundation Classes Reference and Microsoft 
  7. // QuickHelp and/or WinHelp documentation provided with the library. 
  8. // See these sources for detailed information regarding the 
  9. // Microsoft Foundation Classes product. 
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_AUX_SEG
  14. #pragma code_seg(AFX_AUX_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char BASED_CODE THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. ////////////////////////////////////////////////////////////////////////////
  25. // Archive support for polymorphic reading/writing of CObjects
  26.  
  27. // Pointer mapping constants
  28. #define wNullTag      ((WORD)0)
  29. #define wNewClassTag  ((WORD)-1)
  30. #define wOldClassTag  ((WORD)-32768) /* 0x8000 or the class index with this */
  31. #define nMaxMapCount  ((WORD)32766)  /* 0x7FFE last valid mapCount */
  32.  
  33. // amount to grow m_loadArray upon insert
  34.     enum { nGrowSize = 10 };
  35.  
  36. ////////////////////////////////////////////////////////////////////////////
  37.  
  38. void CArchive::WriteObject(const CObject* pOb)
  39. {
  40.     // object can be NULL
  41.     ASSERT(IsStoring());    // proper direction
  42.     ASSERT(m_lpBufStart != NULL);
  43.     ASSERT(m_lpBufCur != NULL);
  44.  
  45.     if (m_pStoreMap == NULL)
  46.     {
  47.         // initialize the storage map
  48.         m_pStoreMap = new CMapPtrToWord;
  49.         m_pStoreMap->SetAt(NULL, wNullTag);
  50.         m_nMapCount = 1;
  51.     }
  52.  
  53.     WORD nObIndex;
  54.     ASSERT(sizeof(nObIndex) == 2);
  55.     ASSERT(sizeof(wNullTag) == 2);
  56.     ASSERT(sizeof(wNewClassTag) == 2);
  57.  
  58.     if (pOb == NULL)
  59.     {
  60.         // save out null tag to represent NULL pointer
  61.         *this << wNullTag;
  62.     }
  63.     else if (!(pOb->IsSerializable()))
  64.     {
  65.         // can not save object if it does not have a schema number
  66.         AfxThrowNotSupportedException();
  67.     }
  68.     else if ((nObIndex = (*m_pStoreMap)[(CObject*)pOb]) != 0)
  69.                              // assumes initialized to 0 map
  70.     {
  71.         // save out index of already stored object
  72.         *this << nObIndex;
  73.     }
  74.     else
  75.     {
  76.         CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
  77.         WORD nClassIndex;
  78.  
  79.         // write out class id of pOb, with high bit set to indicate
  80.         // new object follows
  81.  
  82.         // ASSUME: initialized to 0 map
  83.         if ((nClassIndex = (*m_pStoreMap)[pClassRef]) != 0) 
  84.         {
  85.             // previously seen class, write out the index tagged by high bit
  86.             *this << (WORD)(wOldClassTag | nClassIndex);
  87.         }
  88.         else
  89.         {
  90.             // new class
  91.             *this << wNewClassTag;
  92.             pClassRef->Store(*this);
  93.  
  94.             (*m_pStoreMap)[pClassRef] = (WORD) m_nMapCount++;
  95.             if (m_nMapCount > nMaxMapCount)
  96.                 AfxThrowArchiveException(CArchiveException::badIndex);
  97.         }
  98.         // enter in stored object table and output
  99.         (*m_pStoreMap)[(CObject*)pOb] = (WORD)m_nMapCount++;
  100.         if (m_nMapCount > nMaxMapCount)
  101.             AfxThrowArchiveException(CArchiveException::badIndex);
  102.  
  103.         ((CObject*)pOb)->Serialize(*this);
  104.     }
  105. }
  106.  
  107.  
  108. CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
  109. {
  110.     ASSERT(pClassRefRequested == NULL || AfxIsValidAddress(pClassRefRequested, sizeof(struct CRuntimeClass), FALSE));
  111.     ASSERT(IsLoading());    // proper direction
  112.     ASSERT(wNullTag == 0);
  113.     ASSERT(m_lpBufStart != NULL);
  114.     ASSERT(m_lpBufCur != NULL);
  115.  
  116.     CRuntimeClass* pClassRef;
  117.     WORD obTag;
  118.     WORD wSchema;
  119.  
  120.     if (pClassRefRequested && (pClassRefRequested->m_wSchema == 0xFFFF))
  121.         AfxThrowNotSupportedException();
  122.  
  123.     if (m_pLoadArray == NULL)
  124.     {
  125.         // initialize the loaded object pointer array and set special values
  126.         m_pLoadArray = new CPtrArray;
  127.         ASSERT(nGrowSize > 0);
  128.         m_pLoadArray->SetSize(nGrowSize, nGrowSize); 
  129.         ASSERT(wNullTag == 0);
  130.         m_pLoadArray->SetAt(wNullTag, NULL);
  131.         m_nMapCount = 1;
  132.     }
  133.         
  134.     *this >> obTag;
  135.  
  136.     //NOTE: this relies on signed testing of the tag values
  137.     if ((short)obTag >= (short)wNullTag)
  138.     {
  139.         if (obTag > (WORD)m_pLoadArray->GetUpperBound())
  140.         {
  141.             // tag is too large for the number of objects read so far
  142.             AfxThrowArchiveException(CArchiveException::badIndex);
  143.         }
  144.  
  145.         CObject* pOb = (CObject*)m_pLoadArray->GetAt(obTag);
  146.  
  147.         if (pOb != NULL && pClassRefRequested != NULL &&
  148.              !pOb->IsKindOf(pClassRefRequested))
  149.         {
  150.             // loaded an object but of the wrong class
  151.             AfxThrowArchiveException(CArchiveException::badClass);
  152.         }
  153.         return pOb;
  154.     }
  155.  
  156.  
  157.     if (obTag == wNewClassTag)
  158.     {
  159.         // new object follows a new class id
  160.         if (m_nMapCount > nMaxMapCount)
  161.             AfxThrowArchiveException(CArchiveException::badIndex);
  162.  
  163.         if ((pClassRef = CRuntimeClass::Load(*this, (UINT*)&wSchema)) == NULL)
  164.         {
  165.             AfxThrowArchiveException(CArchiveException::badClass);
  166.             return NULL;
  167.         }
  168.         if (pClassRef->m_wSchema != wSchema)
  169.         {
  170.             AfxThrowArchiveException(CArchiveException::badSchema);
  171.             return NULL;
  172.         }
  173.         m_pLoadArray->InsertAt(m_nMapCount++, pClassRef, 1);
  174.         ASSERT(m_nMapCount < (UINT)0x7FFF);
  175.     } 
  176.     else
  177.     {
  178.         // existing class index in obTag followed by new object
  179.  
  180.         WORD nClassIndex = (WORD)(obTag & (WORD)~wOldClassTag);
  181.         ASSERT(sizeof(nClassIndex) == 2);
  182.  
  183.         if (nClassIndex & 0x8000 || 
  184.                 nClassIndex > (WORD)m_pLoadArray->GetUpperBound())
  185.             AfxThrowArchiveException(CArchiveException::badIndex);
  186.  
  187.         pClassRef = (CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex);
  188.     }
  189.  
  190.     // allocate a new object based on the class just acquired
  191.     CObject* pOb = pClassRef->CreateObject();
  192.     ASSERT(pOb != NULL);
  193.  
  194.     // Add to mapping array BEFORE de-serializing
  195.     m_pLoadArray->InsertAt(m_nMapCount++, pOb, 1);
  196.  
  197.     pOb->Serialize(*this);
  198.  
  199.     ASSERT(pOb != NULL);
  200.     if (pClassRefRequested && !pOb->IsKindOf(pClassRefRequested))
  201.         AfxThrowArchiveException(CArchiveException::badClass);
  202.  
  203.     return pOb;
  204. }
  205.  
  206.  
  207. ////////////////////////////////////////////////////////////////////////////
  208.