MFC analysis (8) CARCHIVE principle

zhaozj2021-02-08  215

CARCHIVE principle

FMD (http://www.fmdstudio.net)

The MFC provides buffer reading and writing of the CARCHIVE class to implement data, while defining the storage and reading scheme of the class object.

The following is an analysis of the internal implementation of CarchVie.

1 Overview

2. Internal data

3. Basic data reading and writing

4. Update of buffer

5. Specify the reading and writing of the length data paragraph

6. Reading and writing of strings

7.cObject derived object read and write

1 Overview

CARCHIVE uses a buffer, which is a memory space as a temporary data storage. The read and write to CARCHIVE will be arranged in this buffer, when the buffer is full or user requirements, the data after the data is read and written to the designated Storage coal quality.

When establishing a CARCHIVE object, you should specify whether its mode is used for buffer reading or is used for buffer writing.

It can be understood that the CARCHIVE object is equivalent to the freight training station of the railway, and the zero-scattered goods are collected. When the total amount arrives at the train, it is shipped from the train.

When receiving the goods from the train, the goods are dispersed to their respective cargo owners. Unlike the freight, delivery, pick-up is performed in time, not with the ticket. Therefore, it is necessary to ensure that the delivery of the goods and pick-up goods must be deposited or taken in the same sequential.

For large goods, it is disassembled into a train unit, run away, takes the goods, and assembles the original.

2. Internal data

Buffer pointer BYTE * M_LPBUFSTART, point to buffer, this buffer may be provided by the underlying CFILE (such as the party cMemfile) object, but it is generally CARCHIVE itself created.

Buffer tail pointer byte * m_lpbufmax;

Buffer Current Position Pointer BYTE * M_LPBUFCUR;

When initialization, if it is a read mode, the current location is on the tail, if it is write mode, the current location at the head:

M_LPBUFCUR = (isloading ())? m_lpbuffax: m_lpbufstart;

3. Basic data reading and writing

For basic data types, such as bytes, double words, etc., you can use ">>", "<<" symbols to read, write.

// Operator definition arrest:

// Insert operation

CARCHIVE & OPERATOR << (Byte by);

CARCHIVE & OPERATOR << (Word W);

CARCHIVE & OPERATOR << (long L);

CARCHIVE & OPERATOR << (DWORD DW);

CARCHIVE & OPERATOR << (float f);

CARCHIVE & OPERATOR << (Double D);

CARCHIVE & OPERATOR << (INT I);

CARCHIVE & OPERATOR << (Short W);

CARCHIVE & OPERATOR << (Char CH);

CARCHIVE & OPERATOR << (unsigned u);

// extraction operation

CARCHIVE & OPERATOR >> (BYTE & BY);

CARCHIVE & OPERATOR >> (Word & W);

CARCHIVE & OPERATOR >> (DWORD & DW);

CARCHIVE & OPERATOR >> (long & l);

CARCHIVE & OPERATOR >> (Float & f);

CARCHIVE & Operator >> (Double & D); Carchive & Operator >> (INT & I);

CARCHIVE & OPERATOR >> (Short & W);

CARCHIVE & OPERATOR >> (CHAR & CH);

CARCHIVE & OPERATOR >> (UNSIGNED & U);

The following is a double word as an example, analyze the original code

Double word insertion (write)

CARCHIVE & CARCHIVE :: Operator << (DWORD DW)

{

IF (M_LPBUFCUR SIZEOF (DWORD> M_LPBUFMAX) // Buffer space is not enough

Flush (); // Buffer content is submitted to the actual storage of coal quality.

IF (! (m_nmode&bnobyteswap)

_Afxbyteswap (dw, m_lpbufcur); // Process byte order

Else

* (DWORD *) M_LPBUFCUR = DW; // Add to the buffer

m_lpbufcur = sizeof (dword); // Mobile current pointer

RETURN * THIS;

}

Double word extraction (read)

CARCHIVE & CARCHIVE :: Operator >> (DWORD & DW)

{

IF (M_LPBUFCUR SIZEOF (DWORD)> M_LPBUFMAX) // Buffer is read

FillBuffer (M_LPBUFMAX - M_LPBUFCUR); // Re-read the content to the buffer

DW = * (dword *) m_lpbufcur; // read double word

m_lpbufcur = sizeof (dword); // Mobile Current Pointer

IF (! (m_nmode&bnobyteswap)

_Afxbyteswap (dw, (byte *) & dw); // Process the byte order

RETURN * THIS;

}

4. Update of buffer

In the above operation, the buffer will be updated when the buffer will be extracted when the buffer is inserted or the buffer will extract.

The buffer calls flush () when the buffer is inserted.

Void Carchive :: flush ()

{

AskERT_VALID (M_PFILE);

Assert (m_bdirectbuffer || m_lpbufstart! = Null);

Assert (m_bdirectbuffer || m_lpbufcur! = Null);

Assert (m_lpbufstart == null ||

AFXISVALIDADDRESS (M_LPBUFSTART, M_LPBUFMAX - M_LPBUFSTART, ISSTORING ()));

Assert (m_lpbufcur == null ||

AFXISVALIDADDRESS (M_LPBUFCUR, M_LPBUFMAX - M_LPBUFCUR, ISSTORING ());

Isloading ())

{

// Unget the Characters in The Buffer, Seek Back Unused Amount

IF (M_LPBUFMAX! = M_LPBUFCUR)

m_pfile-> seek (- (M_LPBUFMAX - M_LPBUFCUR), CFILE :: Current;

m_lpbufcur = m_lpbufmax; // Point to the tail

}

ELSE // write mode

{

IF (! m_bdirectbuffer)

{

/ / Content write to file

IF (m_lpbufcur! = m_lpbufstart) m_pfile-> Write (M_LPBUFSTART, M_LPBUFCUR - M_LPBUFSTART);

}

Else

{

/ / If it is directly for the memory area (eg, cMemfile) (only moving the relevant pointer, point to the new memory)

IF (m_lpbufcur! = m_lpbuffstart)

m_pfile-> getBufferptr (cfile :: buffercommit, m_lpbufcur - m_lpbufstart);

// Get Next Buffer

Verify (m_pfile-> getBufferptr (cfile :: bufferwrite, m_nbufsize,

(void **) & m_lpbufstart, (void **) & m_lpbufmax) == (uint) m_nbufsize;

Assert ((uint) m_nbufsize == (uint) (M_LPBUFMAX - M_LPBUFSTART));

}

m_lpbufcur = m_lpbufstart; // Point to the first buffer

}

}

The buffer will extract air will call GFILEBuffer, NBytesneeded is a useful byte on the current remaining part.

Void Carchive :: FillBuffer (uint nbytesneed)

{

AskERT_VALID (M_PFILE);

Assert (isloading ());

Assert (m_bdirectbuffer || m_lpbufstart! = Null);

Assert (m_bdirectbuffer || m_lpbufcur! = Null);

Assert (nbytesneeded> 0);

Assert (nbytesneeded <= (uint) m_nbufsize;

Assert (m_lpbufstart == null ||

AFXISVALIDADDRESS (M_LPBUFMAX - M_LPBUFSTART, FALSE);

Assert (m_lpbufcur == null ||

AFXISVALIDADDRESS (M_LPBUFCUR, M_LPBUFMAX - M_LPBUFCUR, FALSE);

UINT NUNUSED = M_LPBUFMAX - M_LPBUFCUR;

Ulong ntotalneeded = (ulong) NBYTESNEDEDED NUNUSED;

// Read from the file

IF (! m_bdirectbuffer)

{

Assert (m_lpbufcur! = Null);

Assert (m_lpbufstart! = Null);

Assert (m_lpbufmax! = Null);

IF (m_lpbufcur> m_lpbufstart)

{

/ / Retain the remaining parts that have not been processed, move them to the head

IF ((int) nunused> 0)

{

Memmove (M_LPBUFSTART, M_LPBUFCUR, NUNUSED);

m_lpbufcur = m_lpbufstart;

M_LPBUFMAX = M_LPBUFSTART NUNUSED;

}

// read to satisfy nbytesneeded or nleft if Possible

Uint NREAD = NunUses;

UINT NLEFT = m_nbufsize-nunused;

Uint nbytes;

BYTE * lptemp = m_lpbufstart nunused; do

{

NBYTES = m_pfile-> read (lptemp, nleft);

LPTEMP = LPTEMP NBYTES;

NREAD = NBYTES;

NLEFT - = Nbytes;

}

While (Nbytes> 0 && NLEFT> 0 && Nread

m_lpbufcur = m_lpbufstart;

M_LPBUFMAX = M_LPBUFSTART NREAD;

}

}

Else

{

/ / If it is for the memory area, a mobile related pointer, point to a new piece of memory

IF (Nunused! = 0)

M_pfile-> seek ((long) nunused, cfile :: current);

UINT NACTUAL = m_pfile-> getBufferptr (cfile :: bufferread, m_nbufsize,

(void **) & m_lpbufstart, (void **) & m_lpbufffmax);

Assert (Nactual == (UINT) (M_LPBUFMAX - M_LPBUFSTART);

m_lpbufcur = m_lpbufstart;

}

// Not Enough Data To Fill Request?

IF ((Ulong) (M_LPBUFMAX - M_LPBUFCUR)

AFXTHROWARCHIVEEXCEPTION (CARCHIVEEXCEPTION :: Endoffile);

}

5. Specify the reading and writing of the length data paragraph

The following analysis

UINT READ (VOID * LPBUF, UINT NMAX); data reading length NMAX

Void Write (const void * lpbuf, uint nmax); data writes to specify the length Nmax

For read and write to large segment data, first read or write content or space in the current buffer, if these spaces are enough, they end.

Otherwise, a piece of data of the maximum buffer integer multiple is found from the remaining data, and directly read and write to the storage coal quality (not repeatedly using the buffer).

The remaining number of remaining parts, then read and write using the buffer.

(Description: The main purpose of the buffer reading and writing is to process the scattered data in a buffer size. For large data, between the part, the part, not zero-scattered data, the use of the buffer is not meaningful, so directly read and write)

1 read

UINT CARCHIVE :: Read (Void * Lpbuf, UINT NMAX)

{

AskERT_VALID (M_PFILE);

IF (nmax == 0)

Return 0;

UINT nmaxtemp = nmax; // The length of the read is also needed, and the read portion is read, and the corresponding value is reduced until this value becomes zero.

// Process the remainder in the current buffer.

// If the read bytes are required to be less than the remainder in the buffer, the first part is the number of bytes that require read.

/ / Otherwise read all remaining parts

Uint ntemp = min (nmaxtemp, (uint) (M_LPBUFMAX - M_LPBUFCUR));

Memcpy (LPBUF, M_LPBUFCUR, NTEMP);

M_LPBUFCUR = NTEMP;

LPBUF = (Byte *) LPBUF NTEMP; / / Move pointers in the area where the content is located

NmaxTemp - = NTEMP;

// The remainder in the current buffer is not required to be read. // The byte needs to be read, then perform several fill buffers and read as needed until the specified byte is read.

IF (nmaxtemp! = 0)

{

/ / Calculate the byte size of the undispet portion (integer buffer size)

// For these parts, bytes are read from the file object, put it in the output buffer

ntemp = nmaxtemp - (nmaxtemp% m_nbufsize);

UINT NREAD = 0;

UINT NLEFT = NTEMP;

Uint nbytes;

DO

{

nbytes = m_pfile-> read (lpbuf, nleft); // Requires reading this integer buffer part size

LPBUF = (Byte *) lpbuf nbytes;

NREAD = NBYTES;

NLEFT - = Nbytes;

}

While (NBYTES> 0) && (NLEFT> 0)); knowing the predetermined size, or reaches the file

NmaxTemp - = NREAD;

If (nuced == ntemp) // The byte read is equal to the reading of the integer number of the read, which is the last remaining portion.

{

// Cover the work buffer of the CARCHIVE containing the contents of this last number.

IF (! m_bdirectbuffer)

{

UINT NLEFT = Max (nmaxtemp, (uint) m_nbufsize;

Uint nbytes;

BYTE * lptemp = m_lpbufstart;

NREAD = 0;

DO

{

nbytes = m_pfile-> read (lptemp, nleft); / / read from the file to the CARCHIVE buffer

LPTEMP = LPTEMP NBYTES;

NREAD = NBYTES;

NLEFT - = Nbytes;

}

While (NBYTES> 0) && (NLEFT> 0) && Nread

m_lpbufcur = m_lpbufstart;

M_LPBUFMAX = M_LPBUFSTART NREAD;

}

Else

{

NREAD = m_pfile-> getBufferptr (cfile :: bufferread, m_nbufsize,

(void **) & m_lpbufstart, (void **) & m_lpbufffmax);

Assert (NREAD == (UINT) (M_LPBUFMAX - M_LPBUFSTART);

m_lpbufcur = m_lpbufstart;

}

/ / Read this remainder to the output

ntemp = min (nmaxtemp, (uint) (M_LPBUFMAX - M_LPBUFCUR));

Memcpy (LPBUF, M_LPBUFCUR, NTEMP);

M_LPBUFCUR = NTEMP;

NmaxTemp - = NTEMP;

}

}

Return nmax - nmaxtemp;

}

2 save, write

Void Carchive :: Write (const void * lpbuf, uint nmax)

{

IF (nmax == 0)

Return;

// Read the possible part to the current remainder of the buffer

Uint ntemp = min (nmax, (uint) (M_LPBUFMAX - M_LPBUFCUR));

Memcpy (M_LPBUFCUR, LPBUF, NTEMP); M_LPBUFCUR = NTEMP;

LPBUF = (Byte *) LPBUF NTEMP;

Nmax - = NTEMP;

IF (nmax> 0) // There is no part to be written

{

Flush (); // Write the current buffer to storage coal quality

/ / Calculate the number of bytes of the integer multiple buffer size

ntemp = nmax - (nmax% m_nbufsize);

m_pfile-> write (lpbuf, ntemp); // Write directly to the file

LPBUF = (Byte *) LPBUF NTEMP;

Nmax - = NTEMP;

// The remainder is added to the buffer

IF (m_bdirectbuffer)

{

// Sync Up Direct Mode Buffer to New File Position

Verify (m_pfile-> getBufferptr (cfile :: bufferwrite, m_nbufsize,

(void **) & m_lpbufstart, (void **) & m_lpbufmax) == (uint) m_nbufsize;

Assert ((uint) m_nbufsize == (uint) (M_LPBUFMAX - M_LPBUFSTART));

m_lpbufcur = m_lpbufstart;

}

// Copy Remaining to Active Buffer

Assert (nmax <(uint) m_nbufsize;

Assert (m_lpbufcur == m_lpbufstart);

Memcpy (M_LPBUFCUR, LPBUF, NMAX);

M_LPBUFCUR = Nmax;

}

}

6. Reading and writing of strings

1. WritestRing and ReadString provided by Carchive

Character string

Void Carchive :: WriteString (LPCTSTR LPSZ)

{

ASSERT (AFXISVALIDSTRING (LPSZ));

Write (LPSZ, LSTRLEN (LPSZ) * SIZEOF (TCHAR)); // Call WRITE, write a data of a string corresponding to

}

Character reading (read a string of strings)

LPTSTR CARCHIVE :: ReadString (LPTSTR LPSZ, UINT NMAX)

{

// if nmax is negative (Such A Large Number Doesn't make Sense Given Today's

// 2GB Address Space, The AssumeT to Mean "Keep The Newline".

INT NSTOP = (int) nmax <0? - (int) Nmax: (int) Nmax;

ASSERT (AFXISVALIDIDDRESS (LPSZ, (NSTOP 1) * sizeof (tchar)));

_Tuchar CH;

INT NREAD = 0;

Try

{

While (NREAD

{

* this >> CH; // read a byte

// stop and end-of-line (trailing '/ n' is ignored) changing line - Enter

IF (CH == '/ n' || CH == '/ r')

{

IF (CH == '/ r')

* this >> CH;

// store the newline when Called with negative nmaxif ((int) nmax! = nstop)

LPSZ [NREAD ] = CH;

Break;

}

LPSZ [NREAD ] = CH;

}

}

Catch (CARCHIVEXCEPTION, E)

{

IF (e-> m_cause == carchiveException :: endoffile)

{

DELETE_EXCEPTION (E);

IF (NREAD == 0)

Return NULL;

}

Else

{

Throw_last ();

}

}

END_CATCH

LPSZ [NREAD] = '/ 0';

Return LPSZ;

}

ReadString to CString objects, you can make multiple characters

Bool Carchive :: ReadString (CString & Rstring)

{

Rstring = & afxchnil; // Empty string without deallocating

Const int nmaxsize = 128;

LPTSTR LPSZ = RString.getBuffer (NMAXSIZE);

LPTSTSTR LPSZRESULT;

Int Nlen;

For (;;)

{

LpszResult = readstring (lpsz, (uint) -nmaxsize; // store the newline

rstring.releasebuffer ();

// if string is read completion or eof

IF (lpszResult == null ||

(Nlen = lstrlen (lpsz))

LPSZ [NLEN-1] == '/ n')

{

Break;

}

Nlen = rstring.getLength ();

LPSZ = RString.getBuffer (NmaxSize Nlen) Nlen;

}

// Remove '/ n' from end of string if present

LPSZ = RString.getBuffer (0);

Nlen = rstring.getLength ();

IF (Nlen! = 0 && LPSZ [NLEN-1] == '/ n')

Rstring.getBuffersetLength (Nlen-1);

Return lpszResult! = null;

}

2 read strings with "<<" and ">>" in CSTRING object

CString Defines the input and output, which can be used as the basic type of data. Use CARCHIVE

Operator definition

Friend CARCHIVE & AFXAPI Operator << (CARCHIVE & Ar, Const Cstring & String);

Friend Carchive & Afxapi Operator >> (CARCHIVE & Ar, CString & String);

// CString Serialization Code

// String Format:

// unicode strings are always prefixed by 0xff, 0xffe

// IF <0xff Chars: Len: Byte, Tchar Chars // IF> = 0xff Characters: 0xff, Len: Word, Tchar Chars

// if> = 0xffe characters: 0xff, 0xffff, len: dword, tchars

Carchive & AFXAPI Operator << (Carchive & Ar, Const Cstring & String)

{

// Special Signature to Recognize Unicode Strings

#ifdef _unicode

Ar << (Byte) 0xFF;

Ar << (Word) 0xffe;

#ENDIF

IF (String.getdata () -> NDATALENGTH <255)

{

Ar << (byte) string.getdata () -> ndatalength;

}

Else IF (String.getData () -> NDATALENGTH <0xffe)

{

Ar << (Byte) 0xFF;

Ar << (word) string.getdata () -> NDATALENGTH;

}

Else

{

Ar << (Byte) 0xFF;

AR << (word) 0xfff;

Ar << (dword) string.getdata () -> NDATALENGTH;

}

ar.write (string.m_pchdata) -> nDaTangth * sizeof (tchar);

Return AR;

}

// Return String Length or -1 if uncode string is found in the archive

AFX_STATIC uint AfxApi _AFXReadStringLength (carchive & ar)

{

DWORD NNEWLEN

// Attempt byte Length Firsth First

Byte blen;

Ar >> Blen;

IF (Blen <0xFF)

Return blen;

// Attempt Word LENGTH

Word Wlen;

AR >> WLEN;

IF (wlen == 0xffe)

{

// Unicode String Prefix (Length Will Follow)

Return (uint) -1;

}

ELSE IF (Wlen == 0xfff)

{

// read DWord of Length

AR >> NNEWLEN;

Return (uint) nnewlen;

}

Else

Return Wlen;

}

CARCHIVE & AFXAPI Operator >> (CARCHIVE & Ar, CString & String)

{

#ifdef _unicode

INT nConvert = 1; // if we get Ansi, Convert

#ELSE

INT nConvert = 0; // if We get unicode, Convert

#ENDIF

Uint nnewlen = _afxreadstringLength (AR);

IF (nnewlen == (uint) -1)

{

NCONVERT = 1 - NCONVERT;

nnewlen = _afxreadstringLENGTH (AR); Assert (nnewlen! = -1);

}

// set length of string to new length

Uint nbytelen = nnewlen;

#ifdef _unicode

String.getBuffersetLength (INT) NNEWLEN;

NBytelen = nbytelen * (1 - nconvert); // bytes to read

#ELSE

NBytelen = nbytelen * nconvert; // bytes to read

IF (nnewlen == 0)

String.getBuffersetLength (0);

Else

String.getBuffersetLength (INT) NBYTELEN NCONVERT);

#ENDIF

// read in the characters

IF (nnewlen! = 0)

{

Assert (nbytelen! = 0);

// read new data

IF (ar.read (string.m_pchdata, nbytelen)! = nbytelen

AFXTHROWARCHIVEEXCEPTION (CARCHIVEEXCEPTION :: Endoffile);

// Convert the data if as necessary

IF (nconvert! = 0)

{

#ifdef _unicode

CStringData * PoldData = String.getdata ();

LPSTR LPSZ = (LPSTR) String.m_pchdata;

#ELSE

CStringData * PoldData = String.getdata ();

LPWSTR LPSZ = (LPWSTR) String.m_pchdata;

#ENDIF

LPSZ [NNEWLEN] = '/ 0'; // must be nul terminated

String.init (); // Don't delete the old data

String = LPSZ; // Convert with operator = (LPWCSTR)

CSTRING :: Freedata (PoldData);

}

}

Return AR;

}

7.cObject derived object read and write

Most classes in the MFC are derived from the COBJECT class, and the COBJECT class has a good relationship with the CARCHIVE class, which can implement the object serialization to file or other media, or read the pre-stored object, dynamically establish objects.

1cObject defines the input and output operators for Carvhive, you can use "<<", "<<" symbol like other basic data types.

CARCHIVE & AFXAPI Operator << (Carchive & Ar, Const Cobject * POB)

{Ar.WriteObject (POB); Return Ar;}

CARCHIVE & AFXAPI Operator >> (CARCHIVE & AR, COBJECT * & POB)

{Pob = ar.readObject (null); return ar;}

When using these symbols, actually executing CARCHIVE WRITEOBJECT and READOBJECT members

2WriteObject with readobject

In WriteObject and ReadObject, write or read runtime information (CRUNTIMECLAS), then call serialze (..), and write the specific object data. Therefore, as long as the Serilize () function is overloaded in the COBJECT derived class, the object can be stored and creative.

// Write the object to the buffer

Void Carchive :: WriteObject (const cobject * pob)

{

DWORD NOBINDEX;

// 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) [(void *) POB])! = 0)

// Assumes Initialized to 0 MAP

{

// Save out index of already stiled object

NoBindex

* this << (word) NobIndex;

Else

{

* this << wbigObjecttag;

* this << NobIndex;

}

}

Else

{

// Write Class of Object First First First

Cruntimeclass * pclassref = POB-> getRuntimeClass ();

WriteClass (PCLASSREF); // Write to run information

// Enter in Stored Object Table, Checking for overflow

Checkcount ();

(* m_pStoremap) [(void *) pob] = (void *) m_nmapcount ;

// Call the COBJECT's Serialize member, written in the class data.

((COBJECT *) POB -> Serialize (* this);

}

}

COBJECT * CARCHIVE :: readObject (const cruntimeclass * pclassrefrequested)

{

// Attempt to load next stream as cruntimeclass

Uint nschema;

DWORD OBTAG;

// read the runtime information

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

AfXTHROWARCHIVEXCEPTION (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

{

// Establish an object

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); // Call the COBJECT's Serialize, press the code to read the object data.

m_nObjectschema = nschemasave;

Assert_Valid (POB);

}

Return POB;

}

3 Read and write of runtime information

To avoid many duplicate similar objects to write duplicate class information, CMAP objects are used to store and retrieve classes in CARCHIVE.

Void Carchive :: WriteClass (const cruntimeclass * pclassref)

{

Assert (PCLASSREF! = NULL);

Assert (isstoring ()); // Proper Direction

IF (PCLASSREF-> m_wschema == 0xfff)

{

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 indeicate

// New Object Follows

// Assume: Initialized to 0 MAP

DWORD NCLASSINDEX;

IF ((NclassIndex = (DWORD) [(void *) PCLASSREF])! = 0)

{

// previously seen class, write out the index tagged by high bit

NclassIndex

* 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 == 0xfff)

{

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 Ten 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 & DWBIGCLASTAG))

{

IF (pobtag == null)

AFXTHROWARCHIVEXCEPTION (CARCHIVEXCEPTION :: 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 (CARCHIVEXCEPTION :: 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 ())

AfXTHROWARCHIVEXCEPTION (CARCHIVEEXCEPTION :: BadIndex,

m_strfilename;

PCLASSREF = (cruntimeclass *) m_ploadArray-> getat (nclassindex);

Assert (PCLASSREF! = NULL);

// determine Schema Stored Against Objects of this Type

Void * ptemp;

Bool bfound = false;

NSChema = 0;

IF (m_pschemamap! = null)

{

BFOUND = m_pschemamap-> look (PclassRef, PTEMP);

IF (bFound)

nschema = (uint) PTEMP;

}

IF (! bfound)

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 eschema

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;

}

转载请注明原文地址:https://www.9cbs.com/read-3155.html

New Post(0)