|
|
1.1 ! root 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 documentation provided with the library. ! 8: // See these sources for detailed information regarding the ! 9: // Microsoft Foundation Classes product. ! 10: ! 11: #include "afx.h" ! 12: #include "afxcoll.h" ! 13: #pragma hdrstop ! 14: ! 15: #include <malloc.h> ! 16: ! 17: #ifdef AFX_CORE_SEG ! 18: #pragma code_seg(AFX_CORE_SEG) ! 19: #endif ! 20: ! 21: ! 22: #ifndef min ! 23: #define min(a,b) (((a) < (b)) ? (a) : (b)) ! 24: #endif ! 25: ! 26: #ifdef _DEBUG ! 27: #undef THIS_FILE ! 28: static char BASED_CODE THIS_FILE[] = __FILE__; ! 29: #endif ! 30: ! 31: #define new DEBUG_NEW ! 32: ! 33: //////////////////////////////////////////////////////////////////////////// ! 34: // Serialize member functions for low level classes put here ! 35: // for code swapping improvements ! 36: ! 37: // CString serialization code ! 38: // String format: if < 255 chars: len:BYTE, characters in bytes ! 39: // if >= 255 characters: 0xff, len:WORD, characters in bytes ! 40: ! 41: CArchive& ! 42: operator <<(CArchive& ar, const CString& string) ! 43: { ! 44: if (string.m_nDataLength < 255) ! 45: { ! 46: ar << (BYTE) string.m_nDataLength; ! 47: } ! 48: else ! 49: { ! 50: ar << (BYTE) 0xff; ! 51: ar << (WORD) string.m_nDataLength; ! 52: } ! 53: ar.Write(string.m_pchData, string.m_nDataLength); ! 54: return ar; ! 55: } ! 56: ! 57: CArchive& ! 58: operator >>(CArchive& ar, CString& string) ! 59: { ! 60: string.Empty(); ! 61: ! 62: BYTE bLen; ! 63: ar >> bLen; ! 64: ! 65: WORD nNewLen; ! 66: if (bLen == 0xff) ! 67: // read word of length ! 68: ar >> nNewLen; ! 69: else ! 70: nNewLen = bLen; ! 71: ! 72: // read in as normal characters ! 73: if (nNewLen != 0) ! 74: { ! 75: string.AllocBuffer(nNewLen); ! 76: if (ar.Read(string.m_pchData, nNewLen) != nNewLen) ! 77: AfxThrowArchiveException(CArchiveException::endOfFile); ! 78: } ! 79: return ar; ! 80: } ! 81: ! 82: // Runtime class serialization code ! 83: CRuntimeClass* ! 84: CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum) ! 85: { ! 86: WORD nLen; ! 87: char szClassName[64]; ! 88: CRuntimeClass* pClass; ! 89: ! 90: ar >> (WORD&)(*pwSchemaNum) >> nLen; ! 91: ! 92: if (nLen >= sizeof(szClassName) || ar.Read(szClassName, nLen) != nLen) ! 93: return NULL; ! 94: szClassName[nLen] = '\0'; ! 95: ! 96: for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass) ! 97: { ! 98: if (strcmp(szClassName, pClass->m_pszClassName) == 0) ! 99: return pClass; ! 100: } ! 101: ! 102: return NULL; ! 103: } ! 104: ! 105: void ! 106: CRuntimeClass::Store(CArchive& ar) ! 107: // Stores a class ref ! 108: { ! 109: WORD nLen = (WORD)strlen(m_pszClassName); ! 110: ! 111: ar << (WORD)m_wSchema << nLen; ! 112: ar.Write(m_pszClassName, nLen); ! 113: } ! 114: ! 115: //////////////////////////////////////////////////////////////////////////// ! 116: //////////////////////////////////////////////////////////////////////////// ! 117: // Archive object input/output ! 118: ! 119: // amount to grow m_loadArray upon insert ! 120: enum { nGrowSize = 10 }; ! 121: ! 122: // minimum buffer size ! 123: enum { nBufSizeMin = 128 }; ! 124: ! 125: //////////////////////////////////////////////////////////////////////////// ! 126: // Pointer mapping constants ! 127: #define wNullTag ((WORD)0) ! 128: #define wNewClassTag ((WORD)-1) ! 129: #define wOldClassTag ((WORD)-32768) /* 0x8000 or the class index with this */ ! 130: #define nMaxMapCount ((WORD)32766) /* 0x7FFE last valid mapCount */ ! 131: ! 132: ! 133: // TRY/CATCH cannot be used with /Ox ! 134: #pragma optimize("elg", off) ! 135: ! 136: CArchive::CArchive(CFile* pFile, ! 137: UINT nMode, ! 138: int nBufSize /* = 512 */, ! 139: void FAR* lpBuf /* = NULL */) ! 140: { ! 141: ASSERT_VALID(pFile); ! 142: ! 143: m_nMode = nMode; ! 144: ! 145: // initialize the buffer. minimum size is 128 ! 146: m_lpBufStart = (BYTE FAR*)lpBuf; ! 147: ! 148: if (nBufSize < nBufSizeMin) ! 149: { ! 150: // force use of private buffer of minimum size ! 151: m_nBufSize = nBufSizeMin; ! 152: m_lpBufStart = NULL; ! 153: } ! 154: else ! 155: m_nBufSize = nBufSize; ! 156: ! 157: if (m_lpBufStart == NULL) ! 158: { ! 159: m_lpBufStart = (BYTE FAR*)_fmalloc(m_nBufSize); ! 160: m_bUserBuf = FALSE; ! 161: } ! 162: else ! 163: m_bUserBuf = TRUE; ! 164: ! 165: ASSERT(m_lpBufStart != NULL); ! 166: ASSERT(AfxIsValidAddress(m_lpBufStart, m_nBufSize)); ! 167: ! 168: m_lpBufMax = m_lpBufStart + m_nBufSize; ! 169: m_lpBufCur = (IsLoading()) ? m_lpBufMax : m_lpBufStart; ! 170: m_pFile = pFile; ! 171: ! 172: // allocate the load/store map/array fail gracefully if OOM ! 173: TRY ! 174: { ! 175: if (nMode == CArchive::load) ! 176: m_pLoadArray = new CPtrArray; ! 177: else ! 178: m_pStoreMap = new CMapPtrToWord; ! 179: } ! 180: CATCH(CMemoryException, e) ! 181: { ! 182: if (!m_bUserBuf) ! 183: _ffree(m_lpBufStart); ! 184: THROW_LAST(); ! 185: } ! 186: END_CATCH ! 187: ! 188: if (nMode == CArchive::load) ! 189: { ! 190: ASSERT(IsLoading()); ! 191: ASSERT(nGrowSize > 0); ! 192: m_pLoadArray->SetSize(nGrowSize, nGrowSize); ! 193: ASSERT(wNullTag == 0); ! 194: m_pLoadArray->SetAt(wNullTag, NULL); ! 195: m_nMapCount = 1; ! 196: } ! 197: else ! 198: { ! 199: ASSERT(IsStoring()); ! 200: ! 201: m_pStoreMap->SetAt(NULL, wNullTag); ! 202: m_nMapCount = 1; ! 203: } ! 204: ! 205: } ! 206: #pragma optimize("", on) ! 207: ! 208: ! 209: CArchive::~CArchive() ! 210: { ! 211: ASSERT(AfxIsValidAddress(m_lpBufStart, (UINT)(m_lpBufMax - m_lpBufStart))); ! 212: ASSERT(AfxIsValidAddress(m_lpBufCur, (UINT)(m_lpBufMax - m_lpBufCur))); ! 213: ASSERT(m_lpBufStart != NULL); ! 214: ! 215: // Close makes m_pFile NULL. If it is not NULL, we must Close the ! 216: // CArchive. ! 217: if (m_pFile) ! 218: Close(); ! 219: ! 220: if (!m_bUserBuf) ! 221: _ffree(m_lpBufStart); ! 222: ! 223: if (m_nMode == CArchive::load) ! 224: delete m_pLoadArray; ! 225: else ! 226: delete m_pStoreMap; ! 227: } ! 228: ! 229: void ! 230: CArchive::Close() ! 231: { ! 232: ASSERT_VALID(m_pFile); ! 233: ! 234: Flush(); ! 235: m_pFile = NULL; ! 236: } ! 237: ! 238: void ! 239: CArchive::WriteObject(const CObject* cpOb) ! 240: { ! 241: // object can be NULL ! 242: ASSERT(IsStoring()); // proper direction ! 243: ASSERT(m_lpBufStart != NULL); ! 244: ASSERT(m_lpBufCur != NULL); ! 245: ! 246: CObject* pOb = (CObject*)cpOb; ! 247: WORD nObIndex; ! 248: ! 249: ASSERT(sizeof(nObIndex) == 2); ! 250: ASSERT(sizeof(wNullTag) == 2); ! 251: ASSERT(sizeof(wNewClassTag) == 2); ! 252: ! 253: if (pOb == NULL) ! 254: *this << wNullTag; ! 255: else if (!(cpOb->IsSerializable())) ! 256: AfxThrowNotSupportedException(); ! 257: else if ((nObIndex = (*m_pStoreMap)[pOb]) != 0) //ASSUME: initialized to 0 map ! 258: *this << nObIndex; ! 259: else ! 260: { ! 261: CRuntimeClass* pClassRef = pOb->GetRuntimeClass(); ! 262: WORD nClassIndex; ! 263: ! 264: // write out class id of pOb, with high bit set to indicate ! 265: // new object follows ! 266: ! 267: // ASSUME: initialized to 0 map ! 268: if ((nClassIndex = (*m_pStoreMap)[pClassRef]) != 0) ! 269: { ! 270: // previously seen class, write out the index tagged by high bit ! 271: *this << (WORD)(wOldClassTag | nClassIndex); ! 272: } ! 273: else ! 274: { ! 275: // new class ! 276: *this << wNewClassTag; ! 277: pClassRef->Store(*this); ! 278: ! 279: (*m_pStoreMap)[pClassRef] = (WORD) m_nMapCount++; ! 280: if (m_nMapCount > nMaxMapCount) ! 281: AfxThrowArchiveException(CArchiveException::badIndex); ! 282: } ! 283: // enter in stored object table and output ! 284: (*m_pStoreMap)[pOb] = (WORD)m_nMapCount++; ! 285: if (m_nMapCount > nMaxMapCount) ! 286: AfxThrowArchiveException(CArchiveException::badIndex); ! 287: ! 288: pOb->Serialize(*this); ! 289: } ! 290: } ! 291: ! 292: ! 293: ! 294: CObject* ! 295: CArchive::ReadObject(const CRuntimeClass* pClassRefRequested) ! 296: { ! 297: ASSERT(pClassRefRequested == NULL || AfxIsValidAddress(pClassRefRequested, sizeof(struct CRuntimeClass))); ! 298: ASSERT(IsLoading()); // proper direction ! 299: ASSERT(wNullTag == 0); ! 300: ASSERT(m_lpBufStart != NULL); ! 301: ASSERT(m_lpBufCur != NULL); ! 302: ! 303: CRuntimeClass* pClassRef; ! 304: WORD obTag; ! 305: WORD wSchema; ! 306: ! 307: if (pClassRefRequested && (pClassRefRequested->m_wSchema == 0xFFFF)) ! 308: AfxThrowNotSupportedException(); ! 309: ! 310: *this >> obTag; ! 311: ! 312: //NOTE: this relies on signed testing of the tag values ! 313: if ((short)obTag >= (short)wNullTag) ! 314: { ! 315: if (obTag > (WORD)m_pLoadArray->GetUpperBound()) ! 316: AfxThrowArchiveException(CArchiveException::badIndex); ! 317: ! 318: CObject* pOb = (CObject*)m_pLoadArray->GetAt(obTag); ! 319: ! 320: if (pOb != NULL && pClassRefRequested && !pOb->IsKindOf(pClassRefRequested)) ! 321: AfxThrowArchiveException(CArchiveException::badClass); ! 322: return pOb; ! 323: } ! 324: ! 325: ! 326: if (obTag == wNewClassTag) ! 327: { ! 328: // new object follows a new class id ! 329: if (m_nMapCount > nMaxMapCount) ! 330: AfxThrowArchiveException(CArchiveException::badIndex); ! 331: ! 332: if ((pClassRef = CRuntimeClass::Load(*this, (UINT*)&wSchema)) == NULL) ! 333: { ! 334: AfxThrowArchiveException(CArchiveException::badClass); ! 335: return NULL; ! 336: } ! 337: if (pClassRef->m_wSchema != wSchema) ! 338: { ! 339: AfxThrowArchiveException(CArchiveException::badSchema); ! 340: return NULL; ! 341: } ! 342: m_pLoadArray->InsertAt(m_nMapCount++, pClassRef, 1); ! 343: ASSERT(m_nMapCount < (UINT)0x7FFF); ! 344: } ! 345: else ! 346: { ! 347: // existing class index in obTag followed by new object ! 348: ! 349: WORD nClassIndex = (WORD)(obTag & (WORD)~wOldClassTag); ! 350: ASSERT(sizeof(nClassIndex) == 2); ! 351: ! 352: if (nClassIndex & 0x8000 || ! 353: nClassIndex > (WORD)m_pLoadArray->GetUpperBound()) ! 354: AfxThrowArchiveException(CArchiveException::badIndex); ! 355: ! 356: pClassRef = (CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex); ! 357: } ! 358: ! 359: // allocate a new object based on the class just acquired ! 360: CObject* pOb = pClassRef->CreateObject(); ! 361: ASSERT(pOb != NULL); ! 362: ! 363: // Add to mapping array BEFORE de-serializing ! 364: m_pLoadArray->InsertAt(m_nMapCount++, pOb, 1); ! 365: ! 366: pOb->Serialize(*this); ! 367: ! 368: ASSERT(pOb != NULL); ! 369: if (pClassRefRequested && !pOb->IsKindOf(pClassRefRequested)) ! 370: AfxThrowArchiveException(CArchiveException::badClass); ! 371: ! 372: return pOb; ! 373: } ! 374: ! 375: ! 376: UINT ! 377: CArchive::Read(void FAR* lpBuf, UINT nMax) ! 378: { ! 379: ASSERT_VALID(m_pFile); ! 380: ASSERT(lpBuf != NULL); ! 381: ASSERT(m_lpBufStart != NULL); ! 382: ASSERT(m_lpBufCur != NULL); ! 383: ASSERT(AfxIsValidAddress(lpBuf, nMax)); ! 384: ASSERT(AfxIsValidAddress(m_lpBufStart, (UINT)(m_lpBufMax - m_lpBufStart))); ! 385: ASSERT(AfxIsValidAddress(m_lpBufCur, (UINT)(m_lpBufMax - m_lpBufCur))); ! 386: ASSERT(IsLoading()); ! 387: ! 388: register UINT nRead = 0; ! 389: ! 390: if (nMax == 0) ! 391: return 0; ! 392: ! 393: while (nMax > 0) ! 394: { ! 395: UINT nCopy = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur)); ! 396: _fmemcpy(lpBuf, m_lpBufCur, nCopy); ! 397: m_lpBufCur += nCopy; ! 398: lpBuf = ((BYTE FAR*)lpBuf) + nCopy; ! 399: nMax -= nCopy; ! 400: nRead += nCopy; ! 401: if (nMax != 0) ! 402: FillBuffer(min(nMax, (UINT)m_nBufSize)); ! 403: } ! 404: return nRead; ! 405: } ! 406: ! 407: void ! 408: CArchive::Write(const void FAR* lpBuf, UINT nMax) ! 409: { ! 410: ASSERT_VALID(m_pFile); ! 411: ASSERT(m_lpBufStart != NULL); ! 412: ASSERT(m_lpBufCur != NULL); ! 413: ASSERT(AfxIsValidAddress(lpBuf, nMax)); ! 414: ASSERT(AfxIsValidAddress(m_lpBufStart, (UINT)(m_lpBufMax - m_lpBufStart))); ! 415: ASSERT(AfxIsValidAddress(m_lpBufCur, (UINT)(m_lpBufMax - m_lpBufCur))); ! 416: ASSERT(IsStoring()); ! 417: ! 418: register void FAR* lpBufT = (void FAR*)lpBuf; ! 419: ! 420: while (nMax > 0) ! 421: { ! 422: UINT nCopy = min(nMax, (UINT)(m_lpBufMax - m_lpBufCur)); ! 423: _fmemcpy(m_lpBufCur, lpBufT, nCopy); ! 424: m_lpBufCur += nCopy; ! 425: lpBufT = ((BYTE FAR*)lpBufT) + nCopy; ! 426: nMax -= nCopy; ! 427: if (nMax != 0) ! 428: { ! 429: // write out the current buffer to file ! 430: if (m_lpBufCur != m_lpBufStart) ! 431: m_pFile->Write(m_lpBufStart, m_lpBufCur - m_lpBufStart); ! 432: ! 433: // restore buffer to initial state ! 434: m_lpBufCur = m_lpBufStart; ! 435: } ! 436: } ! 437: } ! 438: ! 439: ! 440: void ! 441: CArchive::Flush() ! 442: { ! 443: ASSERT(m_lpBufStart != NULL); ! 444: ASSERT(m_lpBufCur != NULL); ! 445: ASSERT_VALID(m_pFile); ! 446: ASSERT(m_lpBufStart != NULL); ! 447: ASSERT(m_lpBufCur != NULL); ! 448: ASSERT(AfxIsValidAddress(m_lpBufStart, (UINT)(m_lpBufMax - m_lpBufStart))); ! 449: ASSERT(AfxIsValidAddress(m_lpBufCur, (UINT)(m_lpBufMax - m_lpBufCur))); ! 450: ! 451: if (IsLoading()) ! 452: { ! 453: // unget the characters in the buffer, seek back unused amount ! 454: m_pFile->Seek(-(m_lpBufMax - m_lpBufCur), CFile::current); ! 455: m_lpBufCur = m_lpBufMax; // empty ! 456: } ! 457: else ! 458: { ! 459: // write out the current buffer to file ! 460: if (m_lpBufCur != m_lpBufStart) ! 461: { ! 462: m_pFile->Write(m_lpBufStart, m_lpBufCur - m_lpBufStart); ! 463: m_pFile->Flush(); ! 464: } ! 465: ! 466: // restore buffer to initial state ! 467: m_lpBufCur = m_lpBufStart; ! 468: } ! 469: } ! 470: ! 471: void ! 472: CArchive::FillBuffer(UINT nBytesNeeded) ! 473: { ! 474: ASSERT(IsLoading()); ! 475: ASSERT_VALID(m_pFile); ! 476: ASSERT(m_lpBufStart != NULL); ! 477: ASSERT(m_lpBufCur != NULL); ! 478: ASSERT(nBytesNeeded > 0); ! 479: ASSERT(AfxIsValidAddress(m_lpBufStart, (UINT)(m_lpBufMax - m_lpBufStart))); ! 480: ASSERT(AfxIsValidAddress(m_lpBufCur, (UINT)(m_lpBufMax - m_lpBufCur))); ! 481: ! 482: ! 483: // fill up the current buffer from file ! 484: if (m_lpBufCur > m_lpBufStart) ! 485: { ! 486: // there is at least some room to fill ! 487: UINT nUnused = 0; // bytes remaining in buffer ! 488: UINT nActual = 0; // bytes read from file ! 489: ! 490: if ((nUnused = m_lpBufMax - m_lpBufCur) > 0) ! 491: { ! 492: _fmemcpy(m_lpBufStart, m_lpBufCur, m_lpBufMax - m_lpBufCur); // copy unused ! 493: } ! 494: ! 495: nActual = m_pFile->Read(m_lpBufStart+nUnused, m_nBufSize-nUnused); ! 496: ! 497: if (nActual < nBytesNeeded) ! 498: // not enough data to fill request ! 499: AfxThrowArchiveException(CArchiveException::endOfFile); ! 500: ! 501: m_lpBufCur = m_lpBufStart; ! 502: m_lpBufMax = m_lpBufStart + nUnused + nActual; ! 503: } ! 504: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.