Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

373 lines
10 KiB

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#ifdef AFX_CORE2_SEG
#pragma code_seg(AFX_CORE2_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
////////////////////////////////////////////////////////////////////////////
// Archive support for polymorphic reading/writing of CObjects
// Note: Starting with MFC 4.0, the file format written/read has been
// extended to eliminate the previous 32k limit. Files previously written
// can still be read by old versions (even 16-bit versions). In addition,
// new files, unless they are large enough to take advantage of 32-bit tags,
// can be read by old versions.
// Pointer mapping constants
#define wNullTag ((WORD)0) // special tag indicating NULL ptrs
#define wNewClassTag ((WORD)0xFFFF) // special tag indicating new CRuntimeClass
#define wClassTag ((WORD)0x8000) // 0x8000 indicates class tag (OR'd)
#define dwBigClassTag ((DWORD)0x80000000) // 0x8000000 indicates big class tag (OR'd)
#define wBigObjectTag ((WORD)0x7FFF) // 0x7FFF indicates DWORD object tag
#define nMaxMapCount ((DWORD)0x3FFFFFFE) // 0x3FFFFFFE last valid mapCount
// Note: tag value 0x8000 could be used for something in the future, since
// it is currently an invalid tag (0x8000 means zero wClassTag, but zero
// index is always reserved for a NULL pointer, and a NULL runtime class
// does not make any sense).
// This is how the tags have been allocated currently:
//
// 0x0000 represents NULL pointer
// 0x0001 - 0x7FFE "small" object tags
// 0x7FFF header for "big" object/class tag
// 0x8000 reserved for future use
// 0x8001 - 0xFFFE "small" class tag
// 0xFFFF header for class definition
//
// The special value of 0x7FFF indicates that a DWORD tag follows. This
// two part "big" tag is used for 32-bit tag values 0x7FFF and above.
// The tag value of 0x7FFF was unused in MFC versions prior to MFC 4.0.
////////////////////////////////////////////////////////////////////////////
void CArchive::CheckCount()
{
if (m_nMapCount >= nMaxMapCount)
AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);
}
void CArchive::WriteObject(const CObject* pOb)
{
// object can be NULL
ASSERT(IsStoring()); // proper direction
DWORD nObIndex;
ASSERT(sizeof(nObIndex) == 4);
ASSERT(sizeof(wNullTag) == 2);
ASSERT(sizeof(wBigObjectTag) == 2);
ASSERT(sizeof(wNewClassTag) == 2);
// make sure m_pStoreMap is initialized
MapObject(NULL);
if (pOb == NULL)
{
// save out null tag to represent NULL pointer
*this << wNullTag;
}
else if ((nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0)
// assumes initialized to 0 map
{
// save out index of already stored object
if (nObIndex < wBigObjectTag)
*this << (WORD)nObIndex;
else
{
*this << wBigObjectTag;
*this << nObIndex;
}
}
else
{
// write class of object first
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
WriteClass(pClassRef);
// enter in stored object table, checking for overflow
CheckCount();
(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;
// cause the object to serialize itself
((CObject*)pOb)->Serialize(*this);
}
}
CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
{
ASSERT(pClassRefRequested == NULL ||
AfxIsValidAddress(pClassRefRequested, sizeof(CRuntimeClass), FALSE));
ASSERT(IsLoading()); // proper direction
ASSERT(wNullTag == 0);
ASSERT((wClassTag << 16) == dwBigClassTag);
ASSERT((wNewClassTag & wClassTag) == wClassTag);
// attempt to load next stream as CRuntimeClass
UINT nSchema;
DWORD obTag;
CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag);
// check to see if tag to already loaded object
CObject* pOb;
if (pClassRef == NULL)
{
if (obTag > (DWORD)m_pLoadArray->GetUpperBound())
{
// tag is too large for the number of objects read so far
AfxThrowArchiveException(CArchiveException::badIndex,
m_strFileName);
}
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,
m_strFileName);
}
}
else
{
// allocate a new object based on the class just acquired
pOb = pClassRef->CreateObject();
if (pOb == NULL)
AfxThrowMemoryException();
// Add to mapping array BEFORE de-serializing
CheckCount();
m_pLoadArray->InsertAt(m_nMapCount++, pOb);
// Serialize the object with the schema number set in the archive
UINT nSchemaSave = m_nObjectSchema;
m_nObjectSchema = nSchema;
pOb->Serialize(*this);
m_nObjectSchema = nSchemaSave;
ASSERT_VALID(pOb);
}
return pOb;
}
/////////////////////////////////////////////////////////////////////////////
// advanced versioning and back-pointer support
UINT CArchive::GetObjectSchema()
{
UINT nResult = m_nObjectSchema;
m_nObjectSchema = (UINT)-1; // can only be called once per Serialize
return nResult;
}
void CArchive::MapObject(const CObject* pOb)
{
if (IsStoring())
{
if (m_pStoreMap == NULL)
{
// initialize the storage map
// (use CMapPtrToPtr because it is used for HANDLE maps too)
m_pStoreMap = new CMapPtrToPtr(m_nGrowSize);
m_pStoreMap->InitHashTable(m_nHashSize);
m_pStoreMap->SetAt(NULL, (void*)(DWORD)wNullTag);
m_nMapCount = 1;
}
if (pOb != NULL)
{
CheckCount();
(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;
}
}
else
{
if (m_pLoadArray == NULL)
{
// initialize the loaded object pointer array and set special values
m_pLoadArray = new CPtrArray;
m_pLoadArray->SetSize(1, m_nGrowSize);
ASSERT(wNullTag == 0);
m_pLoadArray->SetAt(wNullTag, NULL);
m_nMapCount = 1;
}
if (pOb != NULL)
{
CheckCount();
m_pLoadArray->InsertAt(m_nMapCount++, (void*)pOb);
}
}
}
void CArchive::WriteClass(const CRuntimeClass* pClassRef)
{
ASSERT(pClassRef != NULL);
ASSERT(IsStoring()); // proper direction
if (pClassRef->m_wSchema == 0xFFFF)
{
TRACE1("Warning: Cannot call WriteClass/WriteObject for %hs.\n",
pClassRef->m_lpszClassName);
AfxThrowNotSupportedException();
}
// make sure m_pStoreMap is initialized
MapObject(NULL);
// write out class id of pOb, with high bit set to indicate
// new object follows
// ASSUME: initialized to 0 map
DWORD nClassIndex;
if ((nClassIndex = (DWORD)(*m_pStoreMap)[(void*)pClassRef]) != 0)
{
// previously seen class, write out the index tagged by high bit
if (nClassIndex < wBigObjectTag)
*this << (WORD)(wClassTag | nClassIndex);
else
{
*this << wBigObjectTag;
*this << (dwBigClassTag | nClassIndex);
}
}
else
{
// store new class
*this << wNewClassTag;
pClassRef->Store(*this);
// store new class reference in map, checking for overflow
CheckCount();
(*m_pStoreMap)[(void*)pClassRef] = (void*)m_nMapCount++;
}
}
CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested,
UINT* pSchema, DWORD* pObTag)
{
ASSERT(pClassRefRequested == NULL ||
AfxIsValidAddress(pClassRefRequested, sizeof(CRuntimeClass), FALSE));
ASSERT(IsLoading()); // proper direction
if (pClassRefRequested != NULL && pClassRefRequested->m_wSchema == 0xFFFF)
{
TRACE1("Warning: Cannot call ReadClass/ReadObject for %hs.\n",
pClassRefRequested->m_lpszClassName);
AfxThrowNotSupportedException();
}
// make sure m_pLoadArray is initialized
MapObject(NULL);
// read object tag - if prefixed by wBigObjectTag then DWORD tag follows
DWORD obTag;
WORD wTag;
*this >> wTag;
if (wTag == wBigObjectTag)
*this >> obTag;
else
obTag = ((wTag & wClassTag) << 16) | (wTag & ~wClassTag);
// check for object tag (throw exception if expecting class tag)
if (!(obTag & dwBigClassTag))
{
if (pObTag == NULL)
AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);
*pObTag = obTag;
return NULL;
}
CRuntimeClass* pClassRef;
UINT nSchema;
if (wTag == wNewClassTag)
{
// new object follows a new class id
if ((pClassRef = CRuntimeClass::Load(*this, &nSchema)) == NULL)
AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
// check nSchema against the expected schema
if ((pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA) != nSchema)
{
if (!(pClassRef->m_wSchema & VERSIONABLE_SCHEMA))
{
// schema doesn't match and not marked as VERSIONABLE_SCHEMA
AfxThrowArchiveException(CArchiveException::badSchema,
m_strFileName);
}
else
{
// they differ -- store the schema for later retrieval
if (m_pSchemaMap == NULL)
m_pSchemaMap = new CMapPtrToPtr;
ASSERT_VALID(m_pSchemaMap);
m_pSchemaMap->SetAt(pClassRef, (void*)nSchema);
}
}
CheckCount();
m_pLoadArray->InsertAt(m_nMapCount++, pClassRef);
}
else
{
// existing class index in obTag followed by new object
DWORD nClassIndex = (obTag & ~dwBigClassTag);
if (nClassIndex == 0 || nClassIndex > (DWORD)m_pLoadArray->GetUpperBound())
AfxThrowArchiveException(CArchiveException::badIndex,
m_strFileName);
pClassRef = (CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex);
ASSERT(pClassRef != NULL);
// determine schema stored against objects of this type
void* pTemp;
if (m_pSchemaMap != NULL && (pTemp = m_pSchemaMap->GetValueAt(pClassRef)) != NULL)
nSchema = (UINT)pTemp;
else
nSchema = pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA;
}
// check for correct derivation
if (pClassRefRequested != NULL &&
!pClassRef->IsDerivedFrom(pClassRefRequested))
{
AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
}
// store nSchema for later examination
if (pSchema != NULL)
*pSchema = nSchema;
else
m_nObjectSchema = nSchema;
// store obTag for later examination
if (pObTag != NULL)
*pObTag = obTag;
// return the resulting CRuntimeClass*
return pClassRef;
}
void CArchive::SerializeClass(const CRuntimeClass* pClassRef)
{
if (IsStoring())
WriteClass(pClassRef);
else
ReadClass(pClassRef);
}
////////////////////////////////////////////////////////////////////////////