Serializable CListCtrl with check sum verify

More questions on Discussion board are based on store/load a list control to file. One way to serialize the list control is to save information about the header of list control, and then serialize all items from list control. The idea is to open a file in CFile::modeCreate or CFile::modeRead depending on kind of operation, store or load the list control. Then we will create a archive object from this file to easily store/load the objects. For more security this method has implemented a check sum of file.

Storing information in file.

First we will save a signature, as sample I chose this to be ‘ListCtrl – ObjectStore’, for a short check of file type. Then we will store a double word where at the end of the storing operation we will put the calculated check sum. After that, each column in stored, and finished with a -1 value to limit the definitions of columns in file.

Loading information from file.

Read signature. If this is what I stored, then I get the check sum from file, to verify with check sum of file. If all these are right,the loading continues as with the storing procedure.

The implementation contain a class CCheckArchive, and function Serialize. The CCheckArchive class has some virtual functions overridable ( like operator <<, used in Serialize functions) to complete the check sum.

For more detail, I invite the user to see the code. For store/load list control the user can call the function ::Serialize, with the folowing arguments. First is the destinatin list control, the second is the file name, and the last argument is the required operation; TRUE for storing, FALSE for loading. I think that the function Serialize and CCheckArchive, can be easly extended. Any kind of help, or information I will receive/send with pleasure.

Sincerely, Mihai Filimon

class CCheckArchive : public CArchive
{
	DWORD m_wCheckSum;
protected:

	// Function name : Sum
	// Description   : Add every byte from wData
	// Return type   : static DWORD
	// Argument      : DWORD wData
	static DWORD Sum(DWORD wData)
	{
		return HIBYTE(HIWORD(wData)) + LOBYTE(HIWORD(wData)) +
				HIBYTE(LOWORD(wData)) + LOBYTE(LOWORD(wData));
	};

public:

	// Function name : CCheckArchive
	// Description   : Contructor uses in Serialize() function
	// Return type   :
	// Argument      : CFile* pFile
	// Argument      : UINT nMode
	CCheckArchive(CFile* pFile, UINT nMode) : CArchive( pFile, nMode, 4096, NULL )
	{
		m_wCheckSum = 0;
	}

	// Function name : ~CCheckArchive
	// Description   : Destructor
	// Return type   : virtual
	virtual ~CCheckArchive() {};

	// Function name : operator <<
	// Description   : This operator is call in Serialize function. Add
	//				   every byte write in file, in m_wCheckSum
	// Return type   : virtual CArchive&
	// Argument      : DWORD wData
	virtual CArchive& operator << (DWORD wData)
	{
		m_wCheckSum += Sum(wData);
		return ((CArchive&)*this) << wData;
	}

	// Function name : operator <<
	// Description   : This operator is call in Serialize function. Add
	//				   every byte write in file, in m_wCheckSum
	// Return type   : virtual CArchive&
	// Argument      : CString& sData
	virtual CArchive& operator << (CString& sData)
	{
		LPTSTR lpszS = (LPTSTR)(LPCTSTR)sData;

		while (*lpszS)
		m_wCheckSum += BYTE(*lpszS++);
		m_wCheckSum += Sum(sData.GetLength());
		return ((CArchive&)*this) << sData;
	}

	// Function name : GetCheckSum
	// Description   : Return the calculated check sum
	// Return type   : DWORD
	DWORD GetCheckSum()
	{
		return m_wCheckSum;
	};

	// Function name : GetLastPosition
	// Description   : Called for found the position of file in write
	//				   operation
	// Return type   : DWORD
	DWORD GetLastPosition()
	{
		return m_lpBufCur - m_lpBufStart;
	};

