|
|
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.