	// Function name : Verify
	// Description   : Check if chkSum verify the file, that must be in
	//				   loading
	// Return type   : BOOL
	// Argument      : DWORD chkSum
	BOOL Verify(DWORD chkSum)
	{
		static const max = 2048;
		DWORD w = 0;
		ASSERT (IsLoading());
		TRY
		{
			CFile* pFile = GetFile();
			DWORD bookmark = pFile->GetPosition();
			pFile->SeekToBegin();
			BYTE buffer[max], *pBuffer = NULL;
			int nRead = 0;
			while (nRead = pFile->Read(&buffer, max))
			{
				pBuffer = buffer;
				for (int i = 0; i < nRead; i++, w += *pBuffer++);
			}
			w -= Sum(chkSum);
			pFile->Seek(bookmark, CFile::begin);
		}
		CATCH_ALL(e)
		{
			return FALSE;
		}
		END_CATCH_ALL;
		return w == chkSum;
	}
};

// Function name : Serialize
// Description   : Call this function to store/load a list control
// Return type   : BOOL
// Argument      : CListCtrl* pListCtrl
// Argument      : LPCTSTR lpszFileName
// Argument      : BOOL bStoring = TRUE
BOOL Serialize(CListCtrl* pListCtrl, LPCTSTR lpszFileName, BOOL bStoring = TRUE)
{
	static const TCHAR* lpszSignature = _T("ListCtrl - StoreObject");
	CFile file;
	if (file.Open(lpszFileName, bStoring ? CFile::modeWrite | CFile::modeCreate: CFile::modeRead))
	TRY
	{
		CString s; CCheckArchive ar(&file, bStoring ? CArchive::store :CArchive::load);
		DWORD chkSum = 0;
		if (bStoring)
		{
			ar << CString(lpszSignature);
			DWORD sC = ar.GetLastPosition();
			ar << chkSum;
			LV_COLUMN column; TCHAR buffer[MAX_PATH]; int i = NULL, nColumn = 0;

			column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
			column.pszText = buffer;
			column.cchTextMax = MAX_PATH;
			for (i = 0; pListCtrl->GetColumn(i, &column); i++, nColumn++)
			{
				ar << column.fmt;
				ar << column.cx;
				ar << CString(column.pszText);
			}
			ar << UINT(-1);
			int n = pListCtrl->GetItemCount();
			ar << n;
			for (i = 0; i < n; i++)
			{
				for (int j = 0; j < nColumn; j++)
				ar << pListCtrl->GetItemText(i, j);
				ar << pListCtrl->GetItemData(i);
			}
			ar.Flush();
			ar.GetFile()->Seek(sC,CFile::begin);
			chkSum = ar.GetCheckSum();
			ar.GetFile()->Write(&chkSum, sizeof(chkSum));
		}
		else
		{
			ar >> s;
			if (s.Compare(lpszSignature) == 0)
			{
				ar >> chkSum;
				if (ar.Verify(chkSum))
				{
					CString text;
					text.Format(_T("%i"),chkSum);
					AfxMessageBox(text);
					LV_COLUMN column; TCHAR buffer[MAX_PATH]; int i = NULL, nColumn = 0;
					column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
					column.pszText = buffer;
					column.cchTextMax = MAX_PATH;
					for (; TRUE; nColumn++)
					{
						ar >> column.fmt;
						if (column.fmt < 0) break;
						ar >> column.cx;
						ar >> s;
						column.pszText = (LPTSTR)(LPCTSTR)s;
						pListCtrl->InsertColumn(nColumn, &column);
					}
					int n = NULL;
					ar >> n;
					for (i = 0; i < n; i++)
					{
						int nItem = pListCtrl->InsertItem(i, _T(""));
						for (int j = 0; j < nColumn; j++)
						{
							ar >> s;
							pListCtrl->SetItemText(nItem, j, s);
						}
						DWORD wData;
						ar >> wData;
						pListCtrl->SetItemData(nItem, wData);
					}
				}
			}
		}
		ar.Close();
		file.Close();
	}
	CATCH_ALL(e)
	{
		return FALSE;
	}
	END_CATCH_ALL
	return TRUE;
}

Last updated: 29 July 1998 by Rob Osborne

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read